1import abc 2import collections 3import collections.abc 4import contextlib 5import copy 6import gc 7import importlib 8import inspect 9import io 10import pickle 11import re 12import subprocess 13import sys 14import tempfile 15import textwrap 16import types 17import typing 18import warnings 19from collections import defaultdict 20from functools import lru_cache 21from pathlib import Path 22from unittest import TestCase, main, skipIf, skipUnless 23from unittest.mock import patch 24 25import typing_extensions 26from _typed_dict_test_helper import Foo, FooGeneric, VeryAnnotated 27from typing_extensions import ( 28 Annotated, 29 Any, 30 AnyStr, 31 AsyncContextManager, 32 AsyncIterator, 33 Awaitable, 34 Buffer, 35 Callable, 36 ClassVar, 37 Concatenate, 38 Dict, 39 Doc, 40 Final, 41 Generic, 42 IntVar, 43 Iterable, 44 Iterator, 45 List, 46 Literal, 47 LiteralString, 48 NamedTuple, 49 Never, 50 NewType, 51 NoDefault, 52 NoReturn, 53 NotRequired, 54 Optional, 55 ParamSpec, 56 ParamSpecArgs, 57 ParamSpecKwargs, 58 Protocol, 59 ReadOnly, 60 Required, 61 Self, 62 Set, 63 Tuple, 64 Type, 65 TypeAlias, 66 TypeAliasType, 67 TypedDict, 68 TypeGuard, 69 TypeIs, 70 TypeVar, 71 TypeVarTuple, 72 Union, 73 Unpack, 74 assert_never, 75 assert_type, 76 clear_overloads, 77 dataclass_transform, 78 deprecated, 79 final, 80 get_args, 81 get_origin, 82 get_original_bases, 83 get_overloads, 84 get_protocol_members, 85 get_type_hints, 86 is_protocol, 87 is_typeddict, 88 no_type_check, 89 overload, 90 override, 91 reveal_type, 92 runtime, 93 runtime_checkable, 94) 95 96NoneType = type(None) 97T = TypeVar("T") 98KT = TypeVar("KT") 99VT = TypeVar("VT") 100 101# Flags used to mark tests that only apply after a specific 102# version of the typing module. 103TYPING_3_9_0 = sys.version_info[:3] >= (3, 9, 0) 104TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0) 105 106# 3.11 makes runtime type checks (_type_check) more lenient. 107TYPING_3_11_0 = sys.version_info[:3] >= (3, 11, 0) 108 109# 3.12 changes the representation of Unpack[] (PEP 692) 110TYPING_3_12_0 = sys.version_info[:3] >= (3, 12, 0) 111 112# 3.13 drops support for the keyword argument syntax of TypedDict 113TYPING_3_13_0 = sys.version_info[:3] >= (3, 13, 0) 114 115# https://github.com/python/cpython/pull/27017 was backported into some 3.9 and 3.10 116# versions, but not all 117HAS_FORWARD_MODULE = "module" in inspect.signature(typing._type_check).parameters 118 119skip_if_py313_beta_1 = skipIf( 120 sys.version_info[:5] == (3, 13, 0, 'beta', 1), 121 "Bugfixes will be released in 3.13.0b2" 122) 123 124ANN_MODULE_SOURCE = '''\ 125import sys 126from typing import List, Optional 127from functools import wraps 128 129try: 130 __annotations__[1] = 2 131except NameError: 132 assert sys.version_info >= (3, 14) 133 134class C: 135 136 x = 5; y: Optional['C'] = None 137 138from typing import Tuple 139x: int = 5; y: str = x; f: Tuple[int, int] 140 141class M(type): 142 try: 143 __annotations__['123'] = 123 144 except NameError: 145 assert sys.version_info >= (3, 14) 146 o: type = object 147 148(pars): bool = True 149 150class D(C): 151 j: str = 'hi'; k: str= 'bye' 152 153from types import new_class 154h_class = new_class('H', (C,)) 155j_class = new_class('J') 156 157class F(): 158 z: int = 5 159 def __init__(self, x): 160 pass 161 162class Y(F): 163 def __init__(self): 164 super(F, self).__init__(123) 165 166class Meta(type): 167 def __new__(meta, name, bases, namespace): 168 return super().__new__(meta, name, bases, namespace) 169 170class S(metaclass = Meta): 171 x: str = 'something' 172 y: str = 'something else' 173 174def foo(x: int = 10): 175 def bar(y: List[str]): 176 x: str = 'yes' 177 bar() 178 179def dec(func): 180 @wraps(func) 181 def wrapper(*args, **kwargs): 182 return func(*args, **kwargs) 183 return wrapper 184''' 185 186ANN_MODULE_2_SOURCE = '''\ 187from typing import no_type_check, ClassVar 188 189i: int = 1 190j: int 191x: float = i/10 192 193def f(): 194 class C: ... 195 return C() 196 197f().new_attr: object = object() 198 199class C: 200 def __init__(self, x: int) -> None: 201 self.x = x 202 203c = C(5) 204c.new_attr: int = 10 205 206__annotations__ = {} 207 208 209@no_type_check 210class NTC: 211 def meth(self, param: complex) -> None: 212 ... 213 214class CV: 215 var: ClassVar['CV'] 216 217CV.var = CV() 218''' 219 220ANN_MODULE_3_SOURCE = '''\ 221def f_bad_ann(): 222 __annotations__[1] = 2 223 224class C_OK: 225 def __init__(self, x: int) -> None: 226 self.x: no_such_name = x # This one is OK as proposed by Guido 227 228class D_bad_ann: 229 def __init__(self, x: int) -> None: 230 sfel.y: int = 0 231 232def g_bad_ann(): 233 no_such_name.attr: int = 0 234''' 235 236 237class BaseTestCase(TestCase): 238 def assertIsSubclass(self, cls, class_or_tuple, msg=None): 239 if not issubclass(cls, class_or_tuple): 240 message = f'{cls!r} is not a subclass of {class_or_tuple!r}' 241 if msg is not None: 242 message += f' : {msg}' 243 raise self.failureException(message) 244 245 def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): 246 if issubclass(cls, class_or_tuple): 247 message = f'{cls!r} is a subclass of {class_or_tuple!r}' 248 if msg is not None: 249 message += f' : {msg}' 250 raise self.failureException(message) 251 252 253class Employee: 254 pass 255 256 257class BottomTypeTestsMixin: 258 bottom_type: ClassVar[Any] 259 260 def test_equality(self): 261 self.assertEqual(self.bottom_type, self.bottom_type) 262 self.assertIs(self.bottom_type, self.bottom_type) 263 self.assertNotEqual(self.bottom_type, None) 264 265 def test_get_origin(self): 266 self.assertIs(get_origin(self.bottom_type), None) 267 268 def test_instance_type_error(self): 269 with self.assertRaises(TypeError): 270 isinstance(42, self.bottom_type) 271 272 def test_subclass_type_error(self): 273 with self.assertRaises(TypeError): 274 issubclass(Employee, self.bottom_type) 275 with self.assertRaises(TypeError): 276 issubclass(NoReturn, self.bottom_type) 277 278 def test_not_generic(self): 279 with self.assertRaises(TypeError): 280 self.bottom_type[int] 281 282 def test_cannot_subclass(self): 283 with self.assertRaises(TypeError): 284 class A(self.bottom_type): 285 pass 286 with self.assertRaises(TypeError): 287 class B(type(self.bottom_type)): 288 pass 289 290 def test_cannot_instantiate(self): 291 with self.assertRaises(TypeError): 292 self.bottom_type() 293 with self.assertRaises(TypeError): 294 type(self.bottom_type)() 295 296 def test_pickle(self): 297 for proto in range(pickle.HIGHEST_PROTOCOL): 298 pickled = pickle.dumps(self.bottom_type, protocol=proto) 299 self.assertIs(self.bottom_type, pickle.loads(pickled)) 300 301 302class NoReturnTests(BottomTypeTestsMixin, BaseTestCase): 303 bottom_type = NoReturn 304 305 def test_repr(self): 306 if hasattr(typing, 'NoReturn'): 307 self.assertEqual(repr(NoReturn), 'typing.NoReturn') 308 else: 309 self.assertEqual(repr(NoReturn), 'typing_extensions.NoReturn') 310 311 def test_get_type_hints(self): 312 def some(arg: NoReturn) -> NoReturn: ... 313 def some_str(arg: 'NoReturn') -> 'typing.NoReturn': ... 314 315 expected = {'arg': NoReturn, 'return': NoReturn} 316 for target in some, some_str: 317 with self.subTest(target=target): 318 self.assertEqual(gth(target), expected) 319 320 def test_not_equality(self): 321 self.assertNotEqual(NoReturn, Never) 322 self.assertNotEqual(Never, NoReturn) 323 324 325class NeverTests(BottomTypeTestsMixin, BaseTestCase): 326 bottom_type = Never 327 328 def test_repr(self): 329 if hasattr(typing, 'Never'): 330 self.assertEqual(repr(Never), 'typing.Never') 331 else: 332 self.assertEqual(repr(Never), 'typing_extensions.Never') 333 334 def test_get_type_hints(self): 335 def some(arg: Never) -> Never: ... 336 def some_str(arg: 'Never') -> 'typing_extensions.Never': ... 337 338 expected = {'arg': Never, 'return': Never} 339 for target in [some, some_str]: 340 with self.subTest(target=target): 341 self.assertEqual(gth(target), expected) 342 343 344class AssertNeverTests(BaseTestCase): 345 def test_exception(self): 346 with self.assertRaises(AssertionError): 347 assert_never(None) 348 349 value = "some value" 350 with self.assertRaisesRegex(AssertionError, value): 351 assert_never(value) 352 353 # Make sure a huge value doesn't get printed in its entirety 354 huge_value = "a" * 10000 355 with self.assertRaises(AssertionError) as cm: 356 assert_never(huge_value) 357 self.assertLess( 358 len(cm.exception.args[0]), 359 typing_extensions._ASSERT_NEVER_REPR_MAX_LENGTH * 2, 360 ) 361 362 363class OverrideTests(BaseTestCase): 364 def test_override(self): 365 class Base: 366 def normal_method(self): ... 367 @staticmethod 368 def static_method_good_order(): ... 369 @staticmethod 370 def static_method_bad_order(): ... 371 @staticmethod 372 def decorator_with_slots(): ... 373 374 class Derived(Base): 375 @override 376 def normal_method(self): 377 return 42 378 379 @staticmethod 380 @override 381 def static_method_good_order(): 382 return 42 383 384 @override 385 @staticmethod 386 def static_method_bad_order(): 387 return 42 388 389 self.assertIsSubclass(Derived, Base) 390 instance = Derived() 391 self.assertEqual(instance.normal_method(), 42) 392 self.assertIs(True, instance.normal_method.__override__) 393 self.assertEqual(Derived.static_method_good_order(), 42) 394 self.assertIs(True, Derived.static_method_good_order.__override__) 395 self.assertEqual(Derived.static_method_bad_order(), 42) 396 self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__")) 397 398 399class DeprecatedTests(BaseTestCase): 400 def test_dunder_deprecated(self): 401 @deprecated("A will go away soon") 402 class A: 403 pass 404 405 self.assertEqual(A.__deprecated__, "A will go away soon") 406 self.assertIsInstance(A, type) 407 408 @deprecated("b will go away soon") 409 def b(): 410 pass 411 412 self.assertEqual(b.__deprecated__, "b will go away soon") 413 self.assertIsInstance(b, types.FunctionType) 414 415 @overload 416 @deprecated("no more ints") 417 def h(x: int) -> int: ... 418 @overload 419 def h(x: str) -> str: ... 420 def h(x): 421 return x 422 423 overloads = get_overloads(h) 424 self.assertEqual(len(overloads), 2) 425 self.assertEqual(overloads[0].__deprecated__, "no more ints") 426 427 def test_class(self): 428 @deprecated("A will go away soon") 429 class A: 430 pass 431 432 with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"): 433 A() 434 with self.assertWarnsRegex(DeprecationWarning, "A will go away soon"): 435 with self.assertRaises(TypeError): 436 A(42) 437 438 def test_class_with_init(self): 439 @deprecated("HasInit will go away soon") 440 class HasInit: 441 def __init__(self, x): 442 self.x = x 443 444 with self.assertWarnsRegex(DeprecationWarning, "HasInit will go away soon"): 445 instance = HasInit(42) 446 self.assertEqual(instance.x, 42) 447 448 def test_class_with_new(self): 449 has_new_called = False 450 451 @deprecated("HasNew will go away soon") 452 class HasNew: 453 def __new__(cls, x): 454 nonlocal has_new_called 455 has_new_called = True 456 return super().__new__(cls) 457 458 def __init__(self, x) -> None: 459 self.x = x 460 461 with self.assertWarnsRegex(DeprecationWarning, "HasNew will go away soon"): 462 instance = HasNew(42) 463 self.assertEqual(instance.x, 42) 464 self.assertTrue(has_new_called) 465 466 def test_class_with_inherited_new(self): 467 new_base_called = False 468 469 class NewBase: 470 def __new__(cls, x): 471 nonlocal new_base_called 472 new_base_called = True 473 return super().__new__(cls) 474 475 def __init__(self, x) -> None: 476 self.x = x 477 478 @deprecated("HasInheritedNew will go away soon") 479 class HasInheritedNew(NewBase): 480 pass 481 482 with self.assertWarnsRegex(DeprecationWarning, "HasInheritedNew will go away soon"): 483 instance = HasInheritedNew(42) 484 self.assertEqual(instance.x, 42) 485 self.assertTrue(new_base_called) 486 487 def test_class_with_new_but_no_init(self): 488 new_called = False 489 490 @deprecated("HasNewNoInit will go away soon") 491 class HasNewNoInit: 492 def __new__(cls, x): 493 nonlocal new_called 494 new_called = True 495 obj = super().__new__(cls) 496 obj.x = x 497 return obj 498 499 with self.assertWarnsRegex(DeprecationWarning, "HasNewNoInit will go away soon"): 500 instance = HasNewNoInit(42) 501 self.assertEqual(instance.x, 42) 502 self.assertTrue(new_called) 503 504 def test_mixin_class(self): 505 @deprecated("Mixin will go away soon") 506 class Mixin: 507 pass 508 509 class Base: 510 def __init__(self, a) -> None: 511 self.a = a 512 513 with self.assertWarnsRegex(DeprecationWarning, "Mixin will go away soon"): 514 class Child(Base, Mixin): 515 pass 516 517 instance = Child(42) 518 self.assertEqual(instance.a, 42) 519 520 def test_existing_init_subclass(self): 521 @deprecated("C will go away soon") 522 class C: 523 def __init_subclass__(cls) -> None: 524 cls.inited = True 525 526 with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"): 527 C() 528 529 with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"): 530 class D(C): 531 pass 532 533 self.assertTrue(D.inited) 534 self.assertIsInstance(D(), D) # no deprecation 535 536 def test_existing_init_subclass_in_base(self): 537 class Base: 538 def __init_subclass__(cls, x) -> None: 539 cls.inited = x 540 541 @deprecated("C will go away soon") 542 class C(Base, x=42): 543 pass 544 545 self.assertEqual(C.inited, 42) 546 547 with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"): 548 C() 549 550 with self.assertWarnsRegex(DeprecationWarning, "C will go away soon"): 551 class D(C, x=3): 552 pass 553 554 self.assertEqual(D.inited, 3) 555 556 def test_init_subclass_has_correct_cls(self): 557 init_subclass_saw = None 558 559 @deprecated("Base will go away soon") 560 class Base: 561 def __init_subclass__(cls) -> None: 562 nonlocal init_subclass_saw 563 init_subclass_saw = cls 564 565 self.assertIsNone(init_subclass_saw) 566 567 with self.assertWarnsRegex(DeprecationWarning, "Base will go away soon"): 568 class C(Base): 569 pass 570 571 self.assertIs(init_subclass_saw, C) 572 573 def test_init_subclass_with_explicit_classmethod(self): 574 init_subclass_saw = None 575 576 @deprecated("Base will go away soon") 577 class Base: 578 @classmethod 579 def __init_subclass__(cls) -> None: 580 nonlocal init_subclass_saw 581 init_subclass_saw = cls 582 583 self.assertIsNone(init_subclass_saw) 584 585 with self.assertWarnsRegex(DeprecationWarning, "Base will go away soon"): 586 class C(Base): 587 pass 588 589 self.assertIs(init_subclass_saw, C) 590 591 def test_function(self): 592 @deprecated("b will go away soon") 593 def b(): 594 pass 595 596 with self.assertWarnsRegex(DeprecationWarning, "b will go away soon"): 597 b() 598 599 def test_method(self): 600 class Capybara: 601 @deprecated("x will go away soon") 602 def x(self): 603 pass 604 605 instance = Capybara() 606 with self.assertWarnsRegex(DeprecationWarning, "x will go away soon"): 607 instance.x() 608 609 def test_property(self): 610 class Capybara: 611 @property 612 @deprecated("x will go away soon") 613 def x(self): 614 pass 615 616 @property 617 def no_more_setting(self): 618 return 42 619 620 @no_more_setting.setter 621 @deprecated("no more setting") 622 def no_more_setting(self, value): 623 pass 624 625 instance = Capybara() 626 with self.assertWarnsRegex(DeprecationWarning, "x will go away soon"): 627 instance.x 628 629 with warnings.catch_warnings(): 630 warnings.simplefilter("error") 631 self.assertEqual(instance.no_more_setting, 42) 632 633 with self.assertWarnsRegex(DeprecationWarning, "no more setting"): 634 instance.no_more_setting = 42 635 636 def test_category(self): 637 @deprecated("c will go away soon", category=RuntimeWarning) 638 def c(): 639 pass 640 641 with self.assertWarnsRegex(RuntimeWarning, "c will go away soon"): 642 c() 643 644 def test_turn_off_warnings(self): 645 @deprecated("d will go away soon", category=None) 646 def d(): 647 pass 648 649 with warnings.catch_warnings(): 650 warnings.simplefilter("error") 651 d() 652 653 def test_only_strings_allowed(self): 654 with self.assertRaisesRegex( 655 TypeError, 656 "Expected an object of type str for 'message', not 'type'" 657 ): 658 @deprecated 659 class Foo: ... 660 661 with self.assertRaisesRegex( 662 TypeError, 663 "Expected an object of type str for 'message', not 'function'" 664 ): 665 @deprecated 666 def foo(): ... 667 668 def test_no_retained_references_to_wrapper_instance(self): 669 @deprecated('depr') 670 def d(): pass 671 672 self.assertFalse(any( 673 isinstance(cell.cell_contents, deprecated) for cell in d.__closure__ 674 )) 675 676 677class AnyTests(BaseTestCase): 678 def test_can_subclass(self): 679 class Mock(Any): pass 680 self.assertTrue(issubclass(Mock, Any)) 681 self.assertIsInstance(Mock(), Mock) 682 683 class Something: pass 684 self.assertFalse(issubclass(Something, Any)) 685 self.assertNotIsInstance(Something(), Mock) 686 687 class MockSomething(Something, Mock): pass 688 self.assertTrue(issubclass(MockSomething, Any)) 689 ms = MockSomething() 690 self.assertIsInstance(ms, MockSomething) 691 self.assertIsInstance(ms, Something) 692 self.assertIsInstance(ms, Mock) 693 694 class SubclassesAny(Any): 695 ... 696 697 def test_repr(self): 698 if sys.version_info >= (3, 11): 699 mod_name = 'typing' 700 else: 701 mod_name = 'typing_extensions' 702 self.assertEqual(repr(Any), f"{mod_name}.Any") 703 704 @skipIf(sys.version_info[:3] == (3, 11, 0), "A bug was fixed in 3.11.1") 705 def test_repr_on_Any_subclass(self): 706 self.assertEqual( 707 repr(self.SubclassesAny), 708 f"<class '{self.SubclassesAny.__module__}.AnyTests.SubclassesAny'>" 709 ) 710 711 def test_instantiation(self): 712 with self.assertRaises(TypeError): 713 Any() 714 715 self.SubclassesAny() 716 717 def test_isinstance(self): 718 with self.assertRaises(TypeError): 719 isinstance(object(), Any) 720 721 isinstance(object(), self.SubclassesAny) 722 723 724class ClassVarTests(BaseTestCase): 725 726 def test_basics(self): 727 if not TYPING_3_11_0: 728 with self.assertRaises(TypeError): 729 ClassVar[1] 730 with self.assertRaises(TypeError): 731 ClassVar[int, str] 732 with self.assertRaises(TypeError): 733 ClassVar[int][str] 734 735 def test_repr(self): 736 if hasattr(typing, 'ClassVar'): 737 mod_name = 'typing' 738 else: 739 mod_name = 'typing_extensions' 740 self.assertEqual(repr(ClassVar), mod_name + '.ClassVar') 741 cv = ClassVar[int] 742 self.assertEqual(repr(cv), mod_name + '.ClassVar[int]') 743 cv = ClassVar[Employee] 744 self.assertEqual(repr(cv), mod_name + f'.ClassVar[{__name__}.Employee]') 745 746 def test_cannot_subclass(self): 747 with self.assertRaises(TypeError): 748 class C(type(ClassVar)): 749 pass 750 with self.assertRaises(TypeError): 751 class D(type(ClassVar[int])): 752 pass 753 754 def test_cannot_init(self): 755 with self.assertRaises(TypeError): 756 ClassVar() 757 with self.assertRaises(TypeError): 758 type(ClassVar)() 759 with self.assertRaises(TypeError): 760 type(ClassVar[Optional[int]])() 761 762 def test_no_isinstance(self): 763 with self.assertRaises(TypeError): 764 isinstance(1, ClassVar[int]) 765 with self.assertRaises(TypeError): 766 issubclass(int, ClassVar) 767 768 769class FinalTests(BaseTestCase): 770 771 def test_basics(self): 772 if not TYPING_3_11_0: 773 with self.assertRaises(TypeError): 774 Final[1] 775 with self.assertRaises(TypeError): 776 Final[int, str] 777 with self.assertRaises(TypeError): 778 Final[int][str] 779 780 def test_repr(self): 781 self.assertEqual(repr(Final), 'typing.Final') 782 cv = Final[int] 783 self.assertEqual(repr(cv), 'typing.Final[int]') 784 cv = Final[Employee] 785 self.assertEqual(repr(cv), f'typing.Final[{__name__}.Employee]') 786 787 def test_cannot_subclass(self): 788 with self.assertRaises(TypeError): 789 class C(type(Final)): 790 pass 791 with self.assertRaises(TypeError): 792 class D(type(Final[int])): 793 pass 794 795 def test_cannot_init(self): 796 with self.assertRaises(TypeError): 797 Final() 798 with self.assertRaises(TypeError): 799 type(Final)() 800 with self.assertRaises(TypeError): 801 type(Final[Optional[int]])() 802 803 def test_no_isinstance(self): 804 with self.assertRaises(TypeError): 805 isinstance(1, Final[int]) 806 with self.assertRaises(TypeError): 807 issubclass(int, Final) 808 809 810class RequiredTests(BaseTestCase): 811 812 def test_basics(self): 813 if not TYPING_3_11_0: 814 with self.assertRaises(TypeError): 815 Required[1] 816 with self.assertRaises(TypeError): 817 Required[int, str] 818 with self.assertRaises(TypeError): 819 Required[int][str] 820 821 def test_repr(self): 822 if hasattr(typing, 'Required'): 823 mod_name = 'typing' 824 else: 825 mod_name = 'typing_extensions' 826 self.assertEqual(repr(Required), f'{mod_name}.Required') 827 cv = Required[int] 828 self.assertEqual(repr(cv), f'{mod_name}.Required[int]') 829 cv = Required[Employee] 830 self.assertEqual(repr(cv), f'{mod_name}.Required[{__name__}.Employee]') 831 832 def test_cannot_subclass(self): 833 with self.assertRaises(TypeError): 834 class C(type(Required)): 835 pass 836 with self.assertRaises(TypeError): 837 class D(type(Required[int])): 838 pass 839 840 def test_cannot_init(self): 841 with self.assertRaises(TypeError): 842 Required() 843 with self.assertRaises(TypeError): 844 type(Required)() 845 with self.assertRaises(TypeError): 846 type(Required[Optional[int]])() 847 848 def test_no_isinstance(self): 849 with self.assertRaises(TypeError): 850 isinstance(1, Required[int]) 851 with self.assertRaises(TypeError): 852 issubclass(int, Required) 853 854 855class NotRequiredTests(BaseTestCase): 856 857 def test_basics(self): 858 if not TYPING_3_11_0: 859 with self.assertRaises(TypeError): 860 NotRequired[1] 861 with self.assertRaises(TypeError): 862 NotRequired[int, str] 863 with self.assertRaises(TypeError): 864 NotRequired[int][str] 865 866 def test_repr(self): 867 if hasattr(typing, 'NotRequired'): 868 mod_name = 'typing' 869 else: 870 mod_name = 'typing_extensions' 871 self.assertEqual(repr(NotRequired), f'{mod_name}.NotRequired') 872 cv = NotRequired[int] 873 self.assertEqual(repr(cv), f'{mod_name}.NotRequired[int]') 874 cv = NotRequired[Employee] 875 self.assertEqual(repr(cv), f'{mod_name}.NotRequired[{ __name__}.Employee]') 876 877 def test_cannot_subclass(self): 878 with self.assertRaises(TypeError): 879 class C(type(NotRequired)): 880 pass 881 with self.assertRaises(TypeError): 882 class D(type(NotRequired[int])): 883 pass 884 885 def test_cannot_init(self): 886 with self.assertRaises(TypeError): 887 NotRequired() 888 with self.assertRaises(TypeError): 889 type(NotRequired)() 890 with self.assertRaises(TypeError): 891 type(NotRequired[Optional[int]])() 892 893 def test_no_isinstance(self): 894 with self.assertRaises(TypeError): 895 isinstance(1, NotRequired[int]) 896 with self.assertRaises(TypeError): 897 issubclass(int, NotRequired) 898 899 900class IntVarTests(BaseTestCase): 901 def test_valid(self): 902 IntVar("T_ints") 903 904 def test_invalid(self): 905 with self.assertRaises(TypeError): 906 IntVar("T_ints", int) 907 with self.assertRaises(TypeError): 908 IntVar("T_ints", bound=int) 909 with self.assertRaises(TypeError): 910 IntVar("T_ints", covariant=True) 911 912 913class LiteralTests(BaseTestCase): 914 def test_basics(self): 915 Literal[1] 916 Literal[1, 2, 3] 917 Literal["x", "y", "z"] 918 Literal[None] 919 920 def test_enum(self): 921 import enum 922 class My(enum.Enum): 923 A = 'A' 924 925 self.assertEqual(Literal[My.A].__args__, (My.A,)) 926 927 def test_illegal_parameters_do_not_raise_runtime_errors(self): 928 # Type checkers should reject these types, but we do not 929 # raise errors at runtime to maintain maximum flexibility 930 Literal[int] 931 Literal[Literal[1, 2], Literal[4, 5]] 932 Literal[3j + 2, ..., ()] 933 Literal[b"foo", "bar"] 934 Literal[{"foo": 3, "bar": 4}] 935 Literal[T] 936 937 def test_literals_inside_other_types(self): 938 List[Literal[1, 2, 3]] 939 List[Literal[("foo", "bar", "baz")]] 940 941 def test_repr(self): 942 # we backport various bugfixes that were added in 3.10.1 and earlier 943 if sys.version_info >= (3, 10, 1): 944 mod_name = 'typing' 945 else: 946 mod_name = 'typing_extensions' 947 self.assertEqual(repr(Literal[1]), mod_name + ".Literal[1]") 948 self.assertEqual(repr(Literal[1, True, "foo"]), mod_name + ".Literal[1, True, 'foo']") 949 self.assertEqual(repr(Literal[int]), mod_name + ".Literal[int]") 950 self.assertEqual(repr(Literal), mod_name + ".Literal") 951 self.assertEqual(repr(Literal[None]), mod_name + ".Literal[None]") 952 self.assertEqual(repr(Literal[1, 2, 3, 3]), mod_name + ".Literal[1, 2, 3]") 953 954 def test_cannot_init(self): 955 with self.assertRaises(TypeError): 956 Literal() 957 with self.assertRaises(TypeError): 958 Literal[1]() 959 with self.assertRaises(TypeError): 960 type(Literal)() 961 with self.assertRaises(TypeError): 962 type(Literal[1])() 963 964 def test_no_isinstance_or_issubclass(self): 965 with self.assertRaises(TypeError): 966 isinstance(1, Literal[1]) 967 with self.assertRaises(TypeError): 968 isinstance(int, Literal[1]) 969 with self.assertRaises(TypeError): 970 issubclass(1, Literal[1]) 971 with self.assertRaises(TypeError): 972 issubclass(int, Literal[1]) 973 974 def test_no_subclassing(self): 975 with self.assertRaises(TypeError): 976 class Foo(Literal[1]): pass 977 with self.assertRaises(TypeError): 978 class Bar(Literal): pass 979 980 def test_no_multiple_subscripts(self): 981 with self.assertRaises(TypeError): 982 Literal[1][1] 983 984 def test_equal(self): 985 self.assertNotEqual(Literal[0], Literal[False]) 986 self.assertNotEqual(Literal[True], Literal[1]) 987 self.assertNotEqual(Literal[1], Literal[2]) 988 self.assertNotEqual(Literal[1, True], Literal[1]) 989 self.assertNotEqual(Literal[1, True], Literal[1, 1]) 990 self.assertNotEqual(Literal[1, 2], Literal[True, 2]) 991 self.assertEqual(Literal[1], Literal[1]) 992 self.assertEqual(Literal[1, 2], Literal[2, 1]) 993 self.assertEqual(Literal[1, 2, 3], Literal[1, 2, 3, 3]) 994 995 def test_hash(self): 996 self.assertEqual(hash(Literal[1]), hash(Literal[1])) 997 self.assertEqual(hash(Literal[1, 2]), hash(Literal[2, 1])) 998 self.assertEqual(hash(Literal[1, 2, 3]), hash(Literal[1, 2, 3, 3])) 999 1000 def test_args(self): 1001 self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3)) 1002 self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3)) 1003 self.assertEqual(Literal[1, Literal[2], Literal[3, 4]].__args__, (1, 2, 3, 4)) 1004 # Mutable arguments will not be deduplicated 1005 self.assertEqual(Literal[[], []].__args__, ([], [])) 1006 1007 def test_union_of_literals(self): 1008 self.assertEqual(Union[Literal[1], Literal[2]].__args__, 1009 (Literal[1], Literal[2])) 1010 self.assertEqual(Union[Literal[1], Literal[1]], 1011 Literal[1]) 1012 1013 self.assertEqual(Union[Literal[False], Literal[0]].__args__, 1014 (Literal[False], Literal[0])) 1015 self.assertEqual(Union[Literal[True], Literal[1]].__args__, 1016 (Literal[True], Literal[1])) 1017 1018 import enum 1019 class Ints(enum.IntEnum): 1020 A = 0 1021 B = 1 1022 1023 self.assertEqual(Union[Literal[Ints.A], Literal[Ints.B]].__args__, 1024 (Literal[Ints.A], Literal[Ints.B])) 1025 1026 self.assertEqual(Union[Literal[Ints.A], Literal[Ints.A]], 1027 Literal[Ints.A]) 1028 self.assertEqual(Union[Literal[Ints.B], Literal[Ints.B]], 1029 Literal[Ints.B]) 1030 1031 self.assertEqual(Union[Literal[0], Literal[Ints.A], Literal[False]].__args__, 1032 (Literal[0], Literal[Ints.A], Literal[False])) 1033 self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__, 1034 (Literal[1], Literal[Ints.B], Literal[True])) 1035 1036 @skipUnless(TYPING_3_10_0, "Python 3.10+ required") 1037 def test_or_type_operator_with_Literal(self): 1038 self.assertEqual((Literal[1] | Literal[2]).__args__, 1039 (Literal[1], Literal[2])) 1040 1041 self.assertEqual((Literal[0] | Literal[False]).__args__, 1042 (Literal[0], Literal[False])) 1043 self.assertEqual((Literal[1] | Literal[True]).__args__, 1044 (Literal[1], Literal[True])) 1045 1046 self.assertEqual(Literal[1] | Literal[1], Literal[1]) 1047 self.assertEqual(Literal['a'] | Literal['a'], Literal['a']) 1048 1049 import enum 1050 class Ints(enum.IntEnum): 1051 A = 0 1052 B = 1 1053 1054 self.assertEqual(Literal[Ints.A] | Literal[Ints.A], Literal[Ints.A]) 1055 self.assertEqual(Literal[Ints.B] | Literal[Ints.B], Literal[Ints.B]) 1056 1057 self.assertEqual((Literal[Ints.B] | Literal[Ints.A]).__args__, 1058 (Literal[Ints.B], Literal[Ints.A])) 1059 1060 self.assertEqual((Literal[0] | Literal[Ints.A]).__args__, 1061 (Literal[0], Literal[Ints.A])) 1062 self.assertEqual((Literal[1] | Literal[Ints.B]).__args__, 1063 (Literal[1], Literal[Ints.B])) 1064 1065 def test_flatten(self): 1066 l1 = Literal[Literal[1], Literal[2], Literal[3]] 1067 l2 = Literal[Literal[1, 2], 3] 1068 l3 = Literal[Literal[1, 2, 3]] 1069 for lit in l1, l2, l3: 1070 self.assertEqual(lit, Literal[1, 2, 3]) 1071 self.assertEqual(lit.__args__, (1, 2, 3)) 1072 1073 def test_does_not_flatten_enum(self): 1074 import enum 1075 class Ints(enum.IntEnum): 1076 A = 1 1077 B = 2 1078 1079 literal = Literal[ 1080 Literal[Ints.A], 1081 Literal[Ints.B], 1082 Literal[1], 1083 Literal[2], 1084 ] 1085 self.assertEqual(literal.__args__, (Ints.A, Ints.B, 1, 2)) 1086 1087 def test_caching_of_Literal_respects_type(self): 1088 self.assertIs(type(Literal[1].__args__[0]), int) 1089 self.assertIs(type(Literal[True].__args__[0]), bool) 1090 1091 1092class MethodHolder: 1093 @classmethod 1094 def clsmethod(cls): ... 1095 @staticmethod 1096 def stmethod(): ... 1097 def method(self): ... 1098 1099 1100if TYPING_3_11_0: 1101 registry_holder = typing 1102else: 1103 registry_holder = typing_extensions 1104 1105 1106class OverloadTests(BaseTestCase): 1107 1108 def test_overload_fails(self): 1109 with self.assertRaises(RuntimeError): 1110 1111 @overload 1112 def blah(): 1113 pass 1114 1115 blah() 1116 1117 def test_overload_succeeds(self): 1118 @overload 1119 def blah(): 1120 pass 1121 1122 def blah(): 1123 pass 1124 1125 blah() 1126 1127 @skipIf( 1128 sys.implementation.name == "pypy", 1129 "sum() and print() are not compiled in pypy" 1130 ) 1131 @patch( 1132 f"{registry_holder.__name__}._overload_registry", 1133 defaultdict(lambda: defaultdict(dict)) 1134 ) 1135 def test_overload_on_compiled_functions(self): 1136 registry = registry_holder._overload_registry 1137 # The registry starts out empty: 1138 self.assertEqual(registry, {}) 1139 1140 # This should just not fail: 1141 overload(sum) 1142 overload(print) 1143 1144 # No overloads are recorded: 1145 self.assertEqual(get_overloads(sum), []) 1146 self.assertEqual(get_overloads(print), []) 1147 1148 def set_up_overloads(self): 1149 def blah(): 1150 pass 1151 1152 overload1 = blah 1153 overload(blah) 1154 1155 def blah(): 1156 pass 1157 1158 overload2 = blah 1159 overload(blah) 1160 1161 def blah(): 1162 pass 1163 1164 return blah, [overload1, overload2] 1165 1166 # Make sure we don't clear the global overload registry 1167 @patch( 1168 f"{registry_holder.__name__}._overload_registry", 1169 defaultdict(lambda: defaultdict(dict)) 1170 ) 1171 def test_overload_registry(self): 1172 registry = registry_holder._overload_registry 1173 # The registry starts out empty 1174 self.assertEqual(registry, {}) 1175 1176 impl, overloads = self.set_up_overloads() 1177 self.assertNotEqual(registry, {}) 1178 self.assertEqual(list(get_overloads(impl)), overloads) 1179 1180 def some_other_func(): pass 1181 overload(some_other_func) 1182 other_overload = some_other_func 1183 def some_other_func(): pass 1184 self.assertEqual(list(get_overloads(some_other_func)), [other_overload]) 1185 # Unrelated function still has no overloads: 1186 def not_overloaded(): pass 1187 self.assertEqual(list(get_overloads(not_overloaded)), []) 1188 1189 # Make sure that after we clear all overloads, the registry is 1190 # completely empty. 1191 clear_overloads() 1192 self.assertEqual(registry, {}) 1193 self.assertEqual(get_overloads(impl), []) 1194 1195 # Querying a function with no overloads shouldn't change the registry. 1196 def the_only_one(): pass 1197 self.assertEqual(get_overloads(the_only_one), []) 1198 self.assertEqual(registry, {}) 1199 1200 def test_overload_registry_repeated(self): 1201 for _ in range(2): 1202 impl, overloads = self.set_up_overloads() 1203 1204 self.assertEqual(list(get_overloads(impl)), overloads) 1205 1206 1207class AssertTypeTests(BaseTestCase): 1208 1209 def test_basics(self): 1210 arg = 42 1211 self.assertIs(assert_type(arg, int), arg) 1212 self.assertIs(assert_type(arg, Union[str, float]), arg) 1213 self.assertIs(assert_type(arg, AnyStr), arg) 1214 self.assertIs(assert_type(arg, None), arg) 1215 1216 def test_errors(self): 1217 # Bogus calls are not expected to fail. 1218 arg = 42 1219 self.assertIs(assert_type(arg, 42), arg) 1220 self.assertIs(assert_type(arg, 'hello'), arg) 1221 1222 1223T_a = TypeVar('T_a') 1224 1225class AwaitableWrapper(Awaitable[T_a]): 1226 1227 def __init__(self, value): 1228 self.value = value 1229 1230 def __await__(self) -> typing.Iterator[T_a]: 1231 yield 1232 return self.value 1233 1234class AsyncIteratorWrapper(AsyncIterator[T_a]): 1235 1236 def __init__(self, value: Iterable[T_a]): 1237 self.value = value 1238 1239 def __aiter__(self) -> AsyncIterator[T_a]: 1240 return self 1241 1242 async def __anext__(self) -> T_a: 1243 data = await self.value 1244 if data: 1245 return data 1246 else: 1247 raise StopAsyncIteration 1248 1249class ACM: 1250 async def __aenter__(self) -> int: 1251 return 42 1252 1253 async def __aexit__(self, etype, eval, tb): 1254 return None 1255 1256 1257class A: 1258 y: float 1259class B(A): 1260 x: ClassVar[Optional['B']] = None 1261 y: int 1262 b: int 1263class CSub(B): 1264 z: ClassVar['CSub'] = B() 1265class G(Generic[T]): 1266 lst: ClassVar[List[T]] = [] 1267 1268class Loop: 1269 attr: Final['Loop'] 1270 1271class NoneAndForward: 1272 parent: 'NoneAndForward' 1273 meaning: None 1274 1275class XRepr(NamedTuple): 1276 x: int 1277 y: int = 1 1278 1279 def __str__(self): 1280 return f'{self.x} -> {self.y}' 1281 1282 def __add__(self, other): 1283 return 0 1284 1285@runtime_checkable 1286class HasCallProtocol(Protocol): 1287 __call__: typing.Callable 1288 1289 1290async def g_with(am: AsyncContextManager[int]): 1291 x: int 1292 async with am as x: 1293 return x 1294 1295try: 1296 g_with(ACM()).send(None) 1297except StopIteration as e: 1298 assert e.args[0] == 42 1299 1300Label = TypedDict('Label', [('label', str)]) 1301 1302class Point2D(TypedDict): 1303 x: int 1304 y: int 1305 1306class Point2Dor3D(Point2D, total=False): 1307 z: int 1308 1309class LabelPoint2D(Point2D, Label): ... 1310 1311class Options(TypedDict, total=False): 1312 log_level: int 1313 log_path: str 1314 1315class BaseAnimal(TypedDict): 1316 name: str 1317 1318class Animal(BaseAnimal, total=False): 1319 voice: str 1320 tail: bool 1321 1322class Cat(Animal): 1323 fur_color: str 1324 1325class TotalMovie(TypedDict): 1326 title: str 1327 year: NotRequired[int] 1328 1329class NontotalMovie(TypedDict, total=False): 1330 title: Required[str] 1331 year: int 1332 1333class ParentNontotalMovie(TypedDict, total=False): 1334 title: Required[str] 1335 1336class ChildTotalMovie(ParentNontotalMovie): 1337 year: NotRequired[int] 1338 1339class ParentDeeplyAnnotatedMovie(TypedDict): 1340 title: Annotated[Annotated[Required[str], "foobar"], "another level"] 1341 1342class ChildDeeplyAnnotatedMovie(ParentDeeplyAnnotatedMovie): 1343 year: NotRequired[Annotated[int, 2000]] 1344 1345class AnnotatedMovie(TypedDict): 1346 title: Annotated[Required[str], "foobar"] 1347 year: NotRequired[Annotated[int, 2000]] 1348 1349class WeirdlyQuotedMovie(TypedDict): 1350 title: Annotated['Annotated[Required[str], "foobar"]', "another level"] 1351 year: NotRequired['Annotated[int, 2000]'] 1352 1353 1354gth = get_type_hints 1355 1356 1357class GetTypeHintTests(BaseTestCase): 1358 @classmethod 1359 def setUpClass(cls): 1360 with tempfile.TemporaryDirectory() as tempdir: 1361 sys.path.append(tempdir) 1362 Path(tempdir, "ann_module.py").write_text(ANN_MODULE_SOURCE) 1363 Path(tempdir, "ann_module2.py").write_text(ANN_MODULE_2_SOURCE) 1364 Path(tempdir, "ann_module3.py").write_text(ANN_MODULE_3_SOURCE) 1365 cls.ann_module = importlib.import_module("ann_module") 1366 cls.ann_module2 = importlib.import_module("ann_module2") 1367 cls.ann_module3 = importlib.import_module("ann_module3") 1368 sys.path.pop() 1369 1370 @classmethod 1371 def tearDownClass(cls): 1372 for modname in "ann_module", "ann_module2", "ann_module3": 1373 delattr(cls, modname) 1374 del sys.modules[modname] 1375 1376 def test_get_type_hints_modules(self): 1377 if sys.version_info >= (3, 14): 1378 ann_module_type_hints = {'f': Tuple[int, int], 'x': int, 'y': str} 1379 else: 1380 ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} 1381 self.assertEqual(gth(self.ann_module), ann_module_type_hints) 1382 self.assertEqual(gth(self.ann_module2), {}) 1383 self.assertEqual(gth(self.ann_module3), {}) 1384 1385 def test_get_type_hints_classes(self): 1386 self.assertEqual(gth(self.ann_module.C, self.ann_module.__dict__), 1387 {'y': Optional[self.ann_module.C]}) 1388 self.assertIsInstance(gth(self.ann_module.j_class), dict) 1389 if sys.version_info >= (3, 14): 1390 self.assertEqual(gth(self.ann_module.M), {'o': type}) 1391 else: 1392 self.assertEqual(gth(self.ann_module.M), {'123': 123, 'o': type}) 1393 self.assertEqual(gth(self.ann_module.D), 1394 {'j': str, 'k': str, 'y': Optional[self.ann_module.C]}) 1395 self.assertEqual(gth(self.ann_module.Y), {'z': int}) 1396 self.assertEqual(gth(self.ann_module.h_class), 1397 {'y': Optional[self.ann_module.C]}) 1398 self.assertEqual(gth(self.ann_module.S), {'x': str, 'y': str}) 1399 self.assertEqual(gth(self.ann_module.foo), {'x': int}) 1400 self.assertEqual(gth(NoneAndForward, globals()), 1401 {'parent': NoneAndForward, 'meaning': type(None)}) 1402 1403 def test_respect_no_type_check(self): 1404 @no_type_check 1405 class NoTpCheck: 1406 class Inn: 1407 def __init__(self, x: 'not a type'): ... # noqa: F722 # (yes, there's a syntax error in this annotation, that's the point) 1408 self.assertTrue(NoTpCheck.__no_type_check__) 1409 self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) 1410 self.assertEqual(gth(self.ann_module2.NTC.meth), {}) 1411 class ABase(Generic[T]): 1412 def meth(x: int): ... 1413 @no_type_check 1414 class Der(ABase): ... 1415 self.assertEqual(gth(ABase.meth), {'x': int}) 1416 1417 def test_get_type_hints_ClassVar(self): 1418 self.assertEqual(gth(self.ann_module2.CV, self.ann_module2.__dict__), 1419 {'var': ClassVar[self.ann_module2.CV]}) 1420 self.assertEqual(gth(B, globals()), 1421 {'y': int, 'x': ClassVar[Optional[B]], 'b': int}) 1422 self.assertEqual(gth(CSub, globals()), 1423 {'z': ClassVar[CSub], 'y': int, 'b': int, 1424 'x': ClassVar[Optional[B]]}) 1425 self.assertEqual(gth(G), {'lst': ClassVar[List[T]]}) 1426 1427 def test_final_forward_ref(self): 1428 self.assertEqual(gth(Loop, globals())['attr'], Final[Loop]) 1429 self.assertNotEqual(gth(Loop, globals())['attr'], Final[int]) 1430 self.assertNotEqual(gth(Loop, globals())['attr'], Final) 1431 1432 1433class GetUtilitiesTestCase(TestCase): 1434 def test_get_origin(self): 1435 T = TypeVar('T') 1436 P = ParamSpec('P') 1437 Ts = TypeVarTuple('Ts') 1438 class C(Generic[T]): pass 1439 self.assertIs(get_origin(C[int]), C) 1440 self.assertIs(get_origin(C[T]), C) 1441 self.assertIs(get_origin(int), None) 1442 self.assertIs(get_origin(ClassVar[int]), ClassVar) 1443 self.assertIs(get_origin(Union[int, str]), Union) 1444 self.assertIs(get_origin(Literal[42, 43]), Literal) 1445 self.assertIs(get_origin(Final[List[int]]), Final) 1446 self.assertIs(get_origin(Generic), Generic) 1447 self.assertIs(get_origin(Generic[T]), Generic) 1448 self.assertIs(get_origin(List[Tuple[T, T]][int]), list) 1449 self.assertIs(get_origin(Annotated[T, 'thing']), Annotated) 1450 self.assertIs(get_origin(List), list) 1451 self.assertIs(get_origin(Tuple), tuple) 1452 self.assertIs(get_origin(Callable), collections.abc.Callable) 1453 if sys.version_info >= (3, 9): 1454 self.assertIs(get_origin(list[int]), list) 1455 self.assertIs(get_origin(list), None) 1456 self.assertIs(get_origin(P.args), P) 1457 self.assertIs(get_origin(P.kwargs), P) 1458 self.assertIs(get_origin(Required[int]), Required) 1459 self.assertIs(get_origin(NotRequired[int]), NotRequired) 1460 self.assertIs(get_origin(Unpack[Ts]), Unpack) 1461 self.assertIs(get_origin(Unpack), None) 1462 1463 def test_get_args(self): 1464 T = TypeVar('T') 1465 Ts = TypeVarTuple('Ts') 1466 class C(Generic[T]): pass 1467 self.assertEqual(get_args(C[int]), (int,)) 1468 self.assertEqual(get_args(C[T]), (T,)) 1469 self.assertEqual(get_args(int), ()) 1470 self.assertEqual(get_args(ClassVar[int]), (int,)) 1471 self.assertEqual(get_args(Union[int, str]), (int, str)) 1472 self.assertEqual(get_args(Literal[42, 43]), (42, 43)) 1473 self.assertEqual(get_args(Final[List[int]]), (List[int],)) 1474 self.assertEqual(get_args(Union[int, Tuple[T, int]][str]), 1475 (int, Tuple[str, int])) 1476 self.assertEqual(get_args(typing.Dict[int, Tuple[T, T]][Optional[int]]), 1477 (int, Tuple[Optional[int], Optional[int]])) 1478 self.assertEqual(get_args(Callable[[], T][int]), ([], int)) 1479 self.assertEqual(get_args(Callable[..., int]), (..., int)) 1480 self.assertEqual(get_args(Union[int, Callable[[Tuple[T, ...]], str]]), 1481 (int, Callable[[Tuple[T, ...]], str])) 1482 self.assertEqual(get_args(Tuple[int, ...]), (int, ...)) 1483 if TYPING_3_11_0: 1484 self.assertEqual(get_args(Tuple[()]), ()) 1485 else: 1486 self.assertEqual(get_args(Tuple[()]), ((),)) 1487 self.assertEqual(get_args(Annotated[T, 'one', 2, ['three']]), (T, 'one', 2, ['three'])) 1488 self.assertEqual(get_args(List), ()) 1489 self.assertEqual(get_args(Tuple), ()) 1490 self.assertEqual(get_args(Callable), ()) 1491 if sys.version_info >= (3, 9): 1492 self.assertEqual(get_args(list[int]), (int,)) 1493 self.assertEqual(get_args(list), ()) 1494 if sys.version_info >= (3, 9): 1495 # Support Python versions with and without the fix for 1496 # https://bugs.python.org/issue42195 1497 # The first variant is for 3.9.2+, the second for 3.9.0 and 1 1498 self.assertIn(get_args(collections.abc.Callable[[int], str]), 1499 (([int], str), ([[int]], str))) 1500 self.assertIn(get_args(collections.abc.Callable[[], str]), 1501 (([], str), ([[]], str))) 1502 self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str)) 1503 P = ParamSpec('P') 1504 # In 3.9 and lower we use typing_extensions's hacky implementation 1505 # of ParamSpec, which gets incorrectly wrapped in a list 1506 self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)]) 1507 self.assertEqual(get_args(Callable[Concatenate[int, P], int]), 1508 (Concatenate[int, P], int)) 1509 self.assertEqual(get_args(Required[int]), (int,)) 1510 self.assertEqual(get_args(NotRequired[int]), (int,)) 1511 self.assertEqual(get_args(Unpack[Ts]), (Ts,)) 1512 self.assertEqual(get_args(Unpack), ()) 1513 1514 1515class CollectionsAbcTests(BaseTestCase): 1516 1517 def test_isinstance_collections(self): 1518 self.assertNotIsInstance(1, collections.abc.Mapping) 1519 self.assertNotIsInstance(1, collections.abc.Iterable) 1520 self.assertNotIsInstance(1, collections.abc.Container) 1521 self.assertNotIsInstance(1, collections.abc.Sized) 1522 with self.assertRaises(TypeError): 1523 isinstance(collections.deque(), typing_extensions.Deque[int]) 1524 with self.assertRaises(TypeError): 1525 issubclass(collections.Counter, typing_extensions.Counter[str]) 1526 1527 def test_awaitable(self): 1528 async def foo() -> typing_extensions.Awaitable[int]: 1529 return await AwaitableWrapper(42) 1530 1531 g = foo() 1532 self.assertIsInstance(g, typing_extensions.Awaitable) 1533 self.assertNotIsInstance(foo, typing_extensions.Awaitable) 1534 g.send(None) # Run foo() till completion, to avoid warning. 1535 1536 def test_coroutine(self): 1537 async def foo(): 1538 return 1539 1540 g = foo() 1541 self.assertIsInstance(g, typing_extensions.Coroutine) 1542 with self.assertRaises(TypeError): 1543 isinstance(g, typing_extensions.Coroutine[int]) 1544 self.assertNotIsInstance(foo, typing_extensions.Coroutine) 1545 try: 1546 g.send(None) 1547 except StopIteration: 1548 pass 1549 1550 def test_async_iterable(self): 1551 base_it: Iterator[int] = range(10) 1552 it = AsyncIteratorWrapper(base_it) 1553 self.assertIsInstance(it, typing_extensions.AsyncIterable) 1554 self.assertIsInstance(it, typing_extensions.AsyncIterable) 1555 self.assertNotIsInstance(42, typing_extensions.AsyncIterable) 1556 1557 def test_async_iterator(self): 1558 base_it: Iterator[int] = range(10) 1559 it = AsyncIteratorWrapper(base_it) 1560 self.assertIsInstance(it, typing_extensions.AsyncIterator) 1561 self.assertNotIsInstance(42, typing_extensions.AsyncIterator) 1562 1563 def test_deque(self): 1564 self.assertIsSubclass(collections.deque, typing_extensions.Deque) 1565 class MyDeque(typing_extensions.Deque[int]): ... 1566 self.assertIsInstance(MyDeque(), collections.deque) 1567 1568 def test_counter(self): 1569 self.assertIsSubclass(collections.Counter, typing_extensions.Counter) 1570 1571 def test_defaultdict_instantiation(self): 1572 self.assertIs( 1573 type(typing_extensions.DefaultDict()), 1574 collections.defaultdict) 1575 self.assertIs( 1576 type(typing_extensions.DefaultDict[KT, VT]()), 1577 collections.defaultdict) 1578 self.assertIs( 1579 type(typing_extensions.DefaultDict[str, int]()), 1580 collections.defaultdict) 1581 1582 def test_defaultdict_subclass(self): 1583 1584 class MyDefDict(typing_extensions.DefaultDict[str, int]): 1585 pass 1586 1587 dd = MyDefDict() 1588 self.assertIsInstance(dd, MyDefDict) 1589 1590 self.assertIsSubclass(MyDefDict, collections.defaultdict) 1591 self.assertNotIsSubclass(collections.defaultdict, MyDefDict) 1592 1593 def test_ordereddict_instantiation(self): 1594 self.assertIs( 1595 type(typing_extensions.OrderedDict()), 1596 collections.OrderedDict) 1597 self.assertIs( 1598 type(typing_extensions.OrderedDict[KT, VT]()), 1599 collections.OrderedDict) 1600 self.assertIs( 1601 type(typing_extensions.OrderedDict[str, int]()), 1602 collections.OrderedDict) 1603 1604 def test_ordereddict_subclass(self): 1605 1606 class MyOrdDict(typing_extensions.OrderedDict[str, int]): 1607 pass 1608 1609 od = MyOrdDict() 1610 self.assertIsInstance(od, MyOrdDict) 1611 1612 self.assertIsSubclass(MyOrdDict, collections.OrderedDict) 1613 self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict) 1614 1615 def test_chainmap_instantiation(self): 1616 self.assertIs(type(typing_extensions.ChainMap()), collections.ChainMap) 1617 self.assertIs(type(typing_extensions.ChainMap[KT, VT]()), collections.ChainMap) 1618 self.assertIs(type(typing_extensions.ChainMap[str, int]()), collections.ChainMap) 1619 class CM(typing_extensions.ChainMap[KT, VT]): ... 1620 self.assertIs(type(CM[int, str]()), CM) 1621 1622 def test_chainmap_subclass(self): 1623 1624 class MyChainMap(typing_extensions.ChainMap[str, int]): 1625 pass 1626 1627 cm = MyChainMap() 1628 self.assertIsInstance(cm, MyChainMap) 1629 1630 self.assertIsSubclass(MyChainMap, collections.ChainMap) 1631 self.assertNotIsSubclass(collections.ChainMap, MyChainMap) 1632 1633 def test_deque_instantiation(self): 1634 self.assertIs(type(typing_extensions.Deque()), collections.deque) 1635 self.assertIs(type(typing_extensions.Deque[T]()), collections.deque) 1636 self.assertIs(type(typing_extensions.Deque[int]()), collections.deque) 1637 class D(typing_extensions.Deque[T]): ... 1638 self.assertIs(type(D[int]()), D) 1639 1640 def test_counter_instantiation(self): 1641 self.assertIs(type(typing_extensions.Counter()), collections.Counter) 1642 self.assertIs(type(typing_extensions.Counter[T]()), collections.Counter) 1643 self.assertIs(type(typing_extensions.Counter[int]()), collections.Counter) 1644 class C(typing_extensions.Counter[T]): ... 1645 self.assertIs(type(C[int]()), C) 1646 self.assertEqual(C.__bases__, (collections.Counter, typing.Generic)) 1647 1648 def test_counter_subclass_instantiation(self): 1649 1650 class MyCounter(typing_extensions.Counter[int]): 1651 pass 1652 1653 d = MyCounter() 1654 self.assertIsInstance(d, MyCounter) 1655 self.assertIsInstance(d, collections.Counter) 1656 self.assertIsInstance(d, typing_extensions.Counter) 1657 1658 1659# These are a separate TestCase class, 1660# as (unlike most collections.abc aliases in typing_extensions), 1661# these are reimplemented on Python <=3.12 so that we can provide 1662# default values for the second and third parameters 1663class GeneratorTests(BaseTestCase): 1664 1665 def test_generator_basics(self): 1666 def foo(): 1667 yield 42 1668 g = foo() 1669 1670 self.assertIsInstance(g, typing_extensions.Generator) 1671 self.assertNotIsInstance(foo, typing_extensions.Generator) 1672 self.assertIsSubclass(type(g), typing_extensions.Generator) 1673 self.assertNotIsSubclass(type(foo), typing_extensions.Generator) 1674 1675 parameterized = typing_extensions.Generator[int, str, None] 1676 with self.assertRaises(TypeError): 1677 isinstance(g, parameterized) 1678 with self.assertRaises(TypeError): 1679 issubclass(type(g), parameterized) 1680 1681 def test_generator_default(self): 1682 g1 = typing_extensions.Generator[int] 1683 g2 = typing_extensions.Generator[int, None, None] 1684 self.assertEqual(get_args(g1), (int, type(None), type(None))) 1685 self.assertEqual(get_args(g1), get_args(g2)) 1686 1687 g3 = typing_extensions.Generator[int, float] 1688 g4 = typing_extensions.Generator[int, float, None] 1689 self.assertEqual(get_args(g3), (int, float, type(None))) 1690 self.assertEqual(get_args(g3), get_args(g4)) 1691 1692 def test_no_generator_instantiation(self): 1693 with self.assertRaises(TypeError): 1694 typing_extensions.Generator() 1695 with self.assertRaises(TypeError): 1696 typing_extensions.Generator[T, T, T]() 1697 with self.assertRaises(TypeError): 1698 typing_extensions.Generator[int, int, int]() 1699 1700 def test_subclassing_generator(self): 1701 class G(typing_extensions.Generator[int, int, None]): 1702 def send(self, value): 1703 pass 1704 def throw(self, typ, val=None, tb=None): 1705 pass 1706 1707 def g(): yield 0 1708 1709 self.assertIsSubclass(G, typing_extensions.Generator) 1710 self.assertIsSubclass(G, typing_extensions.Iterable) 1711 self.assertIsSubclass(G, collections.abc.Generator) 1712 self.assertIsSubclass(G, collections.abc.Iterable) 1713 self.assertNotIsSubclass(type(g), G) 1714 1715 instance = G() 1716 self.assertIsInstance(instance, typing_extensions.Generator) 1717 self.assertIsInstance(instance, typing_extensions.Iterable) 1718 self.assertIsInstance(instance, collections.abc.Generator) 1719 self.assertIsInstance(instance, collections.abc.Iterable) 1720 self.assertNotIsInstance(type(g), G) 1721 self.assertNotIsInstance(g, G) 1722 1723 def test_async_generator_basics(self): 1724 async def f(): 1725 yield 42 1726 g = f() 1727 1728 self.assertIsInstance(g, typing_extensions.AsyncGenerator) 1729 self.assertIsSubclass(type(g), typing_extensions.AsyncGenerator) 1730 self.assertNotIsInstance(f, typing_extensions.AsyncGenerator) 1731 self.assertNotIsSubclass(type(f), typing_extensions.AsyncGenerator) 1732 1733 parameterized = typing_extensions.AsyncGenerator[int, str] 1734 with self.assertRaises(TypeError): 1735 isinstance(g, parameterized) 1736 with self.assertRaises(TypeError): 1737 issubclass(type(g), parameterized) 1738 1739 def test_async_generator_default(self): 1740 ag1 = typing_extensions.AsyncGenerator[int] 1741 ag2 = typing_extensions.AsyncGenerator[int, None] 1742 self.assertEqual(get_args(ag1), (int, type(None))) 1743 self.assertEqual(get_args(ag1), get_args(ag2)) 1744 1745 def test_no_async_generator_instantiation(self): 1746 with self.assertRaises(TypeError): 1747 typing_extensions.AsyncGenerator() 1748 with self.assertRaises(TypeError): 1749 typing_extensions.AsyncGenerator[T, T]() 1750 with self.assertRaises(TypeError): 1751 typing_extensions.AsyncGenerator[int, int]() 1752 1753 def test_subclassing_async_generator(self): 1754 class G(typing_extensions.AsyncGenerator[int, int]): 1755 def asend(self, value): 1756 pass 1757 def athrow(self, typ, val=None, tb=None): 1758 pass 1759 1760 async def g(): yield 0 1761 1762 self.assertIsSubclass(G, typing_extensions.AsyncGenerator) 1763 self.assertIsSubclass(G, typing_extensions.AsyncIterable) 1764 self.assertIsSubclass(G, collections.abc.AsyncGenerator) 1765 self.assertIsSubclass(G, collections.abc.AsyncIterable) 1766 self.assertNotIsSubclass(type(g), G) 1767 1768 instance = G() 1769 self.assertIsInstance(instance, typing_extensions.AsyncGenerator) 1770 self.assertIsInstance(instance, typing_extensions.AsyncIterable) 1771 self.assertIsInstance(instance, collections.abc.AsyncGenerator) 1772 self.assertIsInstance(instance, collections.abc.AsyncIterable) 1773 self.assertNotIsInstance(type(g), G) 1774 self.assertNotIsInstance(g, G) 1775 1776 def test_subclassing_subclasshook(self): 1777 1778 class Base(typing_extensions.Generator): 1779 @classmethod 1780 def __subclasshook__(cls, other): 1781 if other.__name__ == 'Foo': 1782 return True 1783 else: 1784 return False 1785 1786 class C(Base): ... 1787 class Foo: ... 1788 class Bar: ... 1789 self.assertIsSubclass(Foo, Base) 1790 self.assertIsSubclass(Foo, C) 1791 self.assertNotIsSubclass(Bar, C) 1792 1793 def test_subclassing_register(self): 1794 1795 class A(typing_extensions.Generator): ... 1796 class B(A): ... 1797 1798 class C: ... 1799 A.register(C) 1800 self.assertIsSubclass(C, A) 1801 self.assertNotIsSubclass(C, B) 1802 1803 class D: ... 1804 B.register(D) 1805 self.assertIsSubclass(D, A) 1806 self.assertIsSubclass(D, B) 1807 1808 class M: ... 1809 collections.abc.Generator.register(M) 1810 self.assertIsSubclass(M, typing_extensions.Generator) 1811 1812 def test_collections_as_base(self): 1813 1814 class M(collections.abc.Generator): ... 1815 self.assertIsSubclass(M, typing_extensions.Generator) 1816 self.assertIsSubclass(M, typing_extensions.Iterable) 1817 1818 class S(collections.abc.AsyncGenerator): ... 1819 self.assertIsSubclass(S, typing_extensions.AsyncGenerator) 1820 self.assertIsSubclass(S, typing_extensions.AsyncIterator) 1821 1822 class A(collections.abc.Generator, metaclass=abc.ABCMeta): ... 1823 class B: ... 1824 A.register(B) 1825 self.assertIsSubclass(B, typing_extensions.Generator) 1826 1827 @skipIf(sys.version_info < (3, 10), "PEP 604 has yet to be") 1828 def test_or_and_ror(self): 1829 self.assertEqual( 1830 typing_extensions.Generator | typing_extensions.AsyncGenerator, 1831 Union[typing_extensions.Generator, typing_extensions.AsyncGenerator] 1832 ) 1833 self.assertEqual( 1834 typing_extensions.Generator | typing.Deque, 1835 Union[typing_extensions.Generator, typing.Deque] 1836 ) 1837 1838 1839class OtherABCTests(BaseTestCase): 1840 1841 def test_contextmanager(self): 1842 @contextlib.contextmanager 1843 def manager(): 1844 yield 42 1845 1846 cm = manager() 1847 self.assertIsInstance(cm, typing_extensions.ContextManager) 1848 self.assertNotIsInstance(42, typing_extensions.ContextManager) 1849 1850 def test_contextmanager_type_params(self): 1851 cm1 = typing_extensions.ContextManager[int] 1852 self.assertEqual(get_args(cm1), (int, typing.Optional[bool])) 1853 cm2 = typing_extensions.ContextManager[int, None] 1854 self.assertEqual(get_args(cm2), (int, NoneType)) 1855 1856 def test_async_contextmanager(self): 1857 class NotACM: 1858 pass 1859 self.assertIsInstance(ACM(), typing_extensions.AsyncContextManager) 1860 self.assertNotIsInstance(NotACM(), typing_extensions.AsyncContextManager) 1861 @contextlib.contextmanager 1862 def manager(): 1863 yield 42 1864 1865 cm = manager() 1866 self.assertNotIsInstance(cm, typing_extensions.AsyncContextManager) 1867 self.assertEqual( 1868 typing_extensions.AsyncContextManager[int].__args__, 1869 (int, typing.Optional[bool]) 1870 ) 1871 with self.assertRaises(TypeError): 1872 isinstance(42, typing_extensions.AsyncContextManager[int]) 1873 with self.assertRaises(TypeError): 1874 typing_extensions.AsyncContextManager[int, str, float] 1875 1876 def test_asynccontextmanager_type_params(self): 1877 cm1 = typing_extensions.AsyncContextManager[int] 1878 self.assertEqual(get_args(cm1), (int, typing.Optional[bool])) 1879 cm2 = typing_extensions.AsyncContextManager[int, None] 1880 self.assertEqual(get_args(cm2), (int, NoneType)) 1881 1882 1883class TypeTests(BaseTestCase): 1884 1885 def test_type_basic(self): 1886 1887 class User: pass 1888 class BasicUser(User): pass 1889 class ProUser(User): pass 1890 1891 def new_user(user_class: Type[User]) -> User: 1892 return user_class() 1893 1894 new_user(BasicUser) 1895 1896 def test_type_typevar(self): 1897 1898 class User: pass 1899 class BasicUser(User): pass 1900 class ProUser(User): pass 1901 1902 U = TypeVar('U', bound=User) 1903 1904 def new_user(user_class: Type[U]) -> U: 1905 return user_class() 1906 1907 new_user(BasicUser) 1908 1909 def test_type_optional(self): 1910 A = Optional[Type[BaseException]] 1911 1912 def foo(a: A) -> Optional[BaseException]: 1913 if a is None: 1914 return None 1915 else: 1916 return a() 1917 1918 assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt) 1919 assert foo(None) is None 1920 1921 1922class NewTypeTests(BaseTestCase): 1923 @classmethod 1924 def setUpClass(cls): 1925 global UserId 1926 UserId = NewType('UserId', int) 1927 cls.UserName = NewType(cls.__qualname__ + '.UserName', str) 1928 1929 @classmethod 1930 def tearDownClass(cls): 1931 global UserId 1932 del UserId 1933 del cls.UserName 1934 1935 def test_basic(self): 1936 self.assertIsInstance(UserId(5), int) 1937 self.assertIsInstance(self.UserName('Joe'), str) 1938 self.assertEqual(UserId(5) + 1, 6) 1939 1940 def test_errors(self): 1941 with self.assertRaises(TypeError): 1942 issubclass(UserId, int) 1943 with self.assertRaises(TypeError): 1944 class D(UserId): 1945 pass 1946 1947 @skipUnless(TYPING_3_10_0, "PEP 604 has yet to be") 1948 def test_or(self): 1949 for cls in (int, self.UserName): 1950 with self.subTest(cls=cls): 1951 self.assertEqual(UserId | cls, Union[UserId, cls]) 1952 self.assertEqual(cls | UserId, Union[cls, UserId]) 1953 1954 self.assertEqual(get_args(UserId | cls), (UserId, cls)) 1955 self.assertEqual(get_args(cls | UserId), (cls, UserId)) 1956 1957 def test_special_attrs(self): 1958 self.assertEqual(UserId.__name__, 'UserId') 1959 self.assertEqual(UserId.__qualname__, 'UserId') 1960 self.assertEqual(UserId.__module__, __name__) 1961 self.assertEqual(UserId.__supertype__, int) 1962 1963 UserName = self.UserName 1964 self.assertEqual(UserName.__name__, 'UserName') 1965 self.assertEqual(UserName.__qualname__, 1966 self.__class__.__qualname__ + '.UserName') 1967 self.assertEqual(UserName.__module__, __name__) 1968 self.assertEqual(UserName.__supertype__, str) 1969 1970 def test_repr(self): 1971 self.assertEqual(repr(UserId), f'{__name__}.UserId') 1972 self.assertEqual(repr(self.UserName), 1973 f'{__name__}.{self.__class__.__qualname__}.UserName') 1974 1975 def test_pickle(self): 1976 UserAge = NewType('UserAge', float) 1977 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 1978 with self.subTest(proto=proto): 1979 pickled = pickle.dumps(UserId, proto) 1980 loaded = pickle.loads(pickled) 1981 self.assertIs(loaded, UserId) 1982 1983 pickled = pickle.dumps(self.UserName, proto) 1984 loaded = pickle.loads(pickled) 1985 self.assertIs(loaded, self.UserName) 1986 1987 with self.assertRaises(pickle.PicklingError): 1988 pickle.dumps(UserAge, proto) 1989 1990 def test_missing__name__(self): 1991 code = ("import typing_extensions\n" 1992 "NT = typing_extensions.NewType('NT', int)\n" 1993 ) 1994 exec(code, {}) 1995 1996 def test_error_message_when_subclassing(self): 1997 with self.assertRaisesRegex( 1998 TypeError, 1999 re.escape( 2000 "Cannot subclass an instance of NewType. Perhaps you were looking for: " 2001 "`ProUserId = NewType('ProUserId', UserId)`" 2002 ) 2003 ): 2004 class ProUserId(UserId): 2005 ... 2006 2007 2008class Coordinate(Protocol): 2009 x: int 2010 y: int 2011 2012@runtime_checkable 2013class Point(Coordinate, Protocol): 2014 label: str 2015 2016class MyPoint: 2017 x: int 2018 y: int 2019 label: str 2020 2021class XAxis(Protocol): 2022 x: int 2023 2024class YAxis(Protocol): 2025 y: int 2026 2027@runtime_checkable 2028class Position(XAxis, YAxis, Protocol): 2029 pass 2030 2031@runtime_checkable 2032class Proto(Protocol): 2033 attr: int 2034 2035 def meth(self, arg: str) -> int: 2036 ... 2037 2038class Concrete(Proto): 2039 pass 2040 2041class Other: 2042 attr: int = 1 2043 2044 def meth(self, arg: str) -> int: 2045 if arg == 'this': 2046 return 1 2047 return 0 2048 2049class NT(NamedTuple): 2050 x: int 2051 y: int 2052 2053 2054skip_if_py312b1 = skipIf( 2055 sys.version_info == (3, 12, 0, 'beta', 1), 2056 "CPython had bugs in 3.12.0b1" 2057) 2058 2059 2060class ProtocolTests(BaseTestCase): 2061 def test_runtime_alias(self): 2062 self.assertIs(runtime, runtime_checkable) 2063 2064 def test_basic_protocol(self): 2065 @runtime_checkable 2066 class P(Protocol): 2067 def meth(self): 2068 pass 2069 class C: pass 2070 class D: 2071 def meth(self): 2072 pass 2073 def f(): 2074 pass 2075 self.assertIsSubclass(D, P) 2076 self.assertIsInstance(D(), P) 2077 self.assertNotIsSubclass(C, P) 2078 self.assertNotIsInstance(C(), P) 2079 self.assertNotIsSubclass(types.FunctionType, P) 2080 self.assertNotIsInstance(f, P) 2081 2082 def test_everything_implements_empty_protocol(self): 2083 @runtime_checkable 2084 class Empty(Protocol): pass 2085 class C: pass 2086 def f(): 2087 pass 2088 for thing in (object, type, tuple, C, types.FunctionType): 2089 self.assertIsSubclass(thing, Empty) 2090 for thing in (object(), 1, (), typing, f): 2091 self.assertIsInstance(thing, Empty) 2092 2093 def test_function_implements_protocol(self): 2094 def f(): 2095 pass 2096 self.assertIsInstance(f, HasCallProtocol) 2097 2098 def test_no_inheritance_from_nominal(self): 2099 class C: pass 2100 class BP(Protocol): pass 2101 with self.assertRaises(TypeError): 2102 class P(C, Protocol): 2103 pass 2104 with self.assertRaises(TypeError): 2105 class Q(Protocol, C): 2106 pass 2107 with self.assertRaises(TypeError): 2108 class R(BP, C, Protocol): 2109 pass 2110 class D(BP, C): pass 2111 class E(C, BP): pass 2112 self.assertNotIsInstance(D(), E) 2113 self.assertNotIsInstance(E(), D) 2114 2115 def test_runtimecheckable_on_typing_dot_Protocol(self): 2116 @runtime_checkable 2117 class Foo(typing.Protocol): 2118 x: int 2119 2120 class Bar: 2121 def __init__(self): 2122 self.x = 42 2123 2124 self.assertIsInstance(Bar(), Foo) 2125 self.assertNotIsInstance(object(), Foo) 2126 2127 def test_typing_dot_runtimecheckable_on_Protocol(self): 2128 @typing.runtime_checkable 2129 class Foo(Protocol): 2130 x: int 2131 2132 class Bar: 2133 def __init__(self): 2134 self.x = 42 2135 2136 self.assertIsInstance(Bar(), Foo) 2137 self.assertNotIsInstance(object(), Foo) 2138 2139 def test_typing_Protocol_and_extensions_Protocol_can_mix(self): 2140 class TypingProto(typing.Protocol): 2141 x: int 2142 2143 class ExtensionsProto(Protocol): 2144 y: int 2145 2146 class SubProto(TypingProto, ExtensionsProto, typing.Protocol): 2147 z: int 2148 2149 class SubProto2(TypingProto, ExtensionsProto, Protocol): 2150 z: int 2151 2152 class SubProto3(ExtensionsProto, TypingProto, typing.Protocol): 2153 z: int 2154 2155 class SubProto4(ExtensionsProto, TypingProto, Protocol): 2156 z: int 2157 2158 for proto in ( 2159 ExtensionsProto, SubProto, SubProto2, SubProto3, SubProto4 2160 ): 2161 with self.subTest(proto=proto.__name__): 2162 self.assertTrue(is_protocol(proto)) 2163 if Protocol is not typing.Protocol: 2164 self.assertIsInstance(proto, typing_extensions._ProtocolMeta) 2165 self.assertIsInstance(proto.__protocol_attrs__, set) 2166 with self.assertRaisesRegex( 2167 TypeError, "Protocols cannot be instantiated" 2168 ): 2169 proto() 2170 # check these don't raise 2171 runtime_checkable(proto) 2172 typing.runtime_checkable(proto) 2173 2174 class Concrete(SubProto): pass 2175 class Concrete2(SubProto2): pass 2176 class Concrete3(SubProto3): pass 2177 class Concrete4(SubProto4): pass 2178 2179 for cls in Concrete, Concrete2, Concrete3, Concrete4: 2180 with self.subTest(cls=cls.__name__): 2181 self.assertFalse(is_protocol(cls)) 2182 # Check that this doesn't raise: 2183 self.assertIsInstance(cls(), cls) 2184 with self.assertRaises(TypeError): 2185 runtime_checkable(cls) 2186 with self.assertRaises(TypeError): 2187 typing.runtime_checkable(cls) 2188 2189 def test_no_instantiation(self): 2190 class P(Protocol): pass 2191 with self.assertRaises(TypeError): 2192 P() 2193 class C(P): pass 2194 self.assertIsInstance(C(), C) 2195 T = TypeVar('T') 2196 class PG(Protocol[T]): pass 2197 with self.assertRaises(TypeError): 2198 PG() 2199 with self.assertRaises(TypeError): 2200 PG[int]() 2201 with self.assertRaises(TypeError): 2202 PG[T]() 2203 class CG(PG[T]): pass 2204 self.assertIsInstance(CG[int](), CG) 2205 2206 def test_protocol_defining_init_does_not_get_overridden(self): 2207 # check that P.__init__ doesn't get clobbered 2208 # see https://bugs.python.org/issue44807 2209 2210 class P(Protocol): 2211 x: int 2212 def __init__(self, x: int) -> None: 2213 self.x = x 2214 class C: pass 2215 2216 c = C() 2217 P.__init__(c, 1) 2218 self.assertEqual(c.x, 1) 2219 2220 def test_concrete_class_inheriting_init_from_protocol(self): 2221 class P(Protocol): 2222 x: int 2223 def __init__(self, x: int) -> None: 2224 self.x = x 2225 2226 class C(P): pass 2227 2228 c = C(1) 2229 self.assertIsInstance(c, C) 2230 self.assertEqual(c.x, 1) 2231 2232 def test_cannot_instantiate_abstract(self): 2233 @runtime_checkable 2234 class P(Protocol): 2235 @abc.abstractmethod 2236 def ameth(self) -> int: 2237 raise NotImplementedError 2238 class B(P): 2239 pass 2240 class C(B): 2241 def ameth(self) -> int: 2242 return 26 2243 with self.assertRaises(TypeError): 2244 B() 2245 self.assertIsInstance(C(), P) 2246 2247 def test_subprotocols_extending(self): 2248 class P1(Protocol): 2249 def meth1(self): 2250 pass 2251 @runtime_checkable 2252 class P2(P1, Protocol): 2253 def meth2(self): 2254 pass 2255 class C: 2256 def meth1(self): 2257 pass 2258 def meth2(self): 2259 pass 2260 class C1: 2261 def meth1(self): 2262 pass 2263 class C2: 2264 def meth2(self): 2265 pass 2266 self.assertNotIsInstance(C1(), P2) 2267 self.assertNotIsInstance(C2(), P2) 2268 self.assertNotIsSubclass(C1, P2) 2269 self.assertNotIsSubclass(C2, P2) 2270 self.assertIsInstance(C(), P2) 2271 self.assertIsSubclass(C, P2) 2272 2273 def test_subprotocols_merging(self): 2274 class P1(Protocol): 2275 def meth1(self): 2276 pass 2277 class P2(Protocol): 2278 def meth2(self): 2279 pass 2280 @runtime_checkable 2281 class P(P1, P2, Protocol): 2282 pass 2283 class C: 2284 def meth1(self): 2285 pass 2286 def meth2(self): 2287 pass 2288 class C1: 2289 def meth1(self): 2290 pass 2291 class C2: 2292 def meth2(self): 2293 pass 2294 self.assertNotIsInstance(C1(), P) 2295 self.assertNotIsInstance(C2(), P) 2296 self.assertNotIsSubclass(C1, P) 2297 self.assertNotIsSubclass(C2, P) 2298 self.assertIsInstance(C(), P) 2299 self.assertIsSubclass(C, P) 2300 2301 def test_protocols_issubclass(self): 2302 T = TypeVar('T') 2303 @runtime_checkable 2304 class P(Protocol): 2305 def x(self): ... 2306 @runtime_checkable 2307 class PG(Protocol[T]): 2308 def x(self): ... 2309 class BadP(Protocol): 2310 def x(self): ... 2311 class BadPG(Protocol[T]): 2312 def x(self): ... 2313 class C: 2314 def x(self): ... 2315 self.assertIsSubclass(C, P) 2316 self.assertIsSubclass(C, PG) 2317 self.assertIsSubclass(BadP, PG) 2318 2319 no_subscripted_generics = ( 2320 "Subscripted generics cannot be used with class and instance checks" 2321 ) 2322 2323 with self.assertRaisesRegex(TypeError, no_subscripted_generics): 2324 issubclass(C, PG[T]) 2325 with self.assertRaisesRegex(TypeError, no_subscripted_generics): 2326 issubclass(C, PG[C]) 2327 2328 only_runtime_checkable_protocols = ( 2329 "Instance and class checks can only be used with " 2330 "@runtime_checkable protocols" 2331 ) 2332 2333 with self.assertRaisesRegex(TypeError, only_runtime_checkable_protocols): 2334 issubclass(C, BadP) 2335 with self.assertRaisesRegex(TypeError, only_runtime_checkable_protocols): 2336 issubclass(C, BadPG) 2337 2338 with self.assertRaisesRegex(TypeError, no_subscripted_generics): 2339 issubclass(P, PG[T]) 2340 with self.assertRaisesRegex(TypeError, no_subscripted_generics): 2341 issubclass(PG, PG[int]) 2342 2343 only_classes_allowed = r"issubclass\(\) arg 1 must be a class" 2344 2345 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2346 issubclass(1, P) 2347 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2348 issubclass(1, PG) 2349 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2350 issubclass(1, BadP) 2351 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2352 issubclass(1, BadPG) 2353 2354 def test_implicit_issubclass_between_two_protocols(self): 2355 @runtime_checkable 2356 class CallableMembersProto(Protocol): 2357 def meth(self): ... 2358 2359 # All the below protocols should be considered "subclasses" 2360 # of CallableMembersProto at runtime, 2361 # even though none of them explicitly subclass CallableMembersProto 2362 2363 class IdenticalProto(Protocol): 2364 def meth(self): ... 2365 2366 class SupersetProto(Protocol): 2367 def meth(self): ... 2368 def meth2(self): ... 2369 2370 class NonCallableMembersProto(Protocol): 2371 meth: Callable[[], None] 2372 2373 class NonCallableMembersSupersetProto(Protocol): 2374 meth: Callable[[], None] 2375 meth2: Callable[[str, int], bool] 2376 2377 class MixedMembersProto1(Protocol): 2378 meth: Callable[[], None] 2379 def meth2(self): ... 2380 2381 class MixedMembersProto2(Protocol): 2382 def meth(self): ... 2383 meth2: Callable[[str, int], bool] 2384 2385 for proto in ( 2386 IdenticalProto, SupersetProto, NonCallableMembersProto, 2387 NonCallableMembersSupersetProto, MixedMembersProto1, MixedMembersProto2 2388 ): 2389 with self.subTest(proto=proto.__name__): 2390 self.assertIsSubclass(proto, CallableMembersProto) 2391 2392 # These two shouldn't be considered subclasses of CallableMembersProto, however, 2393 # since they don't have the `meth` protocol member 2394 2395 class EmptyProtocol(Protocol): ... 2396 class UnrelatedProtocol(Protocol): 2397 def wut(self): ... 2398 2399 self.assertNotIsSubclass(EmptyProtocol, CallableMembersProto) 2400 self.assertNotIsSubclass(UnrelatedProtocol, CallableMembersProto) 2401 2402 # These aren't protocols at all (despite having annotations), 2403 # so they should only be considered subclasses of CallableMembersProto 2404 # if they *actually have an attribute* matching the `meth` member 2405 # (just having an annotation is insufficient) 2406 2407 class AnnotatedButNotAProtocol: 2408 meth: Callable[[], None] 2409 2410 class NotAProtocolButAnImplicitSubclass: 2411 def meth(self): pass 2412 2413 class NotAProtocolButAnImplicitSubclass2: 2414 meth: Callable[[], None] 2415 def meth(self): pass 2416 2417 class NotAProtocolButAnImplicitSubclass3: 2418 meth: Callable[[], None] 2419 meth2: Callable[[int, str], bool] 2420 def meth(self): pass 2421 def meth2(self, x, y): return True 2422 2423 self.assertNotIsSubclass(AnnotatedButNotAProtocol, CallableMembersProto) 2424 self.assertIsSubclass(NotAProtocolButAnImplicitSubclass, CallableMembersProto) 2425 self.assertIsSubclass(NotAProtocolButAnImplicitSubclass2, CallableMembersProto) 2426 self.assertIsSubclass(NotAProtocolButAnImplicitSubclass3, CallableMembersProto) 2427 2428 @skip_if_py312b1 2429 def test_issubclass_and_isinstance_on_Protocol_itself(self): 2430 class C: 2431 def x(self): pass 2432 2433 self.assertNotIsSubclass(object, Protocol) 2434 self.assertNotIsInstance(object(), Protocol) 2435 2436 self.assertNotIsSubclass(str, Protocol) 2437 self.assertNotIsInstance('foo', Protocol) 2438 2439 self.assertNotIsSubclass(C, Protocol) 2440 self.assertNotIsInstance(C(), Protocol) 2441 2442 only_classes_allowed = r"issubclass\(\) arg 1 must be a class" 2443 2444 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2445 issubclass(1, Protocol) 2446 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2447 issubclass('foo', Protocol) 2448 with self.assertRaisesRegex(TypeError, only_classes_allowed): 2449 issubclass(C(), Protocol) 2450 2451 T = TypeVar('T') 2452 2453 @runtime_checkable 2454 class EmptyProtocol(Protocol): pass 2455 2456 @runtime_checkable 2457 class SupportsStartsWith(Protocol): 2458 def startswith(self, x: str) -> bool: ... 2459 2460 @runtime_checkable 2461 class SupportsX(Protocol[T]): 2462 def x(self): ... 2463 2464 for proto in EmptyProtocol, SupportsStartsWith, SupportsX: 2465 with self.subTest(proto=proto.__name__): 2466 self.assertIsSubclass(proto, Protocol) 2467 2468 # gh-105237 / PR #105239: 2469 # check that the presence of Protocol subclasses 2470 # where `issubclass(X, <subclass>)` evaluates to True 2471 # doesn't influence the result of `issubclass(X, Protocol)` 2472 2473 self.assertIsSubclass(object, EmptyProtocol) 2474 self.assertIsInstance(object(), EmptyProtocol) 2475 self.assertNotIsSubclass(object, Protocol) 2476 self.assertNotIsInstance(object(), Protocol) 2477 2478 self.assertIsSubclass(str, SupportsStartsWith) 2479 self.assertIsInstance('foo', SupportsStartsWith) 2480 self.assertNotIsSubclass(str, Protocol) 2481 self.assertNotIsInstance('foo', Protocol) 2482 2483 self.assertIsSubclass(C, SupportsX) 2484 self.assertIsInstance(C(), SupportsX) 2485 self.assertNotIsSubclass(C, Protocol) 2486 self.assertNotIsInstance(C(), Protocol) 2487 2488 @skip_if_py312b1 2489 def test_isinstance_checks_not_at_whim_of_gc(self): 2490 self.addCleanup(gc.enable) 2491 gc.disable() 2492 2493 with self.assertRaisesRegex( 2494 TypeError, 2495 "Protocols can only inherit from other protocols" 2496 ): 2497 class Foo(collections.abc.Mapping, Protocol): 2498 pass 2499 2500 self.assertNotIsInstance([], collections.abc.Mapping) 2501 2502 def test_protocols_issubclass_non_callable(self): 2503 class C: 2504 x = 1 2505 2506 @runtime_checkable 2507 class PNonCall(Protocol): 2508 x = 1 2509 2510 non_callable_members_illegal = ( 2511 "Protocols with non-method members don't support issubclass()" 2512 ) 2513 2514 with self.assertRaisesRegex(TypeError, non_callable_members_illegal): 2515 issubclass(C, PNonCall) 2516 2517 self.assertIsInstance(C(), PNonCall) 2518 PNonCall.register(C) 2519 2520 with self.assertRaisesRegex(TypeError, non_callable_members_illegal): 2521 issubclass(C, PNonCall) 2522 2523 self.assertIsInstance(C(), PNonCall) 2524 2525 # check that non-protocol subclasses are not affected 2526 class D(PNonCall): ... 2527 2528 self.assertNotIsSubclass(C, D) 2529 self.assertNotIsInstance(C(), D) 2530 D.register(C) 2531 self.assertIsSubclass(C, D) 2532 self.assertIsInstance(C(), D) 2533 2534 with self.assertRaisesRegex(TypeError, non_callable_members_illegal): 2535 issubclass(D, PNonCall) 2536 2537 def test_no_weird_caching_with_issubclass_after_isinstance(self): 2538 @runtime_checkable 2539 class Spam(Protocol): 2540 x: int 2541 2542 class Eggs: 2543 def __init__(self) -> None: 2544 self.x = 42 2545 2546 self.assertIsInstance(Eggs(), Spam) 2547 2548 # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, 2549 # TypeError wouldn't be raised here, 2550 # as the cached result of the isinstance() check immediately above 2551 # would mean the issubclass() call would short-circuit 2552 # before we got to the "raise TypeError" line 2553 with self.assertRaisesRegex( 2554 TypeError, 2555 "Protocols with non-method members don't support issubclass()" 2556 ): 2557 issubclass(Eggs, Spam) 2558 2559 def test_no_weird_caching_with_issubclass_after_isinstance_2(self): 2560 @runtime_checkable 2561 class Spam(Protocol): 2562 x: int 2563 2564 class Eggs: ... 2565 2566 self.assertNotIsInstance(Eggs(), Spam) 2567 2568 # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, 2569 # TypeError wouldn't be raised here, 2570 # as the cached result of the isinstance() check immediately above 2571 # would mean the issubclass() call would short-circuit 2572 # before we got to the "raise TypeError" line 2573 with self.assertRaisesRegex( 2574 TypeError, 2575 "Protocols with non-method members don't support issubclass()" 2576 ): 2577 issubclass(Eggs, Spam) 2578 2579 def test_no_weird_caching_with_issubclass_after_isinstance_3(self): 2580 @runtime_checkable 2581 class Spam(Protocol): 2582 x: int 2583 2584 class Eggs: 2585 def __getattr__(self, attr): 2586 if attr == "x": 2587 return 42 2588 raise AttributeError(attr) 2589 2590 self.assertNotIsInstance(Eggs(), Spam) 2591 2592 # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, 2593 # TypeError wouldn't be raised here, 2594 # as the cached result of the isinstance() check immediately above 2595 # would mean the issubclass() call would short-circuit 2596 # before we got to the "raise TypeError" line 2597 with self.assertRaisesRegex( 2598 TypeError, 2599 "Protocols with non-method members don't support issubclass()" 2600 ): 2601 issubclass(Eggs, Spam) 2602 2603 def test_protocols_isinstance(self): 2604 T = TypeVar('T') 2605 @runtime_checkable 2606 class P(Protocol): 2607 def meth(x): ... 2608 @runtime_checkable 2609 class PG(Protocol[T]): 2610 def meth(x): ... 2611 @runtime_checkable 2612 class WeirdProto(Protocol): 2613 meth = str.maketrans 2614 @runtime_checkable 2615 class WeirdProto2(Protocol): 2616 meth = lambda *args, **kwargs: None # noqa: E731 2617 class CustomCallable: 2618 def __call__(self, *args, **kwargs): 2619 pass 2620 @runtime_checkable 2621 class WeirderProto(Protocol): 2622 meth = CustomCallable() 2623 class BadP(Protocol): 2624 def meth(x): ... 2625 class BadPG(Protocol[T]): 2626 def meth(x): ... 2627 class C: 2628 def meth(x): ... 2629 class C2: 2630 def __init__(self): 2631 self.meth = lambda: None 2632 for klass in C, C2: 2633 for proto in P, PG, WeirdProto, WeirdProto2, WeirderProto: 2634 with self.subTest(klass=klass.__name__, proto=proto.__name__): 2635 self.assertIsInstance(klass(), proto) 2636 2637 no_subscripted_generics = ( 2638 "Subscripted generics cannot be used with class and instance checks" 2639 ) 2640 2641 with self.assertRaisesRegex(TypeError, no_subscripted_generics): 2642 isinstance(C(), PG[T]) 2643 with self.assertRaisesRegex(TypeError, no_subscripted_generics): 2644 isinstance(C(), PG[C]) 2645 2646 only_runtime_checkable_msg = ( 2647 "Instance and class checks can only be used " 2648 "with @runtime_checkable protocols" 2649 ) 2650 2651 with self.assertRaisesRegex(TypeError, only_runtime_checkable_msg): 2652 isinstance(C(), BadP) 2653 with self.assertRaisesRegex(TypeError, only_runtime_checkable_msg): 2654 isinstance(C(), BadPG) 2655 2656 def test_protocols_isinstance_properties_and_descriptors(self): 2657 class C: 2658 @property 2659 def attr(self): 2660 return 42 2661 2662 class CustomDescriptor: 2663 def __get__(self, obj, objtype=None): 2664 return 42 2665 2666 class D: 2667 attr = CustomDescriptor() 2668 2669 # Check that properties set on superclasses 2670 # are still found by the isinstance() logic 2671 class E(C): ... 2672 class F(D): ... 2673 2674 class Empty: ... 2675 2676 T = TypeVar('T') 2677 2678 @runtime_checkable 2679 class P(Protocol): 2680 @property 2681 def attr(self): ... 2682 2683 @runtime_checkable 2684 class P1(Protocol): 2685 attr: int 2686 2687 @runtime_checkable 2688 class PG(Protocol[T]): 2689 @property 2690 def attr(self): ... 2691 2692 @runtime_checkable 2693 class PG1(Protocol[T]): 2694 attr: T 2695 2696 @runtime_checkable 2697 class MethodP(Protocol): 2698 def attr(self): ... 2699 2700 @runtime_checkable 2701 class MethodPG(Protocol[T]): 2702 def attr(self) -> T: ... 2703 2704 for protocol_class in P, P1, PG, PG1, MethodP, MethodPG: 2705 for klass in C, D, E, F: 2706 with self.subTest( 2707 klass=klass.__name__, 2708 protocol_class=protocol_class.__name__ 2709 ): 2710 self.assertIsInstance(klass(), protocol_class) 2711 2712 with self.subTest(klass="Empty", protocol_class=protocol_class.__name__): 2713 self.assertNotIsInstance(Empty(), protocol_class) 2714 2715 class BadP(Protocol): 2716 @property 2717 def attr(self): ... 2718 2719 class BadP1(Protocol): 2720 attr: int 2721 2722 class BadPG(Protocol[T]): 2723 @property 2724 def attr(self): ... 2725 2726 class BadPG1(Protocol[T]): 2727 attr: T 2728 2729 cases = ( 2730 PG[T], PG[C], PG1[T], PG1[C], MethodPG[T], 2731 MethodPG[C], BadP, BadP1, BadPG, BadPG1 2732 ) 2733 2734 for obj in cases: 2735 for klass in C, D, E, F, Empty: 2736 with self.subTest(klass=klass.__name__, obj=obj): 2737 with self.assertRaises(TypeError): 2738 isinstance(klass(), obj) 2739 2740 def test_protocols_isinstance_not_fooled_by_custom_dir(self): 2741 @runtime_checkable 2742 class HasX(Protocol): 2743 x: int 2744 2745 class CustomDirWithX: 2746 x = 10 2747 def __dir__(self): 2748 return [] 2749 2750 class CustomDirWithoutX: 2751 def __dir__(self): 2752 return ["x"] 2753 2754 self.assertIsInstance(CustomDirWithX(), HasX) 2755 self.assertNotIsInstance(CustomDirWithoutX(), HasX) 2756 2757 def test_protocols_isinstance_attribute_access_with_side_effects(self): 2758 class C: 2759 @property 2760 def attr(self): 2761 raise AttributeError('no') 2762 2763 class CustomDescriptor: 2764 def __get__(self, obj, objtype=None): 2765 raise RuntimeError("NO") 2766 2767 class D: 2768 attr = CustomDescriptor() 2769 2770 # Check that properties set on superclasses 2771 # are still found by the isinstance() logic 2772 class E(C): ... 2773 class F(D): ... 2774 2775 class WhyWouldYouDoThis: 2776 def __getattr__(self, name): 2777 raise RuntimeError("wut") 2778 2779 T = TypeVar('T') 2780 2781 @runtime_checkable 2782 class P(Protocol): 2783 @property 2784 def attr(self): ... 2785 2786 @runtime_checkable 2787 class P1(Protocol): 2788 attr: int 2789 2790 @runtime_checkable 2791 class PG(Protocol[T]): 2792 @property 2793 def attr(self): ... 2794 2795 @runtime_checkable 2796 class PG1(Protocol[T]): 2797 attr: T 2798 2799 @runtime_checkable 2800 class MethodP(Protocol): 2801 def attr(self): ... 2802 2803 @runtime_checkable 2804 class MethodPG(Protocol[T]): 2805 def attr(self) -> T: ... 2806 2807 for protocol_class in P, P1, PG, PG1, MethodP, MethodPG: 2808 for klass in C, D, E, F: 2809 with self.subTest( 2810 klass=klass.__name__, 2811 protocol_class=protocol_class.__name__ 2812 ): 2813 self.assertIsInstance(klass(), protocol_class) 2814 2815 with self.subTest( 2816 klass="WhyWouldYouDoThis", 2817 protocol_class=protocol_class.__name__ 2818 ): 2819 self.assertNotIsInstance(WhyWouldYouDoThis(), protocol_class) 2820 2821 def test_protocols_isinstance___slots__(self): 2822 # As per the consensus in https://github.com/python/typing/issues/1367, 2823 # this is desirable behaviour 2824 @runtime_checkable 2825 class HasX(Protocol): 2826 x: int 2827 2828 class HasNothingButSlots: 2829 __slots__ = ("x",) 2830 2831 self.assertIsInstance(HasNothingButSlots(), HasX) 2832 2833 def test_protocols_isinstance_py36(self): 2834 class APoint: 2835 def __init__(self, x, y, label): 2836 self.x = x 2837 self.y = y 2838 self.label = label 2839 class BPoint: 2840 label = 'B' 2841 def __init__(self, x, y): 2842 self.x = x 2843 self.y = y 2844 class C: 2845 def __init__(self, attr): 2846 self.attr = attr 2847 def meth(self, arg): 2848 return 0 2849 class Bad: pass 2850 self.assertIsInstance(APoint(1, 2, 'A'), Point) 2851 self.assertIsInstance(BPoint(1, 2), Point) 2852 self.assertNotIsInstance(MyPoint(), Point) 2853 self.assertIsInstance(BPoint(1, 2), Position) 2854 self.assertIsInstance(Other(), Proto) 2855 self.assertIsInstance(Concrete(), Proto) 2856 self.assertIsInstance(C(42), Proto) 2857 self.assertNotIsInstance(Bad(), Proto) 2858 self.assertNotIsInstance(Bad(), Point) 2859 self.assertNotIsInstance(Bad(), Position) 2860 self.assertNotIsInstance(Bad(), Concrete) 2861 self.assertNotIsInstance(Other(), Concrete) 2862 self.assertIsInstance(NT(1, 2), Position) 2863 2864 def test_runtime_checkable_with_match_args(self): 2865 @runtime_checkable 2866 class P_regular(Protocol): 2867 x: int 2868 y: int 2869 2870 @runtime_checkable 2871 class P_match(Protocol): 2872 __match_args__ = ("x", "y") 2873 x: int 2874 y: int 2875 2876 class Regular: 2877 def __init__(self, x: int, y: int): 2878 self.x = x 2879 self.y = y 2880 2881 class WithMatch: 2882 __match_args__ = ("x", "y", "z") 2883 def __init__(self, x: int, y: int, z: int): 2884 self.x = x 2885 self.y = y 2886 self.z = z 2887 2888 class Nope: ... 2889 2890 self.assertIsInstance(Regular(1, 2), P_regular) 2891 self.assertIsInstance(Regular(1, 2), P_match) 2892 self.assertIsInstance(WithMatch(1, 2, 3), P_regular) 2893 self.assertIsInstance(WithMatch(1, 2, 3), P_match) 2894 self.assertNotIsInstance(Nope(), P_regular) 2895 self.assertNotIsInstance(Nope(), P_match) 2896 2897 def test_protocols_isinstance_init(self): 2898 T = TypeVar('T') 2899 @runtime_checkable 2900 class P(Protocol): 2901 x = 1 2902 @runtime_checkable 2903 class PG(Protocol[T]): 2904 x = 1 2905 class C: 2906 def __init__(self, x): 2907 self.x = x 2908 self.assertIsInstance(C(1), P) 2909 self.assertIsInstance(C(1), PG) 2910 2911 def test_protocols_isinstance_monkeypatching(self): 2912 @runtime_checkable 2913 class HasX(Protocol): 2914 x: int 2915 2916 class Foo: ... 2917 2918 f = Foo() 2919 self.assertNotIsInstance(f, HasX) 2920 f.x = 42 2921 self.assertIsInstance(f, HasX) 2922 del f.x 2923 self.assertNotIsInstance(f, HasX) 2924 2925 @skip_if_py312b1 2926 def test_runtime_checkable_generic_non_protocol(self): 2927 # Make sure this doesn't raise AttributeError 2928 with self.assertRaisesRegex( 2929 TypeError, 2930 "@runtime_checkable can be only applied to protocol classes", 2931 ): 2932 @runtime_checkable 2933 class Foo(Generic[T]): ... 2934 2935 def test_runtime_checkable_generic(self): 2936 @runtime_checkable 2937 class Foo(Protocol[T]): 2938 def meth(self) -> T: ... 2939 2940 class Impl: 2941 def meth(self) -> int: ... 2942 2943 self.assertIsSubclass(Impl, Foo) 2944 2945 class NotImpl: 2946 def method(self) -> int: ... 2947 2948 self.assertNotIsSubclass(NotImpl, Foo) 2949 2950 if sys.version_info >= (3, 12): 2951 exec(textwrap.dedent( 2952 """ 2953 @skip_if_py312b1 2954 def test_pep695_generics_can_be_runtime_checkable(self): 2955 @runtime_checkable 2956 class HasX(Protocol): 2957 x: int 2958 2959 class Bar[T]: 2960 x: T 2961 def __init__(self, x): 2962 self.x = x 2963 2964 class Capybara[T]: 2965 y: str 2966 def __init__(self, y): 2967 self.y = y 2968 2969 self.assertIsInstance(Bar(1), HasX) 2970 self.assertNotIsInstance(Capybara('a'), HasX) 2971 """ 2972 )) 2973 2974 @skip_if_py312b1 2975 def test_protocols_isinstance_generic_classes(self): 2976 T = TypeVar("T") 2977 2978 class Foo(Generic[T]): 2979 x: T 2980 2981 def __init__(self, x): 2982 self.x = x 2983 2984 class Bar(Foo[int]): 2985 ... 2986 2987 @runtime_checkable 2988 class HasX(Protocol): 2989 x: int 2990 2991 foo = Foo(1) 2992 self.assertIsInstance(foo, HasX) 2993 2994 bar = Bar(2) 2995 self.assertIsInstance(bar, HasX) 2996 2997 def test_protocols_support_register(self): 2998 @runtime_checkable 2999 class P(Protocol): 3000 x = 1 3001 class PM(Protocol): 3002 def meth(self): pass 3003 class D(PM): pass 3004 class C: pass 3005 D.register(C) 3006 P.register(C) 3007 self.assertIsInstance(C(), P) 3008 self.assertIsInstance(C(), D) 3009 3010 def test_none_on_non_callable_doesnt_block_implementation(self): 3011 @runtime_checkable 3012 class P(Protocol): 3013 x = 1 3014 class A: 3015 x = 1 3016 class B(A): 3017 x = None 3018 class C: 3019 def __init__(self): 3020 self.x = None 3021 self.assertIsInstance(B(), P) 3022 self.assertIsInstance(C(), P) 3023 3024 def test_none_on_callable_blocks_implementation(self): 3025 @runtime_checkable 3026 class P(Protocol): 3027 def x(self): ... 3028 class A: 3029 def x(self): ... 3030 class B(A): 3031 x = None 3032 class C: 3033 def __init__(self): 3034 self.x = None 3035 self.assertNotIsInstance(B(), P) 3036 self.assertNotIsInstance(C(), P) 3037 3038 def test_non_protocol_subclasses(self): 3039 class P(Protocol): 3040 x = 1 3041 @runtime_checkable 3042 class PR(Protocol): 3043 def meth(self): pass 3044 class NonP(P): 3045 x = 1 3046 class NonPR(PR): pass 3047 class C(metaclass=abc.ABCMeta): 3048 x = 1 3049 class D(metaclass=abc.ABCMeta): 3050 def meth(self): pass # noqa: B027 3051 self.assertNotIsInstance(C(), NonP) 3052 self.assertNotIsInstance(D(), NonPR) 3053 self.assertNotIsSubclass(C, NonP) 3054 self.assertNotIsSubclass(D, NonPR) 3055 self.assertIsInstance(NonPR(), PR) 3056 self.assertIsSubclass(NonPR, PR) 3057 3058 self.assertNotIn("__protocol_attrs__", vars(NonP)) 3059 self.assertNotIn("__protocol_attrs__", vars(NonPR)) 3060 self.assertNotIn("__non_callable_proto_members__", vars(NonP)) 3061 self.assertNotIn("__non_callable_proto_members__", vars(NonPR)) 3062 3063 acceptable_extra_attrs = { 3064 '_is_protocol', '_is_runtime_protocol', '__parameters__', 3065 '__init__', '__annotations__', '__subclasshook__', '__annotate__' 3066 } 3067 self.assertLessEqual(vars(NonP).keys(), vars(C).keys() | acceptable_extra_attrs) 3068 self.assertLessEqual( 3069 vars(NonPR).keys(), vars(D).keys() | acceptable_extra_attrs 3070 ) 3071 3072 def test_custom_subclasshook(self): 3073 class P(Protocol): 3074 x = 1 3075 class OKClass: pass 3076 class BadClass: 3077 x = 1 3078 class C(P): 3079 @classmethod 3080 def __subclasshook__(cls, other): 3081 return other.__name__.startswith("OK") 3082 self.assertIsInstance(OKClass(), C) 3083 self.assertNotIsInstance(BadClass(), C) 3084 self.assertIsSubclass(OKClass, C) 3085 self.assertNotIsSubclass(BadClass, C) 3086 3087 @skipIf( 3088 sys.version_info[:4] == (3, 12, 0, 'beta') and sys.version_info[4] < 4, 3089 "Early betas of Python 3.12 had a bug" 3090 ) 3091 def test_custom_subclasshook_2(self): 3092 @runtime_checkable 3093 class HasX(Protocol): 3094 # The presence of a non-callable member 3095 # would mean issubclass() checks would fail with TypeError 3096 # if it weren't for the custom `__subclasshook__` method 3097 x = 1 3098 3099 @classmethod 3100 def __subclasshook__(cls, other): 3101 return hasattr(other, 'x') 3102 3103 class Empty: pass 3104 3105 class ImplementsHasX: 3106 x = 1 3107 3108 self.assertIsInstance(ImplementsHasX(), HasX) 3109 self.assertNotIsInstance(Empty(), HasX) 3110 self.assertIsSubclass(ImplementsHasX, HasX) 3111 self.assertNotIsSubclass(Empty, HasX) 3112 3113 # isinstance() and issubclass() checks against this still raise TypeError, 3114 # despite the presence of the custom __subclasshook__ method, 3115 # as it's not decorated with @runtime_checkable 3116 class NotRuntimeCheckable(Protocol): 3117 @classmethod 3118 def __subclasshook__(cls, other): 3119 return hasattr(other, 'x') 3120 3121 must_be_runtime_checkable = ( 3122 "Instance and class checks can only be used " 3123 "with @runtime_checkable protocols" 3124 ) 3125 3126 with self.assertRaisesRegex(TypeError, must_be_runtime_checkable): 3127 issubclass(object, NotRuntimeCheckable) 3128 with self.assertRaisesRegex(TypeError, must_be_runtime_checkable): 3129 isinstance(object(), NotRuntimeCheckable) 3130 3131 @skip_if_py312b1 3132 def test_issubclass_fails_correctly(self): 3133 @runtime_checkable 3134 class NonCallableMembers(Protocol): 3135 x = 1 3136 3137 class NotRuntimeCheckable(Protocol): 3138 def callable_member(self) -> int: ... 3139 3140 @runtime_checkable 3141 class RuntimeCheckable(Protocol): 3142 def callable_member(self) -> int: ... 3143 3144 class C: pass 3145 3146 # These three all exercise different code paths, 3147 # but should result in the same error message: 3148 for protocol in NonCallableMembers, NotRuntimeCheckable, RuntimeCheckable: 3149 with self.subTest(proto_name=protocol.__name__): 3150 with self.assertRaisesRegex( 3151 TypeError, r"issubclass\(\) arg 1 must be a class" 3152 ): 3153 issubclass(C(), protocol) 3154 3155 def test_defining_generic_protocols(self): 3156 T = TypeVar('T') 3157 S = TypeVar('S') 3158 @runtime_checkable 3159 class PR(Protocol[T, S]): 3160 def meth(self): pass 3161 class P(PR[int, T], Protocol[T]): 3162 y = 1 3163 with self.assertRaises(TypeError): 3164 issubclass(PR[int, T], PR) 3165 with self.assertRaises(TypeError): 3166 issubclass(P[str], PR) 3167 with self.assertRaises(TypeError): 3168 PR[int] 3169 with self.assertRaises(TypeError): 3170 P[int, str] 3171 if not TYPING_3_10_0: 3172 with self.assertRaises(TypeError): 3173 PR[int, 1] 3174 with self.assertRaises(TypeError): 3175 PR[int, ClassVar] 3176 class C(PR[int, T]): pass 3177 self.assertIsInstance(C[str](), C) 3178 3179 def test_defining_generic_protocols_old_style(self): 3180 T = TypeVar('T') 3181 S = TypeVar('S') 3182 @runtime_checkable 3183 class PR(Protocol, Generic[T, S]): 3184 def meth(self): pass 3185 class P(PR[int, str], Protocol): 3186 y = 1 3187 with self.assertRaises(TypeError): 3188 self.assertIsSubclass(PR[int, str], PR) 3189 self.assertIsSubclass(P, PR) 3190 with self.assertRaises(TypeError): 3191 PR[int] 3192 if not TYPING_3_10_0: 3193 with self.assertRaises(TypeError): 3194 PR[int, 1] 3195 class P1(Protocol, Generic[T]): 3196 def bar(self, x: T) -> str: ... 3197 class P2(Generic[T], Protocol): 3198 def bar(self, x: T) -> str: ... 3199 @runtime_checkable 3200 class PSub(P1[str], Protocol): 3201 x = 1 3202 class Test: 3203 x = 1 3204 def bar(self, x: str) -> str: 3205 return x 3206 self.assertIsInstance(Test(), PSub) 3207 if not TYPING_3_10_0: 3208 with self.assertRaises(TypeError): 3209 PR[int, ClassVar] 3210 3211 if hasattr(typing, "TypeAliasType"): 3212 exec(textwrap.dedent( 3213 """ 3214 def test_pep695_generic_protocol_callable_members(self): 3215 @runtime_checkable 3216 class Foo[T](Protocol): 3217 def meth(self, x: T) -> None: ... 3218 3219 class Bar[T]: 3220 def meth(self, x: T) -> None: ... 3221 3222 self.assertIsInstance(Bar(), Foo) 3223 self.assertIsSubclass(Bar, Foo) 3224 3225 @runtime_checkable 3226 class SupportsTrunc[T](Protocol): 3227 def __trunc__(self) -> T: ... 3228 3229 self.assertIsInstance(0.0, SupportsTrunc) 3230 self.assertIsSubclass(float, SupportsTrunc) 3231 3232 def test_no_weird_caching_with_issubclass_after_isinstance_pep695(self): 3233 @runtime_checkable 3234 class Spam[T](Protocol): 3235 x: T 3236 3237 class Eggs[T]: 3238 def __init__(self, x: T) -> None: 3239 self.x = x 3240 3241 self.assertIsInstance(Eggs(42), Spam) 3242 3243 # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, 3244 # TypeError wouldn't be raised here, 3245 # as the cached result of the isinstance() check immediately above 3246 # would mean the issubclass() call would short-circuit 3247 # before we got to the "raise TypeError" line 3248 with self.assertRaises(TypeError): 3249 issubclass(Eggs, Spam) 3250 """ 3251 )) 3252 3253 def test_init_called(self): 3254 T = TypeVar('T') 3255 class P(Protocol[T]): pass 3256 class C(P[T]): 3257 def __init__(self): 3258 self.test = 'OK' 3259 self.assertEqual(C[int]().test, 'OK') 3260 3261 def test_protocols_bad_subscripts(self): 3262 T = TypeVar('T') 3263 S = TypeVar('S') 3264 with self.assertRaises(TypeError): 3265 class P(Protocol[T, T]): pass 3266 with self.assertRaises(TypeError): 3267 class P2(Protocol[int]): pass 3268 with self.assertRaises(TypeError): 3269 class P3(Protocol[T], Protocol[S]): pass 3270 with self.assertRaises(TypeError): 3271 class P4(typing.Mapping[T, S], Protocol[T]): pass 3272 3273 def test_generic_protocols_repr(self): 3274 T = TypeVar('T') 3275 S = TypeVar('S') 3276 class P(Protocol[T, S]): pass 3277 self.assertTrue(repr(P[T, S]).endswith('P[~T, ~S]')) 3278 self.assertTrue(repr(P[int, str]).endswith('P[int, str]')) 3279 3280 def test_generic_protocols_eq(self): 3281 T = TypeVar('T') 3282 S = TypeVar('S') 3283 class P(Protocol[T, S]): pass 3284 self.assertEqual(P, P) 3285 self.assertEqual(P[int, T], P[int, T]) 3286 self.assertEqual(P[T, T][Tuple[T, S]][int, str], 3287 P[Tuple[int, str], Tuple[int, str]]) 3288 3289 def test_generic_protocols_special_from_generic(self): 3290 T = TypeVar('T') 3291 class P(Protocol[T]): pass 3292 self.assertEqual(P.__parameters__, (T,)) 3293 self.assertEqual(P[int].__parameters__, ()) 3294 self.assertEqual(P[int].__args__, (int,)) 3295 self.assertIs(P[int].__origin__, P) 3296 3297 def test_generic_protocols_special_from_protocol(self): 3298 @runtime_checkable 3299 class PR(Protocol): 3300 x = 1 3301 class P(Protocol): 3302 def meth(self): 3303 pass 3304 T = TypeVar('T') 3305 class PG(Protocol[T]): 3306 x = 1 3307 def meth(self): 3308 pass 3309 self.assertTrue(P._is_protocol) 3310 self.assertTrue(PR._is_protocol) 3311 self.assertTrue(PG._is_protocol) 3312 self.assertFalse(P._is_runtime_protocol) 3313 self.assertTrue(PR._is_runtime_protocol) 3314 self.assertTrue(PG[int]._is_protocol) 3315 self.assertEqual(typing_extensions._get_protocol_attrs(P), {'meth'}) 3316 self.assertEqual(typing_extensions._get_protocol_attrs(PR), {'x'}) 3317 self.assertEqual(frozenset(typing_extensions._get_protocol_attrs(PG)), 3318 frozenset({'x', 'meth'})) 3319 3320 def test_no_runtime_deco_on_nominal(self): 3321 with self.assertRaises(TypeError): 3322 @runtime_checkable 3323 class C: pass 3324 class Proto(Protocol): 3325 x = 1 3326 with self.assertRaises(TypeError): 3327 @runtime_checkable 3328 class Concrete(Proto): 3329 pass 3330 3331 def test_none_treated_correctly(self): 3332 @runtime_checkable 3333 class P(Protocol): 3334 x: int = None 3335 class B: pass 3336 self.assertNotIsInstance(B(), P) 3337 class C: 3338 x = 1 3339 class D: 3340 x = None 3341 self.assertIsInstance(C(), P) 3342 self.assertIsInstance(D(), P) 3343 class CI: 3344 def __init__(self): 3345 self.x = 1 3346 class DI: 3347 def __init__(self): 3348 self.x = None 3349 self.assertIsInstance(CI(), P) 3350 self.assertIsInstance(DI(), P) 3351 3352 def test_protocols_in_unions(self): 3353 class P(Protocol): 3354 x: int = None 3355 Alias = typing.Union[typing.Iterable, P] 3356 Alias2 = typing.Union[P, typing.Iterable] 3357 self.assertEqual(Alias, Alias2) 3358 3359 def test_protocols_pickleable(self): 3360 global P, CP # pickle wants to reference the class by name 3361 T = TypeVar('T') 3362 3363 @runtime_checkable 3364 class P(Protocol[T]): 3365 x = 1 3366 class CP(P[int]): 3367 pass 3368 3369 c = CP() 3370 c.foo = 42 3371 c.bar = 'abc' 3372 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 3373 z = pickle.dumps(c, proto) 3374 x = pickle.loads(z) 3375 self.assertEqual(x.foo, 42) 3376 self.assertEqual(x.bar, 'abc') 3377 self.assertEqual(x.x, 1) 3378 self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) 3379 s = pickle.dumps(P) 3380 D = pickle.loads(s) 3381 class E: 3382 x = 1 3383 self.assertIsInstance(E(), D) 3384 3385 def test_collections_protocols_allowed(self): 3386 @runtime_checkable 3387 class Custom(collections.abc.Iterable, Protocol): 3388 def close(self): pass 3389 3390 class A: ... 3391 class B: 3392 def __iter__(self): 3393 return [] 3394 def close(self): 3395 return 0 3396 3397 self.assertIsSubclass(B, Custom) 3398 self.assertNotIsSubclass(A, Custom) 3399 3400 @skipUnless( 3401 hasattr(collections.abc, "Buffer"), 3402 "needs collections.abc.Buffer to exist" 3403 ) 3404 @skip_if_py312b1 3405 def test_collections_abc_buffer_protocol_allowed(self): 3406 @runtime_checkable 3407 class ReleasableBuffer(collections.abc.Buffer, Protocol): 3408 def __release_buffer__(self, mv: memoryview) -> None: ... 3409 3410 class C: pass 3411 class D: 3412 def __buffer__(self, flags: int) -> memoryview: 3413 return memoryview(b'') 3414 def __release_buffer__(self, mv: memoryview) -> None: 3415 pass 3416 3417 self.assertIsSubclass(D, ReleasableBuffer) 3418 self.assertIsInstance(D(), ReleasableBuffer) 3419 self.assertNotIsSubclass(C, ReleasableBuffer) 3420 self.assertNotIsInstance(C(), ReleasableBuffer) 3421 3422 def test_builtin_protocol_allowlist(self): 3423 with self.assertRaises(TypeError): 3424 class CustomProtocol(TestCase, Protocol): 3425 pass 3426 3427 class CustomContextManager(typing.ContextManager, Protocol): 3428 pass 3429 3430 @skip_if_py312b1 3431 def test_typing_extensions_protocol_allowlist(self): 3432 @runtime_checkable 3433 class ReleasableBuffer(Buffer, Protocol): 3434 def __release_buffer__(self, mv: memoryview) -> None: ... 3435 3436 class C: pass 3437 class D: 3438 def __buffer__(self, flags: int) -> memoryview: 3439 return memoryview(b'') 3440 def __release_buffer__(self, mv: memoryview) -> None: 3441 pass 3442 3443 self.assertIsSubclass(D, ReleasableBuffer) 3444 self.assertIsInstance(D(), ReleasableBuffer) 3445 self.assertNotIsSubclass(C, ReleasableBuffer) 3446 self.assertNotIsInstance(C(), ReleasableBuffer) 3447 3448 def test_non_runtime_protocol_isinstance_check(self): 3449 class P(Protocol): 3450 x: int 3451 3452 with self.assertRaisesRegex(TypeError, "@runtime_checkable"): 3453 isinstance(1, P) 3454 3455 def test_no_init_same_for_different_protocol_implementations(self): 3456 class CustomProtocolWithoutInitA(Protocol): 3457 pass 3458 3459 class CustomProtocolWithoutInitB(Protocol): 3460 pass 3461 3462 self.assertEqual(CustomProtocolWithoutInitA.__init__, CustomProtocolWithoutInitB.__init__) 3463 3464 def test_protocol_generic_over_paramspec(self): 3465 P = ParamSpec("P") 3466 T = TypeVar("T") 3467 T2 = TypeVar("T2") 3468 3469 class MemoizedFunc(Protocol[P, T, T2]): 3470 cache: typing.Dict[T2, T] 3471 def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ... 3472 3473 self.assertEqual(MemoizedFunc.__parameters__, (P, T, T2)) 3474 self.assertTrue(MemoizedFunc._is_protocol) 3475 3476 with self.assertRaises(TypeError): 3477 MemoizedFunc[[int, str, str]] 3478 3479 if sys.version_info >= (3, 10): 3480 # These unfortunately don't pass on <=3.9, 3481 # due to typing._type_check on older Python versions 3482 X = MemoizedFunc[[int, str, str], T, T2] 3483 self.assertEqual(X.__parameters__, (T, T2)) 3484 self.assertEqual(X.__args__, ((int, str, str), T, T2)) 3485 3486 Y = X[bytes, memoryview] 3487 self.assertEqual(Y.__parameters__, ()) 3488 self.assertEqual(Y.__args__, ((int, str, str), bytes, memoryview)) 3489 3490 def test_protocol_generic_over_typevartuple(self): 3491 Ts = TypeVarTuple("Ts") 3492 T = TypeVar("T") 3493 T2 = TypeVar("T2") 3494 3495 class MemoizedFunc(Protocol[Unpack[Ts], T, T2]): 3496 cache: typing.Dict[T2, T] 3497 def __call__(self, *args: Unpack[Ts]) -> T: ... 3498 3499 self.assertEqual(MemoizedFunc.__parameters__, (Ts, T, T2)) 3500 self.assertTrue(MemoizedFunc._is_protocol) 3501 3502 things = "arguments" if sys.version_info >= (3, 10) else "parameters" 3503 3504 # A bug was fixed in 3.11.1 3505 # (https://github.com/python/cpython/commit/74920aa27d0c57443dd7f704d6272cca9c507ab3) 3506 # That means this assertion doesn't pass on 3.11.0, 3507 # but it passes on all other Python versions 3508 if sys.version_info[:3] != (3, 11, 0): 3509 with self.assertRaisesRegex(TypeError, f"Too few {things}"): 3510 MemoizedFunc[int] 3511 3512 X = MemoizedFunc[int, T, T2] 3513 self.assertEqual(X.__parameters__, (T, T2)) 3514 self.assertEqual(X.__args__, (int, T, T2)) 3515 3516 Y = X[bytes, memoryview] 3517 self.assertEqual(Y.__parameters__, ()) 3518 self.assertEqual(Y.__args__, (int, bytes, memoryview)) 3519 3520 def test_get_protocol_members(self): 3521 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3522 get_protocol_members(object) 3523 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3524 get_protocol_members(object()) 3525 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3526 get_protocol_members(Protocol) 3527 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3528 get_protocol_members(Generic) 3529 3530 class P(Protocol): 3531 a: int 3532 def b(self) -> str: ... 3533 @property 3534 def c(self) -> int: ... 3535 3536 self.assertEqual(get_protocol_members(P), {'a', 'b', 'c'}) 3537 self.assertIsInstance(get_protocol_members(P), frozenset) 3538 self.assertIsNot(get_protocol_members(P), P.__protocol_attrs__) 3539 3540 class Concrete: 3541 a: int 3542 def b(self) -> str: return "capybara" 3543 @property 3544 def c(self) -> int: return 5 3545 3546 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3547 get_protocol_members(Concrete) 3548 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3549 get_protocol_members(Concrete()) 3550 3551 class ConcreteInherit(P): 3552 a: int = 42 3553 def b(self) -> str: return "capybara" 3554 @property 3555 def c(self) -> int: return 5 3556 3557 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3558 get_protocol_members(ConcreteInherit) 3559 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3560 get_protocol_members(ConcreteInherit()) 3561 3562 def test_get_protocol_members_typing(self): 3563 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3564 get_protocol_members(typing.Protocol) 3565 3566 class P(typing.Protocol): 3567 a: int 3568 def b(self) -> str: ... 3569 @property 3570 def c(self) -> int: ... 3571 3572 self.assertEqual(get_protocol_members(P), {'a', 'b', 'c'}) 3573 self.assertIsInstance(get_protocol_members(P), frozenset) 3574 if hasattr(P, "__protocol_attrs__"): 3575 self.assertIsNot(get_protocol_members(P), P.__protocol_attrs__) 3576 3577 class Concrete: 3578 a: int 3579 def b(self) -> str: return "capybara" 3580 @property 3581 def c(self) -> int: return 5 3582 3583 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3584 get_protocol_members(Concrete) 3585 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3586 get_protocol_members(Concrete()) 3587 3588 class ConcreteInherit(P): 3589 a: int = 42 3590 def b(self) -> str: return "capybara" 3591 @property 3592 def c(self) -> int: return 5 3593 3594 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3595 get_protocol_members(ConcreteInherit) 3596 with self.assertRaisesRegex(TypeError, "not a Protocol"): 3597 get_protocol_members(ConcreteInherit()) 3598 3599 def test_is_protocol(self): 3600 self.assertTrue(is_protocol(Proto)) 3601 self.assertTrue(is_protocol(Point)) 3602 self.assertFalse(is_protocol(Concrete)) 3603 self.assertFalse(is_protocol(Concrete())) 3604 self.assertFalse(is_protocol(Generic)) 3605 self.assertFalse(is_protocol(object)) 3606 3607 # Protocol is not itself a protocol 3608 self.assertFalse(is_protocol(Protocol)) 3609 3610 def test_is_protocol_with_typing(self): 3611 self.assertFalse(is_protocol(typing.Protocol)) 3612 3613 class TypingProto(typing.Protocol): 3614 a: int 3615 3616 self.assertTrue(is_protocol(TypingProto)) 3617 3618 class Concrete(TypingProto): 3619 a: int 3620 3621 self.assertFalse(is_protocol(Concrete)) 3622 3623 @skip_if_py312b1 3624 def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta(self): 3625 # Ensure the cache is empty, or this test won't work correctly 3626 collections.abc.Sized._abc_registry_clear() 3627 3628 class Foo(collections.abc.Sized, Protocol): pass 3629 3630 # CPython gh-105144: this previously raised TypeError 3631 # if a Protocol subclass of Sized had been created 3632 # before any isinstance() checks against Sized 3633 self.assertNotIsInstance(1, collections.abc.Sized) 3634 3635 @skip_if_py312b1 3636 def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta_2(self): 3637 # Ensure the cache is empty, or this test won't work correctly 3638 collections.abc.Sized._abc_registry_clear() 3639 3640 class Foo(typing.Sized, Protocol): pass 3641 3642 # CPython gh-105144: this previously raised TypeError 3643 # if a Protocol subclass of Sized had been created 3644 # before any isinstance() checks against Sized 3645 self.assertNotIsInstance(1, typing.Sized) 3646 3647 def test_empty_protocol_decorated_with_final(self): 3648 @final 3649 @runtime_checkable 3650 class EmptyProtocol(Protocol): ... 3651 3652 self.assertIsSubclass(object, EmptyProtocol) 3653 self.assertIsInstance(object(), EmptyProtocol) 3654 3655 def test_protocol_decorated_with_final_callable_members(self): 3656 @final 3657 @runtime_checkable 3658 class ProtocolWithMethod(Protocol): 3659 def startswith(self, string: str) -> bool: ... 3660 3661 self.assertIsSubclass(str, ProtocolWithMethod) 3662 self.assertNotIsSubclass(int, ProtocolWithMethod) 3663 self.assertIsInstance('foo', ProtocolWithMethod) 3664 self.assertNotIsInstance(42, ProtocolWithMethod) 3665 3666 def test_protocol_decorated_with_final_noncallable_members(self): 3667 @final 3668 @runtime_checkable 3669 class ProtocolWithNonCallableMember(Protocol): 3670 x: int 3671 3672 class Foo: 3673 x = 42 3674 3675 only_callable_members_please = ( 3676 r"Protocols with non-method members don't support issubclass()" 3677 ) 3678 3679 with self.assertRaisesRegex(TypeError, only_callable_members_please): 3680 issubclass(Foo, ProtocolWithNonCallableMember) 3681 3682 with self.assertRaisesRegex(TypeError, only_callable_members_please): 3683 issubclass(int, ProtocolWithNonCallableMember) 3684 3685 self.assertIsInstance(Foo(), ProtocolWithNonCallableMember) 3686 self.assertNotIsInstance(42, ProtocolWithNonCallableMember) 3687 3688 def test_protocol_decorated_with_final_mixed_members(self): 3689 @final 3690 @runtime_checkable 3691 class ProtocolWithMixedMembers(Protocol): 3692 x: int 3693 def method(self) -> None: ... 3694 3695 class Foo: 3696 x = 42 3697 def method(self) -> None: ... 3698 3699 only_callable_members_please = ( 3700 r"Protocols with non-method members don't support issubclass()" 3701 ) 3702 3703 with self.assertRaisesRegex(TypeError, only_callable_members_please): 3704 issubclass(Foo, ProtocolWithMixedMembers) 3705 3706 with self.assertRaisesRegex(TypeError, only_callable_members_please): 3707 issubclass(int, ProtocolWithMixedMembers) 3708 3709 self.assertIsInstance(Foo(), ProtocolWithMixedMembers) 3710 self.assertNotIsInstance(42, ProtocolWithMixedMembers) 3711 3712 def test_protocol_issubclass_error_message(self): 3713 @runtime_checkable 3714 class Vec2D(Protocol): 3715 x: float 3716 y: float 3717 3718 def square_norm(self) -> float: 3719 return self.x ** 2 + self.y ** 2 3720 3721 self.assertEqual(Vec2D.__protocol_attrs__, {'x', 'y', 'square_norm'}) 3722 expected_error_message = ( 3723 "Protocols with non-method members don't support issubclass()." 3724 " Non-method members: 'x', 'y'." 3725 ) 3726 with self.assertRaisesRegex(TypeError, re.escape(expected_error_message)): 3727 issubclass(int, Vec2D) 3728 3729 def test_nonruntime_protocol_interaction_with_evil_classproperty(self): 3730 class classproperty: 3731 def __get__(self, instance, type): 3732 raise RuntimeError("NO") 3733 3734 class Commentable(Protocol): 3735 evil = classproperty() 3736 3737 # recognised as a protocol attr, 3738 # but not actually accessed by the protocol metaclass 3739 # (which would raise RuntimeError) for non-runtime protocols. 3740 # See gh-113320 3741 self.assertEqual(get_protocol_members(Commentable), {"evil"}) 3742 3743 def test_runtime_protocol_interaction_with_evil_classproperty(self): 3744 class CustomError(Exception): pass 3745 3746 class classproperty: 3747 def __get__(self, instance, type): 3748 raise CustomError 3749 3750 with self.assertRaises(TypeError) as cm: 3751 @runtime_checkable 3752 class Commentable(Protocol): 3753 evil = classproperty() 3754 3755 exc = cm.exception 3756 self.assertEqual( 3757 exc.args[0], 3758 "Failed to determine whether protocol member 'evil' is a method member" 3759 ) 3760 self.assertIs(type(exc.__cause__), CustomError) 3761 3762 def test_extensions_runtimecheckable_on_typing_Protocol(self): 3763 @runtime_checkable 3764 class Functor(typing.Protocol): 3765 def foo(self) -> None: ... 3766 3767 self.assertNotIsSubclass(object, Functor) 3768 3769 class Bar: 3770 def foo(self): pass 3771 3772 self.assertIsSubclass(Bar, Functor) 3773 3774 3775class Point2DGeneric(Generic[T], TypedDict): 3776 a: T 3777 b: T 3778 3779 3780class Bar(Foo): 3781 b: int 3782 3783 3784class BarGeneric(FooGeneric[T], total=False): 3785 b: int 3786 3787 3788class TypedDictTests(BaseTestCase): 3789 def test_basics_functional_syntax(self): 3790 Emp = TypedDict('Emp', {'name': str, 'id': int}) 3791 self.assertIsSubclass(Emp, dict) 3792 self.assertIsSubclass(Emp, typing.MutableMapping) 3793 self.assertNotIsSubclass(Emp, collections.abc.Sequence) 3794 jim = Emp(name='Jim', id=1) 3795 self.assertIs(type(jim), dict) 3796 self.assertEqual(jim['name'], 'Jim') 3797 self.assertEqual(jim['id'], 1) 3798 self.assertEqual(Emp.__name__, 'Emp') 3799 self.assertEqual(Emp.__module__, __name__) 3800 self.assertEqual(Emp.__bases__, (dict,)) 3801 self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) 3802 self.assertEqual(Emp.__total__, True) 3803 3804 @skipIf(sys.version_info < (3, 13), "Change in behavior in 3.13") 3805 def test_keywords_syntax_raises_on_3_13(self): 3806 with self.assertRaises(TypeError), self.assertWarns(DeprecationWarning): 3807 TypedDict('Emp', name=str, id=int) 3808 3809 @skipIf(sys.version_info >= (3, 13), "3.13 removes support for kwargs") 3810 def test_basics_keywords_syntax(self): 3811 with self.assertWarns(DeprecationWarning): 3812 Emp = TypedDict('Emp', name=str, id=int) 3813 self.assertIsSubclass(Emp, dict) 3814 self.assertIsSubclass(Emp, typing.MutableMapping) 3815 self.assertNotIsSubclass(Emp, collections.abc.Sequence) 3816 jim = Emp(name='Jim', id=1) 3817 self.assertIs(type(jim), dict) 3818 self.assertEqual(jim['name'], 'Jim') 3819 self.assertEqual(jim['id'], 1) 3820 self.assertEqual(Emp.__name__, 'Emp') 3821 self.assertEqual(Emp.__module__, __name__) 3822 self.assertEqual(Emp.__bases__, (dict,)) 3823 self.assertEqual(Emp.__annotations__, {'name': str, 'id': int}) 3824 self.assertEqual(Emp.__total__, True) 3825 3826 @skipIf(sys.version_info >= (3, 13), "3.13 removes support for kwargs") 3827 def test_typeddict_special_keyword_names(self): 3828 with self.assertWarns(DeprecationWarning): 3829 TD = TypedDict("TD", cls=type, self=object, typename=str, _typename=int, 3830 fields=list, _fields=dict) 3831 self.assertEqual(TD.__name__, 'TD') 3832 self.assertEqual(TD.__annotations__, {'cls': type, 'self': object, 'typename': str, 3833 '_typename': int, 'fields': list, '_fields': dict}) 3834 a = TD(cls=str, self=42, typename='foo', _typename=53, 3835 fields=[('bar', tuple)], _fields={'baz', set}) 3836 self.assertEqual(a['cls'], str) 3837 self.assertEqual(a['self'], 42) 3838 self.assertEqual(a['typename'], 'foo') 3839 self.assertEqual(a['_typename'], 53) 3840 self.assertEqual(a['fields'], [('bar', tuple)]) 3841 self.assertEqual(a['_fields'], {'baz', set}) 3842 3843 def test_typeddict_create_errors(self): 3844 with self.assertRaises(TypeError): 3845 TypedDict.__new__() 3846 with self.assertRaises(TypeError): 3847 TypedDict() 3848 with self.assertRaises(TypeError): 3849 TypedDict('Emp', [('name', str)], None) 3850 3851 def test_typeddict_errors(self): 3852 Emp = TypedDict('Emp', {'name': str, 'id': int}) 3853 self.assertEqual(TypedDict.__module__, 'typing_extensions') 3854 jim = Emp(name='Jim', id=1) 3855 with self.assertRaises(TypeError): 3856 isinstance({}, Emp) 3857 with self.assertRaises(TypeError): 3858 isinstance(jim, Emp) 3859 with self.assertRaises(TypeError): 3860 issubclass(dict, Emp) 3861 3862 if not TYPING_3_11_0: 3863 with self.assertRaises(TypeError), self.assertWarns(DeprecationWarning): 3864 TypedDict('Hi', x=1) 3865 with self.assertRaises(TypeError): 3866 TypedDict('Hi', [('x', int), ('y', 1)]) 3867 with self.assertRaises(TypeError): 3868 TypedDict('Hi', [('x', int)], y=int) 3869 3870 def test_py36_class_syntax_usage(self): 3871 self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D') 3872 self.assertEqual(LabelPoint2D.__module__, __name__) 3873 self.assertEqual(LabelPoint2D.__annotations__, {'x': int, 'y': int, 'label': str}) 3874 self.assertEqual(LabelPoint2D.__bases__, (dict,)) 3875 self.assertEqual(LabelPoint2D.__total__, True) 3876 self.assertNotIsSubclass(LabelPoint2D, typing.Sequence) 3877 not_origin = Point2D(x=0, y=1) 3878 self.assertEqual(not_origin['x'], 0) 3879 self.assertEqual(not_origin['y'], 1) 3880 other = LabelPoint2D(x=0, y=1, label='hi') 3881 self.assertEqual(other['label'], 'hi') 3882 3883 def test_pickle(self): 3884 global EmpD # pickle wants to reference the class by name 3885 EmpD = TypedDict('EmpD', {'name': str, 'id': int}) 3886 jane = EmpD({'name': 'jane', 'id': 37}) 3887 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 3888 z = pickle.dumps(jane, proto) 3889 jane2 = pickle.loads(z) 3890 self.assertEqual(jane2, jane) 3891 self.assertEqual(jane2, {'name': 'jane', 'id': 37}) 3892 ZZ = pickle.dumps(EmpD, proto) 3893 EmpDnew = pickle.loads(ZZ) 3894 self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane) 3895 3896 def test_pickle_generic(self): 3897 point = Point2DGeneric(a=5.0, b=3.0) 3898 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 3899 z = pickle.dumps(point, proto) 3900 point2 = pickle.loads(z) 3901 self.assertEqual(point2, point) 3902 self.assertEqual(point2, {'a': 5.0, 'b': 3.0}) 3903 ZZ = pickle.dumps(Point2DGeneric, proto) 3904 Point2DGenericNew = pickle.loads(ZZ) 3905 self.assertEqual(Point2DGenericNew({'a': 5.0, 'b': 3.0}), point) 3906 3907 def test_optional(self): 3908 EmpD = TypedDict('EmpD', {'name': str, 'id': int}) 3909 3910 self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD]) 3911 self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD]) 3912 3913 def test_total(self): 3914 D = TypedDict('D', {'x': int}, total=False) 3915 self.assertEqual(D(), {}) 3916 self.assertEqual(D(x=1), {'x': 1}) 3917 self.assertEqual(D.__total__, False) 3918 self.assertEqual(D.__required_keys__, frozenset()) 3919 self.assertEqual(D.__optional_keys__, {'x'}) 3920 3921 self.assertEqual(Options(), {}) 3922 self.assertEqual(Options(log_level=2), {'log_level': 2}) 3923 self.assertEqual(Options.__total__, False) 3924 self.assertEqual(Options.__required_keys__, frozenset()) 3925 self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'}) 3926 3927 def test_optional_keys(self): 3928 class Point2Dor3D(Point2D, total=False): 3929 z: int 3930 3931 assert Point2Dor3D.__required_keys__ == frozenset(['x', 'y']) 3932 assert Point2Dor3D.__optional_keys__ == frozenset(['z']) 3933 3934 def test_keys_inheritance(self): 3935 class BaseAnimal(TypedDict): 3936 name: str 3937 3938 class Animal(BaseAnimal, total=False): 3939 voice: str 3940 tail: bool 3941 3942 class Cat(Animal): 3943 fur_color: str 3944 3945 assert BaseAnimal.__required_keys__ == frozenset(['name']) 3946 assert BaseAnimal.__optional_keys__ == frozenset([]) 3947 assert BaseAnimal.__annotations__ == {'name': str} 3948 3949 assert Animal.__required_keys__ == frozenset(['name']) 3950 assert Animal.__optional_keys__ == frozenset(['tail', 'voice']) 3951 assert Animal.__annotations__ == { 3952 'name': str, 3953 'tail': bool, 3954 'voice': str, 3955 } 3956 3957 assert Cat.__required_keys__ == frozenset(['name', 'fur_color']) 3958 assert Cat.__optional_keys__ == frozenset(['tail', 'voice']) 3959 assert Cat.__annotations__ == { 3960 'fur_color': str, 3961 'name': str, 3962 'tail': bool, 3963 'voice': str, 3964 } 3965 3966 def test_required_notrequired_keys(self): 3967 self.assertEqual(NontotalMovie.__required_keys__, 3968 frozenset({"title"})) 3969 self.assertEqual(NontotalMovie.__optional_keys__, 3970 frozenset({"year"})) 3971 3972 self.assertEqual(TotalMovie.__required_keys__, 3973 frozenset({"title"})) 3974 self.assertEqual(TotalMovie.__optional_keys__, 3975 frozenset({"year"})) 3976 3977 self.assertEqual(VeryAnnotated.__required_keys__, 3978 frozenset()) 3979 self.assertEqual(VeryAnnotated.__optional_keys__, 3980 frozenset({"a"})) 3981 3982 self.assertEqual(AnnotatedMovie.__required_keys__, 3983 frozenset({"title"})) 3984 self.assertEqual(AnnotatedMovie.__optional_keys__, 3985 frozenset({"year"})) 3986 3987 self.assertEqual(WeirdlyQuotedMovie.__required_keys__, 3988 frozenset({"title"})) 3989 self.assertEqual(WeirdlyQuotedMovie.__optional_keys__, 3990 frozenset({"year"})) 3991 3992 self.assertEqual(ChildTotalMovie.__required_keys__, 3993 frozenset({"title"})) 3994 self.assertEqual(ChildTotalMovie.__optional_keys__, 3995 frozenset({"year"})) 3996 3997 self.assertEqual(ChildDeeplyAnnotatedMovie.__required_keys__, 3998 frozenset({"title"})) 3999 self.assertEqual(ChildDeeplyAnnotatedMovie.__optional_keys__, 4000 frozenset({"year"})) 4001 4002 def test_multiple_inheritance(self): 4003 class One(TypedDict): 4004 one: int 4005 class Two(TypedDict): 4006 two: str 4007 class Untotal(TypedDict, total=False): 4008 untotal: str 4009 Inline = TypedDict('Inline', {'inline': bool}) 4010 class Regular: 4011 pass 4012 4013 class Child(One, Two): 4014 child: bool 4015 self.assertEqual( 4016 Child.__required_keys__, 4017 frozenset(['one', 'two', 'child']), 4018 ) 4019 self.assertEqual( 4020 Child.__optional_keys__, 4021 frozenset([]), 4022 ) 4023 self.assertEqual( 4024 Child.__annotations__, 4025 {'one': int, 'two': str, 'child': bool}, 4026 ) 4027 4028 class ChildWithOptional(One, Untotal): 4029 child: bool 4030 self.assertEqual( 4031 ChildWithOptional.__required_keys__, 4032 frozenset(['one', 'child']), 4033 ) 4034 self.assertEqual( 4035 ChildWithOptional.__optional_keys__, 4036 frozenset(['untotal']), 4037 ) 4038 self.assertEqual( 4039 ChildWithOptional.__annotations__, 4040 {'one': int, 'untotal': str, 'child': bool}, 4041 ) 4042 4043 class ChildWithTotalFalse(One, Untotal, total=False): 4044 child: bool 4045 self.assertEqual( 4046 ChildWithTotalFalse.__required_keys__, 4047 frozenset(['one']), 4048 ) 4049 self.assertEqual( 4050 ChildWithTotalFalse.__optional_keys__, 4051 frozenset(['untotal', 'child']), 4052 ) 4053 self.assertEqual( 4054 ChildWithTotalFalse.__annotations__, 4055 {'one': int, 'untotal': str, 'child': bool}, 4056 ) 4057 4058 class ChildWithInlineAndOptional(Untotal, Inline): 4059 child: bool 4060 self.assertEqual( 4061 ChildWithInlineAndOptional.__required_keys__, 4062 frozenset(['inline', 'child']), 4063 ) 4064 self.assertEqual( 4065 ChildWithInlineAndOptional.__optional_keys__, 4066 frozenset(['untotal']), 4067 ) 4068 self.assertEqual( 4069 ChildWithInlineAndOptional.__annotations__, 4070 {'inline': bool, 'untotal': str, 'child': bool}, 4071 ) 4072 4073 class Closed(TypedDict, closed=True): 4074 __extra_items__: None 4075 4076 class Unclosed(TypedDict, closed=False): 4077 ... 4078 4079 class ChildUnclosed(Closed, Unclosed): 4080 ... 4081 4082 self.assertFalse(ChildUnclosed.__closed__) 4083 self.assertEqual(ChildUnclosed.__extra_items__, type(None)) 4084 4085 class ChildClosed(Unclosed, Closed): 4086 ... 4087 4088 self.assertFalse(ChildClosed.__closed__) 4089 self.assertEqual(ChildClosed.__extra_items__, type(None)) 4090 4091 wrong_bases = [ 4092 (One, Regular), 4093 (Regular, One), 4094 (One, Two, Regular), 4095 (Inline, Regular), 4096 (Untotal, Regular), 4097 ] 4098 for bases in wrong_bases: 4099 with self.subTest(bases=bases): 4100 with self.assertRaisesRegex( 4101 TypeError, 4102 'cannot inherit from both a TypedDict type and a non-TypedDict', 4103 ): 4104 class Wrong(*bases): 4105 pass 4106 4107 def test_is_typeddict(self): 4108 self.assertIs(is_typeddict(Point2D), True) 4109 self.assertIs(is_typeddict(Point2Dor3D), True) 4110 self.assertIs(is_typeddict(Union[str, int]), False) 4111 # classes, not instances 4112 self.assertIs(is_typeddict(Point2D()), False) 4113 call_based = TypedDict('call_based', {'a': int}) 4114 self.assertIs(is_typeddict(call_based), True) 4115 self.assertIs(is_typeddict(call_based()), False) 4116 4117 T = TypeVar("T") 4118 class BarGeneric(TypedDict, Generic[T]): 4119 a: T 4120 self.assertIs(is_typeddict(BarGeneric), True) 4121 self.assertIs(is_typeddict(BarGeneric[int]), False) 4122 self.assertIs(is_typeddict(BarGeneric()), False) 4123 4124 if hasattr(typing, "TypeAliasType"): 4125 ns = {"TypedDict": TypedDict} 4126 exec("""if True: 4127 class NewGeneric[T](TypedDict): 4128 a: T 4129 """, ns) 4130 NewGeneric = ns["NewGeneric"] 4131 self.assertIs(is_typeddict(NewGeneric), True) 4132 self.assertIs(is_typeddict(NewGeneric[int]), False) 4133 self.assertIs(is_typeddict(NewGeneric()), False) 4134 4135 # The TypedDict constructor is not itself a TypedDict 4136 self.assertIs(is_typeddict(TypedDict), False) 4137 if hasattr(typing, "TypedDict"): 4138 self.assertIs(is_typeddict(typing.TypedDict), False) 4139 4140 def test_is_typeddict_against_typeddict_from_typing(self): 4141 Point = typing.TypedDict('Point', {'x': int, 'y': int}) 4142 4143 class PointDict2D(typing.TypedDict): 4144 x: int 4145 y: int 4146 4147 class PointDict3D(PointDict2D, total=False): 4148 z: int 4149 4150 assert is_typeddict(Point) is True 4151 assert is_typeddict(PointDict2D) is True 4152 assert is_typeddict(PointDict3D) is True 4153 4154 @skipUnless(HAS_FORWARD_MODULE, "ForwardRef.__forward_module__ was added in 3.9") 4155 def test_get_type_hints_cross_module_subclass(self): 4156 self.assertNotIn("_DoNotImport", globals()) 4157 self.assertEqual( 4158 {k: v.__name__ for k, v in get_type_hints(Bar).items()}, 4159 {'a': "_DoNotImport", 'b': "int"} 4160 ) 4161 4162 def test_get_type_hints_generic(self): 4163 self.assertEqual( 4164 get_type_hints(BarGeneric), 4165 {'a': typing.Optional[T], 'b': int} 4166 ) 4167 4168 class FooBarGeneric(BarGeneric[int]): 4169 c: str 4170 4171 self.assertEqual( 4172 get_type_hints(FooBarGeneric), 4173 {'a': typing.Optional[T], 'b': int, 'c': str} 4174 ) 4175 4176 @skipUnless(TYPING_3_12_0, "PEP 695 required") 4177 def test_pep695_generic_typeddict(self): 4178 ns = {"TypedDict": TypedDict} 4179 exec("""if True: 4180 class A[T](TypedDict): 4181 a: T 4182 """, ns) 4183 A = ns["A"] 4184 T, = A.__type_params__ 4185 self.assertIsInstance(T, TypeVar) 4186 self.assertEqual(T.__name__, 'T') 4187 self.assertEqual(A.__bases__, (Generic, dict)) 4188 self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T])) 4189 self.assertEqual(A.__mro__, (A, Generic, dict, object)) 4190 self.assertEqual(A.__parameters__, (T,)) 4191 self.assertEqual(A[str].__parameters__, ()) 4192 self.assertEqual(A[str].__args__, (str,)) 4193 4194 def test_generic_inheritance(self): 4195 class A(TypedDict, Generic[T]): 4196 a: T 4197 4198 self.assertEqual(A.__bases__, (Generic, dict)) 4199 self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T])) 4200 self.assertEqual(A.__mro__, (A, Generic, dict, object)) 4201 self.assertEqual(A.__parameters__, (T,)) 4202 self.assertEqual(A[str].__parameters__, ()) 4203 self.assertEqual(A[str].__args__, (str,)) 4204 4205 class A2(Generic[T], TypedDict): 4206 a: T 4207 4208 self.assertEqual(A2.__bases__, (Generic, dict)) 4209 self.assertEqual(A2.__orig_bases__, (Generic[T], TypedDict)) 4210 self.assertEqual(A2.__mro__, (A2, Generic, dict, object)) 4211 self.assertEqual(A2.__parameters__, (T,)) 4212 self.assertEqual(A2[str].__parameters__, ()) 4213 self.assertEqual(A2[str].__args__, (str,)) 4214 4215 class B(A[KT], total=False): 4216 b: KT 4217 4218 self.assertEqual(B.__bases__, (Generic, dict)) 4219 self.assertEqual(B.__orig_bases__, (A[KT],)) 4220 self.assertEqual(B.__mro__, (B, Generic, dict, object)) 4221 self.assertEqual(B.__parameters__, (KT,)) 4222 self.assertEqual(B.__total__, False) 4223 self.assertEqual(B.__optional_keys__, frozenset(['b'])) 4224 self.assertEqual(B.__required_keys__, frozenset(['a'])) 4225 4226 self.assertEqual(B[str].__parameters__, ()) 4227 self.assertEqual(B[str].__args__, (str,)) 4228 self.assertEqual(B[str].__origin__, B) 4229 4230 class C(B[int]): 4231 c: int 4232 4233 self.assertEqual(C.__bases__, (Generic, dict)) 4234 self.assertEqual(C.__orig_bases__, (B[int],)) 4235 self.assertEqual(C.__mro__, (C, Generic, dict, object)) 4236 self.assertEqual(C.__parameters__, ()) 4237 self.assertEqual(C.__total__, True) 4238 self.assertEqual(C.__optional_keys__, frozenset(['b'])) 4239 self.assertEqual(C.__required_keys__, frozenset(['a', 'c'])) 4240 assert C.__annotations__ == { 4241 'a': T, 4242 'b': KT, 4243 'c': int, 4244 } 4245 with self.assertRaises(TypeError): 4246 C[str] 4247 4248 class Point3D(Point2DGeneric[T], Generic[T, KT]): 4249 c: KT 4250 4251 self.assertEqual(Point3D.__bases__, (Generic, dict)) 4252 self.assertEqual(Point3D.__orig_bases__, (Point2DGeneric[T], Generic[T, KT])) 4253 self.assertEqual(Point3D.__mro__, (Point3D, Generic, dict, object)) 4254 self.assertEqual(Point3D.__parameters__, (T, KT)) 4255 self.assertEqual(Point3D.__total__, True) 4256 self.assertEqual(Point3D.__optional_keys__, frozenset()) 4257 self.assertEqual(Point3D.__required_keys__, frozenset(['a', 'b', 'c'])) 4258 self.assertEqual(Point3D.__annotations__, { 4259 'a': T, 4260 'b': T, 4261 'c': KT, 4262 }) 4263 self.assertEqual(Point3D[int, str].__origin__, Point3D) 4264 4265 with self.assertRaises(TypeError): 4266 Point3D[int] 4267 4268 with self.assertRaises(TypeError): 4269 class Point3D(Point2DGeneric[T], Generic[KT]): 4270 c: KT 4271 4272 def test_implicit_any_inheritance(self): 4273 class A(TypedDict, Generic[T]): 4274 a: T 4275 4276 class B(A[KT], total=False): 4277 b: KT 4278 4279 class WithImplicitAny(B): 4280 c: int 4281 4282 self.assertEqual(WithImplicitAny.__bases__, (Generic, dict,)) 4283 self.assertEqual(WithImplicitAny.__mro__, (WithImplicitAny, Generic, dict, object)) 4284 # Consistent with GenericTests.test_implicit_any 4285 self.assertEqual(WithImplicitAny.__parameters__, ()) 4286 self.assertEqual(WithImplicitAny.__total__, True) 4287 self.assertEqual(WithImplicitAny.__optional_keys__, frozenset(['b'])) 4288 self.assertEqual(WithImplicitAny.__required_keys__, frozenset(['a', 'c'])) 4289 assert WithImplicitAny.__annotations__ == { 4290 'a': T, 4291 'b': KT, 4292 'c': int, 4293 } 4294 with self.assertRaises(TypeError): 4295 WithImplicitAny[str] 4296 4297 @skipUnless(TYPING_3_9_0, "Was changed in 3.9") 4298 def test_non_generic_subscript(self): 4299 # For backward compatibility, subscription works 4300 # on arbitrary TypedDict types. 4301 # (But we don't attempt to backport this misfeature onto 3.8.) 4302 class TD(TypedDict): 4303 a: T 4304 A = TD[int] 4305 self.assertEqual(A.__origin__, TD) 4306 self.assertEqual(A.__parameters__, ()) 4307 self.assertEqual(A.__args__, (int,)) 4308 a = A(a=1) 4309 self.assertIs(type(a), dict) 4310 self.assertEqual(a, {'a': 1}) 4311 4312 def test_orig_bases(self): 4313 T = TypeVar('T') 4314 4315 class Parent(TypedDict): 4316 pass 4317 4318 class Child(Parent): 4319 pass 4320 4321 class OtherChild(Parent): 4322 pass 4323 4324 class MixedChild(Child, OtherChild, Parent): 4325 pass 4326 4327 class GenericParent(TypedDict, Generic[T]): 4328 pass 4329 4330 class GenericChild(GenericParent[int]): 4331 pass 4332 4333 class OtherGenericChild(GenericParent[str]): 4334 pass 4335 4336 class MixedGenericChild(GenericChild, OtherGenericChild, GenericParent[float]): 4337 pass 4338 4339 class MultipleGenericBases(GenericParent[int], GenericParent[float]): 4340 pass 4341 4342 CallTypedDict = TypedDict('CallTypedDict', {}) 4343 4344 self.assertEqual(Parent.__orig_bases__, (TypedDict,)) 4345 self.assertEqual(Child.__orig_bases__, (Parent,)) 4346 self.assertEqual(OtherChild.__orig_bases__, (Parent,)) 4347 self.assertEqual(MixedChild.__orig_bases__, (Child, OtherChild, Parent,)) 4348 self.assertEqual(GenericParent.__orig_bases__, (TypedDict, Generic[T])) 4349 self.assertEqual(GenericChild.__orig_bases__, (GenericParent[int],)) 4350 self.assertEqual(OtherGenericChild.__orig_bases__, (GenericParent[str],)) 4351 self.assertEqual(MixedGenericChild.__orig_bases__, (GenericChild, OtherGenericChild, GenericParent[float])) 4352 self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float])) 4353 self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,)) 4354 4355 def test_zero_fields_typeddicts(self): 4356 T1 = TypedDict("T1", {}) 4357 class T2(TypedDict): pass 4358 try: 4359 ns = {"TypedDict": TypedDict} 4360 exec("class T3[tvar](TypedDict): pass", ns) 4361 T3 = ns["T3"] 4362 except SyntaxError: 4363 class T3(TypedDict): pass 4364 S = TypeVar("S") 4365 class T4(TypedDict, Generic[S]): pass 4366 4367 expected_warning = re.escape( 4368 "Failing to pass a value for the 'fields' parameter is deprecated " 4369 "and will be disallowed in Python 3.15. " 4370 "To create a TypedDict class with 0 fields " 4371 "using the functional syntax, " 4372 "pass an empty dictionary, e.g. `T5 = TypedDict('T5', {})`." 4373 ) 4374 with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): 4375 T5 = TypedDict('T5') 4376 4377 expected_warning = re.escape( 4378 "Passing `None` as the 'fields' parameter is deprecated " 4379 "and will be disallowed in Python 3.15. " 4380 "To create a TypedDict class with 0 fields " 4381 "using the functional syntax, " 4382 "pass an empty dictionary, e.g. `T6 = TypedDict('T6', {})`." 4383 ) 4384 with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): 4385 T6 = TypedDict('T6', None) 4386 4387 for klass in T1, T2, T3, T4, T5, T6: 4388 with self.subTest(klass=klass.__name__): 4389 self.assertEqual(klass.__annotations__, {}) 4390 self.assertEqual(klass.__required_keys__, set()) 4391 self.assertEqual(klass.__optional_keys__, set()) 4392 self.assertIsInstance(klass(), dict) 4393 4394 def test_readonly_inheritance(self): 4395 class Base1(TypedDict): 4396 a: ReadOnly[int] 4397 4398 class Child1(Base1): 4399 b: str 4400 4401 self.assertEqual(Child1.__readonly_keys__, frozenset({'a'})) 4402 self.assertEqual(Child1.__mutable_keys__, frozenset({'b'})) 4403 4404 class Base2(TypedDict): 4405 a: ReadOnly[int] 4406 4407 class Child2(Base2): 4408 b: str 4409 4410 self.assertEqual(Child1.__readonly_keys__, frozenset({'a'})) 4411 self.assertEqual(Child1.__mutable_keys__, frozenset({'b'})) 4412 4413 def test_make_mutable_key_readonly(self): 4414 class Base(TypedDict): 4415 a: int 4416 4417 self.assertEqual(Base.__readonly_keys__, frozenset()) 4418 self.assertEqual(Base.__mutable_keys__, frozenset({'a'})) 4419 4420 class Child(Base): 4421 a: ReadOnly[int] # type checker error, but allowed at runtime 4422 4423 self.assertEqual(Child.__readonly_keys__, frozenset({'a'})) 4424 self.assertEqual(Child.__mutable_keys__, frozenset()) 4425 4426 def test_can_make_readonly_key_mutable(self): 4427 class Base(TypedDict): 4428 a: ReadOnly[int] 4429 4430 class Child(Base): 4431 a: int 4432 4433 self.assertEqual(Child.__readonly_keys__, frozenset()) 4434 self.assertEqual(Child.__mutable_keys__, frozenset({'a'})) 4435 4436 def test_combine_qualifiers(self): 4437 class AllTheThings(TypedDict): 4438 a: Annotated[Required[ReadOnly[int]], "why not"] 4439 b: Required[Annotated[ReadOnly[int], "why not"]] 4440 c: ReadOnly[NotRequired[Annotated[int, "why not"]]] 4441 d: NotRequired[Annotated[int, "why not"]] 4442 4443 self.assertEqual(AllTheThings.__required_keys__, frozenset({'a', 'b'})) 4444 self.assertEqual(AllTheThings.__optional_keys__, frozenset({'c', 'd'})) 4445 self.assertEqual(AllTheThings.__readonly_keys__, frozenset({'a', 'b', 'c'})) 4446 self.assertEqual(AllTheThings.__mutable_keys__, frozenset({'d'})) 4447 4448 self.assertEqual( 4449 get_type_hints(AllTheThings, include_extras=False), 4450 {'a': int, 'b': int, 'c': int, 'd': int}, 4451 ) 4452 self.assertEqual( 4453 get_type_hints(AllTheThings, include_extras=True), 4454 { 4455 'a': Annotated[Required[ReadOnly[int]], 'why not'], 4456 'b': Required[Annotated[ReadOnly[int], 'why not']], 4457 'c': ReadOnly[NotRequired[Annotated[int, 'why not']]], 4458 'd': NotRequired[Annotated[int, 'why not']], 4459 }, 4460 ) 4461 4462 def test_extra_keys_non_readonly(self): 4463 class Base(TypedDict, closed=True): 4464 __extra_items__: str 4465 4466 class Child(Base): 4467 a: NotRequired[int] 4468 4469 self.assertEqual(Child.__required_keys__, frozenset({})) 4470 self.assertEqual(Child.__optional_keys__, frozenset({'a'})) 4471 self.assertEqual(Child.__readonly_keys__, frozenset({})) 4472 self.assertEqual(Child.__mutable_keys__, frozenset({'a'})) 4473 4474 def test_extra_keys_readonly(self): 4475 class Base(TypedDict, closed=True): 4476 __extra_items__: ReadOnly[str] 4477 4478 class Child(Base): 4479 a: NotRequired[str] 4480 4481 self.assertEqual(Child.__required_keys__, frozenset({})) 4482 self.assertEqual(Child.__optional_keys__, frozenset({'a'})) 4483 self.assertEqual(Child.__readonly_keys__, frozenset({})) 4484 self.assertEqual(Child.__mutable_keys__, frozenset({'a'})) 4485 4486 def test_extra_key_required(self): 4487 with self.assertRaisesRegex( 4488 TypeError, 4489 "Special key __extra_items__ does not support Required" 4490 ): 4491 TypedDict("A", {"__extra_items__": Required[int]}, closed=True) 4492 4493 with self.assertRaisesRegex( 4494 TypeError, 4495 "Special key __extra_items__ does not support NotRequired" 4496 ): 4497 TypedDict("A", {"__extra_items__": NotRequired[int]}, closed=True) 4498 4499 def test_regular_extra_items(self): 4500 class ExtraReadOnly(TypedDict): 4501 __extra_items__: ReadOnly[str] 4502 4503 self.assertEqual(ExtraReadOnly.__required_keys__, frozenset({'__extra_items__'})) 4504 self.assertEqual(ExtraReadOnly.__optional_keys__, frozenset({})) 4505 self.assertEqual(ExtraReadOnly.__readonly_keys__, frozenset({'__extra_items__'})) 4506 self.assertEqual(ExtraReadOnly.__mutable_keys__, frozenset({})) 4507 self.assertEqual(ExtraReadOnly.__extra_items__, None) 4508 self.assertFalse(ExtraReadOnly.__closed__) 4509 4510 class ExtraRequired(TypedDict): 4511 __extra_items__: Required[str] 4512 4513 self.assertEqual(ExtraRequired.__required_keys__, frozenset({'__extra_items__'})) 4514 self.assertEqual(ExtraRequired.__optional_keys__, frozenset({})) 4515 self.assertEqual(ExtraRequired.__readonly_keys__, frozenset({})) 4516 self.assertEqual(ExtraRequired.__mutable_keys__, frozenset({'__extra_items__'})) 4517 self.assertEqual(ExtraRequired.__extra_items__, None) 4518 self.assertFalse(ExtraRequired.__closed__) 4519 4520 class ExtraNotRequired(TypedDict): 4521 __extra_items__: NotRequired[str] 4522 4523 self.assertEqual(ExtraNotRequired.__required_keys__, frozenset({})) 4524 self.assertEqual(ExtraNotRequired.__optional_keys__, frozenset({'__extra_items__'})) 4525 self.assertEqual(ExtraNotRequired.__readonly_keys__, frozenset({})) 4526 self.assertEqual(ExtraNotRequired.__mutable_keys__, frozenset({'__extra_items__'})) 4527 self.assertEqual(ExtraNotRequired.__extra_items__, None) 4528 self.assertFalse(ExtraNotRequired.__closed__) 4529 4530 def test_closed_inheritance(self): 4531 class Base(TypedDict, closed=True): 4532 __extra_items__: ReadOnly[Union[str, None]] 4533 4534 self.assertEqual(Base.__required_keys__, frozenset({})) 4535 self.assertEqual(Base.__optional_keys__, frozenset({})) 4536 self.assertEqual(Base.__readonly_keys__, frozenset({})) 4537 self.assertEqual(Base.__mutable_keys__, frozenset({})) 4538 self.assertEqual(Base.__annotations__, {}) 4539 self.assertEqual(Base.__extra_items__, ReadOnly[Union[str, None]]) 4540 self.assertTrue(Base.__closed__) 4541 4542 class Child(Base): 4543 a: int 4544 __extra_items__: int 4545 4546 self.assertEqual(Child.__required_keys__, frozenset({'a', "__extra_items__"})) 4547 self.assertEqual(Child.__optional_keys__, frozenset({})) 4548 self.assertEqual(Child.__readonly_keys__, frozenset({})) 4549 self.assertEqual(Child.__mutable_keys__, frozenset({'a', "__extra_items__"})) 4550 self.assertEqual(Child.__annotations__, {"__extra_items__": int, "a": int}) 4551 self.assertEqual(Child.__extra_items__, ReadOnly[Union[str, None]]) 4552 self.assertFalse(Child.__closed__) 4553 4554 class GrandChild(Child, closed=True): 4555 __extra_items__: str 4556 4557 self.assertEqual(GrandChild.__required_keys__, frozenset({'a', "__extra_items__"})) 4558 self.assertEqual(GrandChild.__optional_keys__, frozenset({})) 4559 self.assertEqual(GrandChild.__readonly_keys__, frozenset({})) 4560 self.assertEqual(GrandChild.__mutable_keys__, frozenset({'a', "__extra_items__"})) 4561 self.assertEqual(GrandChild.__annotations__, {"__extra_items__": int, "a": int}) 4562 self.assertEqual(GrandChild.__extra_items__, str) 4563 self.assertTrue(GrandChild.__closed__) 4564 4565 def test_implicit_extra_items(self): 4566 class Base(TypedDict): 4567 a: int 4568 4569 self.assertEqual(Base.__extra_items__, None) 4570 self.assertFalse(Base.__closed__) 4571 4572 class ChildA(Base, closed=True): 4573 ... 4574 4575 self.assertEqual(ChildA.__extra_items__, Never) 4576 self.assertTrue(ChildA.__closed__) 4577 4578 class ChildB(Base, closed=True): 4579 __extra_items__: None 4580 4581 self.assertEqual(ChildB.__extra_items__, type(None)) 4582 self.assertTrue(ChildB.__closed__) 4583 4584 @skipIf( 4585 TYPING_3_13_0, 4586 "The keyword argument alternative to define a " 4587 "TypedDict type using the functional syntax is no longer supported" 4588 ) 4589 def test_backwards_compatibility(self): 4590 with self.assertWarns(DeprecationWarning): 4591 TD = TypedDict("TD", closed=int) 4592 self.assertFalse(TD.__closed__) 4593 self.assertEqual(TD.__annotations__, {"closed": int}) 4594 4595 4596class AnnotatedTests(BaseTestCase): 4597 4598 def test_repr(self): 4599 if hasattr(typing, 'Annotated'): 4600 mod_name = 'typing' 4601 else: 4602 mod_name = "typing_extensions" 4603 self.assertEqual( 4604 repr(Annotated[int, 4, 5]), 4605 mod_name + ".Annotated[int, 4, 5]" 4606 ) 4607 self.assertEqual( 4608 repr(Annotated[List[int], 4, 5]), 4609 mod_name + ".Annotated[typing.List[int], 4, 5]" 4610 ) 4611 4612 def test_flatten(self): 4613 A = Annotated[Annotated[int, 4], 5] 4614 self.assertEqual(A, Annotated[int, 4, 5]) 4615 self.assertEqual(A.__metadata__, (4, 5)) 4616 self.assertEqual(A.__origin__, int) 4617 4618 def test_specialize(self): 4619 L = Annotated[List[T], "my decoration"] 4620 LI = Annotated[List[int], "my decoration"] 4621 self.assertEqual(L[int], Annotated[List[int], "my decoration"]) 4622 self.assertEqual(L[int].__metadata__, ("my decoration",)) 4623 self.assertEqual(L[int].__origin__, List[int]) 4624 with self.assertRaises(TypeError): 4625 LI[int] 4626 with self.assertRaises(TypeError): 4627 L[int, float] 4628 4629 def test_hash_eq(self): 4630 self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) 4631 self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) 4632 self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) 4633 self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) 4634 self.assertEqual( 4635 {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, 4636 {Annotated[int, 4, 5], Annotated[T, 4, 5]} 4637 ) 4638 4639 def test_instantiate(self): 4640 class C: 4641 classvar = 4 4642 4643 def __init__(self, x): 4644 self.x = x 4645 4646 def __eq__(self, other): 4647 if not isinstance(other, C): 4648 return NotImplemented 4649 return other.x == self.x 4650 4651 A = Annotated[C, "a decoration"] 4652 a = A(5) 4653 c = C(5) 4654 self.assertEqual(a, c) 4655 self.assertEqual(a.x, c.x) 4656 self.assertEqual(a.classvar, c.classvar) 4657 4658 def test_instantiate_generic(self): 4659 MyCount = Annotated[typing_extensions.Counter[T], "my decoration"] 4660 self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1}) 4661 self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1}) 4662 4663 def test_cannot_instantiate_forward(self): 4664 A = Annotated["int", (5, 6)] 4665 with self.assertRaises(TypeError): 4666 A(5) 4667 4668 def test_cannot_instantiate_type_var(self): 4669 A = Annotated[T, (5, 6)] 4670 with self.assertRaises(TypeError): 4671 A(5) 4672 4673 def test_cannot_getattr_typevar(self): 4674 with self.assertRaises(AttributeError): 4675 Annotated[T, (5, 7)].x 4676 4677 def test_attr_passthrough(self): 4678 class C: 4679 classvar = 4 4680 4681 A = Annotated[C, "a decoration"] 4682 self.assertEqual(A.classvar, 4) 4683 A.x = 5 4684 self.assertEqual(C.x, 5) 4685 4686 @skipIf(sys.version_info[:2] in ((3, 9), (3, 10)), "Waiting for bpo-46491 bugfix.") 4687 def test_special_form_containment(self): 4688 class C: 4689 classvar: Annotated[ClassVar[int], "a decoration"] = 4 4690 const: Annotated[Final[int], "Const"] = 4 4691 4692 self.assertEqual(get_type_hints(C, globals())["classvar"], ClassVar[int]) 4693 self.assertEqual(get_type_hints(C, globals())["const"], Final[int]) 4694 4695 def test_cannot_subclass(self): 4696 with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): 4697 class C(Annotated): 4698 pass 4699 4700 def test_cannot_check_instance(self): 4701 with self.assertRaises(TypeError): 4702 isinstance(5, Annotated[int, "positive"]) 4703 4704 def test_cannot_check_subclass(self): 4705 with self.assertRaises(TypeError): 4706 issubclass(int, Annotated[int, "positive"]) 4707 4708 def test_pickle(self): 4709 samples = [typing.Any, typing.Union[int, str], 4710 typing.Optional[str], Tuple[int, ...], 4711 typing.Callable[[str], bytes], 4712 Self, LiteralString, Never] 4713 4714 for t in samples: 4715 x = Annotated[t, "a"] 4716 4717 for prot in range(pickle.HIGHEST_PROTOCOL + 1): 4718 with self.subTest(protocol=prot, type=t): 4719 pickled = pickle.dumps(x, prot) 4720 restored = pickle.loads(pickled) 4721 self.assertEqual(x, restored) 4722 4723 global _Annotated_test_G 4724 4725 class _Annotated_test_G(Generic[T]): 4726 x = 1 4727 4728 G = Annotated[_Annotated_test_G[int], "A decoration"] 4729 G.foo = 42 4730 G.bar = 'abc' 4731 4732 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 4733 z = pickle.dumps(G, proto) 4734 x = pickle.loads(z) 4735 self.assertEqual(x.foo, 42) 4736 self.assertEqual(x.bar, 'abc') 4737 self.assertEqual(x.x, 1) 4738 4739 def test_subst(self): 4740 dec = "a decoration" 4741 dec2 = "another decoration" 4742 4743 S = Annotated[T, dec2] 4744 self.assertEqual(S[int], Annotated[int, dec2]) 4745 4746 self.assertEqual(S[Annotated[int, dec]], Annotated[int, dec, dec2]) 4747 L = Annotated[List[T], dec] 4748 4749 self.assertEqual(L[int], Annotated[List[int], dec]) 4750 with self.assertRaises(TypeError): 4751 L[int, int] 4752 4753 self.assertEqual(S[L[int]], Annotated[List[int], dec, dec2]) 4754 4755 D = Annotated[Dict[KT, VT], dec] 4756 self.assertEqual(D[str, int], Annotated[Dict[str, int], dec]) 4757 with self.assertRaises(TypeError): 4758 D[int] 4759 4760 It = Annotated[int, dec] 4761 with self.assertRaises(TypeError): 4762 It[None] 4763 4764 LI = L[int] 4765 with self.assertRaises(TypeError): 4766 LI[None] 4767 4768 def test_annotated_in_other_types(self): 4769 X = List[Annotated[T, 5]] 4770 self.assertEqual(X[int], List[Annotated[int, 5]]) 4771 4772 def test_nested_annotated_with_unhashable_metadata(self): 4773 X = Annotated[ 4774 List[Annotated[str, {"unhashable_metadata"}]], 4775 "metadata" 4776 ] 4777 self.assertEqual(X.__origin__, List[Annotated[str, {"unhashable_metadata"}]]) 4778 self.assertEqual(X.__metadata__, ("metadata",)) 4779 4780 4781class GetTypeHintsTests(BaseTestCase): 4782 def test_get_type_hints(self): 4783 def foobar(x: List['X']): ... 4784 X = Annotated[int, (1, 10)] 4785 self.assertEqual( 4786 get_type_hints(foobar, globals(), locals()), 4787 {'x': List[int]} 4788 ) 4789 self.assertEqual( 4790 get_type_hints(foobar, globals(), locals(), include_extras=True), 4791 {'x': List[Annotated[int, (1, 10)]]} 4792 ) 4793 BA = Tuple[Annotated[T, (1, 0)], ...] 4794 def barfoo(x: BA): ... 4795 self.assertEqual(get_type_hints(barfoo, globals(), locals())['x'], Tuple[T, ...]) 4796 self.assertIs( 4797 get_type_hints(barfoo, globals(), locals(), include_extras=True)['x'], 4798 BA 4799 ) 4800 def barfoo2(x: typing.Callable[..., Annotated[List[T], "const"]], 4801 y: typing.Union[int, Annotated[T, "mutable"]]): ... 4802 self.assertEqual( 4803 get_type_hints(barfoo2, globals(), locals()), 4804 {'x': typing.Callable[..., List[T]], 'y': typing.Union[int, T]} 4805 ) 4806 BA2 = typing.Callable[..., List[T]] 4807 def barfoo3(x: BA2): ... 4808 self.assertIs( 4809 get_type_hints(barfoo3, globals(), locals(), include_extras=True)["x"], 4810 BA2 4811 ) 4812 4813 def test_get_type_hints_refs(self): 4814 4815 Const = Annotated[T, "Const"] 4816 4817 class MySet(Generic[T]): 4818 4819 def __ior__(self, other: "Const[MySet[T]]") -> "MySet[T]": 4820 ... 4821 4822 def __iand__(self, other: Const["MySet[T]"]) -> "MySet[T]": 4823 ... 4824 4825 self.assertEqual( 4826 get_type_hints(MySet.__iand__, globals(), locals()), 4827 {'other': MySet[T], 'return': MySet[T]} 4828 ) 4829 4830 self.assertEqual( 4831 get_type_hints(MySet.__iand__, globals(), locals(), include_extras=True), 4832 {'other': Const[MySet[T]], 'return': MySet[T]} 4833 ) 4834 4835 self.assertEqual( 4836 get_type_hints(MySet.__ior__, globals(), locals()), 4837 {'other': MySet[T], 'return': MySet[T]} 4838 ) 4839 4840 def test_get_type_hints_typeddict(self): 4841 assert get_type_hints(TotalMovie) == {'title': str, 'year': int} 4842 assert get_type_hints(TotalMovie, include_extras=True) == { 4843 'title': str, 4844 'year': NotRequired[int], 4845 } 4846 4847 assert get_type_hints(AnnotatedMovie) == {'title': str, 'year': int} 4848 assert get_type_hints(AnnotatedMovie, include_extras=True) == { 4849 'title': Annotated[Required[str], "foobar"], 4850 'year': NotRequired[Annotated[int, 2000]], 4851 } 4852 4853 def test_orig_bases(self): 4854 T = TypeVar('T') 4855 4856 class Parent(TypedDict): 4857 pass 4858 4859 class Child(Parent): 4860 pass 4861 4862 class OtherChild(Parent): 4863 pass 4864 4865 class MixedChild(Child, OtherChild, Parent): 4866 pass 4867 4868 class GenericParent(TypedDict, Generic[T]): 4869 pass 4870 4871 class GenericChild(GenericParent[int]): 4872 pass 4873 4874 class OtherGenericChild(GenericParent[str]): 4875 pass 4876 4877 class MixedGenericChild(GenericChild, OtherGenericChild, GenericParent[float]): 4878 pass 4879 4880 class MultipleGenericBases(GenericParent[int], GenericParent[float]): 4881 pass 4882 4883 CallTypedDict = TypedDict('CallTypedDict', {}) 4884 4885 self.assertEqual(Parent.__orig_bases__, (TypedDict,)) 4886 self.assertEqual(Child.__orig_bases__, (Parent,)) 4887 self.assertEqual(OtherChild.__orig_bases__, (Parent,)) 4888 self.assertEqual(MixedChild.__orig_bases__, (Child, OtherChild, Parent,)) 4889 self.assertEqual(GenericParent.__orig_bases__, (TypedDict, Generic[T])) 4890 self.assertEqual(GenericChild.__orig_bases__, (GenericParent[int],)) 4891 self.assertEqual(OtherGenericChild.__orig_bases__, (GenericParent[str],)) 4892 self.assertEqual(MixedGenericChild.__orig_bases__, (GenericChild, OtherGenericChild, GenericParent[float])) 4893 self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float])) 4894 self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,)) 4895 4896 4897class TypeAliasTests(BaseTestCase): 4898 def test_canonical_usage_with_variable_annotation(self): 4899 ns = {} 4900 exec('Alias: TypeAlias = Employee', globals(), ns) 4901 4902 def test_canonical_usage_with_type_comment(self): 4903 Alias: TypeAlias = Employee # noqa: F841 4904 4905 def test_cannot_instantiate(self): 4906 with self.assertRaises(TypeError): 4907 TypeAlias() 4908 4909 def test_no_isinstance(self): 4910 with self.assertRaises(TypeError): 4911 isinstance(42, TypeAlias) 4912 4913 def test_no_issubclass(self): 4914 with self.assertRaises(TypeError): 4915 issubclass(Employee, TypeAlias) 4916 4917 with self.assertRaises(TypeError): 4918 issubclass(TypeAlias, Employee) 4919 4920 def test_cannot_subclass(self): 4921 with self.assertRaises(TypeError): 4922 class C(TypeAlias): 4923 pass 4924 4925 with self.assertRaises(TypeError): 4926 class D(type(TypeAlias)): 4927 pass 4928 4929 def test_repr(self): 4930 if hasattr(typing, 'TypeAlias'): 4931 self.assertEqual(repr(TypeAlias), 'typing.TypeAlias') 4932 else: 4933 self.assertEqual(repr(TypeAlias), 'typing_extensions.TypeAlias') 4934 4935 def test_cannot_subscript(self): 4936 with self.assertRaises(TypeError): 4937 TypeAlias[int] 4938 4939class ParamSpecTests(BaseTestCase): 4940 4941 def test_basic_plain(self): 4942 P = ParamSpec('P') 4943 self.assertEqual(P, P) 4944 self.assertIsInstance(P, ParamSpec) 4945 self.assertEqual(P.__name__, 'P') 4946 # Should be hashable 4947 hash(P) 4948 4949 def test_repr(self): 4950 P = ParamSpec('P') 4951 P_co = ParamSpec('P_co', covariant=True) 4952 P_contra = ParamSpec('P_contra', contravariant=True) 4953 P_infer = ParamSpec('P_infer', infer_variance=True) 4954 P_2 = ParamSpec('P_2') 4955 self.assertEqual(repr(P), '~P') 4956 self.assertEqual(repr(P_2), '~P_2') 4957 4958 # Note: PEP 612 doesn't require these to be repr-ed correctly, but 4959 # just follow CPython. 4960 self.assertEqual(repr(P_co), '+P_co') 4961 self.assertEqual(repr(P_contra), '-P_contra') 4962 # On other versions we use typing.ParamSpec, but it is not aware of 4963 # infer_variance=. Not worth creating our own version of ParamSpec 4964 # for this. 4965 if hasattr(typing, 'TypeAliasType') or not hasattr(typing, 'ParamSpec'): 4966 self.assertEqual(repr(P_infer), 'P_infer') 4967 else: 4968 self.assertEqual(repr(P_infer), '~P_infer') 4969 4970 def test_variance(self): 4971 P_co = ParamSpec('P_co', covariant=True) 4972 P_contra = ParamSpec('P_contra', contravariant=True) 4973 P_infer = ParamSpec('P_infer', infer_variance=True) 4974 4975 self.assertIs(P_co.__covariant__, True) 4976 self.assertIs(P_co.__contravariant__, False) 4977 self.assertIs(P_co.__infer_variance__, False) 4978 4979 self.assertIs(P_contra.__covariant__, False) 4980 self.assertIs(P_contra.__contravariant__, True) 4981 self.assertIs(P_contra.__infer_variance__, False) 4982 4983 self.assertIs(P_infer.__covariant__, False) 4984 self.assertIs(P_infer.__contravariant__, False) 4985 self.assertIs(P_infer.__infer_variance__, True) 4986 4987 def test_valid_uses(self): 4988 P = ParamSpec('P') 4989 T = TypeVar('T') 4990 C1 = typing.Callable[P, int] 4991 self.assertEqual(C1.__args__, (P, int)) 4992 self.assertEqual(C1.__parameters__, (P,)) 4993 C2 = typing.Callable[P, T] 4994 self.assertEqual(C2.__args__, (P, T)) 4995 self.assertEqual(C2.__parameters__, (P, T)) 4996 4997 # Test collections.abc.Callable too. 4998 if sys.version_info[:2] >= (3, 9): 4999 # Note: no tests for Callable.__parameters__ here 5000 # because types.GenericAlias Callable is hardcoded to search 5001 # for tp_name "TypeVar" in C. This was changed in 3.10. 5002 C3 = collections.abc.Callable[P, int] 5003 self.assertEqual(C3.__args__, (P, int)) 5004 C4 = collections.abc.Callable[P, T] 5005 self.assertEqual(C4.__args__, (P, T)) 5006 5007 # ParamSpec instances should also have args and kwargs attributes. 5008 # Note: not in dir(P) because of __class__ hacks 5009 self.assertTrue(hasattr(P, 'args')) 5010 self.assertTrue(hasattr(P, 'kwargs')) 5011 5012 @skipIf((3, 10, 0) <= sys.version_info[:3] <= (3, 10, 2), "Needs bpo-46676.") 5013 def test_args_kwargs(self): 5014 P = ParamSpec('P') 5015 P_2 = ParamSpec('P_2') 5016 # Note: not in dir(P) because of __class__ hacks 5017 self.assertTrue(hasattr(P, 'args')) 5018 self.assertTrue(hasattr(P, 'kwargs')) 5019 self.assertIsInstance(P.args, ParamSpecArgs) 5020 self.assertIsInstance(P.kwargs, ParamSpecKwargs) 5021 self.assertIs(P.args.__origin__, P) 5022 self.assertIs(P.kwargs.__origin__, P) 5023 self.assertEqual(P.args, P.args) 5024 self.assertEqual(P.kwargs, P.kwargs) 5025 self.assertNotEqual(P.args, P_2.args) 5026 self.assertNotEqual(P.kwargs, P_2.kwargs) 5027 self.assertNotEqual(P.args, P.kwargs) 5028 self.assertNotEqual(P.kwargs, P.args) 5029 self.assertNotEqual(P.args, P_2.kwargs) 5030 self.assertEqual(repr(P.args), "P.args") 5031 self.assertEqual(repr(P.kwargs), "P.kwargs") 5032 5033 def test_user_generics(self): 5034 T = TypeVar("T") 5035 P = ParamSpec("P") 5036 P_2 = ParamSpec("P_2") 5037 5038 class X(Generic[T, P]): 5039 pass 5040 5041 class Y(Protocol[T, P]): 5042 pass 5043 5044 for klass in X, Y: 5045 with self.subTest(klass=klass.__name__): 5046 G1 = klass[int, P_2] 5047 self.assertEqual(G1.__args__, (int, P_2)) 5048 self.assertEqual(G1.__parameters__, (P_2,)) 5049 5050 G2 = klass[int, Concatenate[int, P_2]] 5051 self.assertEqual(G2.__args__, (int, Concatenate[int, P_2])) 5052 self.assertEqual(G2.__parameters__, (P_2,)) 5053 5054 # The following are some valid uses cases in PEP 612 that don't work: 5055 # These do not work in 3.9, _type_check blocks the list and ellipsis. 5056 # G3 = X[int, [int, bool]] 5057 # G4 = X[int, ...] 5058 # G5 = Z[[int, str, bool]] 5059 # Not working because this is special-cased in 3.10. 5060 # G6 = Z[int, str, bool] 5061 5062 class Z(Generic[P]): 5063 pass 5064 5065 class ProtoZ(Protocol[P]): 5066 pass 5067 5068 def test_pickle(self): 5069 global P, P_co, P_contra, P_default 5070 P = ParamSpec('P') 5071 P_co = ParamSpec('P_co', covariant=True) 5072 P_contra = ParamSpec('P_contra', contravariant=True) 5073 P_default = ParamSpec('P_default', default=[int]) 5074 for proto in range(pickle.HIGHEST_PROTOCOL): 5075 with self.subTest(f'Pickle protocol {proto}'): 5076 for paramspec in (P, P_co, P_contra, P_default): 5077 z = pickle.loads(pickle.dumps(paramspec, proto)) 5078 self.assertEqual(z.__name__, paramspec.__name__) 5079 self.assertEqual(z.__covariant__, paramspec.__covariant__) 5080 self.assertEqual(z.__contravariant__, paramspec.__contravariant__) 5081 self.assertEqual(z.__bound__, paramspec.__bound__) 5082 self.assertEqual(z.__default__, paramspec.__default__) 5083 5084 def test_eq(self): 5085 P = ParamSpec('P') 5086 self.assertEqual(P, P) 5087 self.assertEqual(hash(P), hash(P)) 5088 # ParamSpec should compare by id similar to TypeVar in CPython 5089 self.assertNotEqual(ParamSpec('P'), P) 5090 self.assertIsNot(ParamSpec('P'), P) 5091 # Note: normally you don't test this as it breaks when there's 5092 # a hash collision. However, ParamSpec *must* guarantee that 5093 # as long as two objects don't have the same ID, their hashes 5094 # won't be the same. 5095 self.assertNotEqual(hash(ParamSpec('P')), hash(P)) 5096 5097 def test_isinstance_results_unaffected_by_presence_of_tracing_function(self): 5098 # See https://github.com/python/typing_extensions/issues/318 5099 5100 code = textwrap.dedent( 5101 """\ 5102 import sys, typing 5103 5104 def trace_call(*args): 5105 return trace_call 5106 5107 def run(): 5108 sys.modules.pop("typing_extensions", None) 5109 from typing_extensions import ParamSpec 5110 return isinstance(ParamSpec("P"), typing.TypeVar) 5111 5112 isinstance_result_1 = run() 5113 sys.setprofile(trace_call) 5114 isinstance_result_2 = run() 5115 sys.stdout.write(f"{isinstance_result_1} {isinstance_result_2}") 5116 """ 5117 ) 5118 5119 # Run this in an isolated process or it pollutes the environment 5120 # and makes other tests fail: 5121 try: 5122 proc = subprocess.run( 5123 [sys.executable, "-c", code], check=True, capture_output=True, text=True, 5124 ) 5125 except subprocess.CalledProcessError as exc: 5126 print("stdout", exc.stdout, sep="\n") 5127 print("stderr", exc.stderr, sep="\n") 5128 raise 5129 5130 # Sanity checks that assert the test is working as expected 5131 self.assertIsInstance(proc.stdout, str) 5132 result1, result2 = proc.stdout.split(" ") 5133 self.assertIn(result1, {"True", "False"}) 5134 self.assertIn(result2, {"True", "False"}) 5135 5136 # The actual test: 5137 self.assertEqual(result1, result2) 5138 5139 5140class ConcatenateTests(BaseTestCase): 5141 def test_basics(self): 5142 P = ParamSpec('P') 5143 5144 class MyClass: ... 5145 5146 c = Concatenate[MyClass, P] 5147 self.assertNotEqual(c, Concatenate) 5148 5149 def test_valid_uses(self): 5150 P = ParamSpec('P') 5151 T = TypeVar('T') 5152 5153 C1 = Callable[Concatenate[int, P], int] 5154 C2 = Callable[Concatenate[int, T, P], T] 5155 self.assertEqual(C1.__origin__, C2.__origin__) 5156 self.assertNotEqual(C1, C2) 5157 5158 # Test collections.abc.Callable too. 5159 if sys.version_info[:2] >= (3, 9): 5160 C3 = collections.abc.Callable[Concatenate[int, P], int] 5161 C4 = collections.abc.Callable[Concatenate[int, T, P], T] 5162 self.assertEqual(C3.__origin__, C4.__origin__) 5163 self.assertNotEqual(C3, C4) 5164 5165 def test_invalid_uses(self): 5166 P = ParamSpec('P') 5167 T = TypeVar('T') 5168 5169 with self.assertRaisesRegex( 5170 TypeError, 5171 'Cannot take a Concatenate of no types', 5172 ): 5173 Concatenate[()] 5174 5175 with self.assertRaisesRegex( 5176 TypeError, 5177 'The last parameter to Concatenate should be a ParamSpec variable', 5178 ): 5179 Concatenate[P, T] 5180 5181 if not TYPING_3_11_0: 5182 with self.assertRaisesRegex( 5183 TypeError, 5184 'each arg must be a type', 5185 ): 5186 Concatenate[1, P] 5187 5188 def test_basic_introspection(self): 5189 P = ParamSpec('P') 5190 C1 = Concatenate[int, P] 5191 C2 = Concatenate[int, T, P] 5192 self.assertEqual(C1.__origin__, Concatenate) 5193 self.assertEqual(C1.__args__, (int, P)) 5194 self.assertEqual(C2.__origin__, Concatenate) 5195 self.assertEqual(C2.__args__, (int, T, P)) 5196 5197 def test_eq(self): 5198 P = ParamSpec('P') 5199 C1 = Concatenate[int, P] 5200 C2 = Concatenate[int, P] 5201 C3 = Concatenate[int, T, P] 5202 self.assertEqual(C1, C2) 5203 self.assertEqual(hash(C1), hash(C2)) 5204 self.assertNotEqual(C1, C3) 5205 5206 5207class TypeGuardTests(BaseTestCase): 5208 def test_basics(self): 5209 TypeGuard[int] # OK 5210 self.assertEqual(TypeGuard[int], TypeGuard[int]) 5211 5212 def foo(arg) -> TypeGuard[int]: ... 5213 self.assertEqual(gth(foo), {'return': TypeGuard[int]}) 5214 5215 def test_repr(self): 5216 if hasattr(typing, 'TypeGuard'): 5217 mod_name = 'typing' 5218 else: 5219 mod_name = 'typing_extensions' 5220 self.assertEqual(repr(TypeGuard), f'{mod_name}.TypeGuard') 5221 cv = TypeGuard[int] 5222 self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[int]') 5223 cv = TypeGuard[Employee] 5224 self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[{__name__}.Employee]') 5225 cv = TypeGuard[Tuple[int]] 5226 self.assertEqual(repr(cv), f'{mod_name}.TypeGuard[typing.Tuple[int]]') 5227 5228 def test_cannot_subclass(self): 5229 with self.assertRaises(TypeError): 5230 class C(type(TypeGuard)): 5231 pass 5232 with self.assertRaises(TypeError): 5233 class D(type(TypeGuard[int])): 5234 pass 5235 5236 def test_cannot_init(self): 5237 with self.assertRaises(TypeError): 5238 TypeGuard() 5239 with self.assertRaises(TypeError): 5240 type(TypeGuard)() 5241 with self.assertRaises(TypeError): 5242 type(TypeGuard[Optional[int]])() 5243 5244 def test_no_isinstance(self): 5245 with self.assertRaises(TypeError): 5246 isinstance(1, TypeGuard[int]) 5247 with self.assertRaises(TypeError): 5248 issubclass(int, TypeGuard) 5249 5250 5251class TypeIsTests(BaseTestCase): 5252 def test_basics(self): 5253 TypeIs[int] # OK 5254 self.assertEqual(TypeIs[int], TypeIs[int]) 5255 5256 def foo(arg) -> TypeIs[int]: ... 5257 self.assertEqual(gth(foo), {'return': TypeIs[int]}) 5258 5259 def test_repr(self): 5260 if hasattr(typing, 'TypeIs'): 5261 mod_name = 'typing' 5262 else: 5263 mod_name = 'typing_extensions' 5264 self.assertEqual(repr(TypeIs), f'{mod_name}.TypeIs') 5265 cv = TypeIs[int] 5266 self.assertEqual(repr(cv), f'{mod_name}.TypeIs[int]') 5267 cv = TypeIs[Employee] 5268 self.assertEqual(repr(cv), f'{mod_name}.TypeIs[{__name__}.Employee]') 5269 cv = TypeIs[Tuple[int]] 5270 self.assertEqual(repr(cv), f'{mod_name}.TypeIs[typing.Tuple[int]]') 5271 5272 def test_cannot_subclass(self): 5273 with self.assertRaises(TypeError): 5274 class C(type(TypeIs)): 5275 pass 5276 with self.assertRaises(TypeError): 5277 class D(type(TypeIs[int])): 5278 pass 5279 5280 def test_cannot_init(self): 5281 with self.assertRaises(TypeError): 5282 TypeIs() 5283 with self.assertRaises(TypeError): 5284 type(TypeIs)() 5285 with self.assertRaises(TypeError): 5286 type(TypeIs[Optional[int]])() 5287 5288 def test_no_isinstance(self): 5289 with self.assertRaises(TypeError): 5290 isinstance(1, TypeIs[int]) 5291 with self.assertRaises(TypeError): 5292 issubclass(int, TypeIs) 5293 5294 5295class LiteralStringTests(BaseTestCase): 5296 def test_basics(self): 5297 class Foo: 5298 def bar(self) -> LiteralString: ... 5299 def baz(self) -> "LiteralString": ... 5300 5301 self.assertEqual(gth(Foo.bar), {'return': LiteralString}) 5302 self.assertEqual(gth(Foo.baz), {'return': LiteralString}) 5303 5304 def test_get_origin(self): 5305 self.assertIsNone(get_origin(LiteralString)) 5306 5307 def test_repr(self): 5308 if hasattr(typing, 'LiteralString'): 5309 mod_name = 'typing' 5310 else: 5311 mod_name = 'typing_extensions' 5312 self.assertEqual(repr(LiteralString), f'{mod_name}.LiteralString') 5313 5314 def test_cannot_subscript(self): 5315 with self.assertRaises(TypeError): 5316 LiteralString[int] 5317 5318 def test_cannot_subclass(self): 5319 with self.assertRaises(TypeError): 5320 class C(type(LiteralString)): 5321 pass 5322 with self.assertRaises(TypeError): 5323 class D(LiteralString): 5324 pass 5325 5326 def test_cannot_init(self): 5327 with self.assertRaises(TypeError): 5328 LiteralString() 5329 with self.assertRaises(TypeError): 5330 type(LiteralString)() 5331 5332 def test_no_isinstance(self): 5333 with self.assertRaises(TypeError): 5334 isinstance(1, LiteralString) 5335 with self.assertRaises(TypeError): 5336 issubclass(int, LiteralString) 5337 5338 def test_alias(self): 5339 StringTuple = Tuple[LiteralString, LiteralString] 5340 class Alias: 5341 def return_tuple(self) -> StringTuple: 5342 return ("foo", "pep" + "675") 5343 5344 def test_typevar(self): 5345 StrT = TypeVar("StrT", bound=LiteralString) 5346 self.assertIs(StrT.__bound__, LiteralString) 5347 5348 def test_pickle(self): 5349 for proto in range(pickle.HIGHEST_PROTOCOL): 5350 pickled = pickle.dumps(LiteralString, protocol=proto) 5351 self.assertIs(LiteralString, pickle.loads(pickled)) 5352 5353 5354class SelfTests(BaseTestCase): 5355 def test_basics(self): 5356 class Foo: 5357 def bar(self) -> Self: ... 5358 5359 self.assertEqual(gth(Foo.bar), {'return': Self}) 5360 5361 def test_repr(self): 5362 if hasattr(typing, 'Self'): 5363 mod_name = 'typing' 5364 else: 5365 mod_name = 'typing_extensions' 5366 self.assertEqual(repr(Self), f'{mod_name}.Self') 5367 5368 def test_cannot_subscript(self): 5369 with self.assertRaises(TypeError): 5370 Self[int] 5371 5372 def test_cannot_subclass(self): 5373 with self.assertRaises(TypeError): 5374 class C(type(Self)): 5375 pass 5376 5377 def test_cannot_init(self): 5378 with self.assertRaises(TypeError): 5379 Self() 5380 with self.assertRaises(TypeError): 5381 type(Self)() 5382 5383 def test_no_isinstance(self): 5384 with self.assertRaises(TypeError): 5385 isinstance(1, Self) 5386 with self.assertRaises(TypeError): 5387 issubclass(int, Self) 5388 5389 def test_alias(self): 5390 TupleSelf = Tuple[Self, Self] 5391 class Alias: 5392 def return_tuple(self) -> TupleSelf: 5393 return (self, self) 5394 5395 def test_pickle(self): 5396 for proto in range(pickle.HIGHEST_PROTOCOL): 5397 pickled = pickle.dumps(Self, protocol=proto) 5398 self.assertIs(Self, pickle.loads(pickled)) 5399 5400 5401class UnpackTests(BaseTestCase): 5402 def test_basic_plain(self): 5403 Ts = TypeVarTuple('Ts') 5404 self.assertEqual(Unpack[Ts], Unpack[Ts]) 5405 with self.assertRaises(TypeError): 5406 Unpack() 5407 5408 def test_repr(self): 5409 Ts = TypeVarTuple('Ts') 5410 self.assertEqual(repr(Unpack[Ts]), f'{Unpack.__module__}.Unpack[Ts]') 5411 5412 def test_cannot_subclass_vars(self): 5413 with self.assertRaises(TypeError): 5414 class V(Unpack[TypeVarTuple('Ts')]): 5415 pass 5416 5417 def test_tuple(self): 5418 Ts = TypeVarTuple('Ts') 5419 Tuple[Unpack[Ts]] 5420 5421 def test_union(self): 5422 Xs = TypeVarTuple('Xs') 5423 Ys = TypeVarTuple('Ys') 5424 self.assertEqual( 5425 Union[Unpack[Xs]], 5426 Unpack[Xs] 5427 ) 5428 self.assertNotEqual( 5429 Union[Unpack[Xs]], 5430 Union[Unpack[Xs], Unpack[Ys]] 5431 ) 5432 self.assertEqual( 5433 Union[Unpack[Xs], Unpack[Xs]], 5434 Unpack[Xs] 5435 ) 5436 self.assertNotEqual( 5437 Union[Unpack[Xs], int], 5438 Union[Unpack[Xs]] 5439 ) 5440 self.assertNotEqual( 5441 Union[Unpack[Xs], int], 5442 Union[int] 5443 ) 5444 self.assertEqual( 5445 Union[Unpack[Xs], int].__args__, 5446 (Unpack[Xs], int) 5447 ) 5448 self.assertEqual( 5449 Union[Unpack[Xs], int].__parameters__, 5450 (Xs,) 5451 ) 5452 self.assertIs( 5453 Union[Unpack[Xs], int].__origin__, 5454 Union 5455 ) 5456 5457 def test_concatenation(self): 5458 Xs = TypeVarTuple('Xs') 5459 self.assertEqual(Tuple[int, Unpack[Xs]].__args__, (int, Unpack[Xs])) 5460 self.assertEqual(Tuple[Unpack[Xs], int].__args__, (Unpack[Xs], int)) 5461 self.assertEqual(Tuple[int, Unpack[Xs], str].__args__, 5462 (int, Unpack[Xs], str)) 5463 class C(Generic[Unpack[Xs]]): pass 5464 class D(Protocol[Unpack[Xs]]): pass 5465 for klass in C, D: 5466 with self.subTest(klass=klass.__name__): 5467 self.assertEqual(klass[int, Unpack[Xs]].__args__, (int, Unpack[Xs])) 5468 self.assertEqual(klass[Unpack[Xs], int].__args__, (Unpack[Xs], int)) 5469 self.assertEqual(klass[int, Unpack[Xs], str].__args__, 5470 (int, Unpack[Xs], str)) 5471 5472 def test_class(self): 5473 Ts = TypeVarTuple('Ts') 5474 5475 class C(Generic[Unpack[Ts]]): pass 5476 class D(Protocol[Unpack[Ts]]): pass 5477 5478 for klass in C, D: 5479 with self.subTest(klass=klass.__name__): 5480 self.assertEqual(klass[int].__args__, (int,)) 5481 self.assertEqual(klass[int, str].__args__, (int, str)) 5482 5483 with self.assertRaises(TypeError): 5484 class C(Generic[Unpack[Ts], int]): pass 5485 5486 with self.assertRaises(TypeError): 5487 class D(Protocol[Unpack[Ts], int]): pass 5488 5489 T1 = TypeVar('T') 5490 T2 = TypeVar('T') 5491 class C(Generic[T1, T2, Unpack[Ts]]): pass 5492 class D(Protocol[T1, T2, Unpack[Ts]]): pass 5493 for klass in C, D: 5494 with self.subTest(klass=klass.__name__): 5495 self.assertEqual(klass[int, str].__args__, (int, str)) 5496 self.assertEqual(klass[int, str, float].__args__, (int, str, float)) 5497 self.assertEqual( 5498 klass[int, str, float, bool].__args__, (int, str, float, bool) 5499 ) 5500 # A bug was fixed in 3.11.1 5501 # (https://github.com/python/cpython/commit/74920aa27d0c57443dd7f704d6272cca9c507ab3) 5502 # That means this assertion doesn't pass on 3.11.0, 5503 # but it passes on all other Python versions 5504 if sys.version_info[:3] != (3, 11, 0): 5505 with self.assertRaises(TypeError): 5506 klass[int] 5507 5508 5509class TypeVarTupleTests(BaseTestCase): 5510 5511 def test_basic_plain(self): 5512 Ts = TypeVarTuple('Ts') 5513 self.assertEqual(Ts, Ts) 5514 self.assertIsInstance(Ts, TypeVarTuple) 5515 Xs = TypeVarTuple('Xs') 5516 Ys = TypeVarTuple('Ys') 5517 self.assertNotEqual(Xs, Ys) 5518 5519 def test_repr(self): 5520 Ts = TypeVarTuple('Ts') 5521 self.assertEqual(repr(Ts), 'Ts') 5522 5523 def test_no_redefinition(self): 5524 self.assertNotEqual(TypeVarTuple('Ts'), TypeVarTuple('Ts')) 5525 5526 def test_cannot_subclass_vars(self): 5527 with self.assertRaises(TypeError): 5528 class V(TypeVarTuple('Ts')): 5529 pass 5530 5531 def test_cannot_subclass_var_itself(self): 5532 with self.assertRaises(TypeError): 5533 class V(TypeVarTuple): 5534 pass 5535 5536 def test_cannot_instantiate_vars(self): 5537 Ts = TypeVarTuple('Ts') 5538 with self.assertRaises(TypeError): 5539 Ts() 5540 5541 def test_tuple(self): 5542 Ts = TypeVarTuple('Ts') 5543 # Not legal at type checking time but we can't really check against it. 5544 Tuple[Ts] 5545 5546 def test_args_and_parameters(self): 5547 Ts = TypeVarTuple('Ts') 5548 5549 t = Tuple[tuple(Ts)] 5550 if sys.version_info >= (3, 11): 5551 self.assertEqual(t.__args__, (typing.Unpack[Ts],)) 5552 else: 5553 self.assertEqual(t.__args__, (Unpack[Ts],)) 5554 self.assertEqual(t.__parameters__, (Ts,)) 5555 5556 def test_pickle(self): 5557 global Ts, Ts_default # pickle wants to reference the class by name 5558 Ts = TypeVarTuple('Ts') 5559 Ts_default = TypeVarTuple('Ts_default', default=Unpack[Tuple[int, str]]) 5560 5561 for proto in range(pickle.HIGHEST_PROTOCOL): 5562 for typevartuple in (Ts, Ts_default): 5563 z = pickle.loads(pickle.dumps(typevartuple, proto)) 5564 self.assertEqual(z.__name__, typevartuple.__name__) 5565 self.assertEqual(z.__default__, typevartuple.__default__) 5566 5567 5568class FinalDecoratorTests(BaseTestCase): 5569 def test_final_unmodified(self): 5570 def func(x): ... 5571 self.assertIs(func, final(func)) 5572 5573 def test_dunder_final(self): 5574 @final 5575 def func(): ... 5576 @final 5577 class Cls: ... 5578 self.assertIs(True, func.__final__) 5579 self.assertIs(True, Cls.__final__) 5580 5581 class Wrapper: 5582 __slots__ = ("func",) 5583 def __init__(self, func): 5584 self.func = func 5585 def __call__(self, *args, **kwargs): 5586 return self.func(*args, **kwargs) 5587 5588 # Check that no error is thrown if the attribute 5589 # is not writable. 5590 @final 5591 @Wrapper 5592 def wrapped(): ... 5593 self.assertIsInstance(wrapped, Wrapper) 5594 self.assertIs(False, hasattr(wrapped, "__final__")) 5595 5596 class Meta(type): 5597 @property 5598 def __final__(self): return "can't set me" 5599 @final 5600 class WithMeta(metaclass=Meta): ... 5601 self.assertEqual(WithMeta.__final__, "can't set me") 5602 5603 # Builtin classes throw TypeError if you try to set an 5604 # attribute. 5605 final(int) 5606 self.assertIs(False, hasattr(int, "__final__")) 5607 5608 # Make sure it works with common builtin decorators 5609 class Methods: 5610 @final 5611 @classmethod 5612 def clsmethod(cls): ... 5613 5614 @final 5615 @staticmethod 5616 def stmethod(): ... 5617 5618 # The other order doesn't work because property objects 5619 # don't allow attribute assignment. 5620 @property 5621 @final 5622 def prop(self): ... 5623 5624 @final 5625 @lru_cache # noqa: B019 5626 def cached(self): ... 5627 5628 # Use getattr_static because the descriptor returns the 5629 # underlying function, which doesn't have __final__. 5630 self.assertIs( 5631 True, 5632 inspect.getattr_static(Methods, "clsmethod").__final__ 5633 ) 5634 self.assertIs( 5635 True, 5636 inspect.getattr_static(Methods, "stmethod").__final__ 5637 ) 5638 self.assertIs(True, Methods.prop.fget.__final__) 5639 self.assertIs(True, Methods.cached.__final__) 5640 5641 5642class RevealTypeTests(BaseTestCase): 5643 def test_reveal_type(self): 5644 obj = object() 5645 5646 with contextlib.redirect_stderr(io.StringIO()) as stderr: 5647 self.assertIs(obj, reveal_type(obj)) 5648 self.assertEqual("Runtime type is 'object'", stderr.getvalue().strip()) 5649 5650 5651class DataclassTransformTests(BaseTestCase): 5652 def test_decorator(self): 5653 def create_model(*, frozen: bool = False, kw_only: bool = True): 5654 return lambda cls: cls 5655 5656 decorated = dataclass_transform(kw_only_default=True, order_default=False)(create_model) 5657 5658 class CustomerModel: 5659 id: int 5660 5661 self.assertIs(decorated, create_model) 5662 self.assertEqual( 5663 decorated.__dataclass_transform__, 5664 { 5665 "eq_default": True, 5666 "order_default": False, 5667 "kw_only_default": True, 5668 "frozen_default": False, 5669 "field_specifiers": (), 5670 "kwargs": {}, 5671 } 5672 ) 5673 self.assertIs( 5674 decorated(frozen=True, kw_only=False)(CustomerModel), 5675 CustomerModel 5676 ) 5677 5678 def test_base_class(self): 5679 class ModelBase: 5680 def __init_subclass__(cls, *, frozen: bool = False): ... 5681 5682 Decorated = dataclass_transform( 5683 eq_default=True, 5684 order_default=True, 5685 # Arbitrary unrecognized kwargs are accepted at runtime. 5686 make_everything_awesome=True, 5687 )(ModelBase) 5688 5689 class CustomerModel(Decorated, frozen=True): 5690 id: int 5691 5692 self.assertIs(Decorated, ModelBase) 5693 self.assertEqual( 5694 Decorated.__dataclass_transform__, 5695 { 5696 "eq_default": True, 5697 "order_default": True, 5698 "kw_only_default": False, 5699 "frozen_default": False, 5700 "field_specifiers": (), 5701 "kwargs": {"make_everything_awesome": True}, 5702 } 5703 ) 5704 self.assertIsSubclass(CustomerModel, Decorated) 5705 5706 def test_metaclass(self): 5707 class Field: ... 5708 5709 class ModelMeta(type): 5710 def __new__( 5711 cls, name, bases, namespace, *, init: bool = True, 5712 ): 5713 return super().__new__(cls, name, bases, namespace) 5714 5715 Decorated = dataclass_transform( 5716 order_default=True, field_specifiers=(Field,) 5717 )(ModelMeta) 5718 5719 class ModelBase(metaclass=Decorated): ... 5720 5721 class CustomerModel(ModelBase, init=False): 5722 id: int 5723 5724 self.assertIs(Decorated, ModelMeta) 5725 self.assertEqual( 5726 Decorated.__dataclass_transform__, 5727 { 5728 "eq_default": True, 5729 "order_default": True, 5730 "kw_only_default": False, 5731 "frozen_default": False, 5732 "field_specifiers": (Field,), 5733 "kwargs": {}, 5734 } 5735 ) 5736 self.assertIsInstance(CustomerModel, Decorated) 5737 5738 5739class AllTests(BaseTestCase): 5740 5741 def test_drop_in_for_typing(self): 5742 # Check that the typing_extensions.__all__ is a superset of 5743 # typing.__all__. 5744 t_all = set(typing.__all__) 5745 te_all = set(typing_extensions.__all__) 5746 exceptions = {"ByteString"} 5747 self.assertGreaterEqual(te_all, t_all - exceptions) 5748 # Deprecated, to be removed in 3.14 5749 self.assertFalse(hasattr(typing_extensions, "ByteString")) 5750 # These were never included in `typing.__all__`, 5751 # and have been removed in Python 3.13 5752 self.assertNotIn('re', te_all) 5753 self.assertNotIn('io', te_all) 5754 5755 def test_typing_extensions_includes_standard(self): 5756 a = typing_extensions.__all__ 5757 self.assertIn('ClassVar', a) 5758 self.assertIn('Type', a) 5759 self.assertIn('ChainMap', a) 5760 self.assertIn('ContextManager', a) 5761 self.assertIn('Counter', a) 5762 self.assertIn('DefaultDict', a) 5763 self.assertIn('Deque', a) 5764 self.assertIn('NewType', a) 5765 self.assertIn('overload', a) 5766 self.assertIn('Text', a) 5767 self.assertIn('TYPE_CHECKING', a) 5768 self.assertIn('TypeAlias', a) 5769 self.assertIn('ParamSpec', a) 5770 self.assertIn("Concatenate", a) 5771 5772 self.assertIn('Annotated', a) 5773 self.assertIn('get_type_hints', a) 5774 5775 self.assertIn('Awaitable', a) 5776 self.assertIn('AsyncIterator', a) 5777 self.assertIn('AsyncIterable', a) 5778 self.assertIn('Coroutine', a) 5779 self.assertIn('AsyncContextManager', a) 5780 5781 self.assertIn('AsyncGenerator', a) 5782 5783 self.assertIn('Protocol', a) 5784 self.assertIn('runtime', a) 5785 5786 # Check that all objects in `__all__` are present in the module 5787 for name in a: 5788 self.assertTrue(hasattr(typing_extensions, name)) 5789 5790 def test_all_names_in___all__(self): 5791 exclude = { 5792 'GenericMeta', 5793 'KT', 5794 'PEP_560', 5795 'T', 5796 'T_co', 5797 'T_contra', 5798 'VT', 5799 } 5800 actual_names = { 5801 name for name in dir(typing_extensions) 5802 if not name.startswith("_") 5803 and not isinstance(getattr(typing_extensions, name), types.ModuleType) 5804 } 5805 # Make sure all public names are in __all__ 5806 self.assertEqual({*exclude, *typing_extensions.__all__}, 5807 actual_names) 5808 # Make sure all excluded names actually exist 5809 self.assertLessEqual(exclude, actual_names) 5810 5811 def test_typing_extensions_defers_when_possible(self): 5812 exclude = set() 5813 if sys.version_info < (3, 10): 5814 exclude |= {'get_args', 'get_origin'} 5815 if sys.version_info < (3, 10, 1): 5816 exclude |= {"Literal"} 5817 if sys.version_info < (3, 11): 5818 exclude |= {'final', 'Any', 'NewType', 'overload'} 5819 if sys.version_info < (3, 12): 5820 exclude |= { 5821 'SupportsAbs', 'SupportsBytes', 5822 'SupportsComplex', 'SupportsFloat', 'SupportsIndex', 'SupportsInt', 5823 'SupportsRound', 'Unpack', 'dataclass_transform', 5824 } 5825 if sys.version_info < (3, 13): 5826 exclude |= { 5827 'NamedTuple', 'Protocol', 'runtime_checkable', 'Generator', 5828 'AsyncGenerator', 'ContextManager', 'AsyncContextManager', 5829 'ParamSpec', 'TypeVar', 'TypeVarTuple', 'get_type_hints', 5830 } 5831 if not typing_extensions._PEP_728_IMPLEMENTED: 5832 exclude |= {'TypedDict', 'is_typeddict'} 5833 for item in typing_extensions.__all__: 5834 if item not in exclude and hasattr(typing, item): 5835 self.assertIs( 5836 getattr(typing_extensions, item), 5837 getattr(typing, item)) 5838 5839 def test_typing_extensions_compiles_with_opt(self): 5840 file_path = typing_extensions.__file__ 5841 try: 5842 subprocess.check_output(f'{sys.executable} -OO {file_path}', 5843 stderr=subprocess.STDOUT, 5844 shell=True) 5845 except subprocess.CalledProcessError: 5846 self.fail('Module does not compile with optimize=2 (-OO flag).') 5847 5848 5849class CoolEmployee(NamedTuple): 5850 name: str 5851 cool: int 5852 5853 5854class CoolEmployeeWithDefault(NamedTuple): 5855 name: str 5856 cool: int = 0 5857 5858 5859class XMeth(NamedTuple): 5860 x: int 5861 5862 def double(self): 5863 return 2 * self.x 5864 5865 5866class NamedTupleTests(BaseTestCase): 5867 class NestedEmployee(NamedTuple): 5868 name: str 5869 cool: int 5870 5871 def test_basics(self): 5872 Emp = NamedTuple('Emp', [('name', str), ('id', int)]) 5873 self.assertIsSubclass(Emp, tuple) 5874 joe = Emp('Joe', 42) 5875 jim = Emp(name='Jim', id=1) 5876 self.assertIsInstance(joe, Emp) 5877 self.assertIsInstance(joe, tuple) 5878 self.assertEqual(joe.name, 'Joe') 5879 self.assertEqual(joe.id, 42) 5880 self.assertEqual(jim.name, 'Jim') 5881 self.assertEqual(jim.id, 1) 5882 self.assertEqual(Emp.__name__, 'Emp') 5883 self.assertEqual(Emp._fields, ('name', 'id')) 5884 self.assertEqual(Emp.__annotations__, 5885 collections.OrderedDict([('name', str), ('id', int)])) 5886 5887 def test_annotation_usage(self): 5888 tim = CoolEmployee('Tim', 9000) 5889 self.assertIsInstance(tim, CoolEmployee) 5890 self.assertIsInstance(tim, tuple) 5891 self.assertEqual(tim.name, 'Tim') 5892 self.assertEqual(tim.cool, 9000) 5893 self.assertEqual(CoolEmployee.__name__, 'CoolEmployee') 5894 self.assertEqual(CoolEmployee._fields, ('name', 'cool')) 5895 self.assertEqual(CoolEmployee.__annotations__, 5896 collections.OrderedDict(name=str, cool=int)) 5897 5898 def test_annotation_usage_with_default(self): 5899 jelle = CoolEmployeeWithDefault('Jelle') 5900 self.assertIsInstance(jelle, CoolEmployeeWithDefault) 5901 self.assertIsInstance(jelle, tuple) 5902 self.assertEqual(jelle.name, 'Jelle') 5903 self.assertEqual(jelle.cool, 0) 5904 cooler_employee = CoolEmployeeWithDefault('Sjoerd', 1) 5905 self.assertEqual(cooler_employee.cool, 1) 5906 5907 self.assertEqual(CoolEmployeeWithDefault.__name__, 'CoolEmployeeWithDefault') 5908 self.assertEqual(CoolEmployeeWithDefault._fields, ('name', 'cool')) 5909 self.assertEqual(CoolEmployeeWithDefault.__annotations__, 5910 dict(name=str, cool=int)) 5911 5912 with self.assertRaisesRegex( 5913 TypeError, 5914 'Non-default namedtuple field y cannot follow default field x' 5915 ): 5916 class NonDefaultAfterDefault(NamedTuple): 5917 x: int = 3 5918 y: int 5919 5920 def test_field_defaults(self): 5921 self.assertEqual(CoolEmployeeWithDefault._field_defaults, dict(cool=0)) 5922 5923 def test_annotation_usage_with_methods(self): 5924 self.assertEqual(XMeth(1).double(), 2) 5925 self.assertEqual(XMeth(42).x, XMeth(42)[0]) 5926 self.assertEqual(str(XRepr(42)), '42 -> 1') 5927 self.assertEqual(XRepr(1, 2) + XRepr(3), 0) 5928 5929 bad_overwrite_error_message = 'Cannot overwrite NamedTuple attribute' 5930 5931 with self.assertRaisesRegex(AttributeError, bad_overwrite_error_message): 5932 class XMethBad(NamedTuple): 5933 x: int 5934 def _fields(self): 5935 return 'no chance for this' 5936 5937 with self.assertRaisesRegex(AttributeError, bad_overwrite_error_message): 5938 class XMethBad2(NamedTuple): 5939 x: int 5940 def _source(self): 5941 return 'no chance for this as well' 5942 5943 def test_multiple_inheritance(self): 5944 class A: 5945 pass 5946 with self.assertRaisesRegex( 5947 TypeError, 5948 'can only inherit from a NamedTuple type and Generic' 5949 ): 5950 class X(NamedTuple, A): 5951 x: int 5952 5953 with self.assertRaisesRegex( 5954 TypeError, 5955 'can only inherit from a NamedTuple type and Generic' 5956 ): 5957 class Y(NamedTuple, tuple): 5958 x: int 5959 5960 with self.assertRaisesRegex(TypeError, 'duplicate base class'): 5961 class Z(NamedTuple, NamedTuple): 5962 x: int 5963 5964 class A(NamedTuple): 5965 x: int 5966 with self.assertRaisesRegex( 5967 TypeError, 5968 'can only inherit from a NamedTuple type and Generic' 5969 ): 5970 class XX(NamedTuple, A): 5971 y: str 5972 5973 def test_generic(self): 5974 class X(NamedTuple, Generic[T]): 5975 x: T 5976 self.assertEqual(X.__bases__, (tuple, Generic)) 5977 self.assertEqual(X.__orig_bases__, (NamedTuple, Generic[T])) 5978 self.assertEqual(X.__mro__, (X, tuple, Generic, object)) 5979 5980 class Y(Generic[T], NamedTuple): 5981 x: T 5982 self.assertEqual(Y.__bases__, (Generic, tuple)) 5983 self.assertEqual(Y.__orig_bases__, (Generic[T], NamedTuple)) 5984 self.assertEqual(Y.__mro__, (Y, Generic, tuple, object)) 5985 5986 for G in X, Y: 5987 with self.subTest(type=G): 5988 self.assertEqual(G.__parameters__, (T,)) 5989 A = G[int] 5990 self.assertIs(A.__origin__, G) 5991 self.assertEqual(A.__args__, (int,)) 5992 self.assertEqual(A.__parameters__, ()) 5993 5994 a = A(3) 5995 self.assertIs(type(a), G) 5996 self.assertIsInstance(a, G) 5997 self.assertEqual(a.x, 3) 5998 5999 things = "arguments" if sys.version_info >= (3, 10) else "parameters" 6000 with self.assertRaisesRegex(TypeError, f'Too many {things}'): 6001 G[int, str] 6002 6003 @skipUnless(TYPING_3_9_0, "tuple.__class_getitem__ was added in 3.9") 6004 def test_non_generic_subscript_py39_plus(self): 6005 # For backward compatibility, subscription works 6006 # on arbitrary NamedTuple types. 6007 class Group(NamedTuple): 6008 key: T 6009 group: list[T] 6010 A = Group[int] 6011 self.assertEqual(A.__origin__, Group) 6012 self.assertEqual(A.__parameters__, ()) 6013 self.assertEqual(A.__args__, (int,)) 6014 a = A(1, [2]) 6015 self.assertIs(type(a), Group) 6016 self.assertEqual(a, (1, [2])) 6017 6018 @skipIf(TYPING_3_9_0, "Test isn't relevant to 3.9+") 6019 def test_non_generic_subscript_error_message_py38(self): 6020 class Group(NamedTuple): 6021 key: T 6022 group: List[T] 6023 6024 with self.assertRaisesRegex(TypeError, 'not subscriptable'): 6025 Group[int] 6026 6027 for attr in ('__args__', '__origin__', '__parameters__'): 6028 with self.subTest(attr=attr): 6029 self.assertFalse(hasattr(Group, attr)) 6030 6031 def test_namedtuple_keyword_usage(self): 6032 with self.assertWarnsRegex( 6033 DeprecationWarning, 6034 "Creating NamedTuple classes using keyword arguments is deprecated" 6035 ): 6036 LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int) 6037 6038 nick = LocalEmployee('Nick', 25) 6039 self.assertIsInstance(nick, tuple) 6040 self.assertEqual(nick.name, 'Nick') 6041 self.assertEqual(LocalEmployee.__name__, 'LocalEmployee') 6042 self.assertEqual(LocalEmployee._fields, ('name', 'age')) 6043 self.assertEqual(LocalEmployee.__annotations__, dict(name=str, age=int)) 6044 6045 with self.assertRaisesRegex( 6046 TypeError, 6047 "Either list of fields or keywords can be provided to NamedTuple, not both" 6048 ): 6049 NamedTuple('Name', [('x', int)], y=str) 6050 6051 with self.assertRaisesRegex( 6052 TypeError, 6053 "Either list of fields or keywords can be provided to NamedTuple, not both" 6054 ): 6055 NamedTuple('Name', [], y=str) 6056 6057 with self.assertRaisesRegex( 6058 TypeError, 6059 ( 6060 r"Cannot pass `None` as the 'fields' parameter " 6061 r"and also specify fields using keyword arguments" 6062 ) 6063 ): 6064 NamedTuple('Name', None, x=int) 6065 6066 def test_namedtuple_special_keyword_names(self): 6067 with self.assertWarnsRegex( 6068 DeprecationWarning, 6069 "Creating NamedTuple classes using keyword arguments is deprecated" 6070 ): 6071 NT = NamedTuple("NT", cls=type, self=object, typename=str, fields=list) 6072 6073 self.assertEqual(NT.__name__, 'NT') 6074 self.assertEqual(NT._fields, ('cls', 'self', 'typename', 'fields')) 6075 a = NT(cls=str, self=42, typename='foo', fields=[('bar', tuple)]) 6076 self.assertEqual(a.cls, str) 6077 self.assertEqual(a.self, 42) 6078 self.assertEqual(a.typename, 'foo') 6079 self.assertEqual(a.fields, [('bar', tuple)]) 6080 6081 def test_empty_namedtuple(self): 6082 expected_warning = re.escape( 6083 "Failing to pass a value for the 'fields' parameter is deprecated " 6084 "and will be disallowed in Python 3.15. " 6085 "To create a NamedTuple class with 0 fields " 6086 "using the functional syntax, " 6087 "pass an empty list, e.g. `NT1 = NamedTuple('NT1', [])`." 6088 ) 6089 with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): 6090 NT1 = NamedTuple('NT1') 6091 6092 expected_warning = re.escape( 6093 "Passing `None` as the 'fields' parameter is deprecated " 6094 "and will be disallowed in Python 3.15. " 6095 "To create a NamedTuple class with 0 fields " 6096 "using the functional syntax, " 6097 "pass an empty list, e.g. `NT2 = NamedTuple('NT2', [])`." 6098 ) 6099 with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): 6100 NT2 = NamedTuple('NT2', None) 6101 6102 NT3 = NamedTuple('NT2', []) 6103 6104 class CNT(NamedTuple): 6105 pass # empty body 6106 6107 for struct in NT1, NT2, NT3, CNT: 6108 with self.subTest(struct=struct): 6109 self.assertEqual(struct._fields, ()) 6110 self.assertEqual(struct.__annotations__, {}) 6111 self.assertIsInstance(struct(), struct) 6112 self.assertEqual(struct._field_defaults, {}) 6113 6114 def test_namedtuple_errors(self): 6115 with self.assertRaises(TypeError): 6116 NamedTuple.__new__() 6117 with self.assertRaises(TypeError): 6118 NamedTuple() 6119 with self.assertRaises(TypeError): 6120 NamedTuple('Emp', [('name', str)], None) 6121 with self.assertRaisesRegex(ValueError, 'cannot start with an underscore'): 6122 NamedTuple('Emp', [('_name', str)]) 6123 with self.assertRaises(TypeError): 6124 NamedTuple(typename='Emp', name=str, id=int) 6125 6126 def test_copy_and_pickle(self): 6127 global Emp # pickle wants to reference the class by name 6128 Emp = NamedTuple('Emp', [('name', str), ('cool', int)]) 6129 for cls in Emp, CoolEmployee, self.NestedEmployee: 6130 with self.subTest(cls=cls): 6131 jane = cls('jane', 37) 6132 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 6133 z = pickle.dumps(jane, proto) 6134 jane2 = pickle.loads(z) 6135 self.assertEqual(jane2, jane) 6136 self.assertIsInstance(jane2, cls) 6137 6138 jane2 = copy.copy(jane) 6139 self.assertEqual(jane2, jane) 6140 self.assertIsInstance(jane2, cls) 6141 6142 jane2 = copy.deepcopy(jane) 6143 self.assertEqual(jane2, jane) 6144 self.assertIsInstance(jane2, cls) 6145 6146 def test_docstring(self): 6147 self.assertIsInstance(NamedTuple.__doc__, str) 6148 6149 @skipUnless(TYPING_3_9_0, "NamedTuple was a class on 3.8 and lower") 6150 def test_same_as_typing_NamedTuple_39_plus(self): 6151 self.assertEqual( 6152 set(dir(NamedTuple)) - {"__text_signature__"}, 6153 set(dir(typing.NamedTuple)) 6154 ) 6155 self.assertIs(type(NamedTuple), type(typing.NamedTuple)) 6156 6157 @skipIf(TYPING_3_9_0, "tests are only relevant to <=3.8") 6158 def test_same_as_typing_NamedTuple_38_minus(self): 6159 self.assertEqual( 6160 self.NestedEmployee.__annotations__, 6161 self.NestedEmployee._field_types 6162 ) 6163 6164 def test_orig_bases(self): 6165 T = TypeVar('T') 6166 6167 class SimpleNamedTuple(NamedTuple): 6168 pass 6169 6170 class GenericNamedTuple(NamedTuple, Generic[T]): 6171 pass 6172 6173 self.assertEqual(SimpleNamedTuple.__orig_bases__, (NamedTuple,)) 6174 self.assertEqual(GenericNamedTuple.__orig_bases__, (NamedTuple, Generic[T])) 6175 6176 CallNamedTuple = NamedTuple('CallNamedTuple', []) 6177 6178 self.assertEqual(CallNamedTuple.__orig_bases__, (NamedTuple,)) 6179 6180 def test_setname_called_on_values_in_class_dictionary(self): 6181 class Vanilla: 6182 def __set_name__(self, owner, name): 6183 self.name = name 6184 6185 class Foo(NamedTuple): 6186 attr = Vanilla() 6187 6188 foo = Foo() 6189 self.assertEqual(len(foo), 0) 6190 self.assertNotIn('attr', Foo._fields) 6191 self.assertIsInstance(foo.attr, Vanilla) 6192 self.assertEqual(foo.attr.name, "attr") 6193 6194 class Bar(NamedTuple): 6195 attr: Vanilla = Vanilla() 6196 6197 bar = Bar() 6198 self.assertEqual(len(bar), 1) 6199 self.assertIn('attr', Bar._fields) 6200 self.assertIsInstance(bar.attr, Vanilla) 6201 self.assertEqual(bar.attr.name, "attr") 6202 6203 @skipIf( 6204 TYPING_3_12_0, 6205 "__set_name__ behaviour changed on py312+ to use BaseException.add_note()" 6206 ) 6207 def test_setname_raises_the_same_as_on_other_classes_py311_minus(self): 6208 class CustomException(BaseException): pass 6209 6210 class Annoying: 6211 def __set_name__(self, owner, name): 6212 raise CustomException 6213 6214 annoying = Annoying() 6215 6216 with self.assertRaises(RuntimeError) as cm: 6217 class NormalClass: 6218 attr = annoying 6219 normal_exception = cm.exception 6220 6221 with self.assertRaises(RuntimeError) as cm: 6222 class NamedTupleClass(NamedTuple): 6223 attr = annoying 6224 namedtuple_exception = cm.exception 6225 6226 self.assertIs(type(namedtuple_exception), RuntimeError) 6227 self.assertIs(type(namedtuple_exception), type(normal_exception)) 6228 self.assertEqual(len(namedtuple_exception.args), len(normal_exception.args)) 6229 self.assertEqual( 6230 namedtuple_exception.args[0], 6231 normal_exception.args[0].replace("NormalClass", "NamedTupleClass") 6232 ) 6233 6234 self.assertIs(type(namedtuple_exception.__cause__), CustomException) 6235 self.assertIs( 6236 type(namedtuple_exception.__cause__), type(normal_exception.__cause__) 6237 ) 6238 self.assertEqual( 6239 namedtuple_exception.__cause__.args, normal_exception.__cause__.args 6240 ) 6241 6242 @skipUnless( 6243 TYPING_3_12_0, 6244 "__set_name__ behaviour changed on py312+ to use BaseException.add_note()" 6245 ) 6246 def test_setname_raises_the_same_as_on_other_classes_py312_plus(self): 6247 class CustomException(BaseException): pass 6248 6249 class Annoying: 6250 def __set_name__(self, owner, name): 6251 raise CustomException 6252 6253 annoying = Annoying() 6254 6255 with self.assertRaises(CustomException) as cm: 6256 class NormalClass: 6257 attr = annoying 6258 normal_exception = cm.exception 6259 6260 with self.assertRaises(CustomException) as cm: 6261 class NamedTupleClass(NamedTuple): 6262 attr = annoying 6263 namedtuple_exception = cm.exception 6264 6265 expected_note = ( 6266 "Error calling __set_name__ on 'Annoying' instance " 6267 "'attr' in 'NamedTupleClass'" 6268 ) 6269 6270 self.assertIs(type(namedtuple_exception), CustomException) 6271 self.assertIs(type(namedtuple_exception), type(normal_exception)) 6272 self.assertEqual(namedtuple_exception.args, normal_exception.args) 6273 6274 self.assertEqual(len(namedtuple_exception.__notes__), 1) 6275 self.assertEqual( 6276 len(namedtuple_exception.__notes__), len(normal_exception.__notes__) 6277 ) 6278 6279 self.assertEqual(namedtuple_exception.__notes__[0], expected_note) 6280 self.assertEqual( 6281 namedtuple_exception.__notes__[0], 6282 normal_exception.__notes__[0].replace("NormalClass", "NamedTupleClass") 6283 ) 6284 6285 def test_strange_errors_when_accessing_set_name_itself(self): 6286 class CustomException(Exception): pass 6287 6288 class Meta(type): 6289 def __getattribute__(self, attr): 6290 if attr == "__set_name__": 6291 raise CustomException 6292 return object.__getattribute__(self, attr) 6293 6294 class VeryAnnoying(metaclass=Meta): pass 6295 6296 very_annoying = VeryAnnoying() 6297 6298 with self.assertRaises(CustomException): 6299 class Foo(NamedTuple): 6300 attr = very_annoying 6301 6302 6303class TypeVarTests(BaseTestCase): 6304 def test_basic_plain(self): 6305 T = TypeVar('T') 6306 # T equals itself. 6307 self.assertEqual(T, T) 6308 # T is an instance of TypeVar 6309 self.assertIsInstance(T, TypeVar) 6310 self.assertEqual(T.__name__, 'T') 6311 self.assertEqual(T.__constraints__, ()) 6312 self.assertIs(T.__bound__, None) 6313 self.assertIs(T.__covariant__, False) 6314 self.assertIs(T.__contravariant__, False) 6315 self.assertIs(T.__infer_variance__, False) 6316 6317 def test_attributes(self): 6318 T_bound = TypeVar('T_bound', bound=int) 6319 self.assertEqual(T_bound.__name__, 'T_bound') 6320 self.assertEqual(T_bound.__constraints__, ()) 6321 self.assertIs(T_bound.__bound__, int) 6322 6323 T_constraints = TypeVar('T_constraints', int, str) 6324 self.assertEqual(T_constraints.__name__, 'T_constraints') 6325 self.assertEqual(T_constraints.__constraints__, (int, str)) 6326 self.assertIs(T_constraints.__bound__, None) 6327 6328 T_co = TypeVar('T_co', covariant=True) 6329 self.assertEqual(T_co.__name__, 'T_co') 6330 self.assertIs(T_co.__covariant__, True) 6331 self.assertIs(T_co.__contravariant__, False) 6332 self.assertIs(T_co.__infer_variance__, False) 6333 6334 T_contra = TypeVar('T_contra', contravariant=True) 6335 self.assertEqual(T_contra.__name__, 'T_contra') 6336 self.assertIs(T_contra.__covariant__, False) 6337 self.assertIs(T_contra.__contravariant__, True) 6338 self.assertIs(T_contra.__infer_variance__, False) 6339 6340 T_infer = TypeVar('T_infer', infer_variance=True) 6341 self.assertEqual(T_infer.__name__, 'T_infer') 6342 self.assertIs(T_infer.__covariant__, False) 6343 self.assertIs(T_infer.__contravariant__, False) 6344 self.assertIs(T_infer.__infer_variance__, True) 6345 6346 def test_typevar_instance_type_error(self): 6347 T = TypeVar('T') 6348 with self.assertRaises(TypeError): 6349 isinstance(42, T) 6350 6351 def test_typevar_subclass_type_error(self): 6352 T = TypeVar('T') 6353 with self.assertRaises(TypeError): 6354 issubclass(int, T) 6355 with self.assertRaises(TypeError): 6356 issubclass(T, int) 6357 6358 def test_constrained_error(self): 6359 with self.assertRaises(TypeError): 6360 X = TypeVar('X', int) 6361 X 6362 6363 def test_union_unique(self): 6364 X = TypeVar('X') 6365 Y = TypeVar('Y') 6366 self.assertNotEqual(X, Y) 6367 self.assertEqual(Union[X], X) 6368 self.assertNotEqual(Union[X], Union[X, Y]) 6369 self.assertEqual(Union[X, X], X) 6370 self.assertNotEqual(Union[X, int], Union[X]) 6371 self.assertNotEqual(Union[X, int], Union[int]) 6372 self.assertEqual(Union[X, int].__args__, (X, int)) 6373 self.assertEqual(Union[X, int].__parameters__, (X,)) 6374 self.assertIs(Union[X, int].__origin__, Union) 6375 6376 if hasattr(types, "UnionType"): 6377 def test_or(self): 6378 X = TypeVar('X') 6379 # use a string because str doesn't implement 6380 # __or__/__ror__ itself 6381 self.assertEqual(X | "x", Union[X, "x"]) 6382 self.assertEqual("x" | X, Union["x", X]) 6383 # make sure the order is correct 6384 self.assertEqual(get_args(X | "x"), (X, typing.ForwardRef("x"))) 6385 self.assertEqual(get_args("x" | X), (typing.ForwardRef("x"), X)) 6386 6387 def test_union_constrained(self): 6388 A = TypeVar('A', str, bytes) 6389 self.assertNotEqual(Union[A, str], Union[A]) 6390 6391 def test_repr(self): 6392 self.assertEqual(repr(T), '~T') 6393 self.assertEqual(repr(KT), '~KT') 6394 self.assertEqual(repr(VT), '~VT') 6395 self.assertEqual(repr(AnyStr), '~AnyStr') 6396 T_co = TypeVar('T_co', covariant=True) 6397 self.assertEqual(repr(T_co), '+T_co') 6398 T_contra = TypeVar('T_contra', contravariant=True) 6399 self.assertEqual(repr(T_contra), '-T_contra') 6400 6401 def test_no_redefinition(self): 6402 self.assertNotEqual(TypeVar('T'), TypeVar('T')) 6403 self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str)) 6404 6405 def test_cannot_subclass(self): 6406 with self.assertRaises(TypeError): 6407 class V(TypeVar): pass 6408 T = TypeVar("T") 6409 with self.assertRaises(TypeError): 6410 class W(T): pass 6411 6412 def test_cannot_instantiate_vars(self): 6413 with self.assertRaises(TypeError): 6414 TypeVar('A')() 6415 6416 def test_bound_errors(self): 6417 with self.assertRaises(TypeError): 6418 TypeVar('X', bound=Union) 6419 with self.assertRaises(TypeError): 6420 TypeVar('X', str, float, bound=Employee) 6421 with self.assertRaisesRegex(TypeError, 6422 r"Bound must be a type\. Got \(1, 2\)\."): 6423 TypeVar('X', bound=(1, 2)) 6424 6425 # Technically we could run it on later versions of 3.8, 6426 # but that's not worth the effort. 6427 @skipUnless(TYPING_3_9_0, "Fix was not backported") 6428 def test_missing__name__(self): 6429 # See bpo-39942 6430 code = ("import typing\n" 6431 "T = typing.TypeVar('T')\n" 6432 ) 6433 exec(code, {}) 6434 6435 def test_no_bivariant(self): 6436 with self.assertRaises(ValueError): 6437 TypeVar('T', covariant=True, contravariant=True) 6438 6439 def test_cannot_combine_explicit_and_infer(self): 6440 with self.assertRaises(ValueError): 6441 TypeVar('T', covariant=True, infer_variance=True) 6442 with self.assertRaises(ValueError): 6443 TypeVar('T', contravariant=True, infer_variance=True) 6444 6445 6446class TypeVarLikeDefaultsTests(BaseTestCase): 6447 def test_typevar(self): 6448 T = typing_extensions.TypeVar('T', default=int) 6449 typing_T = typing.TypeVar('T') 6450 self.assertEqual(T.__default__, int) 6451 self.assertIsInstance(T, typing_extensions.TypeVar) 6452 self.assertIsInstance(T, typing.TypeVar) 6453 self.assertIsInstance(typing_T, typing.TypeVar) 6454 self.assertIsInstance(typing_T, typing_extensions.TypeVar) 6455 6456 class A(Generic[T]): ... 6457 self.assertEqual(Optional[T].__args__, (T, type(None))) 6458 6459 def test_typevar_none(self): 6460 U = typing_extensions.TypeVar('U') 6461 U_None = typing_extensions.TypeVar('U_None', default=None) 6462 self.assertIs(U.__default__, NoDefault) 6463 self.assertFalse(U.has_default()) 6464 self.assertEqual(U_None.__default__, None) 6465 self.assertTrue(U_None.has_default()) 6466 6467 def test_paramspec(self): 6468 P = ParamSpec('P', default=[str, int]) 6469 self.assertEqual(P.__default__, [str, int]) 6470 self.assertTrue(P.has_default()) 6471 self.assertIsInstance(P, ParamSpec) 6472 if hasattr(typing, "ParamSpec"): 6473 self.assertIsInstance(P, typing.ParamSpec) 6474 typing_P = typing.ParamSpec('P') 6475 self.assertIsInstance(typing_P, typing.ParamSpec) 6476 self.assertIsInstance(typing_P, ParamSpec) 6477 6478 class A(Generic[P]): ... 6479 self.assertEqual(typing.Callable[P, None].__args__, (P, type(None))) 6480 6481 P_default = ParamSpec('P_default', default=...) 6482 self.assertIs(P_default.__default__, ...) 6483 self.assertTrue(P_default.has_default()) 6484 6485 def test_paramspec_none(self): 6486 U = ParamSpec('U') 6487 U_None = ParamSpec('U_None', default=None) 6488 self.assertIs(U.__default__, NoDefault) 6489 self.assertFalse(U.has_default()) 6490 self.assertIs(U_None.__default__, None) 6491 self.assertTrue(U_None.has_default()) 6492 6493 def test_typevartuple(self): 6494 Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]]) 6495 self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]]) 6496 self.assertIsInstance(Ts, TypeVarTuple) 6497 self.assertTrue(Ts.has_default()) 6498 if hasattr(typing, "TypeVarTuple"): 6499 self.assertIsInstance(Ts, typing.TypeVarTuple) 6500 typing_Ts = typing.TypeVarTuple('Ts') 6501 self.assertIsInstance(typing_Ts, typing.TypeVarTuple) 6502 self.assertIsInstance(typing_Ts, TypeVarTuple) 6503 6504 class A(Generic[Unpack[Ts]]): ... 6505 self.assertEqual(Optional[Unpack[Ts]].__args__, (Unpack[Ts], type(None))) 6506 6507 @skipIf( 6508 sys.version_info < (3, 11, 1), 6509 "Not yet backported for older versions of Python" 6510 ) 6511 def test_typevartuple_specialization(self): 6512 T = TypeVar("T") 6513 Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]]) 6514 self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]]) 6515 class A(Generic[T, Unpack[Ts]]): ... 6516 self.assertEqual(A[float].__args__, (float, str, int)) 6517 self.assertEqual(A[float, range].__args__, (float, range)) 6518 self.assertEqual(A[float, Unpack[tuple[int, ...]]].__args__, (float, Unpack[tuple[int, ...]])) 6519 6520 @skipIf( 6521 sys.version_info < (3, 11, 1), 6522 "Not yet backported for older versions of Python" 6523 ) 6524 def test_typevar_and_typevartuple_specialization(self): 6525 T = TypeVar("T") 6526 U = TypeVar("U", default=float) 6527 Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]]) 6528 self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]]) 6529 class A(Generic[T, U, Unpack[Ts]]): ... 6530 self.assertEqual(A[int].__args__, (int, float, str, int)) 6531 self.assertEqual(A[int, str].__args__, (int, str, str, int)) 6532 self.assertEqual(A[int, str, range].__args__, (int, str, range)) 6533 self.assertEqual(A[int, str, Unpack[tuple[int, ...]]].__args__, (int, str, Unpack[tuple[int, ...]])) 6534 6535 def test_no_default_after_typevar_tuple(self): 6536 T = TypeVar("T", default=int) 6537 Ts = TypeVarTuple("Ts") 6538 Ts_default = TypeVarTuple("Ts_default", default=Unpack[Tuple[str, int]]) 6539 6540 with self.assertRaises(TypeError): 6541 class X(Generic[Unpack[Ts], T]): ... 6542 6543 with self.assertRaises(TypeError): 6544 class Y(Generic[Unpack[Ts_default], T]): ... 6545 6546 def test_typevartuple_none(self): 6547 U = TypeVarTuple('U') 6548 U_None = TypeVarTuple('U_None', default=None) 6549 self.assertIs(U.__default__, NoDefault) 6550 self.assertFalse(U.has_default()) 6551 self.assertIs(U_None.__default__, None) 6552 self.assertTrue(U_None.has_default()) 6553 6554 def test_no_default_after_non_default(self): 6555 DefaultStrT = typing_extensions.TypeVar('DefaultStrT', default=str) 6556 T = TypeVar('T') 6557 6558 with self.assertRaises(TypeError): 6559 Generic[DefaultStrT, T] 6560 6561 def test_need_more_params(self): 6562 DefaultStrT = typing_extensions.TypeVar('DefaultStrT', default=str) 6563 T = typing_extensions.TypeVar('T') 6564 U = typing_extensions.TypeVar('U') 6565 6566 class A(Generic[T, U, DefaultStrT]): ... 6567 A[int, bool] 6568 A[int, bool, str] 6569 6570 with self.assertRaises( 6571 TypeError, msg="Too few arguments for .+; actual 1, expected at least 2" 6572 ): 6573 A[int] 6574 6575 def test_pickle(self): 6576 global U, U_co, U_contra, U_default # pickle wants to reference the class by name 6577 U = typing_extensions.TypeVar('U') 6578 U_co = typing_extensions.TypeVar('U_co', covariant=True) 6579 U_contra = typing_extensions.TypeVar('U_contra', contravariant=True) 6580 U_default = typing_extensions.TypeVar('U_default', default=int) 6581 for proto in range(pickle.HIGHEST_PROTOCOL): 6582 for typevar in (U, U_co, U_contra, U_default): 6583 z = pickle.loads(pickle.dumps(typevar, proto)) 6584 self.assertEqual(z.__name__, typevar.__name__) 6585 self.assertEqual(z.__covariant__, typevar.__covariant__) 6586 self.assertEqual(z.__contravariant__, typevar.__contravariant__) 6587 self.assertEqual(z.__bound__, typevar.__bound__) 6588 self.assertEqual(z.__default__, typevar.__default__) 6589 6590 def test_strange_defaults_are_allowed(self): 6591 # Leave it to type checkers to check whether strange default values 6592 # should be allowed or disallowed 6593 def not_a_type(): ... 6594 6595 for typevarlike_cls in TypeVar, ParamSpec, TypeVarTuple: 6596 for default in not_a_type, 42, bytearray(), (int, not_a_type, 42): 6597 with self.subTest(typevarlike_cls=typevarlike_cls, default=default): 6598 T = typevarlike_cls("T", default=default) 6599 self.assertEqual(T.__default__, default) 6600 6601 @skip_if_py313_beta_1 6602 def test_allow_default_after_non_default_in_alias(self): 6603 T_default = TypeVar('T_default', default=int) 6604 T = TypeVar('T') 6605 Ts = TypeVarTuple('Ts') 6606 6607 a1 = Callable[[T_default], T] 6608 self.assertEqual(a1.__args__, (T_default, T)) 6609 6610 if sys.version_info >= (3, 9): 6611 a2 = dict[T_default, T] 6612 self.assertEqual(a2.__args__, (T_default, T)) 6613 6614 a3 = typing.Dict[T_default, T] 6615 self.assertEqual(a3.__args__, (T_default, T)) 6616 6617 a4 = Callable[[Unpack[Ts]], T] 6618 self.assertEqual(a4.__args__, (Unpack[Ts], T)) 6619 6620 @skipIf( 6621 typing_extensions.Protocol is typing.Protocol, 6622 "Test currently fails with the CPython version of Protocol and that's not our fault" 6623 ) 6624 def test_generic_with_broken_eq(self): 6625 # See https://github.com/python/typing_extensions/pull/422 for context 6626 class BrokenEq(type): 6627 def __eq__(self, other): 6628 if other is typing_extensions.Protocol: 6629 raise TypeError("I'm broken") 6630 return False 6631 6632 class G(Generic[T], metaclass=BrokenEq): 6633 pass 6634 6635 alias = G[int] 6636 self.assertIs(get_origin(alias), G) 6637 self.assertEqual(get_args(alias), (int,)) 6638 6639 @skipIf( 6640 sys.version_info < (3, 11, 1), 6641 "Not yet backported for older versions of Python" 6642 ) 6643 def test_paramspec_specialization(self): 6644 T = TypeVar("T") 6645 P = ParamSpec('P', default=[str, int]) 6646 self.assertEqual(P.__default__, [str, int]) 6647 class A(Generic[T, P]): ... 6648 self.assertEqual(A[float].__args__, (float, (str, int))) 6649 self.assertEqual(A[float, [range]].__args__, (float, (range,))) 6650 6651 @skipIf( 6652 sys.version_info < (3, 11, 1), 6653 "Not yet backported for older versions of Python" 6654 ) 6655 def test_typevar_and_paramspec_specialization(self): 6656 T = TypeVar("T") 6657 U = TypeVar("U", default=float) 6658 P = ParamSpec('P', default=[str, int]) 6659 self.assertEqual(P.__default__, [str, int]) 6660 class A(Generic[T, U, P]): ... 6661 self.assertEqual(A[float].__args__, (float, float, (str, int))) 6662 self.assertEqual(A[float, int].__args__, (float, int, (str, int))) 6663 self.assertEqual(A[float, int, [range]].__args__, (float, int, (range,))) 6664 6665 @skipIf( 6666 sys.version_info < (3, 11, 1), 6667 "Not yet backported for older versions of Python" 6668 ) 6669 def test_paramspec_and_typevar_specialization(self): 6670 T = TypeVar("T") 6671 P = ParamSpec('P', default=[str, int]) 6672 U = TypeVar("U", default=float) 6673 self.assertEqual(P.__default__, [str, int]) 6674 class A(Generic[T, P, U]): ... 6675 self.assertEqual(A[float].__args__, (float, (str, int), float)) 6676 self.assertEqual(A[float, [range]].__args__, (float, (range,), float)) 6677 self.assertEqual(A[float, [range], int].__args__, (float, (range,), int)) 6678 6679 6680class NoDefaultTests(BaseTestCase): 6681 @skip_if_py313_beta_1 6682 def test_pickling(self): 6683 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 6684 s = pickle.dumps(NoDefault, proto) 6685 loaded = pickle.loads(s) 6686 self.assertIs(NoDefault, loaded) 6687 6688 @skip_if_py313_beta_1 6689 def test_doc(self): 6690 self.assertIsInstance(NoDefault.__doc__, str) 6691 6692 def test_constructor(self): 6693 self.assertIs(NoDefault, type(NoDefault)()) 6694 with self.assertRaises(TypeError): 6695 type(NoDefault)(1) 6696 6697 def test_repr(self): 6698 self.assertRegex(repr(NoDefault), r'typing(_extensions)?\.NoDefault') 6699 6700 def test_no_call(self): 6701 with self.assertRaises(TypeError): 6702 NoDefault() 6703 6704 @skip_if_py313_beta_1 6705 def test_immutable(self): 6706 with self.assertRaises(AttributeError): 6707 NoDefault.foo = 'bar' 6708 with self.assertRaises(AttributeError): 6709 NoDefault.foo 6710 6711 # TypeError is consistent with the behavior of NoneType 6712 with self.assertRaises(TypeError): 6713 type(NoDefault).foo = 3 6714 with self.assertRaises(AttributeError): 6715 type(NoDefault).foo 6716 6717 6718class TypeVarInferVarianceTests(BaseTestCase): 6719 def test_typevar(self): 6720 T = typing_extensions.TypeVar('T') 6721 self.assertFalse(T.__infer_variance__) 6722 T_infer = typing_extensions.TypeVar('T_infer', infer_variance=True) 6723 self.assertTrue(T_infer.__infer_variance__) 6724 T_noinfer = typing_extensions.TypeVar('T_noinfer', infer_variance=False) 6725 self.assertFalse(T_noinfer.__infer_variance__) 6726 6727 def test_pickle(self): 6728 global U, U_infer # pickle wants to reference the class by name 6729 U = typing_extensions.TypeVar('U') 6730 U_infer = typing_extensions.TypeVar('U_infer', infer_variance=True) 6731 for proto in range(pickle.HIGHEST_PROTOCOL): 6732 for typevar in (U, U_infer): 6733 z = pickle.loads(pickle.dumps(typevar, proto)) 6734 self.assertEqual(z.__name__, typevar.__name__) 6735 self.assertEqual(z.__covariant__, typevar.__covariant__) 6736 self.assertEqual(z.__contravariant__, typevar.__contravariant__) 6737 self.assertEqual(z.__bound__, typevar.__bound__) 6738 self.assertEqual(z.__infer_variance__, typevar.__infer_variance__) 6739 6740 6741class BufferTests(BaseTestCase): 6742 def test(self): 6743 self.assertIsInstance(memoryview(b''), Buffer) 6744 self.assertIsInstance(bytearray(), Buffer) 6745 self.assertIsInstance(b"x", Buffer) 6746 self.assertNotIsInstance(1, Buffer) 6747 6748 self.assertIsSubclass(bytearray, Buffer) 6749 self.assertIsSubclass(memoryview, Buffer) 6750 self.assertIsSubclass(bytes, Buffer) 6751 self.assertNotIsSubclass(int, Buffer) 6752 6753 class MyRegisteredBuffer: 6754 def __buffer__(self, flags: int) -> memoryview: 6755 return memoryview(b'') 6756 6757 # On 3.12, collections.abc.Buffer does a structural compatibility check 6758 if TYPING_3_12_0: 6759 self.assertIsInstance(MyRegisteredBuffer(), Buffer) 6760 self.assertIsSubclass(MyRegisteredBuffer, Buffer) 6761 else: 6762 self.assertNotIsInstance(MyRegisteredBuffer(), Buffer) 6763 self.assertNotIsSubclass(MyRegisteredBuffer, Buffer) 6764 Buffer.register(MyRegisteredBuffer) 6765 self.assertIsInstance(MyRegisteredBuffer(), Buffer) 6766 self.assertIsSubclass(MyRegisteredBuffer, Buffer) 6767 6768 class MySubclassedBuffer(Buffer): 6769 def __buffer__(self, flags: int) -> memoryview: 6770 return memoryview(b'') 6771 6772 self.assertIsInstance(MySubclassedBuffer(), Buffer) 6773 self.assertIsSubclass(MySubclassedBuffer, Buffer) 6774 6775 6776class GetOriginalBasesTests(BaseTestCase): 6777 def test_basics(self): 6778 T = TypeVar('T') 6779 class A: pass 6780 class B(Generic[T]): pass 6781 class C(B[int]): pass 6782 class D(B[str], float): pass 6783 self.assertEqual(get_original_bases(A), (object,)) 6784 self.assertEqual(get_original_bases(B), (Generic[T],)) 6785 self.assertEqual(get_original_bases(C), (B[int],)) 6786 self.assertEqual(get_original_bases(int), (object,)) 6787 self.assertEqual(get_original_bases(D), (B[str], float)) 6788 6789 with self.assertRaisesRegex(TypeError, "Expected an instance of type"): 6790 get_original_bases(object()) 6791 6792 @skipUnless(TYPING_3_9_0, "PEP 585 is yet to be") 6793 def test_builtin_generics(self): 6794 class E(list[T]): pass 6795 class F(list[int]): pass 6796 6797 self.assertEqual(get_original_bases(E), (list[T],)) 6798 self.assertEqual(get_original_bases(F), (list[int],)) 6799 6800 @skipIf( 6801 sys.version_info[:3] == (3, 12, 0) and sys.version_info[3] in {"alpha", "beta"}, 6802 "Early versions of py312 had a bug" 6803 ) 6804 def test_concrete_subclasses_of_generic_classes(self): 6805 T = TypeVar("T") 6806 6807 class FirstBase(Generic[T]): pass 6808 class SecondBase(Generic[T]): pass 6809 class First(FirstBase[int]): pass 6810 class Second(SecondBase[int]): pass 6811 class G(First, Second): pass 6812 self.assertEqual(get_original_bases(G), (First, Second)) 6813 6814 class First_(Generic[T]): pass 6815 class Second_(Generic[T]): pass 6816 class H(First_, Second_): pass 6817 self.assertEqual(get_original_bases(H), (First_, Second_)) 6818 6819 def test_namedtuples(self): 6820 # On 3.12, this should work well with typing.NamedTuple and typing_extensions.NamedTuple 6821 # On lower versions, it will only work fully with typing_extensions.NamedTuple 6822 if sys.version_info >= (3, 12): 6823 namedtuple_classes = (typing.NamedTuple, typing_extensions.NamedTuple) 6824 else: 6825 namedtuple_classes = (typing_extensions.NamedTuple,) 6826 6827 for NamedTuple in namedtuple_classes: # noqa: F402 6828 with self.subTest(cls=NamedTuple): 6829 class ClassBasedNamedTuple(NamedTuple): 6830 x: int 6831 6832 class GenericNamedTuple(NamedTuple, Generic[T]): 6833 x: T 6834 6835 CallBasedNamedTuple = NamedTuple("CallBasedNamedTuple", [("x", int)]) 6836 6837 self.assertIs( 6838 get_original_bases(ClassBasedNamedTuple)[0], NamedTuple 6839 ) 6840 self.assertEqual( 6841 get_original_bases(GenericNamedTuple), 6842 (NamedTuple, Generic[T]) 6843 ) 6844 self.assertIs( 6845 get_original_bases(CallBasedNamedTuple)[0], NamedTuple 6846 ) 6847 6848 def test_typeddicts(self): 6849 # On 3.12, this should work well with typing.TypedDict and typing_extensions.TypedDict 6850 # On lower versions, it will only work fully with typing_extensions.TypedDict 6851 if sys.version_info >= (3, 12): 6852 typeddict_classes = (typing.TypedDict, typing_extensions.TypedDict) 6853 else: 6854 typeddict_classes = (typing_extensions.TypedDict,) 6855 6856 for TypedDict in typeddict_classes: # noqa: F402 6857 with self.subTest(cls=TypedDict): 6858 class ClassBasedTypedDict(TypedDict): 6859 x: int 6860 6861 class GenericTypedDict(TypedDict, Generic[T]): 6862 x: T 6863 6864 CallBasedTypedDict = TypedDict("CallBasedTypedDict", {"x": int}) 6865 6866 self.assertIs( 6867 get_original_bases(ClassBasedTypedDict)[0], 6868 TypedDict 6869 ) 6870 self.assertEqual( 6871 get_original_bases(GenericTypedDict), 6872 (TypedDict, Generic[T]) 6873 ) 6874 self.assertIs( 6875 get_original_bases(CallBasedTypedDict)[0], 6876 TypedDict 6877 ) 6878 6879 6880class TypeAliasTypeTests(BaseTestCase): 6881 def test_attributes(self): 6882 Simple = TypeAliasType("Simple", int) 6883 self.assertEqual(Simple.__name__, "Simple") 6884 self.assertIs(Simple.__value__, int) 6885 self.assertEqual(Simple.__type_params__, ()) 6886 self.assertEqual(Simple.__parameters__, ()) 6887 6888 T = TypeVar("T") 6889 ListOrSetT = TypeAliasType("ListOrSetT", Union[List[T], Set[T]], type_params=(T,)) 6890 self.assertEqual(ListOrSetT.__name__, "ListOrSetT") 6891 self.assertEqual(ListOrSetT.__value__, Union[List[T], Set[T]]) 6892 self.assertEqual(ListOrSetT.__type_params__, (T,)) 6893 self.assertEqual(ListOrSetT.__parameters__, (T,)) 6894 6895 Ts = TypeVarTuple("Ts") 6896 Variadic = TypeAliasType("Variadic", Tuple[int, Unpack[Ts]], type_params=(Ts,)) 6897 self.assertEqual(Variadic.__name__, "Variadic") 6898 self.assertEqual(Variadic.__value__, Tuple[int, Unpack[Ts]]) 6899 self.assertEqual(Variadic.__type_params__, (Ts,)) 6900 self.assertEqual(Variadic.__parameters__, tuple(iter(Ts))) 6901 6902 def test_cannot_set_attributes(self): 6903 Simple = TypeAliasType("Simple", int) 6904 with self.assertRaisesRegex(AttributeError, "readonly attribute"): 6905 Simple.__name__ = "NewName" 6906 with self.assertRaisesRegex( 6907 AttributeError, 6908 "attribute '__value__' of 'typing.TypeAliasType' objects is not writable", 6909 ): 6910 Simple.__value__ = str 6911 with self.assertRaisesRegex( 6912 AttributeError, 6913 "attribute '__type_params__' of 'typing.TypeAliasType' objects is not writable", 6914 ): 6915 Simple.__type_params__ = (T,) 6916 with self.assertRaisesRegex( 6917 AttributeError, 6918 "attribute '__parameters__' of 'typing.TypeAliasType' objects is not writable", 6919 ): 6920 Simple.__parameters__ = (T,) 6921 with self.assertRaisesRegex( 6922 AttributeError, 6923 "attribute '__module__' of 'typing.TypeAliasType' objects is not writable", 6924 ): 6925 Simple.__module__ = 42 6926 with self.assertRaisesRegex( 6927 AttributeError, 6928 "'typing.TypeAliasType' object has no attribute 'some_attribute'", 6929 ): 6930 Simple.some_attribute = "not allowed" 6931 6932 def test_cannot_delete_attributes(self): 6933 Simple = TypeAliasType("Simple", int) 6934 with self.assertRaisesRegex(AttributeError, "readonly attribute"): 6935 del Simple.__name__ 6936 with self.assertRaisesRegex( 6937 AttributeError, 6938 "attribute '__value__' of 'typing.TypeAliasType' objects is not writable", 6939 ): 6940 del Simple.__value__ 6941 with self.assertRaisesRegex( 6942 AttributeError, 6943 "'typing.TypeAliasType' object has no attribute 'some_attribute'", 6944 ): 6945 del Simple.some_attribute 6946 6947 def test_or(self): 6948 Alias = TypeAliasType("Alias", int) 6949 if sys.version_info >= (3, 10): 6950 self.assertEqual(Alias | int, Union[Alias, int]) 6951 self.assertEqual(Alias | None, Union[Alias, None]) 6952 self.assertEqual(Alias | (int | str), Union[Alias, int | str]) 6953 self.assertEqual(Alias | list[float], Union[Alias, list[float]]) 6954 else: 6955 with self.assertRaises(TypeError): 6956 Alias | int 6957 # Rejected on all versions 6958 with self.assertRaises(TypeError): 6959 Alias | "Ref" 6960 6961 def test_getitem(self): 6962 ListOrSetT = TypeAliasType("ListOrSetT", Union[List[T], Set[T]], type_params=(T,)) 6963 subscripted = ListOrSetT[int] 6964 self.assertEqual(get_args(subscripted), (int,)) 6965 self.assertIs(get_origin(subscripted), ListOrSetT) 6966 with self.assertRaises(TypeError): 6967 subscripted[str] 6968 6969 still_generic = ListOrSetT[Iterable[T]] 6970 self.assertEqual(get_args(still_generic), (Iterable[T],)) 6971 self.assertIs(get_origin(still_generic), ListOrSetT) 6972 fully_subscripted = still_generic[float] 6973 self.assertEqual(get_args(fully_subscripted), (Iterable[float],)) 6974 self.assertIs(get_origin(fully_subscripted), ListOrSetT) 6975 6976 def test_pickle(self): 6977 global Alias 6978 Alias = TypeAliasType("Alias", int) 6979 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 6980 with self.subTest(proto=proto): 6981 pickled = pickle.dumps(Alias, proto) 6982 unpickled = pickle.loads(pickled) 6983 self.assertIs(unpickled, Alias) 6984 6985 def test_no_instance_subclassing(self): 6986 with self.assertRaises(TypeError): 6987 class MyAlias(TypeAliasType): 6988 pass 6989 6990 6991class DocTests(BaseTestCase): 6992 def test_annotation(self): 6993 6994 def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: pass 6995 6996 hints = get_type_hints(hi, include_extras=True) 6997 doc_info = hints["to"].__metadata__[0] 6998 self.assertEqual(doc_info.documentation, "Who to say hi to") 6999 self.assertIsInstance(doc_info, Doc) 7000 7001 def test_repr(self): 7002 doc_info = Doc("Who to say hi to") 7003 self.assertEqual(repr(doc_info), "Doc('Who to say hi to')") 7004 7005 def test_hashability(self): 7006 doc_info = Doc("Who to say hi to") 7007 self.assertIsInstance(hash(doc_info), int) 7008 self.assertNotEqual(hash(doc_info), hash(Doc("Who not to say hi to"))) 7009 7010 def test_equality(self): 7011 doc_info = Doc("Who to say hi to") 7012 # Equal to itself 7013 self.assertEqual(doc_info, doc_info) 7014 # Equal to another instance with the same string 7015 self.assertEqual(doc_info, Doc("Who to say hi to")) 7016 # Not equal to another instance with a different string 7017 self.assertNotEqual(doc_info, Doc("Who not to say hi to")) 7018 7019 def test_pickle(self): 7020 doc_info = Doc("Who to say hi to") 7021 for proto in range(pickle.HIGHEST_PROTOCOL): 7022 pickled = pickle.dumps(doc_info, protocol=proto) 7023 self.assertEqual(doc_info, pickle.loads(pickled)) 7024 7025 7026@skipUnless( 7027 hasattr(typing_extensions, "CapsuleType"), 7028 "CapsuleType is not available on all Python implementations" 7029) 7030class CapsuleTypeTests(BaseTestCase): 7031 def test_capsule_type(self): 7032 import _datetime 7033 self.assertIsInstance(_datetime.datetime_CAPI, typing_extensions.CapsuleType) 7034 7035 7036if __name__ == '__main__': 7037 main() 7038