From 3719f02dbfdda7ea579e6aed173e8ac62b2b4784 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 21 Aug 2024 21:34:52 -0400 Subject: [PATCH] Using precise code for `pyright: ignore` and re-enabling various pyright tests (#12576) --- .../test_cases/builtins/check_dict-py39.py | 7 ++-- .../@tests/test_cases/builtins/check_dict.py | 1 + .../@tests/test_cases/builtins/check_pow.py | 12 +++---- .../@tests/test_cases/builtins/check_sum.py | 4 +-- stdlib/@tests/test_cases/check_dataclasses.py | 35 ++++++------------- .../collections/check_defaultdict-py39.py | 7 ++-- stdlib/collections/__init__.pyi | 6 ++-- stdlib/dataclasses.pyi | 9 +++-- stdlib/typing.pyi | 2 +- stubs/JACK-Client/jack/__init__.pyi | 2 +- .../@tests/test_cases/check_tk_compat.py | 20 +++++------ stubs/WebOb/@tests/test_cases/check_wsgify.py | 18 ++++------ .../test_cases/check_base_descriptors.py | 2 +- .../test_cases/check_nested_descriptors.py | 2 +- stubs/pygit2/pygit2/_pygit2.pyi | 2 +- stubs/pygit2/pygit2/utils.pyi | 2 +- .../pywin32/win32comext/axdebug/documents.pyi | 2 +- tests/pytype_test.py | 2 +- 18 files changed, 60 insertions(+), 75 deletions(-) diff --git a/stdlib/@tests/test_cases/builtins/check_dict-py39.py b/stdlib/@tests/test_cases/builtins/check_dict-py39.py index d707cfed2..20ac4e622 100644 --- a/stdlib/@tests/test_cases/builtins/check_dict-py39.py +++ b/stdlib/@tests/test_cases/builtins/check_dict-py39.py @@ -58,10 +58,13 @@ if sys.version_info >= (3, 9): assert_type(os.environ | c, dict[str, str]) assert_type(e | c, dict[str, str]) + # store "untainted" `CustomMappingWithDunderOr[str, str]` to test `__ior__` against ` dict[str, str]` later + # Invalid `e |= a` causes pyright to join `Unknown` to `e`'s type + f = e + e |= c e |= a # type: ignore - # TODO: this test passes mypy, but fails pyright for some reason: - # c |= e + c |= f c |= a # type: ignore diff --git a/stdlib/@tests/test_cases/builtins/check_dict.py b/stdlib/@tests/test_cases/builtins/check_dict.py index aa920d045..96c60e779 100644 --- a/stdlib/@tests/test_cases/builtins/check_dict.py +++ b/stdlib/@tests/test_cases/builtins/check_dict.py @@ -7,6 +7,7 @@ from typing_extensions import assert_type # mypy and pyright have different opinions about this one: # mypy raises: 'Need type annotation for "bad"' # pyright is fine with it. +# https://github.com/python/mypy/issues/12358 # bad = dict() good: dict[str, str] = dict() assert_type(good, Dict[str, str]) diff --git a/stdlib/@tests/test_cases/builtins/check_pow.py b/stdlib/@tests/test_cases/builtins/check_pow.py index c8e2d277e..6fe7aacff 100644 --- a/stdlib/@tests/test_cases/builtins/check_pow.py +++ b/stdlib/@tests/test_cases/builtins/check_pow.py @@ -17,10 +17,11 @@ assert_type(pow(1, 0, None), Literal[1]) # assert_type(pow(2, 4, 0), NoReturn) assert_type(pow(2, 4), int) -# pyright infers a literal type here, but mypy does not. Unfortunately, -# there is no way to ignore an error only for mypy, so we can't check -# pyright's handling (https://github.com/python/mypy/issues/12358). -assert_type(2**4, int) # pyright: ignore +# pyright infers a literal type here, but mypy does not. +# Unfortunately, there is no way to ignore an error only for mypy, +# whilst getting both pyright and mypy to respect `type: ignore`. +# So we can't check pyright's handling (https://github.com/python/mypy/issues/12358). +assert_type(2**4, int) # pyright: ignore[reportAssertTypeFailure] # pyright version: assert_type(2**4, Literal[16]) assert_type(pow(4, 6, None), int) @@ -34,8 +35,7 @@ assert_type(pow(2, 8.5), float) assert_type(2**8.6, float) assert_type(pow(2, 8.6, None), float) -# TODO: Why does this pass pyright but not mypy?? -# assert_type((-2) ** 0.5, complex) +assert_type((-2) ** 0.5, complex) assert_type(pow((-5), 8.42, None), complex) diff --git a/stdlib/@tests/test_cases/builtins/check_sum.py b/stdlib/@tests/test_cases/builtins/check_sum.py index cda7eadbb..ec9cd335c 100644 --- a/stdlib/@tests/test_cases/builtins/check_sum.py +++ b/stdlib/@tests/test_cases/builtins/check_sum.py @@ -38,7 +38,7 @@ assert_type(sum([Baz(), Baz()]), Union[Baz, Literal[0]]) # mypy and pyright infer the types differently for these, so we can't use assert_type # Just test that no error is emitted for any of these -sum([("foo",), ("bar", "baz")], ()) # mypy: `tuple[str, ...]`; pyright: `tuple[()] | tuple[str] | tuple[str, str]` +sum([("foo",), ("bar", "baz")], ()) # mypy: `tuple[str, ...]`; pyright: `tuple[str] | tuple[str, str] | tuple[()]` sum([5.6, 3.2]) # mypy: `float`; pyright: `float | Literal[0]` sum([2.5, 5.8], 5) # mypy: `float`; pyright: `float | int` @@ -52,4 +52,4 @@ sum([Bar(), Bar()]) # type: ignore # TODO: these pass pyright with the current stubs, but mypy erroneously emits an error: # sum([3, Fraction(7, 22), complex(8, 0), 9.83]) -# sum([3, Decimal('0.98')]) +# sum([3, Decimal("0.98")]) diff --git a/stdlib/@tests/test_cases/check_dataclasses.py b/stdlib/@tests/test_cases/check_dataclasses.py index 598cbe6e9..4582e14ae 100644 --- a/stdlib/@tests/test_cases/check_dataclasses.py +++ b/stdlib/@tests/test_cases/check_dataclasses.py @@ -15,14 +15,9 @@ class Foo: assert_type(dc.fields(Foo), Tuple[dc.Field[Any], ...]) -# Mypy correctly emits errors on these -# due to the fact it's a dataclass class, not an instance. -# Pyright, however, handles ClassVar members in protocols differently. -# See https://github.com/microsoft/pyright/issues/4339 -# -# dc.asdict(Foo) -# dc.astuple(Foo) -# dc.replace(Foo) +dc.asdict(Foo) # type: ignore +dc.astuple(Foo) # type: ignore +dc.replace(Foo) # type: ignore # See #9723 for why we can't make this assertion # if dc.is_dataclass(Foo): @@ -57,7 +52,7 @@ def is_dataclass_type(arg: type) -> None: def check_other_isdataclass_overloads(x: type, y: object) -> None: - # TODO: pyright correctly emits an error on this, but mypy does not -- why? + # TODO: neither pyright nor mypy emit error on this -- why? # dc.fields(x) dc.fields(y) # type: ignore @@ -75,27 +70,17 @@ def check_other_isdataclass_overloads(x: type, y: object) -> None: assert_type(x, Type["DataclassInstance"]) assert_type(dc.fields(x), Tuple[dc.Field[Any], ...]) - # Mypy correctly emits an error on these due to the fact - # that it's a dataclass class, not a dataclass instance. - # Pyright, however, handles ClassVar members in protocols differently. - # See https://github.com/microsoft/pyright/issues/4339 - # - # dc.asdict(x) - # dc.astuple(x) - # dc.replace(x) + dc.asdict(x) # type: ignore + dc.astuple(x) # type: ignore + dc.replace(x) # type: ignore if dc.is_dataclass(y): assert_type(y, Union["DataclassInstance", Type["DataclassInstance"]]) assert_type(dc.fields(y), Tuple[dc.Field[Any], ...]) - # Mypy correctly emits an error on these due to the fact we don't know - # whether it's a dataclass class or a dataclass instance. - # Pyright, however, handles ClassVar members in protocols differently. - # See https://github.com/microsoft/pyright/issues/4339 - # - # dc.asdict(y) - # dc.astuple(y) - # dc.replace(y) + dc.asdict(y) # type: ignore + dc.astuple(y) # type: ignore + dc.replace(y) # type: ignore if dc.is_dataclass(y) and not isinstance(y, type): assert_type(y, "DataclassInstance") diff --git a/stdlib/@tests/test_cases/collections/check_defaultdict-py39.py b/stdlib/@tests/test_cases/collections/check_defaultdict-py39.py index 9fe5ec807..ff2d1d1f5 100644 --- a/stdlib/@tests/test_cases/collections/check_defaultdict-py39.py +++ b/stdlib/@tests/test_cases/collections/check_defaultdict-py39.py @@ -60,10 +60,13 @@ if sys.version_info >= (3, 9): assert_type(os.environ | c, dict[str, str]) assert_type(e | c, dict[str, str]) + # store "untainted" `CustomMappingWithDunderOr[str, str]` to test `__ior__` against ` defaultdict[str, str]` later + # Invalid `e |= a` causes pyright to join `Unknown` to `e`'s type + f = e + e |= c e |= a # type: ignore - # TODO: this test passes mypy, but fails pyright for some reason: - # c |= e + c |= f c |= a # type: ignore diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index 9097287ce..b2ed53e44 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -345,15 +345,15 @@ class _OrderedDictValuesView(ValuesView[_VT_co], Reversible[_VT_co]): # but they are not exposed anywhere) # pyright doesn't have a specific error code for subclassing error! @final -class _odict_keys(dict_keys[_KT_co, _VT_co], Reversible[_KT_co]): # type: ignore[misc] # pyright: ignore +class _odict_keys(dict_keys[_KT_co, _VT_co], Reversible[_KT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[_KT_co]: ... @final -class _odict_items(dict_items[_KT_co, _VT_co], Reversible[tuple[_KT_co, _VT_co]]): # type: ignore[misc] # pyright: ignore +class _odict_items(dict_items[_KT_co, _VT_co], Reversible[tuple[_KT_co, _VT_co]]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... @final -class _odict_values(dict_values[_KT_co, _VT_co], Reversible[_VT_co], Generic[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore +class _odict_values(dict_values[_KT_co, _VT_co], Reversible[_VT_co], Generic[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[_VT_co]: ... class OrderedDict(dict[_KT, _VT], Reversible[_KT], Generic[_KT, _VT]): diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index f93797583..3295b1c1f 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -229,18 +229,17 @@ if sys.version_info >= (3, 9): else: class _InitVarMeta(type): # Not used, instead `InitVar.__class_getitem__` is called. - # pyright ignore is needed because pyright (not unreasonably) thinks this - # is an invalid use of InitVar. - def __getitem__(self, params: Any) -> InitVar[Any]: ... # pyright: ignore + # pyright (not unreasonably) thinks this is an invalid use of InitVar. + def __getitem__(self, params: Any) -> InitVar[Any]: ... # pyright: ignore[reportInvalidTypeForm] class InitVar(Generic[_T], metaclass=_InitVarMeta): type: Type[_T] def __init__(self, type: Type[_T]) -> None: ... if sys.version_info >= (3, 9): @overload - def __class_getitem__(cls, type: Type[_T]) -> InitVar[_T]: ... # pyright: ignore + def __class_getitem__(cls, type: Type[_T]) -> InitVar[_T]: ... # pyright: ignore[reportInvalidTypeForm] @overload - def __class_getitem__(cls, type: Any) -> InitVar[Any]: ... # pyright: ignore + def __class_getitem__(cls, type: Any) -> InitVar[Any]: ... # pyright: ignore[reportInvalidTypeForm] if sys.version_info >= (3, 12): def make_dataclass( diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 14d0b45f2..cadd06358 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -2,7 +2,7 @@ # ruff: noqa: F811 # TODO: The collections import is required, otherwise mypy crashes. # https://github.com/python/mypy/issues/16744 -import collections # noqa: F401 # pyright: ignore +import collections # noqa: F401 # pyright: ignore[reportUnusedImport] import sys import typing_extensions from _collections_abc import dict_items, dict_keys, dict_values diff --git a/stubs/JACK-Client/jack/__init__.pyi b/stubs/JACK-Client/jack/__init__.pyi index 6a4740ca5..4f8d61bd4 100644 --- a/stubs/JACK-Client/jack/__init__.pyi +++ b/stubs/JACK-Client/jack/__init__.pyi @@ -12,7 +12,7 @@ from numpy.typing import NDArray # Actual type: _cffi_backend.__CDataOwn # This is not a real subclassing. Just ensuring type-checkers sees this type as compatible with _CDataBase # pyright has no error code for subclassing final -class _JackPositionT(_CDataBase): # type: ignore[misc] # pyright: ignore +class _JackPositionT(_CDataBase): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] audio_frames_per_video_frame: float bar: int bar_start_tick: float diff --git a/stubs/Pillow/@tests/test_cases/check_tk_compat.py b/stubs/Pillow/@tests/test_cases/check_tk_compat.py index 3cd413602..9dc74cb6c 100644 --- a/stubs/Pillow/@tests/test_cases/check_tk_compat.py +++ b/stubs/Pillow/@tests/test_cases/check_tk_compat.py @@ -1,20 +1,20 @@ # Verify that ImageTK images are valid to pass to TK code. from __future__ import annotations -# The following tests don't work at the moment, due to pyright getting +# The following tests don't work on pyright at the moment, due to it getting # confused by the existence of these stubs and annotations in the actual # Pillow package. # https://github.com/python/typeshed/issues/11688 +# pyright: reportArgumentType=false +import tkinter -# import tkinter +from PIL import ImageTk -# from PIL import ImageTk +photo = ImageTk.PhotoImage() +bitmap = ImageTk.BitmapImage() -# photo = ImageTk.PhotoImage() -# bitmap = ImageTk.BitmapImage() +tkinter.Label(image=photo) +tkinter.Label(image=bitmap) -# tkinter.Label(image=photo) -# tkinter.Label(image=bitmap) - -# tkinter.Label().configure(image=photo) -# tkinter.Label().configure(image=bitmap) +tkinter.Label().configure(image=photo) +tkinter.Label().configure(image=bitmap) diff --git a/stubs/WebOb/@tests/test_cases/check_wsgify.py b/stubs/WebOb/@tests/test_cases/check_wsgify.py index bc9f2a9de..0ca91e28a 100644 --- a/stubs/WebOb/@tests/test_cases/check_wsgify.py +++ b/stubs/WebOb/@tests/test_cases/check_wsgify.py @@ -59,10 +59,7 @@ application = app assert_type(app, "wsgify[Request, []]") assert_type(app(env, start_response), "Iterable[bytes]") assert_type(app(request), _AnyResponse) -# FIXME: For some reason pyright complains here with -# mismatch: expected "wsgify[Request, ()]" but received "wsgify[Request, ()]" -# can you spot the difference? -# assert_type(app(application), "wsgify[Request, []]") +assert_type(app(application), "wsgify[Request, []]") application = app(application) @@ -78,13 +75,10 @@ def m_app(request: Request) -> str: application = m_app -# FIXME: same weird pyright error where it complains about the types -# being the same -# assert_type(m_app, "wsgify[Request, [WSGIApplication]]") +assert_type(m_app, "wsgify[Request, [WSGIApplication]]") assert_type(m_app(env, start_response), "Iterable[bytes]") assert_type(m_app(request), _AnyResponse) -# FIXME: and also here -# assert_type(m_app(application), "wsgify[Request, [WSGIApplication]]") +assert_type(m_app(application), "wsgify[Request, [WSGIApplication]]") application = m_app(application) @@ -109,7 +103,7 @@ def valid_request_app(request: Request) -> None: # but the opposite is not allowed -@wsgify # type:ignore +@wsgify # type: ignore def invalid_request_app(request: MyRequest) -> None: pass @@ -117,5 +111,5 @@ def invalid_request_app(request: MyRequest) -> None: # we can't really make passing extra arguments directly work # otherwise we have to give up most of our type safety for # something that should only be used through wsgify.middleware -wsgify(args=(1,)) # type:ignore -wsgify(kwargs={"ips": ["127.0.0.1"]}) # type:ignore +wsgify(args=(1,)) # type: ignore +wsgify(kwargs={"ips": ["127.0.0.1"]}) # type: ignore diff --git a/stubs/openpyxl/@tests/test_cases/check_base_descriptors.py b/stubs/openpyxl/@tests/test_cases/check_base_descriptors.py index 265e5386c..ecf8ec25e 100644 --- a/stubs/openpyxl/@tests/test_cases/check_base_descriptors.py +++ b/stubs/openpyxl/@tests/test_cases/check_base_descriptors.py @@ -1,4 +1,4 @@ -# Needed until mypy issues are solved +# Needed until mypy issues are solved or https://github.com/python/mypy/issues/12358 # pyright: reportUnnecessaryTypeIgnoreComment=false from __future__ import annotations diff --git a/stubs/openpyxl/@tests/test_cases/check_nested_descriptors.py b/stubs/openpyxl/@tests/test_cases/check_nested_descriptors.py index e0e193ffe..6db00a7ad 100644 --- a/stubs/openpyxl/@tests/test_cases/check_nested_descriptors.py +++ b/stubs/openpyxl/@tests/test_cases/check_nested_descriptors.py @@ -1,4 +1,4 @@ -# Needed until mypy issues are solved +# Needed until mypy issues are solved or https://github.com/python/mypy/issues/12358 # pyright: reportUnnecessaryTypeIgnoreComment=false # These tests are essentially a mirror of check_base_descriptors diff --git a/stubs/pygit2/pygit2/_pygit2.pyi b/stubs/pygit2/pygit2/_pygit2.pyi index 487f9159c..4dfdab534 100644 --- a/stubs/pygit2/pygit2/_pygit2.pyi +++ b/stubs/pygit2/pygit2/_pygit2.pyi @@ -351,7 +351,7 @@ class Blob(Object): # This is not a real subclassing. Just ensuring type-checkers sees this type as compatible with _CDataBase # pyright has no error code for subclassing final @final -class Branch(Reference): # type: ignore[misc] # pyright: ignore +class Branch(Reference): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] branch_name: str raw_branch_name: bytes remote_name: str diff --git a/stubs/pygit2/pygit2/utils.pyi b/stubs/pygit2/pygit2/utils.pyi index 5bffb9cd2..22f4fe9aa 100644 --- a/stubs/pygit2/pygit2/utils.pyi +++ b/stubs/pygit2/pygit2/utils.pyi @@ -18,7 +18,7 @@ def strarray_to_strings(arr: _GitStrArray) -> list[str]: ... # Actual type: _cffi_backend.__CDataOwn # This is not a real subclassing. Just ensuring type-checkers sees this type as compatible with _CDataBase # pyright has no error code for subclassing final -class _GitStrArray(_CDataBase): # type: ignore[misc] # pyright: ignore +class _GitStrArray(_CDataBase): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] count: int strings: _CDataBase # diff --git a/stubs/pywin32/win32comext/axdebug/documents.pyi b/stubs/pywin32/win32comext/axdebug/documents.pyi index 7c1516b6a..5be676213 100644 --- a/stubs/pywin32/win32comext/axdebug/documents.pyi +++ b/stubs/pywin32/win32comext/axdebug/documents.pyi @@ -15,7 +15,7 @@ class DebugDocumentProvider(gateways.DebugDocumentProvider): # error: Cannot determine consistent method resolution order (MRO) for "DebugDocumentText" # pyright doesn't have a specific error code for MRO error! -class DebugDocumentText(gateways.DebugDocumentInfo, gateways.DebugDocumentText, gateways.DebugDocument): # type: ignore[misc] # pyright: ignore +class DebugDocumentText(gateways.DebugDocumentInfo, gateways.DebugDocumentText, gateways.DebugDocument): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] codeContainer: Incomplete def __init__(self, codeContainer) -> None: ... def GetName(self, dnt): ... diff --git a/tests/pytype_test.py b/tests/pytype_test.py index a237e9772..05be3d8dc 100755 --- a/tests/pytype_test.py +++ b/tests/pytype_test.py @@ -198,7 +198,7 @@ def get_missing_modules(files_to_test: Sequence[str]) -> Iterable[str]: # Skips comments, empty lines, and stdlib files, which are in # the exclude list because pytype has its own version. continue - unused_stubs_prefix, unused_pkg, mod_path = fi.split("/", 2) # pyright: ignore [reportUnusedVariable] + unused_stubs_prefix, unused_pkg, mod_path = fi.split("/", 2) # pyright: ignore[reportUnusedVariable] missing_modules.add(os.path.splitext(mod_path)[0]) return missing_modules