Skip to content

Fix FilterSchema list parsing for PEP 695 type aliases (#1720)#1734

Open
Vansh-Sharma27 wants to merge 1 commit into
vitalik:masterfrom
Vansh-Sharma27:fix/filterschema-list-type-alias
Open

Fix FilterSchema list parsing for PEP 695 type aliases (#1720)#1734
Vansh-Sharma27 wants to merge 1 commit into
vitalik:masterfrom
Vansh-Sharma27:fix/filterschema-list-type-alias

Conversation

@Vansh-Sharma27

Copy link
Copy Markdown

Summary

Fixes #1720.

When a PEP 695 type alias for a list[...] type is used in a FilterSchema field, the query parameter fails to parse:

{"detail": [{"type": "list_type", "loc": ["query", "name"], "msg": "Input should be a valid list"}]}

Minimal repro from the issue:

type name_list = Annotated[list[str] | None, FilterLookup("name__in")]

class BookFilter(FilterSchema):
    name: name_list = Field(default=None)

Root cause

type X = ... produces a typing.TypeAliasType whose real annotation lives in __value__, and get_origin() on it returns None. Pydantic stores the alias verbatim as the field annotation, so:

  1. is_collection_type() in ninja/signature/details.py never sees the underlying list, so the field is not registered as a collection and repeated query params are not collected into a list.
  2. FilterSchema._get_filter_lookup() reads field_info.metadata, which is empty for an aliased field, so a FilterLookup defined inside the alias was silently dropped.

Point 2 matters: fixing only the parsing turns the loud 422 into a silently wrong lookup (name instead of name__in), so both paths needed handling.

Changes

  • Add TYPE_ALIAS_TYPES to ninja/compatibility/util.py (covers both the stdlib 3.12+ class and the typing_extensions backport).
  • is_collection_type() now unwraps TypeAliasType (and a contained Annotated) before checking the origin.
  • _get_filter_lookup() now also reads FilterLookup metadata from inside the alias.

Non-list aliases and plain Annotated fields are unchanged.

Tests

Added three tests to tests/test_filter_schema.py:

  • test_filter_lookup_from_list_type_alias — the inner FilterLookup is applied.
  • test_list_type_alias_query_parsing — repeated query params parse into a list (this is the exact 422 from the issue).
  • test_non_list_type_alias_still_works — regression guard for scalar aliases.

The tests build the alias via TypeAliasType(...) (the same runtime object the type statement creates) so the file still imports on Python < 3.12. I confirmed the two bug-specific tests fail on master and pass with the fix.

pytest, ruff format --check, ruff check, and mypy ninja all pass.

A `type X = list[...]` alias used in a FilterSchema field was not unwrapped,
so collection detection treated the field as a scalar and query parsing failed
with "Input should be a valid list". A FilterLookup defined inside the alias
was also dropped because pydantic does not surface the alias metadata.

Unwrap TypeAliasType (and the Annotated it may contain) in is_collection_type,
and read FilterLookup from the alias annotation directly in _get_filter_lookup.

Fixes vitalik#1720
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] filter with list type alias fails to parse

1 participant