From 5856657419bc84d2da6dc45847b3d948347af4c6 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 14:08:24 +0000 Subject: [PATCH 01/14] Fix new style union syntax in type aliases Fix Python 3.10 `|` union syntax in type aliases, when one of the operands is a type alias or a type with an overloaded `__init__`. Fixes #12368. Fixes #12005. Fixes #11426. --- mypy/checkexpr.py | 7 +++---- test-data/unit/check-python310.test | 16 ++++++++++++++++ test-data/unit/fixtures/type.pyi | 1 + test-data/unit/pythoneval.test | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index ac16f9c9c813..1af531727e6f 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -3869,9 +3869,8 @@ class LongName(Generic[T]): ... else: if alias_definition: return AnyType(TypeOfAny.special_form) - # This type is invalid in most runtime contexts, give it an 'object' type. - # TODO: Use typing._SpecialForm instead? - return self.named_type("builtins.object") + # This type is valid in some runtime contexts (e.g. it may have __or__). + return self.named_type("typing._SpecialForm") def apply_type_arguments_to_callable( self, tp: Type, args: Sequence[Type], ctx: Context @@ -4741,7 +4740,7 @@ def has_member(self, typ: Type, member: str) -> bool: typ = typ.fallback if isinstance(typ, Instance): return typ.type.has_readable_member(member) - if isinstance(typ, CallableType) and typ.is_type_obj(): + if isinstance(typ, FunctionLike) and typ.is_type_obj(): return typ.fallback.type.has_readable_member(member) elif isinstance(typ, AnyType): return True diff --git a/test-data/unit/check-python310.test b/test-data/unit/check-python310.test index 1548d5dadcfd..3b90a910e943 100644 --- a/test-data/unit/check-python310.test +++ b/test-data/unit/check-python310.test @@ -1788,3 +1788,19 @@ def f6(a: object) -> None: case _ if y is not None: # E: Name "y" may be undefined pass [builtins fixtures/tuple.pyi] + +[case testTypeAliasWithNewUnionSyntaxAndNoneLeftOperand] +from typing import overload +class C: + @overload + def __init__(self) -> None: pass + @overload + def __init__(self, x: int) -> None: pass + def __init__(self, x=0): + pass + +class D: pass + +X = None | C +Y = None | D +[builtins fixtures/type.pyi] diff --git a/test-data/unit/fixtures/type.pyi b/test-data/unit/fixtures/type.pyi index 755b45ff0bb5..77feb41ba70b 100644 --- a/test-data/unit/fixtures/type.pyi +++ b/test-data/unit/fixtures/type.pyi @@ -13,6 +13,7 @@ class list(Generic[T]): pass class type(Generic[T]): __name__: str def __or__(self, other: Union[type, None]) -> type: pass + def __ror__(self, other: Union[type, None]) -> type: pass def mro(self) -> List['type']: pass class tuple(Generic[T]): pass diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 692f62bf6454..8c9b95ab2139 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1660,3 +1660,19 @@ _testNarrowTypeForDictKeys.py:7: note: Revealed type is "builtins.str" _testNarrowTypeForDictKeys.py:9: note: Revealed type is "Union[builtins.str, None]" _testNarrowTypeForDictKeys.py:14: note: Revealed type is "builtins.str" _testNarrowTypeForDictKeys.py:16: note: Revealed type is "Union[builtins.str, None]" + +[case testTypeAliasWithNewStyleUnion] +# flags: --python-version 3.10 +from typing import Literal + +Foo = Literal[1, 2] +reveal_type(Foo) +Bar = Foo | Literal[3] + +U1 = int | str +U2 = U1 | bytes + +Opt1 = None | int +Opt2 = None | float +[out] +_testTypeAliasWithNewStyleUnion.py:5: note: Revealed type is "typing._SpecialForm" From 76b543df84722fcc31ad1d8ba381e9bffe3a8279 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 14:34:53 +0000 Subject: [PATCH 02/14] Cleaner representation for special forms in error messages --- mypy/messages.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypy/messages.py b/mypy/messages.py index 4e762faa0b32..1e2aec544832 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -2253,6 +2253,9 @@ def format_literal_value(typ: LiteralType) -> str: if itype.extra_attrs and itype.extra_attrs.mod_name and module_names: return f"{base_str} {itype.extra_attrs.mod_name}" return base_str + if itype.type.fullname == "typing._SpecialForm": + # This is not a real type but used for some typing-related constructs. + return "" if verbosity >= 2 or (fullnames and itype.type.fullname in fullnames): base_str = itype.type.fullname else: From b11b023b1f95c4ccaf1c8339ce2de1a3454a1874 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 14:35:12 +0000 Subject: [PATCH 03/14] Fix some tests --- test-data/unit/check-dataclasses.test | 3 ++- test-data/unit/check-generics.test | 8 +++---- test-data/unit/check-literal.test | 5 +++-- test-data/unit/check-singledispatch.test | 5 ++++- test-data/unit/check-type-aliases.test | 26 ++++++++++++----------- test-data/unit/fixtures/args.pyi | 1 + test-data/unit/fixtures/typing-full.pyi | 2 ++ test-data/unit/fixtures/typing-medium.pyi | 2 ++ 8 files changed, 32 insertions(+), 20 deletions(-) diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 3ec4c60e6929..d4064124109b 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -633,8 +633,9 @@ class Two: c = Two() x = c.S -reveal_type(x) # N: Revealed type is "builtins.object" +reveal_type(x) # N: Revealed type is "typing._SpecialForm" [builtins fixtures/dataclasses.pyi] +[typing fixtures/typing-medium.pyi] [case testDataclassOrdering] # flags: --python-version 3.7 diff --git a/test-data/unit/check-generics.test b/test-data/unit/check-generics.test index b7d98a783a49..7df52b60fc0b 100644 --- a/test-data/unit/check-generics.test +++ b/test-data/unit/check-generics.test @@ -1049,20 +1049,20 @@ CA = Callable[[T], int] TA = Tuple[T, int] UA = Union[T, int] -cs = CA + 1 # E: Unsupported left operand type for + ("object") +cs = CA + 1 # E: Unsupported left operand type for + ("") reveal_type(cs) # N: Revealed type is "Any" -ts = TA() # E: "object" not callable +ts = TA() # E: "" not callable reveal_type(ts) # N: Revealed type is "Any" -us = UA.x # E: "object" has no attribute "x" +us = UA.x # E: "" has no attribute "x" reveal_type(us) # N: Revealed type is "Any" xx = CA[str] + 1 # E: Type application is only supported for generic classes yy = TA[str]() # E: Type application is only supported for generic classes zz = UA[str].x # E: Type application is only supported for generic classes [builtins fixtures/tuple.pyi] - +[typing fixtures/typing-medium.pyi] [out] [case testGenericTypeAliasesTypeVarBinding] diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index da8f1570a4f4..ef8c9095e58a 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -1484,16 +1484,17 @@ Alias = Literal[3] isinstance(3, Literal[3]) # E: Cannot use isinstance() with Literal type isinstance(3, Alias) # E: Cannot use isinstance() with Literal type \ - # E: Argument 2 to "isinstance" has incompatible type "object"; expected "Union[type, Tuple[Any, ...]]" + # E: Argument 2 to "isinstance" has incompatible type ""; expected "Union[type, Tuple[Any, ...]]" isinstance(3, Renamed[3]) # E: Cannot use isinstance() with Literal type isinstance(3, indirect.Literal[3]) # E: Cannot use isinstance() with Literal type issubclass(int, Literal[3]) # E: Cannot use issubclass() with Literal type issubclass(int, Alias) # E: Cannot use issubclass() with Literal type \ - # E: Argument 2 to "issubclass" has incompatible type "object"; expected "Union[type, Tuple[Any, ...]]" + # E: Argument 2 to "issubclass" has incompatible type ""; expected "Union[type, Tuple[Any, ...]]" issubclass(int, Renamed[3]) # E: Cannot use issubclass() with Literal type issubclass(int, indirect.Literal[3]) # E: Cannot use issubclass() with Literal type [builtins fixtures/isinstancelist.pyi] +[typing fixtures/typing-medium.pyi] [out] [case testLiteralErrorsWhenSubclassed] diff --git a/test-data/unit/check-singledispatch.test b/test-data/unit/check-singledispatch.test index 8fe049437c57..9a8085e6cd84 100644 --- a/test-data/unit/check-singledispatch.test +++ b/test-data/unit/check-singledispatch.test @@ -15,6 +15,7 @@ fun(1) # E: Argument 1 to "fun" has incompatible type "int"; expected "A" # probably won't be required after singledispatch is special cased [builtins fixtures/args.pyi] +[typing fixtures/typing-medium.pyi] [case testMultipleUnderscoreFunctionsIsntError] from functools import singledispatch @@ -30,6 +31,7 @@ def _(arg: int) -> None: pass [builtins fixtures/args.pyi] +[typing fixtures/typing-medium.pyi] [case testCheckNonDispatchArgumentsWithTypeAlwaysTheSame] from functools import singledispatch @@ -52,6 +54,7 @@ f(B(), 'a') f(B(), 1) # E: Argument 2 to "f" has incompatible type "int"; expected "str" [builtins fixtures/args.pyi] +[typing fixtures/typing-medium.pyi] [case testImplementationHasSameDispatchTypeAsFallback-xfail] from functools import singledispatch @@ -71,7 +74,7 @@ def g(arg: int) -> None: from functools import singledispatch @singledispatch -def f(arg) -> None: +def f(arg) -> None: pass @f.register(str) diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index 8dafc8f47a6c..fab372976ab2 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -821,28 +821,28 @@ c = Child() reveal_type(NormalImplicit) # N: Revealed type is "def () -> __main__.Foo" reveal_type(NormalExplicit) # N: Revealed type is "def () -> __main__.Foo" -reveal_type(SpecialImplicit) # N: Revealed type is "builtins.object" -reveal_type(SpecialExplicit) # N: Revealed type is "builtins.object" +reveal_type(SpecialImplicit) # N: Revealed type is "typing._SpecialForm" +reveal_type(SpecialExplicit) # N: Revealed type is "typing._SpecialForm" reveal_type(Parent.NormalImplicit) # N: Revealed type is "def () -> __main__.Foo" reveal_type(Parent.NormalExplicit) # N: Revealed type is "def () -> __main__.Foo" -reveal_type(Parent.SpecialImplicit) # N: Revealed type is "builtins.object" -reveal_type(Parent.SpecialExplicit) # N: Revealed type is "builtins.object" +reveal_type(Parent.SpecialImplicit) # N: Revealed type is "typing._SpecialForm" +reveal_type(Parent.SpecialExplicit) # N: Revealed type is "typing._SpecialForm" reveal_type(Child.NormalImplicit) # N: Revealed type is "def () -> __main__.Foo" reveal_type(Child.NormalExplicit) # N: Revealed type is "def () -> __main__.Foo" -reveal_type(Child.SpecialImplicit) # N: Revealed type is "builtins.object" -reveal_type(Child.SpecialExplicit) # N: Revealed type is "builtins.object" +reveal_type(Child.SpecialImplicit) # N: Revealed type is "typing._SpecialForm" +reveal_type(Child.SpecialExplicit) # N: Revealed type is "typing._SpecialForm" reveal_type(p.NormalImplicit) # N: Revealed type is "def () -> __main__.Foo" reveal_type(p.NormalExplicit) # N: Revealed type is "def () -> __main__.Foo" -reveal_type(p.SpecialImplicit) # N: Revealed type is "builtins.object" -reveal_type(p.SpecialExplicit) # N: Revealed type is "builtins.object" +reveal_type(p.SpecialImplicit) # N: Revealed type is "typing._SpecialForm" +reveal_type(p.SpecialExplicit) # N: Revealed type is "typing._SpecialForm" reveal_type(c.NormalImplicit) # N: Revealed type is "def () -> __main__.Foo" reveal_type(p.NormalExplicit) # N: Revealed type is "def () -> __main__.Foo" -reveal_type(c.SpecialImplicit) # N: Revealed type is "builtins.object" -reveal_type(c.SpecialExplicit) # N: Revealed type is "builtins.object" +reveal_type(c.SpecialImplicit) # N: Revealed type is "typing._SpecialForm" +reveal_type(c.SpecialExplicit) # N: Revealed type is "typing._SpecialForm" # Use type aliases in a type alias context in a plausible way @@ -895,6 +895,7 @@ reveal_type(weird_child_2) # N: Revealed type is "def () -> Any" reveal_type(weird_child_3) # N: Revealed type is "def () -> Any" reveal_type(weird_child_4) # N: Revealed type is "def () -> Any" [builtins fixtures/tuple.pyi] +[typing fixtures/typing-medium.pyi] [case testMalformedTypeAliasRuntimeReassignments] from typing import Union @@ -927,8 +928,8 @@ SpecialExplicit = 4 # E: Cannot assign multiple types to name "SpecialExplicit" Parent.NormalImplicit = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "Type[Foo]") Parent.NormalExplicit = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "Type[Foo]") -Parent.SpecialImplicit = 4 -Parent.SpecialExplicit = 4 +Parent.SpecialImplicit = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "") +Parent.SpecialExplicit = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "") Child.NormalImplicit = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "Type[Foo]") Child.NormalExplicit = 4 # E: Incompatible types in assignment (expression has type "int", variable has type "Type[Foo]") @@ -945,3 +946,4 @@ c.NormalExplicit = 4 # E: Incompatible types in assignment (expression has type c.SpecialImplicit = 4 c.SpecialExplicit = 4 [builtins fixtures/tuple.pyi] +[typing fixtures/typing-medium.pyi] diff --git a/test-data/unit/fixtures/args.pyi b/test-data/unit/fixtures/args.pyi index 8d0ecc00f4b6..9985ccf84817 100644 --- a/test-data/unit/fixtures/args.pyi +++ b/test-data/unit/fixtures/args.pyi @@ -26,6 +26,7 @@ class list(Sequence[T], Generic[T]): pass class int: def __eq__(self, o: object) -> bool: pass +class float: pass class str: pass class bytes: pass class bool: pass diff --git a/test-data/unit/fixtures/typing-full.pyi b/test-data/unit/fixtures/typing-full.pyi index c406da986818..04568f7c03f3 100644 --- a/test-data/unit/fixtures/typing-full.pyi +++ b/test-data/unit/fixtures/typing-full.pyi @@ -179,3 +179,5 @@ class _TypedDict(Mapping[str, object]): def pop(self, k: NoReturn, default: T = ...) -> object: ... def update(self: T, __m: T) -> None: ... def __delitem__(self, k: NoReturn) -> None: ... + +class _SpecialForm: pass diff --git a/test-data/unit/fixtures/typing-medium.pyi b/test-data/unit/fixtures/typing-medium.pyi index 568fe057c4cf..863b0703989d 100644 --- a/test-data/unit/fixtures/typing-medium.pyi +++ b/test-data/unit/fixtures/typing-medium.pyi @@ -68,4 +68,6 @@ class ContextManager(Generic[T]): # Use Any because not all the precise types are in the fixtures. def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> Any: pass +class _SpecialForm: pass + TYPE_CHECKING = 1 From 8c57be51ab6f0e5f257e418ee2ceb7b962148c51 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 14:58:43 +0000 Subject: [PATCH 04/14] Suggest adding a suitable fixture --- mypy/checker.py | 8 ++++---- mypy/messages.py | 1 + test-data/unit/check-ctypes.test | 13 +++++++++++++ test-data/unit/check-functools.test | 12 ++++++------ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 8973ade98228..fdb87040e04a 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -6019,11 +6019,11 @@ def lookup_qualified(self, name: str) -> SymbolTableNode: last = parts[-1] if last in n.names: return n.names[last] - elif len(parts) == 2 and parts[0] == "builtins": - fullname = "builtins." + last + elif len(parts) == 2 and parts[0] in ("builtins", "typing"): + fullname = ".".join(parts) if fullname in SUGGESTED_TEST_FIXTURES: - suggestion = ", e.g. add '[builtins fixtures/{}]' to your test".format( - SUGGESTED_TEST_FIXTURES[fullname] + suggestion = ", e.g. add '[{} fixtures/{}]' to your test".format( + parts[0], SUGGESTED_TEST_FIXTURES[fullname] ) else: suggestion = "" diff --git a/mypy/messages.py b/mypy/messages.py index 1e2aec544832..e11ee9d0f7f2 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -132,6 +132,7 @@ "builtins.isinstance": "isinstancelist.pyi", "builtins.property": "property.pyi", "builtins.classmethod": "classmethod.pyi", + "typing._SpecialForm": "typing-medium.pyi", } diff --git a/test-data/unit/check-ctypes.test b/test-data/unit/check-ctypes.test index 5a350256f8e9..beb1afd779c0 100644 --- a/test-data/unit/check-ctypes.test +++ b/test-data/unit/check-ctypes.test @@ -20,6 +20,7 @@ a[3] = b"bytes" # E: No overload variant of "__setitem__" of "Array" matches ar for x in a: reveal_type(x) # N: Revealed type is "builtins.int" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesArrayCustomElementType] import ctypes @@ -52,6 +53,7 @@ myu: Union[ctypes.Array[ctypes.c_int], List[str]] for myi in myu: reveal_type(myi) # N: Revealed type is "Union[builtins.int, builtins.str]" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesArrayUnionElementType] import ctypes @@ -76,6 +78,7 @@ mya[3] = b"bytes" # E: No overload variant of "__setitem__" of "Array" matches for myx in mya: reveal_type(myx) # N: Revealed type is "Union[__main__.MyCInt, builtins.int]" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesCharArrayAttrs] import ctypes @@ -84,6 +87,7 @@ ca = (ctypes.c_char * 4)(b'a', b'b', b'c', b'\x00') reveal_type(ca.value) # N: Revealed type is "builtins.bytes" reveal_type(ca.raw) # N: Revealed type is "builtins.bytes" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesCharPArrayDoesNotCrash] import ctypes @@ -91,6 +95,7 @@ import ctypes # The following line used to crash with "Could not find builtin symbol 'NoneType'" ca = (ctypes.c_char_p * 0)() [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesWcharArrayAttrs] import ctypes @@ -99,6 +104,7 @@ wca = (ctypes.c_wchar * 4)('a', 'b', 'c', '\x00') reveal_type(wca.value) # N: Revealed type is "builtins.str" wca.raw # E: Array attribute "raw" is only available with element type "c_char", not "c_wchar" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesCharUnionArrayAttrs] import ctypes @@ -108,6 +114,7 @@ cua: ctypes.Array[Union[ctypes.c_char, ctypes.c_wchar]] reveal_type(cua.value) # N: Revealed type is "Union[builtins.bytes, builtins.str]" cua.raw # E: Array attribute "raw" is only available with element type "c_char", not "Union[c_char, c_wchar]" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesAnyUnionArrayAttrs] import ctypes @@ -117,6 +124,7 @@ caa: ctypes.Array[Union[ctypes.c_char, Any]] reveal_type(caa.value) # N: Revealed type is "Union[builtins.bytes, Any]" reveal_type(caa.raw) # N: Revealed type is "builtins.bytes" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesOtherUnionArrayAttrs] import ctypes @@ -126,6 +134,7 @@ cua: ctypes.Array[Union[ctypes.c_char, ctypes.c_int]] cua.value # E: Array attribute "value" is only available with element type "c_char" or "c_wchar", not "Union[c_char, c_int]" cua.raw # E: Array attribute "raw" is only available with element type "c_char", not "Union[c_char, c_int]" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesAnyArrayAttrs] import ctypes @@ -134,6 +143,7 @@ aa: ctypes.Array[Any] reveal_type(aa.value) # N: Revealed type is "Any" reveal_type(aa.raw) # N: Revealed type is "builtins.bytes" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesOtherArrayAttrs] import ctypes @@ -142,6 +152,7 @@ oa = (ctypes.c_int * 4)(1, 2, 3, 4) oa.value # E: Array attribute "value" is only available with element type "c_char" or "c_wchar", not "c_int" oa.raw # E: Array attribute "raw" is only available with element type "c_char", not "c_int" [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] [case testCtypesArrayConstructorStarargs] import ctypes @@ -154,6 +165,7 @@ reveal_type(intarr4(*int_values)) # N: Revealed type is "ctypes.Array[ctypes.c_ reveal_type(intarr4(*c_int_values)) # N: Revealed type is "ctypes.Array[ctypes.c_int]" reveal_type(intarr6(1, ctypes.c_int(2), *int_values)) # N: Revealed type is "ctypes.Array[ctypes.c_int]" reveal_type(intarr6(1, ctypes.c_int(2), *c_int_values)) # N: Revealed type is "ctypes.Array[ctypes.c_int]" +[typing fixtures/typing-medium.pyi] float_values = [1.0, 2.0, 3.0, 4.0] intarr4(*float_values) # E: Array constructor argument 1 of type "List[float]" is not convertible to the array element type "Iterable[c_int]" @@ -167,3 +179,4 @@ x = {"a": 1, "b": 2} intarr4(**x) [builtins fixtures/floatdict.pyi] +[typing fixtures/typing-medium.pyi] diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index f95b823a5291..4297f0e27e5e 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -20,8 +20,8 @@ Ord() <= 1 # E: Unsupported operand types for <= ("Ord" and "int") Ord() == 1 Ord() > 1 # E: Unsupported operand types for > ("Ord" and "int") Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") -[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] +[typing fixtures/typing-medium.pyi] [case testTotalOrderingLambda] from functools import total_ordering @@ -43,8 +43,8 @@ Ord() <= 1 # E: Unsupported operand types for <= ("Ord" and "int") Ord() == 1 Ord() > 1 # E: Unsupported operand types for > ("Ord" and "int") Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") -[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] +[typing fixtures/typing-medium.pyi] [case testTotalOrderingNonCallable] from functools import total_ordering @@ -60,8 +60,8 @@ Ord() <= Ord() # E: Unsupported left operand type for <= ("Ord") Ord() > Ord() # E: "int" not callable Ord() >= Ord() # E: Unsupported left operand type for >= ("Ord") -[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] +[typing fixtures/typing-medium.pyi] [case testTotalOrderingReturnNotBool] from functools import total_ordering @@ -80,8 +80,8 @@ reveal_type(Ord() == Ord()) # N: Revealed type is "builtins.bool" reveal_type(Ord() > Ord()) # N: Revealed type is "Any" reveal_type(Ord() >= Ord()) # N: Revealed type is "Any" -[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] +[typing fixtures/typing-medium.pyi] [case testTotalOrderingAllowsAny] from functools import total_ordering @@ -105,8 +105,8 @@ Ord() <= 1 # E: Unsupported left operand type for <= ("Ord") Ord() == 1 Ord() > 1 Ord() >= 1 # E: Unsupported left operand type for >= ("Ord") -[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] +[typing fixtures/typing-medium.pyi] [case testCachedProperty] # flags: --python-version 3.8 @@ -151,5 +151,5 @@ def f(d: D[C]) -> None: reveal_type(d.__gt__) # N: Revealed type is "def (other: Any) -> builtins.bool" d: D[int] # E: Type argument "int" of "D" must be a subtype of "C" -[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] +[typing fixtures/typing-medium.pyi] From 06d0c8d20e8c31eb49f926c0bb91ea0b5cc6f150 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 15:15:51 +0000 Subject: [PATCH 05/14] Add functools test fixture --- test-data/unit/lib-stub/functools.pyi | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test-data/unit/lib-stub/functools.pyi diff --git a/test-data/unit/lib-stub/functools.pyi b/test-data/unit/lib-stub/functools.pyi new file mode 100644 index 000000000000..19c5ef3fbb14 --- /dev/null +++ b/test-data/unit/lib-stub/functools.pyi @@ -0,0 +1,35 @@ +from typing import Generic, Callable, Any, Mapping + +_T = TypeVar("_T") + +class _SingleDispatchCallable(Generic[_T]): + registry: Mapping[Any, Callable[..., _T]] + def dispatch(self, cls: Any) -> Callable[..., _T]: ... + # @fun.register(complex) + # def _(arg, verbose=False): ... + @overload + def register(self, cls: type[Any], func: None = ...) -> Callable[[Callable[..., _T]], Callable[..., _T]]: ... + # @fun.register + # def _(arg: int, verbose=False): + @overload + def register(self, cls: Callable[..., _T], func: None = ...) -> Callable[..., _T]: ... + # fun.register(int, lambda x: x) + @overload + def register(self, cls: type[Any], func: Callable[..., _T]) -> Callable[..., _T]: ... + def _clear_cache(self) -> None: ... + def __call__(__self, *args: Any, **kwargs: Any) -> _T: ... + +def singledispatch(func: Callable[..., _T]) -> _SingleDispatchCallable[_T]: ... + +def total_ordering(cls: type[_T]) -> type[_T]: ... + +class cached_property(Generic[_T]): + func: Callable[[Any], _T] + attrname: str | None + def __init__(self, func: Callable[[Any], _T]) -> None: ... + @overload + def __get__(self, instance: None, owner: type[Any] | None = ...) -> cached_property[_T]: ... + @overload + def __get__(self, instance: object, owner: type[Any] | None = ...) -> _T: ... + def __set_name__(self, owner: type[Any], name: str) -> None: ... + def __class_getitem__(cls, item: Any) -> Any: ... From 5a79c20ba90c7ba726572f13417951a1455b8352 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 15:28:54 +0000 Subject: [PATCH 06/14] Fix functools fixture --- test-data/unit/check-functools.test | 12 ++++++------ test-data/unit/check-singledispatch.test | 5 +---- test-data/unit/lib-stub/functools.pyi | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 4297f0e27e5e..f95b823a5291 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -20,8 +20,8 @@ Ord() <= 1 # E: Unsupported operand types for <= ("Ord" and "int") Ord() == 1 Ord() > 1 # E: Unsupported operand types for > ("Ord" and "int") Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") +[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] -[typing fixtures/typing-medium.pyi] [case testTotalOrderingLambda] from functools import total_ordering @@ -43,8 +43,8 @@ Ord() <= 1 # E: Unsupported operand types for <= ("Ord" and "int") Ord() == 1 Ord() > 1 # E: Unsupported operand types for > ("Ord" and "int") Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") +[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] -[typing fixtures/typing-medium.pyi] [case testTotalOrderingNonCallable] from functools import total_ordering @@ -60,8 +60,8 @@ Ord() <= Ord() # E: Unsupported left operand type for <= ("Ord") Ord() > Ord() # E: "int" not callable Ord() >= Ord() # E: Unsupported left operand type for >= ("Ord") +[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] -[typing fixtures/typing-medium.pyi] [case testTotalOrderingReturnNotBool] from functools import total_ordering @@ -80,8 +80,8 @@ reveal_type(Ord() == Ord()) # N: Revealed type is "builtins.bool" reveal_type(Ord() > Ord()) # N: Revealed type is "Any" reveal_type(Ord() >= Ord()) # N: Revealed type is "Any" +[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] -[typing fixtures/typing-medium.pyi] [case testTotalOrderingAllowsAny] from functools import total_ordering @@ -105,8 +105,8 @@ Ord() <= 1 # E: Unsupported left operand type for <= ("Ord") Ord() == 1 Ord() > 1 Ord() >= 1 # E: Unsupported left operand type for >= ("Ord") +[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] -[typing fixtures/typing-medium.pyi] [case testCachedProperty] # flags: --python-version 3.8 @@ -151,5 +151,5 @@ def f(d: D[C]) -> None: reveal_type(d.__gt__) # N: Revealed type is "def (other: Any) -> builtins.bool" d: D[int] # E: Type argument "int" of "D" must be a subtype of "C" +[builtins fixtures/ops.pyi] [builtins fixtures/dict.pyi] -[typing fixtures/typing-medium.pyi] diff --git a/test-data/unit/check-singledispatch.test b/test-data/unit/check-singledispatch.test index 9a8085e6cd84..8fe049437c57 100644 --- a/test-data/unit/check-singledispatch.test +++ b/test-data/unit/check-singledispatch.test @@ -15,7 +15,6 @@ fun(1) # E: Argument 1 to "fun" has incompatible type "int"; expected "A" # probably won't be required after singledispatch is special cased [builtins fixtures/args.pyi] -[typing fixtures/typing-medium.pyi] [case testMultipleUnderscoreFunctionsIsntError] from functools import singledispatch @@ -31,7 +30,6 @@ def _(arg: int) -> None: pass [builtins fixtures/args.pyi] -[typing fixtures/typing-medium.pyi] [case testCheckNonDispatchArgumentsWithTypeAlwaysTheSame] from functools import singledispatch @@ -54,7 +52,6 @@ f(B(), 'a') f(B(), 1) # E: Argument 2 to "f" has incompatible type "int"; expected "str" [builtins fixtures/args.pyi] -[typing fixtures/typing-medium.pyi] [case testImplementationHasSameDispatchTypeAsFallback-xfail] from functools import singledispatch @@ -74,7 +71,7 @@ def g(arg: int) -> None: from functools import singledispatch @singledispatch -def f(arg) -> None: +def f(arg) -> None: pass @f.register(str) diff --git a/test-data/unit/lib-stub/functools.pyi b/test-data/unit/lib-stub/functools.pyi index 19c5ef3fbb14..9e62a14c2f34 100644 --- a/test-data/unit/lib-stub/functools.pyi +++ b/test-data/unit/lib-stub/functools.pyi @@ -1,4 +1,4 @@ -from typing import Generic, Callable, Any, Mapping +from typing import Generic, TypeVar, Callable, Any, Mapping _T = TypeVar("_T") From 5438a2e5851117c5e762b483b0197b648c03a1a0 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 15:34:50 +0000 Subject: [PATCH 07/14] Update comment --- mypy/checkexpr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 1af531727e6f..886d9f483a72 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -3869,7 +3869,7 @@ class LongName(Generic[T]): ... else: if alias_definition: return AnyType(TypeOfAny.special_form) - # This type is valid in some runtime contexts (e.g. it may have __or__). + # The _SpecialForm type can be used in some runtime contexts (e.g. it may have __or__). return self.named_type("typing._SpecialForm") def apply_type_arguments_to_callable( From 6adab4e15046a94a8dc57e111c55bf9d3627a496 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 15:48:15 +0000 Subject: [PATCH 08/14] Update test case --- test-data/unit/pythoneval.test | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 8c9b95ab2139..57dc4761dc90 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1667,12 +1667,16 @@ from typing import Literal Foo = Literal[1, 2] reveal_type(Foo) -Bar = Foo | Literal[3] +Bar1 = Foo | Literal[3] +Bar2 = Literal[3] | Foo U1 = int | str U2 = U1 | bytes +U3 = bytes | U1 Opt1 = None | int Opt2 = None | float +Opt3 = int | None +Opt4 = float | None [out] _testTypeAliasWithNewStyleUnion.py:5: note: Revealed type is "typing._SpecialForm" From 6726101c8ceda8c15b889d6eb94207f72cb39315 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 4 Nov 2022 15:58:03 +0000 Subject: [PATCH 09/14] Update test case --- test-data/unit/pythoneval.test | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 57dc4761dc90..c58dd1d85b44 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1663,7 +1663,7 @@ _testNarrowTypeForDictKeys.py:16: note: Revealed type is "Union[builtins.str, No [case testTypeAliasWithNewStyleUnion] # flags: --python-version 3.10 -from typing import Literal +from typing import Literal, Type, TypeAlias Foo = Literal[1, 2] reveal_type(Foo) @@ -1678,5 +1678,8 @@ Opt1 = None | int Opt2 = None | float Opt3 = int | None Opt4 = float | None + +A = Type[int] | str +B: TypeAlias = Type[int] | str [out] _testTypeAliasWithNewStyleUnion.py:5: note: Revealed type is "typing._SpecialForm" From 967a2cc2509c42bdf99b39af965cedc46ef183f5 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 7 Nov 2022 13:39:10 +0000 Subject: [PATCH 10/14] Test syntax in stubs with older Python version --- test-data/unit/pythoneval.test | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index c58dd1d85b44..94541db0abbc 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1683,3 +1683,30 @@ A = Type[int] | str B: TypeAlias = Type[int] | str [out] _testTypeAliasWithNewStyleUnion.py:5: note: Revealed type is "typing._SpecialForm" + +[case testTypeAliasWithNewStyleUnionInStub] +# flags: --python-version 3.7 +import m + +[file m.pyi] +from typing import Type +from typing_extensions import Literal, TypeAlias + +Foo = Literal[1, 2] +reveal_type(Foo) +Bar1 = Foo | Literal[3] +Bar2 = Literal[3] | Foo + +U1 = int | str +U2 = U1 | bytes +U3 = bytes | U1 + +Opt1 = None | int +Opt2 = None | float +Opt3 = int | None +Opt4 = float | None + +A = Type[int] | str +B: TypeAlias = Type[int] | str +[out] +m.pyi:5: note: Revealed type is "typing._SpecialForm" From 0d7bfa1232c760bf2134dc0f103f4a730d5ee470 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 7 Nov 2022 13:40:59 +0000 Subject: [PATCH 11/14] Update test case --- test-data/unit/pythoneval.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 94541db0abbc..f6336b48ee7b 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1669,6 +1669,7 @@ Foo = Literal[1, 2] reveal_type(Foo) Bar1 = Foo | Literal[3] Bar2 = Literal[3] | Foo +Bar3 = Foo | Foo | Literal[3] | Foo U1 = int | str U2 = U1 | bytes @@ -1696,6 +1697,7 @@ Foo = Literal[1, 2] reveal_type(Foo) Bar1 = Foo | Literal[3] Bar2 = Literal[3] | Foo +Bar3 = Foo | Foo | Literal[3] | Foo U1 = int | str U2 = U1 | bytes From f359e7213cbd039ac921b740ac860ad786417e86 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 7 Nov 2022 14:06:40 +0000 Subject: [PATCH 12/14] Add more test stubs --- test-data/unit/lib-stub/datetime.pyi | 16 ++++++++++++++++ test-data/unit/lib-stub/decimal.pyi | 4 ++++ test-data/unit/lib-stub/traceback.pyi | 3 +++ test-data/unit/lib-stub/unannotated_lib.pyi | 1 + 4 files changed, 24 insertions(+) create mode 100644 test-data/unit/lib-stub/datetime.pyi create mode 100644 test-data/unit/lib-stub/decimal.pyi create mode 100644 test-data/unit/lib-stub/traceback.pyi create mode 100644 test-data/unit/lib-stub/unannotated_lib.pyi diff --git a/test-data/unit/lib-stub/datetime.pyi b/test-data/unit/lib-stub/datetime.pyi new file mode 100644 index 000000000000..7d71682d051d --- /dev/null +++ b/test-data/unit/lib-stub/datetime.pyi @@ -0,0 +1,16 @@ +# Very simplified datetime stubs for use in tests + +class datetime: + def __new__( + cls, + year: int, + month: int, + day: int, + hour: int = ..., + minute: int = ..., + second: int = ..., + microsecond: int = ..., + *, + fold: int = ..., + ) -> datetime: ... + def __format__(self, __fmt: str) -> str: ... diff --git a/test-data/unit/lib-stub/decimal.pyi b/test-data/unit/lib-stub/decimal.pyi new file mode 100644 index 000000000000..768e26344ebb --- /dev/null +++ b/test-data/unit/lib-stub/decimal.pyi @@ -0,0 +1,4 @@ +# Very simplified datetime stubs for use in tests + +class Decimal: + def __new__(cls, value: str = ...) -> Decimal: ... diff --git a/test-data/unit/lib-stub/traceback.pyi b/test-data/unit/lib-stub/traceback.pyi new file mode 100644 index 000000000000..83c1891f80f5 --- /dev/null +++ b/test-data/unit/lib-stub/traceback.pyi @@ -0,0 +1,3 @@ +# Very simplified traceback stubs for use in tests + +def print_tb(*args, **kwargs) -> None: ... diff --git a/test-data/unit/lib-stub/unannotated_lib.pyi b/test-data/unit/lib-stub/unannotated_lib.pyi new file mode 100644 index 000000000000..90bfb6fa47d6 --- /dev/null +++ b/test-data/unit/lib-stub/unannotated_lib.pyi @@ -0,0 +1 @@ +def f(x): ... From 893a918009935a71eb19cf81083c8f350859a313 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 7 Nov 2022 14:23:02 +0000 Subject: [PATCH 13/14] Fix mypyc test case --- mypyc/test-data/run-async.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypyc/test-data/run-async.test b/mypyc/test-data/run-async.test index e664ed3bb55a..85ad172d61df 100644 --- a/mypyc/test-data/run-async.test +++ b/mypyc/test-data/run-async.test @@ -13,6 +13,9 @@ async def g() -> int: async def f() -> int: return await g() +[file asyncio/__init__.pyi] +async def sleep(t: float) -> None: ... + [typing fixtures/typing-full.pyi] [file driver.py] From de9c3915d2313f3ae858ff99f511dbff30a4bfaf Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 7 Nov 2022 14:26:36 +0000 Subject: [PATCH 14/14] Fix test case --- test-data/unit/lib-stub/_decimal.pyi | 4 ++++ test-data/unit/lib-stub/decimal.pyi | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 test-data/unit/lib-stub/_decimal.pyi diff --git a/test-data/unit/lib-stub/_decimal.pyi b/test-data/unit/lib-stub/_decimal.pyi new file mode 100644 index 000000000000..2c2c5bff11f7 --- /dev/null +++ b/test-data/unit/lib-stub/_decimal.pyi @@ -0,0 +1,4 @@ +# Very simplified decimal stubs for use in tests + +class Decimal: + def __new__(cls, value: str = ...) -> Decimal: ... diff --git a/test-data/unit/lib-stub/decimal.pyi b/test-data/unit/lib-stub/decimal.pyi index 768e26344ebb..d2ab6eda9ff1 100644 --- a/test-data/unit/lib-stub/decimal.pyi +++ b/test-data/unit/lib-stub/decimal.pyi @@ -1,4 +1,3 @@ -# Very simplified datetime stubs for use in tests +# Very simplified decimal stubs for use in tests -class Decimal: - def __new__(cls, value: str = ...) -> Decimal: ... +from _decimal import *