From 49a0cea5c2d78b3fca957012c4a4f15deb9205b9 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 13:31:34 +0100 Subject: [PATCH 01/15] Add regression tests for `builtins.pow` and `object.__reduce__` --- pyrightconfig.json | 3 +- pyrightconfig.stricter.json | 3 +- stdlib/builtins.pyi | 12 ------- test_cases/README.md | 18 ++++++++++ test_cases/stdlib/test_builtins.py | 54 ++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 test_cases/README.md create mode 100644 test_cases/stdlib/test_builtins.py diff --git a/pyrightconfig.json b/pyrightconfig.json index 3d35f28a7250..8bcc7aa96657 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -2,7 +2,8 @@ "typeshedPath": ".", "include": [ "stdlib", - "stubs" + "stubs", + "test_cases" ], "exclude": [ "**/@python2" diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 55eea79bf374..2f41cc1deedc 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -3,7 +3,8 @@ "typeshedPath": ".", "include": [ "stdlib", - "stubs" + "stubs", + "test_cases" ], "exclude": [ "**/@python2", diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index bf1e6cde2c08..431c880f07f0 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -101,8 +101,6 @@ class object: def __format__(self, __format_spec: str) -> str: ... def __getattribute__(self, __name: str) -> Any: ... def __sizeof__(self) -> int: ... - # return type of pickle methods is rather hard to express in the current type system - # see #6661 and https://docs.python.org/3/library/pickle.html#object.__reduce__ def __reduce__(self) -> str | tuple[Any, ...]: ... if sys.version_info >= (3, 8): def __reduce_ex__(self, __protocol: SupportsIndex) -> str | tuple[Any, ...]: ... @@ -260,8 +258,6 @@ class int: def __pow__(self, __x: _PositiveInteger, __modulo: None = ...) -> int: ... @overload def __pow__(self, __x: _NegativeInteger, __modulo: None = ...) -> float: ... - # positive x -> int; negative x -> float - # return type must be Any as `int | float` causes too many false-positive errors @overload def __pow__(self, __x: int, __modulo: None = ...) -> Any: ... def __rpow__(self, __x: int, __mod: int | None = ...) -> Any: ... @@ -317,8 +313,6 @@ class float: def __divmod__(self, __x: float) -> tuple[float, float]: ... @overload def __pow__(self, __x: int, __mod: None = ...) -> float: ... - # positive x -> float; negative x -> complex - # return type must be Any as `float | complex` causes too many false-positive errors @overload def __pow__(self, __x: float, __mod: None = ...) -> Any: ... def __radd__(self, __x: float) -> float: ... @@ -328,7 +322,6 @@ class float: def __rtruediv__(self, __x: float) -> float: ... def __rmod__(self, __x: float) -> float: ... def __rdivmod__(self, __x: float) -> tuple[float, float]: ... - # Returns complex if the argument is negative. def __rpow__(self, __x: float, __mod: None = ...) -> Any: ... def __getnewargs__(self) -> tuple[float]: ... def __trunc__(self) -> int: ... @@ -1418,15 +1411,10 @@ if sys.version_info >= (3, 8): def pow(base: int, exp: _PositiveInteger, mod: None = ...) -> int: ... # type: ignore[misc] @overload def pow(base: int, exp: _NegativeInteger, mod: None = ...) -> float: ... # type: ignore[misc] - # int base & positive-int exp -> int; int base & negative-int exp -> float - # return type must be Any as `int | float` causes too many false-positive errors @overload def pow(base: int, exp: int, mod: None = ...) -> Any: ... @overload def pow(base: float, exp: int, mod: None = ...) -> float: ... - # float base & float exp could return float or complex - # return type must be Any (same as complex base, complex exp), - # as `float | complex` causes too many false-positive errors @overload def pow(base: float, exp: complex | _SupportsSomeKindOfPow, mod: None = ...) -> Any: ... @overload diff --git a/test_cases/README.md b/test_cases/README.md new file mode 100644 index 000000000000..306db8384ab1 --- /dev/null +++ b/test_cases/README.md @@ -0,0 +1,18 @@ +## Regression tests for typeshed + +This directory contains regression tests for the stubs found elsewhere in the +typeshed repo. Each file contains a number of test cases, all of which should +pass a type checker without error. + +The internal structure of this directory should mimic typeshed as a whole. +However, unlike the rest of typeshed, this directory largely contains `.py` +files, because the purpose of this folder is to test the implications of +typeshed changes for end-users. For example, the stub for `builtins.pow` is +found in `stdlib/builtins.pyi`, and the regression tests for `pow` are found in +`test_cases/stdlib/test_builtins.py`. + +100% test coverage for typeshed is neither necessary nor desirable, as it would +lead to unnecessary code duplication, and we have multiple other mechanisms for +spotting errors in the stubs. As such, this directory should only contain tests +for functions and classes which are known to have caused problems in the past, +and are difficult to get right. \ No newline at end of file diff --git a/test_cases/stdlib/test_builtins.py b/test_cases/stdlib/test_builtins.py new file mode 100644 index 000000000000..f268ef060ad3 --- /dev/null +++ b/test_cases/stdlib/test_builtins.py @@ -0,0 +1,54 @@ +from decimal import Decimal +from fractions import Fraction +from typing import Any, NoReturn +from typing_extensions import Literal, assert_type + +# +# REGRESSION TESTS FOR OBJECT.__REDUCE__ +# +# The following should pass without error (see #6661): +class Diagnostic: + def __reduce__(self) -> str | tuple[Any, ...]: + res = super().__reduce__() + if isinstance(res, tuple) and len(res) >= 3: + res[2]["_info"] = 42 + + return res + +# +# REGRESSION TESTS FOR POW() +# +assert_type(pow(1, 0), Literal[1]) # See #7163 +assert_type(pow(1, 0, None), Literal[1]) # See #7163 +assert_type(pow(2, 4, 0), NoReturn) +assert_type(pow(2, 4), int) +assert_type(pow(5, -7), float) +assert_type(pow(2, 4, 5), int) # pow(, , ) +assert_type(pow(2, 35, 3), int) # pow(, , ) +assert_type(pow(4.6, 8), float) +assert_type(pow(5.1, 4, None), float) +assert_type(pow(complex(6), 6.2), complex) +assert_type(pow(complex(9), 7.3, None), complex) +assert_type(pow(Fraction(), 4, None), Fraction) +assert_type(pow(Fraction(3, 7), complex(1, 8)), complex) +assert_type(pow(complex(4, -8), Fraction(2, 3)), complex) +assert_type(pow(Decimal("1.0"), Decimal("1.6")), Decimal) +assert_type(pow(Decimal("1.0"), Decimal("1.0"), Decimal("1.0")), Decimal) +assert_type(pow(Decimal("4.6"), 7, None), Decimal) +assert_type((4).__pow__(7, 4), int) +assert_type((4).__pow__(6, None), int) +assert_type(complex(9).__pow__(3.1, None), complex) +assert_type(Decimal("2.6").__pow__(5, None), Decimal) + +# These would ideally be more precise, but `Any` is acceptable +# They have to be `Any` due to the fact that type-checkers can't distinguish between positive and negative numbers for the second argument to `pow()` +# +# int for positive 2nd-arg, float otherwise +assert_type(pow(4, 65), Any) +assert_type(pow(3, 57, None), Any) +# float for positive 2nd-arg, complex otherwise +assert_type(pow(4.7, 7.4), Any) +assert_type(pow(4.7, 9.2, None), Any) +assert_type((6.2).__pow__(5.2, None), Any) +# See #7046 -- float for a positive 1st arg, complex otherwise +assert_type((-2) ** 0.5, Any) From 527a48c6bc11bec14c820957b8ce803a6c9925f4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 12:36:16 +0000 Subject: [PATCH 02/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/test_builtins.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_cases/stdlib/test_builtins.py b/test_cases/stdlib/test_builtins.py index f268ef060ad3..a0a1a9aba199 100644 --- a/test_cases/stdlib/test_builtins.py +++ b/test_cases/stdlib/test_builtins.py @@ -3,6 +3,7 @@ from typing import Any, NoReturn from typing_extensions import Literal, assert_type + # # REGRESSION TESTS FOR OBJECT.__REDUCE__ # @@ -15,6 +16,7 @@ def __reduce__(self) -> str | tuple[Any, ...]: return res + # # REGRESSION TESTS FOR POW() # From 6adc92801ca58f085f74e356d9694860c0bcbb22 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 19 Apr 2022 13:37:09 +0100 Subject: [PATCH 03/15] Union syntax requires future annotations --- test_cases/stdlib/test_builtins.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_cases/stdlib/test_builtins.py b/test_cases/stdlib/test_builtins.py index a0a1a9aba199..75ff3f1713ff 100644 --- a/test_cases/stdlib/test_builtins.py +++ b/test_cases/stdlib/test_builtins.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from decimal import Decimal from fractions import Fraction from typing import Any, NoReturn From 678b5af501fc9a4d1e2d5b25a645b274b4c68e4a Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 19 Apr 2022 13:39:59 +0100 Subject: [PATCH 04/15] `__future__` annotations don't exist on 3.6, use old syntax instead --- test_cases/stdlib/test_builtins.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test_cases/stdlib/test_builtins.py b/test_cases/stdlib/test_builtins.py index 75ff3f1713ff..097d46ae895d 100644 --- a/test_cases/stdlib/test_builtins.py +++ b/test_cases/stdlib/test_builtins.py @@ -1,8 +1,6 @@ -from __future__ import annotations - from decimal import Decimal from fractions import Fraction -from typing import Any, NoReturn +from typing import Any, NoReturn, Tuple, Union from typing_extensions import Literal, assert_type @@ -11,7 +9,7 @@ # # The following should pass without error (see #6661): class Diagnostic: - def __reduce__(self) -> str | tuple[Any, ...]: + def __reduce__(self) -> Union[str, Tuple[Any, ...]]: res = super().__reduce__() if isinstance(res, tuple) and len(res) >= 3: res[2]["_info"] = 42 From 62209c35f8a4b45d29fee16a414ef908d5e7f0a7 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 13:54:57 +0100 Subject: [PATCH 05/15] Add note about why older syntax is used in test cases --- test_cases/README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test_cases/README.md b/test_cases/README.md index 306db8384ab1..c9c6209d3181 100644 --- a/test_cases/README.md +++ b/test_cases/README.md @@ -15,4 +15,13 @@ found in `stdlib/builtins.pyi`, and the regression tests for `pow` are found in lead to unnecessary code duplication, and we have multiple other mechanisms for spotting errors in the stubs. As such, this directory should only contain tests for functions and classes which are known to have caused problems in the past, -and are difficult to get right. \ No newline at end of file +and are difficult to get right. + +Note that, unlike elsewhere in typeshed, the test cases in this directory +cannot always use modern syntax for type hints. For example, PEP 604 syntax +(unions with a pipe `|` operator) is new in Python 3.10. While this syntax can +be used on older Python versions in a `.pyi` file, code using this syntax will +fail at runtime on Python <=3.9. Since the test cases all use `.py` extensions, +and since the tests need to pass on all Python versions >=3.6, PEP 604 syntax +cannot be used in a test case. Use `typing.Union` and `typing.Optional` +instead. \ No newline at end of file From 632a75f54e636419bec91146ca3cb6a1b169a145 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 13:58:31 +0100 Subject: [PATCH 06/15] More wordsmithing --- test_cases/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test_cases/README.md b/test_cases/README.md index c9c6209d3181..d4baf696eea3 100644 --- a/test_cases/README.md +++ b/test_cases/README.md @@ -6,16 +6,16 @@ pass a type checker without error. The internal structure of this directory should mimic typeshed as a whole. However, unlike the rest of typeshed, this directory largely contains `.py` -files, because the purpose of this folder is to test the implications of -typeshed changes for end-users. For example, the stub for `builtins.pow` is +files. This is because the purpose of this folder is to test the implications +of typeshed changes for end users. For example, the stub for `builtins.pow` is found in `stdlib/builtins.pyi`, and the regression tests for `pow` are found in `test_cases/stdlib/test_builtins.py`. 100% test coverage for typeshed is neither necessary nor desirable, as it would -lead to unnecessary code duplication, and we have multiple other mechanisms for -spotting errors in the stubs. As such, this directory should only contain tests -for functions and classes which are known to have caused problems in the past, -and are difficult to get right. +lead to unnecessary code duplication. Moreover, typeshed has multiple other +mechanisms for spotting errors in the stubs. As such, this directory should +only contain tests for functions and classes which are known to have caused +problems in the past, where the stubs are difficult to get right. Note that, unlike elsewhere in typeshed, the test cases in this directory cannot always use modern syntax for type hints. For example, PEP 604 syntax From 78b9dd01d1842ceffde5f0436f53dd29e13e3a0e Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 17:26:25 +0100 Subject: [PATCH 07/15] Add back comments to `builtins` --- stdlib/builtins.pyi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 431c880f07f0..bf1e6cde2c08 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -101,6 +101,8 @@ class object: def __format__(self, __format_spec: str) -> str: ... def __getattribute__(self, __name: str) -> Any: ... def __sizeof__(self) -> int: ... + # return type of pickle methods is rather hard to express in the current type system + # see #6661 and https://docs.python.org/3/library/pickle.html#object.__reduce__ def __reduce__(self) -> str | tuple[Any, ...]: ... if sys.version_info >= (3, 8): def __reduce_ex__(self, __protocol: SupportsIndex) -> str | tuple[Any, ...]: ... @@ -258,6 +260,8 @@ class int: def __pow__(self, __x: _PositiveInteger, __modulo: None = ...) -> int: ... @overload def __pow__(self, __x: _NegativeInteger, __modulo: None = ...) -> float: ... + # positive x -> int; negative x -> float + # return type must be Any as `int | float` causes too many false-positive errors @overload def __pow__(self, __x: int, __modulo: None = ...) -> Any: ... def __rpow__(self, __x: int, __mod: int | None = ...) -> Any: ... @@ -313,6 +317,8 @@ class float: def __divmod__(self, __x: float) -> tuple[float, float]: ... @overload def __pow__(self, __x: int, __mod: None = ...) -> float: ... + # positive x -> float; negative x -> complex + # return type must be Any as `float | complex` causes too many false-positive errors @overload def __pow__(self, __x: float, __mod: None = ...) -> Any: ... def __radd__(self, __x: float) -> float: ... @@ -322,6 +328,7 @@ class float: def __rtruediv__(self, __x: float) -> float: ... def __rmod__(self, __x: float) -> float: ... def __rdivmod__(self, __x: float) -> tuple[float, float]: ... + # Returns complex if the argument is negative. def __rpow__(self, __x: float, __mod: None = ...) -> Any: ... def __getnewargs__(self) -> tuple[float]: ... def __trunc__(self) -> int: ... @@ -1411,10 +1418,15 @@ if sys.version_info >= (3, 8): def pow(base: int, exp: _PositiveInteger, mod: None = ...) -> int: ... # type: ignore[misc] @overload def pow(base: int, exp: _NegativeInteger, mod: None = ...) -> float: ... # type: ignore[misc] + # int base & positive-int exp -> int; int base & negative-int exp -> float + # return type must be Any as `int | float` causes too many false-positive errors @overload def pow(base: int, exp: int, mod: None = ...) -> Any: ... @overload def pow(base: float, exp: int, mod: None = ...) -> float: ... + # float base & float exp could return float or complex + # return type must be Any (same as complex base, complex exp), + # as `float | complex` causes too many false-positive errors @overload def pow(base: float, exp: complex | _SupportsSomeKindOfPow, mod: None = ...) -> Any: ... @overload From 9d3650fdfb908392b626c4e2a3b2964e589bfc57 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 17:38:32 +0100 Subject: [PATCH 08/15] Correct comment, add a few more cases --- test_cases/stdlib/test_builtins.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test_cases/stdlib/test_builtins.py b/test_cases/stdlib/test_builtins.py index 097d46ae895d..cc200a3b5a5a 100644 --- a/test_cases/stdlib/test_builtins.py +++ b/test_cases/stdlib/test_builtins.py @@ -47,9 +47,14 @@ def __reduce__(self) -> Union[str, Tuple[Any, ...]]: # # int for positive 2nd-arg, float otherwise assert_type(pow(4, 65), Any) +assert_type(pow(2, -45), Any) assert_type(pow(3, 57, None), Any) -# float for positive 2nd-arg, complex otherwise +# pow(, ) -> float +# pow(, ) -> complex assert_type(pow(4.7, 7.4), Any) +assert_type(pow(-9.8, 8.3), Any) +assert_type(pow(-9.3, -88.2), Any) +assert_type(pow(8.2, -9.8), Any) assert_type(pow(4.7, 9.2, None), Any) assert_type((6.2).__pow__(5.2, None), Any) # See #7046 -- float for a positive 1st arg, complex otherwise From b2e59b55383fe58cc25f703582a941fcff6cd5c6 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 17:42:03 +0100 Subject: [PATCH 09/15] Make 'DO NOT ADD STUPID TESTS' notice more prominent --- test_cases/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test_cases/README.md b/test_cases/README.md index d4baf696eea3..110e8be50735 100644 --- a/test_cases/README.md +++ b/test_cases/README.md @@ -4,6 +4,12 @@ This directory contains regression tests for the stubs found elsewhere in the typeshed repo. Each file contains a number of test cases, all of which should pass a type checker without error. +**This directory should *only* contain tests for functions and classes which +are known to have caused problems in the past, where the stubs are difficult to +get right.** 100% test coverage for typeshed is neither necessary nor +desirable, as it would lead to code duplication. Moreover, typeshed has +multiple other mechanisms for spotting errors in the stubs. + The internal structure of this directory should mimic typeshed as a whole. However, unlike the rest of typeshed, this directory largely contains `.py` files. This is because the purpose of this folder is to test the implications @@ -11,12 +17,6 @@ of typeshed changes for end users. For example, the stub for `builtins.pow` is found in `stdlib/builtins.pyi`, and the regression tests for `pow` are found in `test_cases/stdlib/test_builtins.py`. -100% test coverage for typeshed is neither necessary nor desirable, as it would -lead to unnecessary code duplication. Moreover, typeshed has multiple other -mechanisms for spotting errors in the stubs. As such, this directory should -only contain tests for functions and classes which are known to have caused -problems in the past, where the stubs are difficult to get right. - Note that, unlike elsewhere in typeshed, the test cases in this directory cannot always use modern syntax for type hints. For example, PEP 604 syntax (unions with a pipe `|` operator) is new in Python 3.10. While this syntax can From 0e2165f3dacccaa571ffa0969b7fc4291de33b90 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 17:48:19 +0100 Subject: [PATCH 10/15] Split up `test_builtins.py` into two files --- test_cases/stdlib/builtins/test_object.py | 10 ++++++++++ .../test_pow.py} | 19 +------------------ 2 files changed, 11 insertions(+), 18 deletions(-) create mode 100644 test_cases/stdlib/builtins/test_object.py rename test_cases/stdlib/{test_builtins.py => builtins/test_pow.py} (82%) diff --git a/test_cases/stdlib/builtins/test_object.py b/test_cases/stdlib/builtins/test_object.py new file mode 100644 index 000000000000..01ab8c5eb739 --- /dev/null +++ b/test_cases/stdlib/builtins/test_object.py @@ -0,0 +1,10 @@ +from typing import Any, Tuple, Union + +# The following should pass without error (see #6661): +class Diagnostic: + def __reduce__(self) -> Union[str, Tuple[Any, ...]]: + res = super().__reduce__() + if isinstance(res, tuple) and len(res) >= 3: + res[2]["_info"] = 42 + + return res diff --git a/test_cases/stdlib/test_builtins.py b/test_cases/stdlib/builtins/test_pow.py similarity index 82% rename from test_cases/stdlib/test_builtins.py rename to test_cases/stdlib/builtins/test_pow.py index cc200a3b5a5a..46a517270f94 100644 --- a/test_cases/stdlib/test_builtins.py +++ b/test_cases/stdlib/builtins/test_pow.py @@ -1,25 +1,8 @@ from decimal import Decimal from fractions import Fraction -from typing import Any, NoReturn, Tuple, Union +from typing import Any, NoReturn from typing_extensions import Literal, assert_type - -# -# REGRESSION TESTS FOR OBJECT.__REDUCE__ -# -# The following should pass without error (see #6661): -class Diagnostic: - def __reduce__(self) -> Union[str, Tuple[Any, ...]]: - res = super().__reduce__() - if isinstance(res, tuple) and len(res) >= 3: - res[2]["_info"] = 42 - - return res - - -# -# REGRESSION TESTS FOR POW() -# assert_type(pow(1, 0), Literal[1]) # See #7163 assert_type(pow(1, 0, None), Literal[1]) # See #7163 assert_type(pow(2, 4, 0), NoReturn) From 62a391614bb7a3096b69dfb03387d64e0cdd698a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 16:50:02 +0000 Subject: [PATCH 11/15] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/builtins/test_object.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test_cases/stdlib/builtins/test_object.py b/test_cases/stdlib/builtins/test_object.py index 01ab8c5eb739..f2b56e4e4569 100644 --- a/test_cases/stdlib/builtins/test_object.py +++ b/test_cases/stdlib/builtins/test_object.py @@ -1,5 +1,6 @@ from typing import Any, Tuple, Union + # The following should pass without error (see #6661): class Diagnostic: def __reduce__(self) -> Union[str, Tuple[Any, ...]]: From 1859f7377d2763dc6ce27672f86e2e1549a26962 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 19:54:43 +0100 Subject: [PATCH 12/15] Tweak the README now that the file structure has changed --- test_cases/README.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/test_cases/README.md b/test_cases/README.md index 110e8be50735..070262fd5f23 100644 --- a/test_cases/README.md +++ b/test_cases/README.md @@ -10,18 +10,15 @@ get right.** 100% test coverage for typeshed is neither necessary nor desirable, as it would lead to code duplication. Moreover, typeshed has multiple other mechanisms for spotting errors in the stubs. -The internal structure of this directory should mimic typeshed as a whole. -However, unlike the rest of typeshed, this directory largely contains `.py` -files. This is because the purpose of this folder is to test the implications -of typeshed changes for end users. For example, the stub for `builtins.pow` is -found in `stdlib/builtins.pyi`, and the regression tests for `pow` are found in -`test_cases/stdlib/test_builtins.py`. +Unlike the rest of typeshed, this directory largely contains `.py` files. This +is because the purpose of this folder is to test the implications of typeshed +changes for end users. -Note that, unlike elsewhere in typeshed, the test cases in this directory -cannot always use modern syntax for type hints. For example, PEP 604 syntax -(unions with a pipe `|` operator) is new in Python 3.10. While this syntax can -be used on older Python versions in a `.pyi` file, code using this syntax will -fail at runtime on Python <=3.9. Since the test cases all use `.py` extensions, -and since the tests need to pass on all Python versions >=3.6, PEP 604 syntax -cannot be used in a test case. Use `typing.Union` and `typing.Optional` -instead. \ No newline at end of file +Another difference to the rest of typeshed is that the test cases in this +directory cannot always use modern syntax for type hints. For example, PEP 604 +syntax (unions with a pipe `|` operator) is new in Python 3.10. While this +syntax can be used on older Python versions in a `.pyi` file, code using this +syntax will fail at runtime on Python <=3.9. Since the test cases all use `.py` +extensions, and since the tests need to pass on all Python versions >=3.6, PEP +604 syntax cannot be used in a test case. Use `typing.Union` and +`typing.Optional` instead. From c4d493ad3519d13a8676e6ca32de77d0dbeb6848 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 21:20:43 +0100 Subject: [PATCH 13/15] Double-check that these tests fail if we break something in typeshed --- stdlib/builtins.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index bf1e6cde2c08..e7d10e4366b6 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -103,7 +103,7 @@ class object: def __sizeof__(self) -> int: ... # return type of pickle methods is rather hard to express in the current type system # see #6661 and https://docs.python.org/3/library/pickle.html#object.__reduce__ - def __reduce__(self) -> str | tuple[Any, ...]: ... + def __reduce__(self) -> str | tuple[object, ...]: ... if sys.version_info >= (3, 8): def __reduce_ex__(self, __protocol: SupportsIndex) -> str | tuple[Any, ...]: ... else: From 8051080083e1d00f2a5ecd87042a07ed274b7ee2 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Tue, 19 Apr 2022 21:23:44 +0100 Subject: [PATCH 14/15] They do --- stdlib/builtins.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index e7d10e4366b6..bf1e6cde2c08 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -103,7 +103,7 @@ class object: def __sizeof__(self) -> int: ... # return type of pickle methods is rather hard to express in the current type system # see #6661 and https://docs.python.org/3/library/pickle.html#object.__reduce__ - def __reduce__(self) -> str | tuple[object, ...]: ... + def __reduce__(self) -> str | tuple[Any, ...]: ... if sys.version_info >= (3, 8): def __reduce_ex__(self, __protocol: SupportsIndex) -> str | tuple[Any, ...]: ... else: From 5aa49a27487743e9d5e7585e5f612a2a56a66e4f Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 20 Apr 2022 18:09:57 +0100 Subject: [PATCH 15/15] Delete weird, unidiomatic tests --- test_cases/stdlib/builtins/test_pow.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test_cases/stdlib/builtins/test_pow.py b/test_cases/stdlib/builtins/test_pow.py index 46a517270f94..c20ab76d70b7 100644 --- a/test_cases/stdlib/builtins/test_pow.py +++ b/test_cases/stdlib/builtins/test_pow.py @@ -7,6 +7,7 @@ assert_type(pow(1, 0, None), Literal[1]) # See #7163 assert_type(pow(2, 4, 0), NoReturn) assert_type(pow(2, 4), int) +assert_type(pow(4, 6, None), int) assert_type(pow(5, -7), float) assert_type(pow(2, 4, 5), int) # pow(, , ) assert_type(pow(2, 35, 3), int) # pow(, , ) @@ -20,10 +21,6 @@ assert_type(pow(Decimal("1.0"), Decimal("1.6")), Decimal) assert_type(pow(Decimal("1.0"), Decimal("1.0"), Decimal("1.0")), Decimal) assert_type(pow(Decimal("4.6"), 7, None), Decimal) -assert_type((4).__pow__(7, 4), int) -assert_type((4).__pow__(6, None), int) -assert_type(complex(9).__pow__(3.1, None), complex) -assert_type(Decimal("2.6").__pow__(5, None), Decimal) # These would ideally be more precise, but `Any` is acceptable # They have to be `Any` due to the fact that type-checkers can't distinguish between positive and negative numbers for the second argument to `pow()` @@ -39,6 +36,5 @@ assert_type(pow(-9.3, -88.2), Any) assert_type(pow(8.2, -9.8), Any) assert_type(pow(4.7, 9.2, None), Any) -assert_type((6.2).__pow__(5.2, None), Any) # See #7046 -- float for a positive 1st arg, complex otherwise assert_type((-2) ** 0.5, Any)