diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d1da0258..47704723 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -92,8 +92,8 @@ jobs: export path_to_file=$(find dist -type f -name "typing_extensions-*.tar.gz") echo "::notice::Unpacking source distribution: $path_to_file" tar xzf $path_to_file -C dist/ - cd ${path_to_file%.tar.gz} - python src/test_typing_extensions.py + cd ${path_to_file%.tar.gz}/src + python test_typing_extensions.py test-sdist-installed: name: Test installed source distribution diff --git a/CHANGELOG.md b/CHANGELOG.md index d1ac543b..f315d1ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# Unreleased + +- Fix incorrect behaviour of `typing_extensions.ParamSpec` on Python 3.8 and + 3.9 that meant that + `isinstance(typing_extensions.ParamSpec("P"), typing.TypeVar)` would have a + different result in some situations depending on whether or not a profiling + function had been set using `sys.setprofile`. Patch by Alex Waygood. + # Release 4.12.0rc1 (May 16, 2024) This release focuses on compatibility with the upcoming release of diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 5d37b5bf..080c0f7c 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -5020,6 +5020,48 @@ def test_eq(self): # won't be the same. self.assertNotEqual(hash(ParamSpec('P')), hash(P)) + def test_isinstance_results_unaffected_by_presence_of_tracing_function(self): + # See https://github.com/python/typing_extensions/issues/318 + + code = textwrap.dedent( + """\ + import sys, typing + + def trace_call(*args): + return trace_call + + def run(): + sys.modules.pop("typing_extensions", None) + from typing_extensions import ParamSpec + return isinstance(ParamSpec("P"), typing.TypeVar) + + isinstance_result_1 = run() + sys.setprofile(trace_call) + isinstance_result_2 = run() + sys.stdout.write(f"{isinstance_result_1} {isinstance_result_2}") + """ + ) + + # Run this in an isolated process or it pollutes the environment + # and makes other tests fail: + try: + proc = subprocess.run( + [sys.executable, "-c", code], check=True, capture_output=True, text=True, + ) + except subprocess.CalledProcessError as exc: + print("stdout", exc.stdout, sep="\n") + print("stderr", exc.stderr, sep="\n") + raise + + # Sanity checks that assert the test is working as expected + self.assertIsInstance(proc.stdout, str) + result1, result2 = proc.stdout.split(" ") + self.assertIn(result1, {"True", "False"}) + self.assertIn(result2, {"True", "False"}) + + # The actual test: + self.assertEqual(result1, result2) + class ConcatenateTests(BaseTestCase): def test_basics(self): diff --git a/src/typing_extensions.py b/src/typing_extensions.py index d549fb69..57e59a8b 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -1711,7 +1711,7 @@ def kwargs(self): def __init__(self, name, *, bound=None, covariant=False, contravariant=False, infer_variance=False, default=NoDefault): - super().__init__([self]) + list.__init__(self, [self]) self.__name__ = name self.__covariant__ = bool(covariant) self.__contravariant__ = bool(contravariant)