Skip to content

Add Python version checks to native parser#21539

Open
KevinRK29 wants to merge 7 commits into
python:masterfrom
KevinRK29:version-check-native-parser
Open

Add Python version checks to native parser#21539
KevinRK29 wants to merge 7 commits into
python:masterfrom
KevinRK29:version-check-native-parser

Conversation

@KevinRK29
Copy link
Copy Markdown
Collaborator

@KevinRK29 KevinRK29 commented May 25, 2026

The native parser (rust based) previously accepted newer Python syntax without checking the configured target Python version, whereas the legacy parser (fastparse) would report when a feature isn't available on the target (although those would be blocking errors). This PR adds those compatibility checks to the native parser so that it produces a non blocking error.

The feature gates added are:

  • improved type parameter syntax for Python 3.12
  • type parameter defaults for Python 3.13
  • type alias statements for Python 3.12
  • exception groups (except*) for Python 3.11
  • star unpack for Python 3.11
  • t-strings for Python 3.14

I've also moved the tests that would now introduce a python version check error to it's own test file so that it gets the correct Python versoin

In a later PR, I will be adding support for checking this feature since it requires modifying the rust parser a bit:

  • Parentheses optional for multiple exception types in except

@github-actions

This comment has been minimized.

@KevinRK29 KevinRK29 force-pushed the version-check-native-parser branch from fc2b267 to 3a8407e Compare May 25, 2026 08:24
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

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

Also these features may need checks:

  • Star unpack (tuple[*Ts]) introduced in 3.11
  • Parentheses optional for multiple exception types in except

The latter may require changes to the parser. If that's the case, we can leave it until later.

Comment thread mypy/nativeparse.py
Comment thread mypy/nativeparse.py Outdated
func_def.is_coroutine = True
read_loc(data, func_def)
if type_params:
state.check_min_version("Type parameter lists", (3, 12), func_def.line, func_def.column)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe call this feature "Improved type parameter syntax"? You'd need to use singular "is" instead of "are" in the error message in this case, or leave out the verb altogether.

Comment thread mypy/nativeparse.py Outdated
class_def.decorators = decorators
read_loc(data, class_def)
if type_params:
state.check_min_version("Type parameter lists", (3, 12), class_def.line, class_def.column)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Similar to above (name of feature).

Comment thread mypy/nativeparse.py Outdated
titems.append(s)
expr = TemplateStrExpr(titems)
read_loc(data, expr)
state.check_min_version("t-strings", (3, 14), expr.line, expr.column)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think T-strings are a bit special since they need to new stdlib type, and it's not defined on older versions. This means that we probably shouldn't allow them in stubs either unless targeting 3.14 or later. Also this is important to test using real stubs (pythoneval.test) to ensure the missing type doesn't cause issues.

@github-actions

This comment has been minimized.

@KevinRK29
Copy link
Copy Markdown
Collaborator Author

@JukkaL

So looking at this further, currently the stance is that version check errors are non blocking, so they have blocker = false, which lets type checking continue against an AST that's been parsed for a feature the target Python doesn't support? Currently we reset the is_star from True to False after we encounter it with the version issue, but that would cause a divergence in the AST. This would also affect what the reveal_type would show.

If we keep it as non blocking but don't reset the is_star, it would cause a mypy crash with INTERNAL_ERROR because typeshed gates that class for the specific version and would complain that the symbol isn't in the builtins symbol table.

The other alernative is to keep make it a blocking error just for this case, however im not sure if that would be inconsistent since it may cause confusion for the user on whether version checks do block or not? Or we follow fastparse and always block.

@KevinRK29
Copy link
Copy Markdown
Collaborator Author

regarding this feature:

  • Parentheses optional for multiple exception types in except

I believe i would need to update the rust side to record whether the source used parenthesis and then have the python read it and do the version check, so it might be better to do it in a later pr

@KevinRK29 KevinRK29 requested a review from JukkaL May 28, 2026 08:28
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

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

I think it's fine to just assign False to the is_star flag for now, since that feature isn't available on older Python versions, and it's more important to not generate a blocking error than to provide the same AST we'd generate on a newer version.

Comment thread test-data/unit/pythoneval.test
Comment thread test-data/unit/native-parser.test Outdated
except* ValueError:
y
[out]
1:0: error: Exception groups: requires Python 3.11 or newer (current target: Python 3.10)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You can move these tests to a new native-parser-python311.test file and register it in test_nativeparse.py so that you'll get the correct Python version set (and similarly for test cases the require 3.12, etc.).

from typing_extensions import TypeVarTuple, Unpack
Ts = TypeVarTuple("Ts")
def f(x: tuple[Unpack[Ts]]) -> None: ...
def g(x: tuple[*Ts]) -> None: ...
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add reveal_type(g) and check what happens if we call g. It's okay if this behaves inconsistently, as long as it doesn't crash and doesn't do anything very strange.

@KevinRK29 KevinRK29 force-pushed the version-check-native-parser branch from 04e318a to 2871a66 Compare May 29, 2026 05:07
@KevinRK29 KevinRK29 force-pushed the version-check-native-parser branch from 2871a66 to faa7f42 Compare May 29, 2026 05:22
@github-actions
Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@KevinRK29
Copy link
Copy Markdown
Collaborator Author

sounds good then, i've addressed the comments!

@KevinRK29 KevinRK29 changed the title [WIP] Add Python version checks to native parser Add Python version checks to native parser May 29, 2026
@KevinRK29 KevinRK29 requested a review from JukkaL May 29, 2026 06:09
@KevinRK29 KevinRK29 marked this pull request as ready for review May 29, 2026 06:09
Copy link
Copy Markdown
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

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

Thanks, looks good! One more thing -- can you add a pythoneval test that uses the new generics syntax in a .pyi file while targeting 3.10? The test case can be added in a follow-up PR if you prefer.

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