Skip to content

fix: pep 695 named alias union fix#6

Open
msnidal wants to merge 2 commits into
masterfrom
mark/pep-695-named-alias-union-fix
Open

fix: pep 695 named alias union fix#6
msnidal wants to merge 2 commits into
masterfrom
mark/pep-695-named-alias-union-fix

Conversation

@msnidal

@msnidal msnidal commented Jul 23, 2026

Copy link
Copy Markdown

CodeAnt-AI Description

Fix validation for named type aliases, including generic aliases

What Changed

  • Validation now correctly follows named type aliases instead of failing on aliased values
  • Generic aliases with type parameters now resolve their inner type before validating data
  • Added coverage for aliased request objects and list aliases with type arguments

Impact

✅ Correct validation for aliased fields
✅ Support for generic type aliases in data validation
✅ Fewer validation failures on PEP 695 aliases

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Jul 23, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 0a3a1e0 Jul 23, 2026 · 22:01 22:04

@codeant-ai codeant-ai Bot added the size:M This PR changes 30-99 lines, ignoring generated files label Jul 23, 2026
Comment on lines +317 to +320
for parameter, argument in zip(
origin.__type_params__, get_args(cls), strict=True
):
type_vars2[id(parameter)] = argument

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The generic type-alias argument binding assumes a 1:1 parameter-to-argument mapping by using zip(..., strict=True), which raises ValueError for valid aliases that use variadic parameters (for example TypeVarTuple/ParamSpec) where one parameter can correspond to multiple arguments. This causes validation to crash with an uncaught exception instead of performing validation; update this mapping logic to handle variadic type parameters explicitly rather than strict pairwise zipping. [api mismatch]

Severity Level: Major ⚠️
❌ Validation crashes for PEP 695 variadic type aliases.
⚠️ Advanced generic alias support fails with uncaught exceptions.
⚠️ Downstream services see ValueError instead of DataValidationError.
Steps of Reproduction ✅
1. In consumer code using this library, define a PEP 695 variadic named type alias with a
TypeVarTuple, e.g. `P = TypeVarTuple("P"); VariadicTupleAlias =
TypeAliasType("VariadicTupleAlias", tuple[*P], type_params=(P,))`, mirroring the existing
TypeAliasType usage pattern in `tests/test_basic.py:22-33`.

2. From the same consumer module (or a new test next to `tests/test_basic.py:48-95` which
already calls `validate`), call the public API `validate((1, "a"), VariadicTupleAlias[int,
str])` imported from `src/latch_data_validation/data_validation.py:39-62`.

3. The call to `validate()` at `data_validation.py:39-59` delegates to
`untraced_validate()` at `data_validation.py:32-36`, which in turn invokes
`_untraced_validate(x, cls, type_vars={})` starting at `data_validation.py:38-55` with
`cls` set to `VariadicTupleAlias[int, str]`.

4. Inside `_untraced_validate`, `get_origin(cls)` is not None and is a `TypeAliasType`,
triggering the branch at `data_validation.py:164-172`; the loop `for parameter, argument
in zip(origin.__type_params__, get_args(cls), strict=True):` at lines `317-319` sees
`origin.__type_params__` of length 1 (the variadic `P`) and `get_args(cls)` of length 2
(`int`, `str`), so `zip(..., strict=True)` raises a `ValueError` before any
`DataValidationError` handling, causing `validate()` to crash with an uncaught exception
whenever a variadic type alias is used.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/latch_data_validation/data_validation.py
**Line:** 317:320
**Comment:**
	*Api Mismatch: The generic type-alias argument binding assumes a 1:1 parameter-to-argument mapping by using `zip(..., strict=True)`, which raises `ValueError` for valid aliases that use variadic parameters (for example `TypeVarTuple`/`ParamSpec`) where one parameter can correspond to multiple arguments. This causes validation to crash with an uncaught exception instead of performing validation; update this mapping logic to handle variadic type parameters explicitly rather than strict pairwise zipping.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty sure the existing typing.Generic handler also fails this, we just don't support ParamSpec or TypeVarTuple right now

supporting that here without support for Callable isn't super useful anyway

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Customized review instruction saved!

Instruction:

Do not flag variadic generic alias binding issues in src/latch_data_validation/data_validation.py for ParamSpec or TypeVarTuple, since support for those variadic generics is not implemented here and would not be useful without Callable support as well.

Applied to:

  • src/latch_data_validation/data_validation.py

💡 To manage or update this instruction, visit: CodeAnt AI Settings

Comment thread tests/test_basic.py
_ = validate({"waiting_reason": "unknown"}, AliasedRequest)


def test_generic_type_alias() -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge this into test_type_alias

Comment thread tests/test_basic.py


AliasT = TypeVar("AliasT")
TestBox = TypeAliasType("TestBox", list[AliasT], type_params=(AliasT,))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move these test resources into the test function rather than defining globally

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, test this only on Python 3.12+ since that's when the type A = B syntax was added

nobody is going around making TypeAliasType instances by hand, it used to just be

A: TypeAlias = B

which is transparent at runtime

Comment thread tests/test_basic.py
)

TestWaitingReason = TypeAliasType(
"TestWaitingReason", typing.Literal["workspace_capacity", "taiga_rate_limited"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this a much simpler test that doesn't also overlap with dataclasses support etc. unless there is a reason for it?

also don't pull in actual names/scenarios from other projects here

x: JsonValue, cls: TypeForm[T], *, type_vars: dict[int, TypeForm[object]]
) -> T:
# todo(maximsmol): improve error messages with generics
alias_origin = get_origin(cls)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already run get_origin later, don't run it twice

probably just move this code down unless it really needs to go first (in which case move the get_origin call up instead)

alias_origin = get_origin(cls)
if isinstance(alias_origin, TypeAliasType):
type_vars2 = {**type_vars}
for parameter, argument in zip(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this duplicates code that handles typing.Generic, which should actually just be able to handle this directly anyway

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants