Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tests on Python 3.12 #162

Merged
merged 9 commits into from
May 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@
- Backport the implementation of `NewType` from 3.10 (where it is implemented
as a class rather than a function). This allows user-defined `NewType`s to be
pickled. Patch by Alex Waygood.
- Fix tests and import on Python 3.12, where `typing.TypeVar` can no longer be
subclassed. Patch by Jelle Zijlstra.
- Add `typing_extensions.TypeAliasType`, a backport of `typing.TypeAliasType`
from PEP 695. Patch by Jelle Zijlstra.
- Backport changes to the repr of `typing.Unpack` that were made in order to
Expand Down
36 changes: 31 additions & 5 deletions src/test_typing_extensions.py
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import re
import subprocess
import tempfile
import textwrap
import types
from pathlib import Path
from unittest import TestCase, main, skipUnless, skipIf
Expand Down Expand Up @@ -47,6 +48,9 @@
# 3.11 makes runtime type checks (_type_check) more lenient.
TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0)

# 3.12 changes the representation of Unpack[] (PEP 692)
TYPING_3_12_0 = sys.version_info[:3] >= (3, 12, 0)

# https://github.com/python/cpython/pull/27017 was backported into some 3.9 and 3.10
# versions, but not all
HAS_FORWARD_MODULE = "module" in inspect.signature(typing._type_check).parameters
Expand Down Expand Up @@ -2396,7 +2400,7 @@ def bar(self, x: str) -> str:
with self.assertRaises(TypeError):
PR[int, ClassVar]

if sys.version_info >= (3, 12):
if hasattr(typing, "TypeAliasType"):
exec(textwrap.dedent(
"""
def test_pep695_generic_protocol_callable_members(self):
Expand Down Expand Up @@ -4342,8 +4346,8 @@ def test_signature_on_37(self):
@skipUnless(TYPING_3_9_0, "NamedTuple was a class on 3.8 and lower")
def test_same_as_typing_NamedTuple_39_plus(self):
self.assertEqual(
set(dir(NamedTuple)),
set(dir(typing.NamedTuple)) | {"__text_signature__"}
set(dir(NamedTuple)) - {"__text_signature__"},
set(dir(typing.NamedTuple))
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
)
self.assertIs(type(NamedTuple), type(typing.NamedTuple))

Expand Down Expand Up @@ -4374,7 +4378,12 @@ class GenericNamedTuple(NamedTuple, Generic[T]):
class TypeVarLikeDefaultsTests(BaseTestCase):
def test_typevar(self):
T = typing_extensions.TypeVar('T', default=int)
typing_T = TypeVar('T')
self.assertEqual(T.__default__, int)
self.assertIsInstance(T, typing_extensions.TypeVar)
self.assertIsInstance(T, typing.TypeVar)
self.assertIsInstance(typing_T, typing.TypeVar)
self.assertIsInstance(typing_T, typing_extensions.TypeVar)

class A(Generic[T]): ...
Alias = Optional[T]
Expand All @@ -4388,13 +4397,25 @@ def test_typevar_none(self):
def test_paramspec(self):
P = ParamSpec('P', default=(str, int))
self.assertEqual(P.__default__, (str, int))
self.assertIsInstance(P, ParamSpec)
if hasattr(typing, "ParamSpec"):
self.assertIsInstance(P, typing.ParamSpec)
typing_P = typing.ParamSpec('P')
self.assertIsInstance(typing_P, typing.ParamSpec)
self.assertIsInstance(typing_P, ParamSpec)

class A(Generic[P]): ...
Alias = typing.Callable[P, None]

def test_typevartuple(self):
Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
self.assertIsInstance(Ts, TypeVarTuple)
if hasattr(typing, "TypeVarTuple"):
self.assertIsInstance(Ts, typing.TypeVarTuple)
typing_Ts = typing.TypeVarTuple('Ts')
self.assertIsInstance(typing_Ts, typing.TypeVarTuple)
self.assertIsInstance(typing_Ts, TypeVarTuple)

class A(Generic[Unpack[Ts]]): ...
Alias = Optional[Unpack[Ts]]
Expand Down Expand Up @@ -4454,8 +4475,13 @@ class MyRegisteredBuffer:
def __buffer__(self, flags: int) -> memoryview:
return memoryview(b'')

self.assertNotIsInstance(MyRegisteredBuffer(), Buffer)
self.assertNotIsSubclass(MyRegisteredBuffer, Buffer)
# On 3.12, collections.abc.Buffer does a structural compatibility check
if TYPING_3_12_0:
self.assertIsInstance(MyRegisteredBuffer(), Buffer)
self.assertIsSubclass(MyRegisteredBuffer, Buffer)
else:
self.assertNotIsInstance(MyRegisteredBuffer(), Buffer)
self.assertNotIsSubclass(MyRegisteredBuffer, Buffer)
Buffer.register(MyRegisteredBuffer)
self.assertIsInstance(MyRegisteredBuffer(), Buffer)
self.assertIsSubclass(MyRegisteredBuffer, Buffer)
Expand Down
109 changes: 70 additions & 39 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ def runtime_checkable(cls):
SupportsInt = typing.SupportsInt
SupportsFloat = typing.SupportsFloat
SupportsComplex = typing.SupportsComplex
SupportsBytes = typing.SupportsBytes
SupportsIndex = typing.SupportsIndex
SupportsAbs = typing.SupportsAbs
SupportsRound = typing.SupportsRound
Expand Down Expand Up @@ -1343,39 +1344,53 @@ def __repr__(self):
above.""")


def _set_default(type_param, default):
if isinstance(default, (tuple, list)):
type_param.__default__ = tuple((typing._type_check(d, "Default must be a type")
for d in default))
elif default != _marker:
type_param.__default__ = typing._type_check(default, "Default must be a type")
else:
type_param.__default__ = None


class _DefaultMixin:
"""Mixin for TypeVarLike defaults."""

__slots__ = ()

def __init__(self, default):
if isinstance(default, (tuple, list)):
self.__default__ = tuple((typing._type_check(d, "Default must be a type")
for d in default))
elif default != _marker:
self.__default__ = typing._type_check(default, "Default must be a type")
else:
self.__default__ = None
__init__ = _set_default


# Add default and infer_variance parameters from PEP 696 and 695
class TypeVar(typing.TypeVar, _DefaultMixin, _root=True):
"""Type variable."""

__module__ = 'typing'

def __init__(self, name, *constraints, bound=None,
class _TypeVarMeta(type):
def __call__(self, name, *constraints, bound=None,
covariant=False, contravariant=False,
default=_marker, infer_variance=False):
super().__init__(name, *constraints, bound=bound, covariant=covariant,
contravariant=contravariant)
_DefaultMixin.__init__(self, default)
self.__infer_variance__ = infer_variance
if hasattr(typing, "TypeAliasType"):
# PEP 695 implemented, can pass infer_variance to typing.TypeVar
typevar = typing.TypeVar(name, *constraints, bound=bound,
covariant=covariant, contravariant=contravariant,
infer_variance=infer_variance)
else:
typevar = typing.TypeVar(name, *constraints, bound=bound,
covariant=covariant, contravariant=contravariant)
typevar.__infer_variance__ = infer_variance
_set_default(typevar, default)

# for pickling:
def_mod = _caller()
if def_mod != 'typing_extensions':
self.__module__ = def_mod
typevar.__module__ = def_mod
return typevar

def __instancecheck__(self, __instance: Any) -> bool:
return isinstance(__instance, typing.TypeVar)


class TypeVar(metaclass=_TypeVarMeta):
"""Type variable."""

__module__ = 'typing'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh



# Python 3.10+ has PEP 612
Expand Down Expand Up @@ -1443,22 +1458,28 @@ def __eq__(self, other):
# 3.10+
if hasattr(typing, 'ParamSpec'):

# Add default Parameter - PEP 696
class ParamSpec(typing.ParamSpec, _DefaultMixin, _root=True):
"""Parameter specification variable."""

__module__ = 'typing'

def __init__(self, name, *, bound=None, covariant=False, contravariant=False,
# Add default parameter - PEP 696
class _ParamSpecMeta(type):
def __call__(self, name, *, bound=None,
covariant=False, contravariant=False,
default=_marker):
super().__init__(name, bound=bound, covariant=covariant,
contravariant=contravariant)
_DefaultMixin.__init__(self, default)
paramspec = typing.ParamSpec(name, bound=bound,
covariant=covariant, contravariant=contravariant)
_set_default(paramspec, default)

# for pickling:
def_mod = _caller()
if def_mod != 'typing_extensions':
self.__module__ = def_mod
paramspec.__module__ = def_mod
return paramspec

def __instancecheck__(self, __instance: Any) -> bool:
return isinstance(__instance, typing.ParamSpec)

class ParamSpec(metaclass=_ParamSpecMeta):
"""Parameter specification."""

__module__ = 'typing'

# 3.7-3.9
else:
Expand Down Expand Up @@ -2061,18 +2082,28 @@ def _is_unpack(obj):

if hasattr(typing, "TypeVarTuple"): # 3.11+

# Add default Parameter - PEP 696
class TypeVarTuple(typing.TypeVarTuple, _DefaultMixin, _root=True):
"""Type variable tuple."""

def __init__(self, name, *, default=_marker):
super().__init__(name)
_DefaultMixin.__init__(self, default)
# Add default parameter - PEP 696
class _TypeVarTupleMeta(type):
def __call__(self, name, *, default=_marker):
tvt = typing.TypeVarTuple(name)
_set_default(tvt, default)

# for pickling:
def_mod = _caller()
if def_mod != 'typing_extensions':
self.__module__ = def_mod
tvt.__module__ = def_mod
return tvt

def __instancecheck__(self, __instance: Any) -> bool:
return isinstance(__instance, typing.TypeVarTuple)

class TypeVarTuple(metaclass=_TypeVarTupleMeta):
"""Type variable tuple."""

__module__ = 'typing'

def __init_subclass__(self, *args, **kwds):
raise TypeError("Cannot subclass special typing classes")

else:
class TypeVarTuple(_DefaultMixin):
Expand Down
Loading