Skip to content

Read string types in PEP 695/696 positions, skip Literal values and Annotated metadata - #367

Merged
hakancelikdev merged 1 commit into
claude/integrationfrom
fix/pep695-string-types-and-literal
Sep 25, 2026
Merged

hakancelikdev merged 1 commit into
claude/integrationfrom
fix/pep695-string-types-and-literal

Conversation

@hakancelikdev

Copy link
Copy Markdown
Owner

From the core-dev review of claude/integration. Follow-up to #344 (issue #329); these cases also exist on main.

Problems

  1. String forward references in new type positions were ignored, so the imports they name were removed and type checking broke:
    • type Money = "Decimal" (PEP 695)
    • def f[T: "Fraction" = "Number"](), class Box[*Ts = "Protocol"] (type-param bound and default, PEP 695/696)
    • TypeVar("T", default="Decimal"), ParamSpec("P", default=...), TypeVarTuple(..., default=...) (PEP 696)
  2. Literal["os"] kept an unused import os. Literal is in SUBSCRIPT_TYPE_VARIABLE, so visit_Subscript parsed its strings before the _is_type_expression guard could run. The guard only worked for t.Literal[...].
  3. Annotated[int, "Decimal"] metadata was parsed as a type by visit_Subscript in the same way.

Fix

  • _is_type_expression recognizes ast.TypeAlias.value and the bound / default_value of ast.TypeVar / ParamSpec / TypeVarTuple. These nodes are looked up with getattr, since they don't exist on 3.9–3.11.
  • visit_Call reads default= for all three factories. Constraints are still read for TypeVar only.
  • visit_Subscript skips Literal[...] and parses only the first element of Annotated[...].

Tests

  • typing/string_type_parameters (3.13+) and typing/string_literal_and_defaults are new. Both fail before this change.
  • typing/function_str_arg is regenerated. It asserted the old behavior, where "Literal['Dict']" counted as a use of Dict; 'Dict' there is a literal value, so Dict is unused.
  • Full suite passes on 3.9 / 3.12 / 3.14, and the cases also pass on 3.13. Pre-commit passes.

🤖 Generated with Claude Code

https://claude.ai/code/session_019P9bvuGwAyVCNUdsAYPB1V


Generated by Claude Code

…nnotated metadata

- `type X = "Y"`, type parameter bounds and defaults
  (`def f[T: "Y" = "Z"]`) and TypeVar/ParamSpec/TypeVarTuple
  `default="Y"` are type expressions, so the imports they name are used.
- visit_Subscript parsed every string in a typing subscript, including
  bare `Literal["os"]` values and `Annotated[T, "meta"]` metadata, which
  kept unused imports. Literal is skipped and only Annotated's first
  element is parsed. The function_str_arg case expected the old behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019P9bvuGwAyVCNUdsAYPB1V
@hakancelikdev
hakancelikdev merged commit 9c7b1f6 into claude/integration Sep 25, 2026
40 checks passed
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.

2 participants