-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
[WIP] Add Python version checks to native parser #21539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -167,8 +167,9 @@ | |
|
|
||
|
|
||
| class State: | ||
| def __init__(self, options: Options) -> None: | ||
| def __init__(self, options: Options, is_stub: bool = False) -> None: | ||
| self.options = options | ||
| self.is_stub = is_stub | ||
| self.errors: list[ParseError] = [] | ||
| self.num_funcs = 0 | ||
|
|
||
|
|
@@ -180,6 +181,22 @@ def add_error( | |
| {"line": line, "column": column, "message": message, "blocker": blocker, "code": code} | ||
| ) | ||
|
|
||
| def check_min_version( | ||
| self, feature: str, min_version: tuple[int, int], line: int, column: int | ||
| ) -> None: | ||
| """Report a non blocker syntax error if the target Python feature is older than min_version.""" | ||
| if self.is_stub: | ||
| return | ||
| if self.options.python_version < min_version: | ||
| self.add_error( | ||
| f"{feature} are only supported in Python " | ||
| f"{min_version[0]}.{min_version[1]} and greater", | ||
| line, | ||
| column, | ||
| blocker=False, | ||
| code="syntax", | ||
| ) | ||
|
|
||
|
|
||
| def native_parse( | ||
| filename: str, | ||
|
|
@@ -607,6 +624,13 @@ def read_parameters(state: State, data: ReadBuffer) -> tuple[list[Argument], boo | |
| return arguments, has_ann | ||
|
|
||
|
|
||
| def check_type_param_defaults( | ||
| state: State, type_params: list[TypeParam], line: int, column: int | ||
| ) -> None: | ||
| if any(p.default is not None for p in type_params): | ||
| state.check_min_version("Type parameter defaults", (3, 13), line, column) | ||
|
|
||
|
|
||
| def read_type_params(state: State, data: ReadBuffer) -> list[TypeParam]: | ||
| """Read type parameters (PEP 695 generics).""" | ||
| type_params: list[TypeParam] = [] | ||
|
|
@@ -680,6 +704,9 @@ def read_func_def(state: State, data: ReadBuffer) -> FuncDef: | |
| if is_async: | ||
| 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| check_type_param_defaults(state, type_params, func_def.line, func_def.column) | ||
| if typ: | ||
| typ.line = func_def.line | ||
| typ.column = func_def.column | ||
|
|
@@ -727,6 +754,9 @@ def read_class_def(state: State, data: ReadBuffer) -> ClassDef: | |
| ) | ||
| 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to above (name of feature). |
||
| check_type_param_defaults(state, type_params, class_def.line, class_def.column) | ||
| expect_end_tag(data) | ||
| return class_def | ||
|
|
||
|
|
@@ -781,6 +811,8 @@ def read_type_alias_stmt(state: State, data: ReadBuffer) -> TypeAliasStmt: | |
|
|
||
| stmt = TypeAliasStmt(name, type_params, lambda_expr) | ||
| read_loc(data, stmt) | ||
| state.check_min_version('"type" statements', (3, 12), stmt.line, stmt.column) | ||
| check_type_param_defaults(state, type_params, stmt.line, stmt.column) | ||
| expect_end_tag(data) | ||
| return stmt | ||
|
|
||
|
|
@@ -832,6 +864,10 @@ def read_try_stmt(state: State, data: ReadBuffer) -> TryStmt: | |
| stmt = TryStmt(body, vars_list, types_list, handlers, else_body, finally_body) | ||
| stmt.is_star = is_star | ||
| read_loc(data, stmt) | ||
| if is_star: | ||
| state.check_min_version("Exception groups", (3, 11), stmt.line, stmt.column) | ||
| if state.options.python_version < (3, 11): | ||
| stmt.is_star = False | ||
| expect_end_tag(data) | ||
| return stmt | ||
|
|
||
|
|
@@ -1474,6 +1510,7 @@ def read_expression(state: State, data: ReadBuffer) -> Expression: | |
| titems.append(s) | ||
| expr = TemplateStrExpr(titems) | ||
| read_loc(data, expr) | ||
| state.check_min_version("t-strings", (3, 14), expr.line, expr.column) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ( |
||
| expect_end_tag(data) | ||
| return expr | ||
| elif tag == nodes.LAMBDA_EXPR: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also add a note like "Current target Python version is X.Y"?