Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add some miscellaneous tests#659

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
AlexWaygood merged 13 commits intopython:mainfrombrianschubert:test-coverage
Aug 30, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
13 commits
Select commitHold shift + click to select a range
b57805e
Add miscellaneous tests
brianschubertAug 23, 2025
611cb74
Remove dead branches in _SpecialGenericAlias.__getitem__
brianschubertAug 26, 2025
168aff0
Copy `ParamSpec.__init_subclass__` implementation to Python 3.9 branch
brianschubertAug 30, 2025
69672c2
Add `__[r]or__` tests to `_SpecialForm` instances with meaningful unions
brianschubertAug 30, 2025
8cb7850
Split off `get_type_hints` w/ types.GenericAlias` test
brianschubertAug 30, 2025
50b55af
Use public API for testing `_SpecialGenericAlias.__setattr__`
brianschubertAug 30, 2025
ed27322
Use mixin for common NoDefault/NoExtraItems tests
brianschubertAug 30, 2025
8032414
name
brianschubertAug 30, 2025
5d7f637
Tidy test_setattr cleanup
brianschubertAug 30, 2025
4a0d76a
Use TYPING_3_11_0
brianschubertAug 30, 2025
ed5ee71
Add changelog entry
brianschubertAug 30, 2025
29473d1
Merge remote-tracking branch 'upstream/main' into test-coverage
brianschubertAug 30, 2025
2e23850
Remove leftover variable
brianschubertAug 30, 2025
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
7 changes: 7 additions & 0 deletionsCHANGELOG.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
# Unreleased

- Raise `TypeError` when attempting to subclass `typing_extensions.ParamSpec` on
Python 3.9. The `typing` implementation has always raised an error, and the
`typing_extensions` implementation has raised an error on Python 3.10+ since
`typing_extensions` v4.6.0. Patch by Brian Schubert.

# Release 4.15.0 (August 25, 2025)

No user-facing changes since 4.15.0rc1.
Expand Down
143 changes: 129 additions & 14 deletionssrc/test_typing_extensions.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -531,6 +531,14 @@ def test_pickle(self):
pickled = pickle.dumps(self.bottom_type, protocol=proto)
self.assertIs(self.bottom_type, pickle.loads(pickled))

@skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
def test_or(self):
self.assertEqual(self.bottom_type | int, Union[self.bottom_type, int])
self.assertEqual(int | self.bottom_type, Union[int, self.bottom_type])

self.assertEqual(get_args(self.bottom_type | int), (self.bottom_type, int))
self.assertEqual(get_args(int | self.bottom_type), (int, self.bottom_type))


class NoReturnTests(BottomTypeTestsMixin, BaseTestCase):
bottom_type = NoReturn
Expand DownExpand Up@@ -2210,6 +2218,39 @@ def test_or_and_ror(self):
Union[typing_extensions.Generator, typing.Deque]
)

def test_setattr(self):
origin = collections.abc.Generator
alias = typing_extensions.Generator
original_name = alias._name

def cleanup():
for obj in origin, alias:
for attr in 'foo', '__dunder__':
try:
delattr(obj, attr)
except Exception:
pass
try:
alias._name = original_name
except Exception:
pass

self.addCleanup(cleanup)

# Attribute assignment on generic alias sets attribute on origin
alias.foo = 1
self.assertEqual(alias.foo, 1)
self.assertEqual(origin.foo, 1)
# Except for dunders...
alias.__dunder__ = 2
self.assertEqual(alias.__dunder__, 2)
self.assertRaises(AttributeError, lambda: origin.__dunder__)

# ...and certain known attributes
alias._name = "NewName"
self.assertEqual(alias._name, "NewName")
self.assertRaises(AttributeError, lambda: origin._name)


class OtherABCTests(BaseTestCase):

Expand DownExpand Up@@ -2379,6 +2420,16 @@ def test_error_message_when_subclassing(self):
class ProUserId(UserId):
...

def test_module_with_incomplete_sys(self):
def does_not_exist(*args):
raise AttributeError
with (
patch("sys._getframemodulename", does_not_exist, create=True),
patch("sys._getframe", does_not_exist, create=True),
):
X = NewType("X", int)
self.assertEqual(X.__module__, None)


class Coordinate(Protocol):
x: int
Expand DownExpand Up@@ -5297,6 +5348,17 @@ class A(TypedDict):
def test_dunder_dict(self):
self.assertIsInstance(TypedDict.__dict__, dict)

@skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
def test_or(self):
class TD(TypedDict):
a: int

self.assertEqual(TD | int, Union[TD, int])
self.assertEqual(int | TD, Union[int, TD])

self.assertEqual(get_args(TD | int), (TD, int))
self.assertEqual(get_args(int | TD), (int, TD))

class AnnotatedTests(BaseTestCase):

def test_repr(self):
Expand DownExpand Up@@ -5519,6 +5581,19 @@ def barfoo3(x: BA2): ...
BA2
)

@skipUnless(TYPING_3_11_0, "TODO: evaluate nested forward refs in Python < 3.11")
def test_get_type_hints_genericalias(self):
def foobar(x: list['X']): ...
X = Annotated[int, (1, 10)]
self.assertEqual(
get_type_hints(foobar, globals(), locals()),
{'x': list[int]}
)
self.assertEqual(
get_type_hints(foobar, globals(), locals(), include_extras=True),
{'x': list[Annotated[int, (1, 10)]]}
)

def test_get_type_hints_refs(self):

Const = Annotated[T, "Const"]
Expand DownExpand Up@@ -5973,6 +6048,11 @@ def run():
# The actual test:
self.assertEqual(result1, result2)

def test_subclass(self):
with self.assertRaises(TypeError):
class MyParamSpec(ParamSpec):
pass


class ConcatenateTests(BaseTestCase):
def test_basics(self):
Expand DownExpand Up@@ -6335,6 +6415,14 @@ def test_pickle(self):
pickled = pickle.dumps(LiteralString, protocol=proto)
self.assertIs(LiteralString, pickle.loads(pickled))

@skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
def test_or(self):
self.assertEqual(LiteralString | int, Union[LiteralString, int])
self.assertEqual(int | LiteralString, Union[int, LiteralString])

self.assertEqual(get_args(LiteralString | int), (LiteralString, int))
self.assertEqual(get_args(int | LiteralString), (int, LiteralString))


class SelfTests(BaseTestCase):
def test_basics(self):
Expand DownExpand Up@@ -6382,6 +6470,14 @@ def test_pickle(self):
pickled = pickle.dumps(Self, protocol=proto)
self.assertIs(Self, pickle.loads(pickled))

@skipUnless(TYPING_3_10_0, "PEP 604 has yet to be")
def test_or(self):
self.assertEqual(Self | int, Union[Self, int])
self.assertEqual(int | Self, Union[int, Self])

self.assertEqual(get_args(Self | int), (Self, int))
self.assertEqual(get_args(int | Self), (int, Self))


class UnpackTests(BaseTestCase):
def test_basic_plain(self):
Expand DownExpand Up@@ -7711,42 +7807,61 @@ class A(Generic[T, P, U]): ...
self.assertEqual(A[float, [range], int].__args__, (float, (range,), int))


classNoDefaultTests(BaseTestCase):
classSentinelTestsMixin:
@skip_if_py313_beta_1
def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(NoDefault, proto)
s = pickle.dumps(self.sentinel_type, proto)
loaded = pickle.loads(s)
self.assertIs(NoDefault, loaded)
self.assertIs(self.sentinel_type, loaded)

@skip_if_py313_beta_1
def test_doc(self):
self.assertIsInstance(NoDefault.__doc__, str)
self.assertIsInstance(self.sentinel_type.__doc__, str)

def test_constructor(self):
self.assertIs(NoDefault, type(NoDefault)())
self.assertIs(self.sentinel_type, type(self.sentinel_type)())
with self.assertRaises(TypeError):
type(NoDefault)(1)

def test_repr(self):
self.assertRegex(repr(NoDefault), r'typing(_extensions)?\.NoDefault')
type(self.sentinel_type)(1)

def test_no_call(self):
with self.assertRaises(TypeError):
NoDefault()
self.sentinel_type()

@skip_if_py313_beta_1
def test_immutable(self):
with self.assertRaises(AttributeError):
NoDefault.foo = 'bar'
self.sentinel_type.foo = 'bar'
with self.assertRaises(AttributeError):
NoDefault.foo
self.sentinel_type.foo

# TypeError is consistent with the behavior of NoneType
with self.assertRaises(TypeError):
type(NoDefault).foo = 3
type(self.sentinel_type).foo = 3
with self.assertRaises(AttributeError):
type(NoDefault).foo
type(self.sentinel_type).foo


class NoDefaultTests(SentinelTestsMixin, BaseTestCase):
sentinel_type = NoDefault

def test_repr(self):
if hasattr(typing, 'NoDefault'):
mod_name = 'typing'
else:
mod_name = "typing_extensions"
self.assertEqual(repr(NoDefault), f"{mod_name}.NoDefault")


class NoExtraItemsTests(SentinelTestsMixin, BaseTestCase):
sentinel_type = NoExtraItems

def test_repr(self):
if hasattr(typing, 'NoExtraItems'):
mod_name = 'typing'
else:
mod_name = "typing_extensions"
self.assertEqual(repr(NoExtraItems), f"{mod_name}.NoExtraItems")


class TypeVarInferVarianceTests(BaseTestCase):
Expand Down
17 changes: 8 additions & 9 deletionssrc/typing_extensions.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -555,7 +555,9 @@ def _is_dunder(attr):


class _SpecialGenericAlias(typing._SpecialGenericAlias, _root=True):
def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()):
def __init__(self, origin, nparams, *, defaults, inst=True, name=None):
assert nparams > 0, "`nparams` must be a positive integer"
assert defaults, "Must always specify a non-empty sequence for `defaults`"
super().__init__(origin, nparams, inst=inst, name=name)
self._defaults = defaults

Expand All@@ -573,20 +575,14 @@ def __getitem__(self, params):
msg = "Parameters to generic types must be types."
params = tuple(typing._type_check(p, msg) for p in params)
if (
self._defaults
and len(params) < self._nparams
len(params) < self._nparams
and len(params) + len(self._defaults) >= self._nparams
):
params = (*params, *self._defaults[len(params) - self._nparams:])
actual_len = len(params)

if actual_len != self._nparams:
if self._defaults:
expected = f"at least {self._nparams - len(self._defaults)}"
else:
expected = str(self._nparams)
if not self._nparams:
raise TypeError(f"{self} is not a generic class")
expected = f"at least {self._nparams - len(self._defaults)}"
raise TypeError(
f"Too {'many' if actual_len > self._nparams else 'few'}"
f" arguments for {self};"
Expand DownExpand Up@@ -1960,6 +1956,9 @@ def __reduce__(self):
def __call__(self, *args, **kwargs):
pass

def __init_subclass__(cls) -> None:
raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type")


# 3.9
if not hasattr(typing, 'Concatenate'):
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp