From 62a1a70c88b23de7f1d530a6cebaebcb2b28129f Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 1 Sep 2023 12:52:24 -0700 Subject: [PATCH 1/2] Make PEP 695 constructs give a reasonable error message Mypy does not yet support PEP 695 Fixes #16011, linking #15238 --- mypy/fastparse.py | 31 +++++++++++++++++++++++++ mypy/test/helpers.py | 4 +++- mypy/test/testcheck.py | 2 ++ test-data/unit/check-python312.test | 35 +++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test-data/unit/check-python312.test diff --git a/mypy/fastparse.py b/mypy/fastparse.py index 6aa626afb81e..a96e697d40bf 100644 --- a/mypy/fastparse.py +++ b/mypy/fastparse.py @@ -144,6 +144,11 @@ def ast3_parse( NamedExpr = ast3.NamedExpr Constant = ast3.Constant +if sys.version_info >= (3, 12): + ast_TypeAlias = ast3.TypeAlias +else: + ast_TypeAlias = Any + if sys.version_info >= (3, 10): Match = ast3.Match MatchValue = ast3.MatchValue @@ -936,6 +941,14 @@ def do_func_def( arg_types = [AnyType(TypeOfAny.from_error)] * len(args) return_type = AnyType(TypeOfAny.from_error) else: + if sys.version_info >= (3, 12) and n.type_params: + self.fail( + ErrorMessage("PEP 695 generics are not yet supported", code=codes.VALID_TYPE), + n.type_params[0].lineno, + n.type_params[0].col_offset, + blocker=False, + ) + arg_types = [a.type_annotation for a in args] return_type = TypeConverter( self.errors, line=n.returns.lineno if n.returns else lineno @@ -1110,6 +1123,14 @@ def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef: self.class_and_function_stack.append("C") keywords = [(kw.arg, self.visit(kw.value)) for kw in n.keywords if kw.arg] + if sys.version_info >= (3, 12) and n.type_params: + self.fail( + ErrorMessage("PEP 695 generics are not yet supported", code=codes.VALID_TYPE), + n.type_params[0].lineno, + n.type_params[0].col_offset, + blocker=False, + ) + cdef = ClassDef( n.name, self.as_required_block(n.body), @@ -1717,6 +1738,16 @@ def visit_MatchOr(self, n: MatchOr) -> OrPattern: node = OrPattern([self.visit(pattern) for pattern in n.patterns]) return self.set_line(node, n) + def visit_TypeAlias(self, n: ast_TypeAlias) -> AssignmentStmt: + self.fail( + ErrorMessage("PEP 695 type aliases are not yet supported", code=codes.VALID_TYPE), + n.lineno, + n.col_offset, + blocker=False, + ) + node = AssignmentStmt([NameExpr(n.name.id)], self.visit(n.value)) + return self.set_line(node, n) + class TypeConverter: def __init__( diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index d1850219e60a..7447391593d5 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -241,7 +241,9 @@ def num_skipped_suffix_lines(a1: list[str], a2: list[str]) -> int: def testfile_pyversion(path: str) -> tuple[int, int]: - if path.endswith("python311.test"): + if path.endswith("python312.test"): + return 3, 12 + elif path.endswith("python311.test"): return 3, 11 elif path.endswith("python310.test"): return 3, 10 diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index 7b81deeafe9d..b20e8cc25f3d 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -43,6 +43,8 @@ typecheck_files.remove("check-python310.test") if sys.version_info < (3, 11): typecheck_files.remove("check-python311.test") +if sys.version_info < (3, 12): + typecheck_files.remove("check-python312.test") # Special tests for platforms with case-insensitive filesystems. if sys.platform not in ("darwin", "win32"): diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test new file mode 100644 index 000000000000..a1718d91479f --- /dev/null +++ b/test-data/unit/check-python312.test @@ -0,0 +1,35 @@ +[case test695TypeAlias] +type MyInt = int # E: PEP 695 type aliases are not yet supported + +def f(x: MyInt) -> MyInt: + return reveal_type(x) # N: Revealed type is "builtins.int" + +type MyList[T] = list[T] # E: PEP 695 type aliases are not yet supported \ + # E: Name "T" is not defined + +def g(x: MyList[int]) -> MyList[int]: # E: Variable "__main__.MyList" is not valid as a type \ + # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases + return reveal_type(x) # N: Revealed type is "MyList?[builtins.int]" + +[case test695Class] +class MyGen[T]: # E: PEP 695 generics are not yet supported + def __init__(self, x: T) -> None: # E: Name "T" is not defined + self.x = x + +def f(x: MyGen[int]): # E: "MyGen" expects no type arguments, but 1 given + reveal_type(x.x) # N: Revealed type is "Any" + +[case test695Function] +def f[T](x: T) -> T: # E: PEP 695 generics are not yet supported \ + # E: Name "T" is not defined + return reveal_type(x) # N: Revealed type is "Any" + +reveal_type(f(1)) # N: Revealed type is "Any" + +async def g[T](x: T) -> T: # E: PEP 695 generics are not yet supported \ + # E: Name "T" is not defined + return reveal_type(x) # N: Revealed type is "Any" + +reveal_type(g(1)) # E: Value of type "Coroutine[Any, Any, Any]" must be used \ + # N: Are you missing an await? \ + # N: Revealed type is "typing.Coroutine[Any, Any, Any]" From df01fa17dd7aed3b2689dd145d2a60033df1817d Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 1 Sep 2023 15:46:31 -0700 Subject: [PATCH 2/2] more test --- test-data/unit/check-python312.test | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index a1718d91479f..91aca7794071 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -33,3 +33,27 @@ async def g[T](x: T) -> T: # E: PEP 695 generics are not yet supported \ reveal_type(g(1)) # E: Value of type "Coroutine[Any, Any, Any]" must be used \ # N: Are you missing an await? \ # N: Revealed type is "typing.Coroutine[Any, Any, Any]" + +[case test695TypeVar] +from typing import Callable +type Alias1[T: int] = list[T] # E: PEP 695 type aliases are not yet supported +type Alias2[**P] = Callable[P, int] # E: PEP 695 type aliases are not yet supported \ + # E: Value of type "int" is not indexable \ + # E: Name "P" is not defined +type Alias3[*Ts] = tuple[*Ts] # E: PEP 695 type aliases are not yet supported \ + # E: Type expected within [...] \ + # E: The type "Type[Tuple[Any, ...]]" is not generic and not indexable \ + # E: Name "Ts" is not defined + +class Cls1[T: int]: ... # E: PEP 695 generics are not yet supported +class Cls2[**P]: ... # E: PEP 695 generics are not yet supported +class Cls3[*Ts]: ... # E: PEP 695 generics are not yet supported + +def func1[T: int](x: T) -> T: ... # E: PEP 695 generics are not yet supported +def func2[**P](x: Callable[P, int]) -> Callable[P, str]: ... # E: PEP 695 generics are not yet supported \ + # E: The first argument to Callable must be a list of types, parameter specification, or "..." \ + # N: See https://mypy.readthedocs.io/en/stable/kinds_of_types.html#callable-types-and-lambdas \ + # E: Name "P" is not defined +def func3[*Ts](x: tuple[*Ts]) -> tuple[int, *Ts]: ... # E: PEP 695 generics are not yet supported \ + # E: Name "Ts" is not defined +[builtins fixtures/tuple.pyi]