| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2017-12-16 11:25:56 +02:00
										 |  |  | from test import support | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  | from test.support.import_helper import import_module | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestMROEntry(unittest.TestCase): | 
					
						
							|  |  |  |     def test_mro_entry_signature(self): | 
					
						
							|  |  |  |         tested = [] | 
					
						
							|  |  |  |         class B: ... | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, *args, **kwargs): | 
					
						
							|  |  |  |                 tested.extend([args, kwargs]) | 
					
						
							|  |  |  |                 return (C,) | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         self.assertEqual(tested, []) | 
					
						
							|  |  |  |         class D(B, c): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[0], ((B, c),)) | 
					
						
							|  |  |  |         self.assertEqual(tested[1], {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry(self): | 
					
						
							|  |  |  |         tested = [] | 
					
						
							|  |  |  |         class A: ... | 
					
						
							|  |  |  |         class B: ... | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases): | 
					
						
							|  |  |  |                 tested.append(bases) | 
					
						
							|  |  |  |                 return (self.__class__,) | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         self.assertEqual(tested, []) | 
					
						
							|  |  |  |         class D(A, c, B): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[-1], (A, c, B)) | 
					
						
							|  |  |  |         self.assertEqual(D.__bases__, (A, C, B)) | 
					
						
							|  |  |  |         self.assertEqual(D.__orig_bases__, (A, c, B)) | 
					
						
							|  |  |  |         self.assertEqual(D.__mro__, (D, A, C, B, object)) | 
					
						
							|  |  |  |         d = D() | 
					
						
							|  |  |  |         class E(d): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[-1], (d,)) | 
					
						
							|  |  |  |         self.assertEqual(E.__bases__, (D,)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_none(self): | 
					
						
							|  |  |  |         tested = [] | 
					
						
							|  |  |  |         class A: ... | 
					
						
							|  |  |  |         class B: ... | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases): | 
					
						
							|  |  |  |                 tested.append(bases) | 
					
						
							|  |  |  |                 return () | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         self.assertEqual(tested, []) | 
					
						
							|  |  |  |         class D(A, c, B): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[-1], (A, c, B)) | 
					
						
							|  |  |  |         self.assertEqual(D.__bases__, (A, B)) | 
					
						
							|  |  |  |         self.assertEqual(D.__orig_bases__, (A, c, B)) | 
					
						
							|  |  |  |         self.assertEqual(D.__mro__, (D, A, B, object)) | 
					
						
							|  |  |  |         class E(c): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[-1], (c,)) | 
					
						
							|  |  |  |         self.assertEqual(E.__bases__, (object,)) | 
					
						
							|  |  |  |         self.assertEqual(E.__orig_bases__, (c,)) | 
					
						
							|  |  |  |         self.assertEqual(E.__mro__, (E, object)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_with_builtins(self): | 
					
						
							|  |  |  |         tested = [] | 
					
						
							|  |  |  |         class A: ... | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases): | 
					
						
							|  |  |  |                 tested.append(bases) | 
					
						
							|  |  |  |                 return (dict,) | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         self.assertEqual(tested, []) | 
					
						
							|  |  |  |         class D(A, c): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[-1], (A, c)) | 
					
						
							|  |  |  |         self.assertEqual(D.__bases__, (A, dict)) | 
					
						
							|  |  |  |         self.assertEqual(D.__orig_bases__, (A, c)) | 
					
						
							|  |  |  |         self.assertEqual(D.__mro__, (D, A, dict, object)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_with_builtins_2(self): | 
					
						
							|  |  |  |         tested = [] | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases): | 
					
						
							|  |  |  |                 tested.append(bases) | 
					
						
							|  |  |  |                 return (C,) | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         self.assertEqual(tested, []) | 
					
						
							|  |  |  |         class D(c, dict): ... | 
					
						
							|  |  |  |         self.assertEqual(tested[-1], (c, dict)) | 
					
						
							|  |  |  |         self.assertEqual(D.__bases__, (C, dict)) | 
					
						
							|  |  |  |         self.assertEqual(D.__orig_bases__, (c, dict)) | 
					
						
							|  |  |  |         self.assertEqual(D.__mro__, (D, C, dict, object)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_errors(self): | 
					
						
							|  |  |  |         class C_too_many: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases, something, other): | 
					
						
							|  |  |  |                 return () | 
					
						
							|  |  |  |         c = C_too_many() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             class D(c): ... | 
					
						
							|  |  |  |         class C_too_few: | 
					
						
							|  |  |  |             def __mro_entries__(self): | 
					
						
							|  |  |  |                 return () | 
					
						
							|  |  |  |         d = C_too_few() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							| 
									
										
										
										
											2023-10-16 15:57:01 +01:00
										 |  |  |             class E(d): ... | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_errors_2(self): | 
					
						
							|  |  |  |         class C_not_callable: | 
					
						
							|  |  |  |             __mro_entries__ = "Surprise!" | 
					
						
							|  |  |  |         c = C_not_callable() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             class D(c): ... | 
					
						
							|  |  |  |         class C_not_tuple: | 
					
						
							|  |  |  |             def __mro_entries__(self): | 
					
						
							|  |  |  |                 return object | 
					
						
							|  |  |  |         c = C_not_tuple() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							| 
									
										
										
										
											2023-10-16 15:57:01 +01:00
										 |  |  |             class E(c): ... | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_metaclass(self): | 
					
						
							|  |  |  |         meta_args = [] | 
					
						
							|  |  |  |         class Meta(type): | 
					
						
							|  |  |  |             def __new__(mcls, name, bases, ns): | 
					
						
							|  |  |  |                 meta_args.extend([mcls, name, bases, ns]) | 
					
						
							|  |  |  |                 return super().__new__(mcls, name, bases, ns) | 
					
						
							|  |  |  |         class A: ... | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases): | 
					
						
							|  |  |  |                 return (A,) | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         class D(c, metaclass=Meta): | 
					
						
							|  |  |  |             x = 1 | 
					
						
							|  |  |  |         self.assertEqual(meta_args[0], Meta) | 
					
						
							|  |  |  |         self.assertEqual(meta_args[1], 'D') | 
					
						
							|  |  |  |         self.assertEqual(meta_args[2], (A,)) | 
					
						
							|  |  |  |         self.assertEqual(meta_args[3]['x'], 1) | 
					
						
							|  |  |  |         self.assertEqual(D.__bases__, (A,)) | 
					
						
							|  |  |  |         self.assertEqual(D.__orig_bases__, (c,)) | 
					
						
							|  |  |  |         self.assertEqual(D.__mro__, (D, A, object)) | 
					
						
							|  |  |  |         self.assertEqual(D.__class__, Meta) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mro_entry_type_call(self): | 
					
						
							|  |  |  |         # Substitution should _not_ happen in direct type call | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __mro_entries__(self, bases): | 
					
						
							|  |  |  |                 return () | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, | 
					
						
							|  |  |  |                                     "MRO entry resolution; " | 
					
						
							|  |  |  |                                     "use types.new_class()"): | 
					
						
							|  |  |  |             type('Bad', (c,), {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestClassGetitem(unittest.TestCase): | 
					
						
							|  |  |  |     def test_class_getitem(self): | 
					
						
							|  |  |  |         getitem_args = [] | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __class_getitem__(*args, **kwargs): | 
					
						
							|  |  |  |                 getitem_args.extend([args, kwargs]) | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |         C[int, str] | 
					
						
							|  |  |  |         self.assertEqual(getitem_args[0], (C, (int, str))) | 
					
						
							|  |  |  |         self.assertEqual(getitem_args[1], {}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-23 02:51:06 +08:00
										 |  |  |     def test_class_getitem_format(self): | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |         class C: | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return f'C[{item.__name__}]' | 
					
						
							|  |  |  |         self.assertEqual(C[int], 'C[int]') | 
					
						
							|  |  |  |         self.assertEqual(C[C], 'C[C]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_class_getitem_inheritance(self): | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return f'{cls.__name__}[{item.__name__}]' | 
					
						
							|  |  |  |         class D(C): ... | 
					
						
							|  |  |  |         self.assertEqual(D[int], 'D[int]') | 
					
						
							|  |  |  |         self.assertEqual(D[D], 'D[D]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_class_getitem_inheritance_2(self): | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return 'Should not see this' | 
					
						
							|  |  |  |         class D(C): | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return f'{cls.__name__}[{item.__name__}]' | 
					
						
							|  |  |  |         self.assertEqual(D[int], 'D[int]') | 
					
						
							|  |  |  |         self.assertEqual(D[D], 'D[D]') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-05 00:21:41 +02:00
										 |  |  |     def test_class_getitem_classmethod(self): | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             @classmethod | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return f'{cls.__name__}[{item.__name__}]' | 
					
						
							|  |  |  |         class D(C): ... | 
					
						
							|  |  |  |         self.assertEqual(D[int], 'D[int]') | 
					
						
							|  |  |  |         self.assertEqual(D[D], 'D[D]') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |     def test_class_getitem_patched(self): | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __init_subclass__(cls): | 
					
						
							|  |  |  |                 def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                     return f'{cls.__name__}[{item.__name__}]' | 
					
						
							| 
									
										
										
										
											2018-01-05 00:21:41 +02:00
										 |  |  |                 cls.__class_getitem__ = classmethod(__class_getitem__) | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |         class D(C): ... | 
					
						
							|  |  |  |         self.assertEqual(D[int], 'D[int]') | 
					
						
							|  |  |  |         self.assertEqual(D[D], 'D[D]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_class_getitem_with_builtins(self): | 
					
						
							|  |  |  |         class A(dict): | 
					
						
							|  |  |  |             called_with = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 cls.called_with = item | 
					
						
							|  |  |  |         class B(A): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         self.assertIs(B.called_with, None) | 
					
						
							|  |  |  |         B[int] | 
					
						
							|  |  |  |         self.assertIs(B.called_with, int) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_class_getitem_errors(self): | 
					
						
							|  |  |  |         class C_too_few: | 
					
						
							|  |  |  |             def __class_getitem__(cls): | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             C_too_few[int] | 
					
						
							| 
									
										
										
										
											2022-05-02 08:29:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |         class C_too_many: | 
					
						
							|  |  |  |             def __class_getitem__(cls, one, two): | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             C_too_many[int] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_class_getitem_errors_2(self): | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             C()[int] | 
					
						
							| 
									
										
										
										
											2022-05-02 08:29:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |         class E: ... | 
					
						
							|  |  |  |         e = E() | 
					
						
							|  |  |  |         e.__class_getitem__ = lambda cls, item: 'This will not work' | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             e[int] | 
					
						
							| 
									
										
										
										
											2022-05-02 08:29:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |         class C_not_callable: | 
					
						
							|  |  |  |             __class_getitem__ = "Surprise!" | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             C_not_callable[int] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-02 08:29:49 +03:00
										 |  |  |         class C_is_none(tuple): | 
					
						
							|  |  |  |             __class_getitem__ = None | 
					
						
							|  |  |  |         with self.assertRaisesRegex(TypeError, "C_is_none"): | 
					
						
							|  |  |  |             C_is_none[int] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |     def test_class_getitem_metaclass(self): | 
					
						
							|  |  |  |         class Meta(type): | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return f'{cls.__name__}[{item.__name__}]' | 
					
						
							|  |  |  |         self.assertEqual(Meta[int], 'Meta[int]') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-17 23:13:46 +00:00
										 |  |  |     def test_class_getitem_with_metaclass(self): | 
					
						
							|  |  |  |         class Meta(type): pass | 
					
						
							|  |  |  |         class C(metaclass=Meta): | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return f'{cls.__name__}[{item.__name__}]' | 
					
						
							|  |  |  |         self.assertEqual(C[int], 'C[int]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_class_getitem_metaclass_first(self): | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  |         class Meta(type): | 
					
						
							|  |  |  |             def __getitem__(cls, item): | 
					
						
							|  |  |  |                 return 'from metaclass' | 
					
						
							|  |  |  |         class C(metaclass=Meta): | 
					
						
							|  |  |  |             def __class_getitem__(cls, item): | 
					
						
							|  |  |  |                 return 'from __class_getitem__' | 
					
						
							|  |  |  |         self.assertEqual(C[int], 'from metaclass') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-16 11:25:56 +02:00
										 |  |  | @support.cpython_only | 
					
						
							|  |  |  | class CAPITest(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_c_class(self): | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  |         _testcapi = import_module("_testcapi") | 
					
						
							|  |  |  |         Generic = _testcapi.Generic | 
					
						
							|  |  |  |         GenericAlias = _testcapi.GenericAlias | 
					
						
							| 
									
										
										
										
											2018-01-05 00:21:41 +02:00
										 |  |  |         self.assertIsInstance(Generic.__class_getitem__(int), GenericAlias) | 
					
						
							| 
									
										
										
										
											2017-12-16 11:25:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         IntGeneric = Generic[int] | 
					
						
							|  |  |  |         self.assertIs(type(IntGeneric), GenericAlias) | 
					
						
							|  |  |  |         self.assertEqual(IntGeneric.__mro_entries__(()), (int,)) | 
					
						
							|  |  |  |         class C(IntGeneric): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         self.assertEqual(C.__bases__, (int,)) | 
					
						
							|  |  |  |         self.assertEqual(C.__orig_bases__, (IntGeneric,)) | 
					
						
							|  |  |  |         self.assertEqual(C.__mro__, (C, int, object)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-14 23:32:56 +01:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |