From 226b528d0034da97544dec157dcb1ae034592c16 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Wed, 17 Apr 2024 09:24:01 -0700 Subject: [PATCH] Fixed bugs in two of the conformance tests: "generics_basic" and "generics_upper_bound". (#1720) These tests attempted to validate that type checkers enforced the rule that constraints and upper bounds within a TypedDict definition cannot be parameterized by other type variables (i.e. cannot be generic). The way the tests were written, they weren't actually testing this check. This allowed mypy and pyre (which both fail to catch this condition) to pass the tests. I've updated the test so it properly tests this condition. --- conformance/results/mypy/generics_basic.toml | 33 ++++----- .../results/mypy/generics_upper_bound.toml | 17 ++--- conformance/results/mypy/version.toml | 2 +- conformance/results/pyre/generics_basic.toml | 29 ++++---- .../results/pyre/generics_upper_bound.toml | 8 +-- conformance/results/pyre/version.toml | 2 +- .../results/pyright/generics_basic.toml | 19 +++-- .../results/pyright/generics_upper_bound.toml | 9 ++- .../results/pytype/generics_basic.toml | 38 +++++----- .../results/pytype/generics_upper_bound.toml | 16 ++--- conformance/results/pytype/version.toml | 2 +- conformance/results/results.html | 12 ++-- conformance/tests/generics_basic.py | 72 ++++++++++++------- conformance/tests/generics_upper_bound.py | 11 +-- 14 files changed, 149 insertions(+), 121 deletions(-) diff --git a/conformance/results/mypy/generics_basic.toml b/conformance/results/mypy/generics_basic.toml index 3fc747bf9..024c77561 100644 --- a/conformance/results/mypy/generics_basic.toml +++ b/conformance/results/mypy/generics_basic.toml @@ -1,20 +1,21 @@ -conformant = "Pass" +conformant = "Partial" +notes = """ +Does not reject the use of a constraint parameterized by another type variable. +""" output = """ -generics_basic.py:36: error: Value of type variable "AnyStr" of "concat" cannot be "Sequence[object]" [type-var] -generics_basic.py:37: error: Value of type variable "AnyStr" of "concat" cannot be "Sequence[object]" [type-var] -generics_basic.py:44: error: TypeVar cannot have only a single constraint [misc] -generics_basic.py:48: error: Type variable "generics_basic.T" is unbound [valid-type] -generics_basic.py:48: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) -generics_basic.py:48: note: (Hint: Use "T" in function signature to bind "T" inside a function) -generics_basic.py:59: error: Value of type variable "AnyStr" of "concat" cannot be "Sequence[object]" [type-var] -generics_basic.py:107: error: Duplicate type variables in Generic[...] or Protocol[...] [misc] -generics_basic.py:140: error: Invalid index type "int" for "MyMap1[str, int]"; expected type "str" [index] -generics_basic.py:141: error: Invalid index type "int" for "MyMap2[int, str]"; expected type "str" [index] -generics_basic.py:167: error: Dynamic metaclass not supported for "GenericMetaInstance" [misc] -generics_basic.py:167: error: Type variable "generics_basic.T" is unbound [valid-type] -generics_basic.py:167: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) -generics_basic.py:167: note: (Hint: Use "T" in function signature to bind "T" inside a function) +generics_basic.py:40: error: Value of type variable "AnyStr" of "concat" cannot be "Sequence[object]" [type-var] +generics_basic.py:41: error: Value of type variable "AnyStr" of "concat" cannot be "Sequence[object]" [type-var] +generics_basic.py:49: error: TypeVar cannot have only a single constraint [misc] +generics_basic.py:69: error: Value of type variable "AnyStr" of "concat" cannot be "Sequence[object]" [type-var] +generics_basic.py:121: error: Duplicate type variables in Generic[...] or Protocol[...] [misc] +generics_basic.py:157: error: Invalid index type "int" for "MyMap1[str, int]"; expected type "str" [index] +generics_basic.py:158: error: Invalid index type "int" for "MyMap2[int, str]"; expected type "str" [index] +generics_basic.py:191: error: Dynamic metaclass not supported for "GenericMetaInstance" [misc] +generics_basic.py:191: error: Type variable "generics_basic.T" is unbound [valid-type] +generics_basic.py:191: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) +generics_basic.py:191: note: (Hint: Use "T" in function signature to bind "T" inside a function) """ -conformance_automated = "Pass" +conformance_automated = "Fail" errors_diff = """ +Line 55: Expected 1 errors """ diff --git a/conformance/results/mypy/generics_upper_bound.toml b/conformance/results/mypy/generics_upper_bound.toml index b8c4e670f..4cf18a8f0 100644 --- a/conformance/results/mypy/generics_upper_bound.toml +++ b/conformance/results/mypy/generics_upper_bound.toml @@ -1,12 +1,13 @@ -conformant = "Pass" +conformant = "Partial" +notes = """ +Does not reject use of type variable within an upper bound. +""" output = """ -generics_upper_bound.py:22: error: Type variable "generics_upper_bound.T" is unbound [valid-type] -generics_upper_bound.py:22: note: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) -generics_upper_bound.py:22: note: (Hint: Use "T" in function signature to bind "T" inside a function) -generics_upper_bound.py:41: error: Expression is of type "Collection[int]", not "list[int] | set[int]" [assert-type] -generics_upper_bound.py:48: error: Value of type variable "ST" of "longer" cannot be "int" [type-var] -generics_upper_bound.py:53: error: TypeVar cannot have both values and an upper bound [misc] +generics_upper_bound.py:43: error: Expression is of type "Collection[int]", not "list[int] | set[int]" [assert-type] +generics_upper_bound.py:51: error: Value of type variable "ST" of "longer" cannot be "int" [type-var] +generics_upper_bound.py:56: error: TypeVar cannot have both values and an upper bound [misc] """ -conformance_automated = "Pass" +conformance_automated = "Fail" errors_diff = """ +Line 24: Expected 1 errors """ diff --git a/conformance/results/mypy/version.toml b/conformance/results/mypy/version.toml index 4f076d3cf..da96566e1 100644 --- a/conformance/results/mypy/version.toml +++ b/conformance/results/mypy/version.toml @@ -1,2 +1,2 @@ version = "mypy 1.9.0" -test_duration = 1.6 +test_duration = 1.5 diff --git a/conformance/results/pyre/generics_basic.toml b/conformance/results/pyre/generics_basic.toml index 0def91060..186066834 100644 --- a/conformance/results/pyre/generics_basic.toml +++ b/conformance/results/pyre/generics_basic.toml @@ -1,26 +1,27 @@ conformant = "Partial" notes = """ False positives in examples using constrained type variables. +False negative for constraint parameterized by a type variable. False negative in custom map example. False positive using `iter`. False negative for generic metaclass. """ output = """ -generics_basic.py:31:4 Incompatible return type [7]: Expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`. -generics_basic.py:31:15 Incompatible parameter type [6]: In call `bytes.__add__`, for 1st positional argument, expected `Union[array[typing.Any], bytearray, bytes, _CData, memoryview, mmap, PickleBuffer]` but got `Variable[AnyStr <: [str, bytes]]`. -generics_basic.py:36:14 Incompatible parameter type [6]: In call `concat`, for 2nd positional argument, expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`. -generics_basic.py:37:14 Incompatible parameter type [6]: In call `concat`, for 2nd positional argument, expected `Variable[AnyStr <: [str, bytes]]` but got `str`. -generics_basic.py:44:0 Invalid type [31]: TypeVar can't have a single explicit constraint. Did you mean `bound=str`? -generics_basic.py:48:0 Invalid type [31]: Expression `Variable[BadConstraint2 <: [str, Variable[generics_basic.T]]]` is not a valid type. Type variables cannot contain other type variables in their constraints. -generics_basic.py:59:14 Incompatible parameter type [6]: In call `concat`, for 2nd positional argument, expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`. -generics_basic.py:107:0 Duplicate type variables [59]: Duplicate type variable `T` in Generic[...]. -generics_basic.py:161:25 Undefined attribute [16]: `typing.Iterator` has no attribute `__getitem__`. +generics_basic.py:34:4 Incompatible return type [7]: Expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`. +generics_basic.py:34:15 Incompatible parameter type [6]: In call `bytes.__add__`, for 1st positional argument, expected `Union[array[typing.Any], bytearray, bytes, _CData, memoryview, mmap, PickleBuffer]` but got `Variable[AnyStr <: [str, bytes]]`. +generics_basic.py:40:14 Incompatible parameter type [6]: In call `concat`, for 2nd positional argument, expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`. +generics_basic.py:41:14 Incompatible parameter type [6]: In call `concat`, for 2nd positional argument, expected `Variable[AnyStr <: [str, bytes]]` but got `str`. +generics_basic.py:49:0 Invalid type [31]: TypeVar can't have a single explicit constraint. Did you mean `bound=str`? +generics_basic.py:55:57 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Type[Variable[_T]]` but got `TypeVar`. +generics_basic.py:69:14 Incompatible parameter type [6]: In call `concat`, for 2nd positional argument, expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`. +generics_basic.py:121:0 Duplicate type variables [59]: Duplicate type variable `T` in Generic[...]. +generics_basic.py:182:25 Undefined attribute [16]: `typing.Iterator` has no attribute `__getitem__`. """ conformance_automated = "Fail" errors_diff = """ -Line 140: Expected 1 errors -Line 141: Expected 1 errors -Line 167: Expected 1 errors -Line 31: Unexpected errors ['generics_basic.py:31:4 Incompatible return type [7]: Expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`.', 'generics_basic.py:31:15 Incompatible parameter type [6]: In call `bytes.__add__`, for 1st positional argument, expected `Union[array[typing.Any], bytearray, bytes, _CData, memoryview, mmap, PickleBuffer]` but got `Variable[AnyStr <: [str, bytes]]`.'] -Line 161: Unexpected errors ['generics_basic.py:161:25 Undefined attribute [16]: `typing.Iterator` has no attribute `__getitem__`.'] +Line 157: Expected 1 errors +Line 158: Expected 1 errors +Line 191: Expected 1 errors +Line 34: Unexpected errors ['generics_basic.py:34:4 Incompatible return type [7]: Expected `Variable[AnyStr <: [str, bytes]]` but got `bytes`.', 'generics_basic.py:34:15 Incompatible parameter type [6]: In call `bytes.__add__`, for 1st positional argument, expected `Union[array[typing.Any], bytearray, bytes, _CData, memoryview, mmap, PickleBuffer]` but got `Variable[AnyStr <: [str, bytes]]`.'] +Line 182: Unexpected errors ['generics_basic.py:182:25 Undefined attribute [16]: `typing.Iterator` has no attribute `__getitem__`.'] """ diff --git a/conformance/results/pyre/generics_upper_bound.toml b/conformance/results/pyre/generics_upper_bound.toml index d3c483acd..19ae4ce0b 100644 --- a/conformance/results/pyre/generics_upper_bound.toml +++ b/conformance/results/pyre/generics_upper_bound.toml @@ -3,11 +3,11 @@ notes = """ Does not reject use of upper bound with constrained TypeVar. """ output = """ -generics_upper_bound.py:22:0 Invalid type [31]: Expression `Variable[T_Bad1 (bound to typing.List[Variable[generics_upper_bound.T]])]` is not a valid type. Type variables cannot contain other type variables in their constraints. -generics_upper_bound.py:48:7 Incompatible parameter type [6]: In call `longer`, for 1st positional argument, expected `Variable[ST (bound to Sized)]` but got `int`. -generics_upper_bound.py:48:10 Incompatible parameter type [6]: In call `longer`, for 2nd positional argument, expected `Variable[ST (bound to Sized)]` but got `int`. +generics_upper_bound.py:24:42 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Type[Variable[_T]]` but got `TypeVar`. +generics_upper_bound.py:51:7 Incompatible parameter type [6]: In call `longer`, for 1st positional argument, expected `Variable[ST (bound to Sized)]` but got `int`. +generics_upper_bound.py:51:10 Incompatible parameter type [6]: In call `longer`, for 2nd positional argument, expected `Variable[ST (bound to Sized)]` but got `int`. """ conformance_automated = "Fail" errors_diff = """ -Line 53: Expected 1 errors +Line 56: Expected 1 errors """ diff --git a/conformance/results/pyre/version.toml b/conformance/results/pyre/version.toml index ac8158f0e..3c523460d 100644 --- a/conformance/results/pyre/version.toml +++ b/conformance/results/pyre/version.toml @@ -1,2 +1,2 @@ version = "pyre 0.9.19" -test_duration = 4.0 +test_duration = 3.2 diff --git a/conformance/results/pyright/generics_basic.toml b/conformance/results/pyright/generics_basic.toml index e57f814c9..b18ae527c 100644 --- a/conformance/results/pyright/generics_basic.toml +++ b/conformance/results/pyright/generics_basic.toml @@ -1,20 +1,19 @@ conformant = "Pass" output = """ -generics_basic.py:36:15 - error: Argument of type "bytes" cannot be assigned to parameter "y" of type "AnyStr@concat" in function "concat" +generics_basic.py:40:15 - error: Argument of type "bytes" cannot be assigned to parameter "y" of type "AnyStr@concat" in function "concat"   "bytes" is incompatible with "str" (reportArgumentType) -generics_basic.py:37:15 - error: Argument of type "str" cannot be assigned to parameter "y" of type "AnyStr@concat" in function "concat" +generics_basic.py:41:15 - error: Argument of type "str" cannot be assigned to parameter "y" of type "AnyStr@concat" in function "concat"   "str" is incompatible with "bytes" (reportArgumentType) -generics_basic.py:44:44 - error: TypeVar must have at least two constrained types (reportGeneralTypeIssues) -generics_basic.py:48:49 - error: Type variable "T" has no meaning in this context (reportGeneralTypeIssues) -generics_basic.py:48:49 - error: TypeVar constraint type cannot be generic -generics_basic.py:59:15 - error: Argument of type "bytes" cannot be assigned to parameter "y" of type "AnyStr@concat" in function "concat" +generics_basic.py:49:44 - error: TypeVar must have at least two constrained types (reportGeneralTypeIssues) +generics_basic.py:55:53 - error: TypeVar constraint type cannot be generic +generics_basic.py:69:15 - error: Argument of type "bytes" cannot be assigned to parameter "y" of type "AnyStr@concat" in function "concat"   "bytes" is incompatible with "str" (reportArgumentType) -generics_basic.py:107:24 - error: Type arguments for "Generic" must be unique -generics_basic.py:140:5 - error: Argument of type "Literal[0]" cannot be assigned to parameter "key" of type "str" in function "__getitem__" +generics_basic.py:121:24 - error: Type arguments for "Generic" must be unique +generics_basic.py:157:5 - error: Argument of type "Literal[0]" cannot be assigned to parameter "key" of type "str" in function "__getitem__"   "Literal[0]" is incompatible with "str" (reportArgumentType) -generics_basic.py:141:5 - error: Argument of type "Literal[0]" cannot be assigned to parameter "key" of type "str" in function "__getitem__" +generics_basic.py:158:5 - error: Argument of type "Literal[0]" cannot be assigned to parameter "key" of type "str" in function "__getitem__"   "Literal[0]" is incompatible with "str" (reportArgumentType) -generics_basic.py:167:37 - error: Metaclass cannot be generic (reportGeneralTypeIssues) +generics_basic.py:191:37 - error: Metaclass cannot be generic (reportGeneralTypeIssues) """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/pyright/generics_upper_bound.toml b/conformance/results/pyright/generics_upper_bound.toml index 5075bba9e..bd21bd9ca 100644 --- a/conformance/results/pyright/generics_upper_bound.toml +++ b/conformance/results/pyright/generics_upper_bound.toml @@ -1,16 +1,15 @@ conformant = "Pass" output = """ -generics_upper_bound.py:22:34 - error: TypeVar bound type cannot be generic -generics_upper_bound.py:22:39 - error: Type variable "T" has no meaning in this context (reportGeneralTypeIssues) -generics_upper_bound.py:48:8 - error: Argument of type "Literal[3]" cannot be assigned to parameter "x" of type "ST@longer" in function "longer" +generics_upper_bound.py:24:38 - error: TypeVar bound type cannot be generic +generics_upper_bound.py:51:8 - error: Argument of type "Literal[3]" cannot be assigned to parameter "x" of type "ST@longer" in function "longer"   Type "Literal[3]" is incompatible with type "Sized"     "Literal[3]" is incompatible with protocol "Sized"       "__len__" is not present (reportArgumentType) -generics_upper_bound.py:48:11 - error: Argument of type "Literal[3]" cannot be assigned to parameter "y" of type "ST@longer" in function "longer" +generics_upper_bound.py:51:11 - error: Argument of type "Literal[3]" cannot be assigned to parameter "y" of type "ST@longer" in function "longer"   Type "Literal[3]" is incompatible with type "Sized"     "Literal[3]" is incompatible with protocol "Sized"       "__len__" is not present (reportArgumentType) -generics_upper_bound.py:53:44 - error: TypeVar cannot be both bound and constrained +generics_upper_bound.py:56:44 - error: TypeVar cannot be both bound and constrained """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/pytype/generics_basic.toml b/conformance/results/pytype/generics_basic.toml index bb789883e..2089cc5d7 100644 --- a/conformance/results/pytype/generics_basic.toml +++ b/conformance/results/pytype/generics_basic.toml @@ -4,27 +4,27 @@ False positives in examples using constrained type variables. False negative for generic metaclass. """ output = """ -File "generics_basic.py", line 31, in concat: bad return type [bad-return-type] +File "generics_basic.py", line 34, in concat: bad return type [bad-return-type] Called from (traceback): - line 57, in test_concat_subtype -File "generics_basic.py", line 36, in test_concat: Function concat was called with the wrong arguments [wrong-arg-types] -File "generics_basic.py", line 37, in test_concat: Function concat was called with the wrong arguments [wrong-arg-types] -File "generics_basic.py", line 44, in : Invalid TypeVar: the number of constraints must be 0 or more than 1 [invalid-typevar] -File "generics_basic.py", line 48, in : Invalid TypeVar: constraint cannot contain TypeVars [invalid-typevar] -File "generics_basic.py", line 57, in test_concat_subtype: MyStr [assert-type] -File "generics_basic.py", line 58, in test_concat_subtype: Function concat was called with the wrong arguments [wrong-arg-types] -File "generics_basic.py", line 58, in test_concat_subtype: Any [assert-type] -File "generics_basic.py", line 59, in test_concat_subtype: Function concat was called with the wrong arguments [wrong-arg-types] -File "generics_basic.py", line 107, in : Invalid type annotation 'Generic' [invalid-annotation] -File "generics_basic.py", line 140, in test_my_map: unsupported operand type(s) for item retrieval: MyMap1[str, int] and int [unsupported-operands] -File "generics_basic.py", line 141, in test_my_map: unsupported operand type(s) for item retrieval: MyMap2[int, str] and int [unsupported-operands] -File "generics_basic.py", line 161, in test_my_iterable_any: Iterator[nothing] [assert-type] + line 67, in test_concat_subtype +File "generics_basic.py", line 40, in test_concat: Function concat was called with the wrong arguments [wrong-arg-types] +File "generics_basic.py", line 41, in test_concat: Function concat was called with the wrong arguments [wrong-arg-types] +File "generics_basic.py", line 49, in : Invalid TypeVar: the number of constraints must be 0 or more than 1 [invalid-typevar] +File "generics_basic.py", line 55, in Test: Invalid TypeVar: constraint cannot contain TypeVars [invalid-typevar] +File "generics_basic.py", line 67, in test_concat_subtype: MyStr [assert-type] +File "generics_basic.py", line 68, in test_concat_subtype: Function concat was called with the wrong arguments [wrong-arg-types] +File "generics_basic.py", line 68, in test_concat_subtype: Any [assert-type] +File "generics_basic.py", line 69, in test_concat_subtype: Function concat was called with the wrong arguments [wrong-arg-types] +File "generics_basic.py", line 121, in : Invalid type annotation 'Generic' [invalid-annotation] +File "generics_basic.py", line 157, in test_my_map: unsupported operand type(s) for item retrieval: MyMap1[str, int] and int [unsupported-operands] +File "generics_basic.py", line 158, in test_my_map: unsupported operand type(s) for item retrieval: MyMap2[int, str] and int [unsupported-operands] +File "generics_basic.py", line 182, in test_my_iterable_any: Iterator[nothing] [assert-type] """ conformance_automated = "Fail" errors_diff = """ -Line 167: Expected 1 errors -Line 31: Unexpected errors ['File "generics_basic.py", line 31, in concat: bad return type [bad-return-type]'] -Line 57: Unexpected errors ['File "generics_basic.py", line 57, in test_concat_subtype: MyStr [assert-type]'] -Line 58: Unexpected errors ['File "generics_basic.py", line 58, in test_concat_subtype: Function concat was called with the wrong arguments [wrong-arg-types]', 'File "generics_basic.py", line 58, in test_concat_subtype: Any [assert-type]'] -Line 161: Unexpected errors ['File "generics_basic.py", line 161, in test_my_iterable_any: Iterator[nothing] [assert-type]'] +Line 191: Expected 1 errors +Line 34: Unexpected errors ['File "generics_basic.py", line 34, in concat: bad return type [bad-return-type]'] +Line 67: Unexpected errors ['File "generics_basic.py", line 67, in test_concat_subtype: MyStr [assert-type]'] +Line 68: Unexpected errors ['File "generics_basic.py", line 68, in test_concat_subtype: Function concat was called with the wrong arguments [wrong-arg-types]', 'File "generics_basic.py", line 68, in test_concat_subtype: Any [assert-type]'] +Line 182: Unexpected errors ['File "generics_basic.py", line 182, in test_my_iterable_any: Iterator[nothing] [assert-type]'] """ diff --git a/conformance/results/pytype/generics_upper_bound.toml b/conformance/results/pytype/generics_upper_bound.toml index 52f7af491..a999a23b4 100644 --- a/conformance/results/pytype/generics_upper_bound.toml +++ b/conformance/results/pytype/generics_upper_bound.toml @@ -3,15 +3,15 @@ notes = """ Does not properly support assert_type. """ output = """ -File "generics_upper_bound.py", line 22, in : Invalid TypeVar: bound cannot contain TypeVars [invalid-typevar] -File "generics_upper_bound.py", line 35, in : list [assert-type] -File "generics_upper_bound.py", line 36, in : set [assert-type] -File "generics_upper_bound.py", line 41, in : Union[list, set] [assert-type] -File "generics_upper_bound.py", line 48, in : Function longer was called with the wrong arguments [wrong-arg-types] -File "generics_upper_bound.py", line 53, in : Invalid TypeVar: constraints and a bound are mutually exclusive [invalid-typevar] +File "generics_upper_bound.py", line 24, in Test: Invalid TypeVar: bound cannot contain TypeVars [invalid-typevar] +File "generics_upper_bound.py", line 37, in : list [assert-type] +File "generics_upper_bound.py", line 38, in : set [assert-type] +File "generics_upper_bound.py", line 43, in : Union[list, set] [assert-type] +File "generics_upper_bound.py", line 51, in : Function longer was called with the wrong arguments [wrong-arg-types] +File "generics_upper_bound.py", line 56, in : Invalid TypeVar: constraints and a bound are mutually exclusive [invalid-typevar] """ conformance_automated = "Fail" errors_diff = """ -Line 35: Unexpected errors ['File "generics_upper_bound.py", line 35, in : list [assert-type]'] -Line 36: Unexpected errors ['File "generics_upper_bound.py", line 36, in : set [assert-type]'] +Line 37: Unexpected errors ['File "generics_upper_bound.py", line 37, in : list [assert-type]'] +Line 38: Unexpected errors ['File "generics_upper_bound.py", line 38, in : set [assert-type]'] """ diff --git a/conformance/results/pytype/version.toml b/conformance/results/pytype/version.toml index 69799be6f..8c0b6d235 100644 --- a/conformance/results/pytype/version.toml +++ b/conformance/results/pytype/version.toml @@ -1,2 +1,2 @@ version = "pytype 2024.04.11" -test_duration = 37.5 +test_duration = 35.1 diff --git a/conformance/results/results.html b/conformance/results/results.html index 6e6fe2006..327802ee5 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -159,16 +159,16 @@

Python Type System Conformance Test Results

+ - - + @@ -403,7 +403,7 @@

Python Type System Conformance Test Results

- + diff --git a/conformance/tests/generics_basic.py b/conformance/tests/generics_basic.py index 02a091357..0a35336bd 100644 --- a/conformance/tests/generics_basic.py +++ b/conformance/tests/generics_basic.py @@ -9,11 +9,12 @@ from collections.abc import Sequence from typing import Any, Generic, TypeVar, assert_type -T = TypeVar('T') +T = TypeVar("T") # > Generics can be parameterized by using a factory available in # > ``typing`` called ``TypeVar``. + def first(l: Sequence[T]) -> T: return l[0] @@ -22,14 +23,17 @@ def test_first(seq_int: Sequence[int], seq_str: Sequence[str]) -> None: assert_type(first(seq_int), int) assert_type(first(seq_str), str) + # > ``TypeVar`` supports constraining parametric types to a fixed set of # > possible types -AnyStr = TypeVar('AnyStr', str, bytes) +AnyStr = TypeVar("AnyStr", str, bytes) + def concat(x: AnyStr, y: AnyStr) -> AnyStr: return x + y + def test_concat(s: str, b: bytes, a: Any) -> None: concat(s, s) # OK concat(b, b) # OK @@ -39,20 +43,26 @@ def test_concat(s: str, b: bytes, a: Any) -> None: concat(s, a) # OK concat(a, b) # OK + # > Specifying a single constraint is disallowed. -BadConstraint1 = TypeVar('BadConstraint1', str) # E +BadConstraint1 = TypeVar("BadConstraint1", str) # E # > Note: those types cannot be parameterized by type variables -BadConstraint2 = TypeVar('BadConstraint2', str, T) # E + +class Test(Generic[T]): + BadConstraint2 = TypeVar("BadConstraint2", str, list[T]) # E + # > Subtypes of types constrained by a type variable should be treated # > as their respective explicitly listed base types in the context of the # > type variable. + class MyStr(str): ... + def test_concat_subtype(s: str, b: bytes, a: Any, m: MyStr) -> None: assert_type(concat(m, m), str) assert_type(concat(m, s), str) @@ -62,6 +72,7 @@ def test_concat_subtype(s: str, b: bytes, a: Any, m: MyStr) -> None: # reveal_type(concat(m, a)) # reveal_type(concat(a, m)) + # Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#user-defined-generic-classes # > You can include a ``Generic`` base class to define a user-defined class @@ -70,6 +81,7 @@ def test_concat_subtype(s: str, b: bytes, a: Any, m: MyStr) -> None: from logging import Logger from collections.abc import Iterable + class LoggedVar(Generic[T]): def __init__(self, value: T, name: str, logger: Logger) -> None: self.name = name @@ -77,15 +89,15 @@ def __init__(self, value: T, name: str, logger: Logger) -> None: self.value = value def set(self, new: T) -> None: - self.log('Set ' + repr(self.value)) + self.log("Set " + repr(self.value)) self.value = new def get(self) -> T: - self.log('Get ' + repr(self.value)) + self.log("Get " + repr(self.value)) return self.value def log(self, message: str) -> None: - self.logger.info('{}: {}'.format(self.name, message)) + self.logger.info("{}: {}".format(self.name, message)) def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None: @@ -97,15 +109,18 @@ def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None: # > A generic type can have any number of type variables, and type variables # > may be constrained. -S = TypeVar('S') +S = TypeVar("S") + + +class Pair1(Generic[T, S]): ... -class Pair1(Generic[T, S]): - ... # > Each type variable argument to ``Generic`` must be distinct. -class Pair2(Generic[T, T]): # E - ... + +class Pair2(Generic[T, T]): # E + ... + # > The ``Generic[T]`` base class is redundant in simple cases where you # > subclass some other generic class and specify type variables for its @@ -113,11 +128,12 @@ class Pair2(Generic[T, T]): # E from collections.abc import Iterator, Mapping -class MyIter1(Iterator[T]): - ... -class MyIter2(Iterator[T], Generic[T]): - ... +class MyIter1(Iterator[T]): ... + + +class MyIter2(Iterator[T], Generic[T]): ... + def test_my_iter(m1: MyIter1[int], m2: MyIter2[int]): assert_type(next(m1), int) @@ -127,11 +143,12 @@ def test_my_iter(m1: MyIter1[int], m2: MyIter2[int]): K = TypeVar("K") V = TypeVar("V") -class MyMap1(Mapping[K, V], Generic[K, V]): - ... -class MyMap2(Mapping[K, V], Generic[V, K]): - ... +class MyMap1(Mapping[K, V], Generic[K, V]): ... + + +class MyMap2(Mapping[K, V], Generic[V, K]): ... + def test_my_map(m1: MyMap1[str, int], m2: MyMap2[int, str]): assert_type(m1["key"], int) @@ -140,29 +157,36 @@ def test_my_map(m1: MyMap1[str, int], m2: MyMap2[int, str]): m1[0] # E m2[0] # E + # > You can use multiple inheritance with ``Generic`` from collections.abc import Sized, Container -class LinkedList(Sized, Generic[T]): - ... -class MyMapping(Iterable[tuple[K, V]], Container[tuple[K, V]], Generic[K, V]): - ... +class LinkedList(Sized, Generic[T]): ... + + +class MyMapping(Iterable[tuple[K, V]], Container[tuple[K, V]], Generic[K, V]): ... + # > Subclassing a generic class without specifying type parameters assumes # > ``Any`` for each position. In the following example, ``MyIterable`` # > is not generic but implicitly inherits from ``Iterable[Any]``:: + class MyIterableAny(Iterable): # Same as Iterable[Any] ... + def test_my_iterable_any(m: MyIterableAny): assert_type(iter(m), Iterator[Any]) + # > Generic metaclasses are not supported + class GenericMeta(type, Generic[T]): ... + class GenericMetaInstance(metaclass=GenericMeta[T]): # E ... diff --git a/conformance/tests/generics_upper_bound.py b/conformance/tests/generics_upper_bound.py index 600b87442..9813bde3d 100644 --- a/conformance/tests/generics_upper_bound.py +++ b/conformance/tests/generics_upper_bound.py @@ -4,7 +4,7 @@ # Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#type-variables-with-an-upper-bound -from typing import Collection, Sized, TypeVar, assert_type +from typing import Collection, Generic, Sized, TypeVar, assert_type # > A type variable may specify an upper bound using bound= @@ -19,7 +19,9 @@ class ForwardRef: ... T = TypeVar("T") -T_Bad1 = TypeVar("T_Bad1", bound=list[T]) # E + +class Test(Generic[T]): + T_Bad1 = TypeVar("T_Bad1", bound=list[T]) # E ST = TypeVar("ST", bound=Sized) @@ -40,8 +42,9 @@ def longer(x: ST, y: ST) -> ST: # Both answers are conformant with the spec. assert_type(longer([1], {1, 2}), list[int] | set[int]) # E? -def requires_collection(c: Collection[int]) -> None: - ... + +def requires_collection(c: Collection[int]) -> None: ... + requires_collection(longer([1], [1, 2])) # OK
 
mypy 1.9.0
-
1.6sec
+
1.5sec
pyright 1.1.359
1.5sec
pyre 0.9.19
-
4.0sec
+
3.2sec
pytype 2024.04.11
-
37.5sec
+
35.1sec
@@ -247,9 +247,9 @@

Python Type System Conformance Test Results

Partial

False negative on passing SymbolTable to dict[str, list[object]].

Does not reject illegal use of Generic.

     generics_basic
Partial

Does not reject the use of a constraint parameterized by another type variable.

PassPass
Partial

False positives in examples using constrained type variables.

False negative in custom map example.

False positive using `iter`.

False negative for generic metaclass.

Partial

False positives in examples using constrained type variables.

False negative for constraint parameterized by a type variable.

False negative in custom map example.

False positive using `iter`.

False negative for generic metaclass.

Partial

False positives in examples using constrained type variables.

False negative for generic metaclass.

     generics_defaults
Unsupported

Does not support TypeVarTuple.

     generics_upper_boundPass
Partial

Does not reject use of type variable within an upper bound.

Pass
Partial

Does not reject use of upper bound with constrained TypeVar.

Partial

Does not properly support assert_type.