1 """
2 Define names for built-in types that aren't directly accessible as a builtin.
3 """
4 import sys
5
6 # Iterators in Python aren't a matter of type but of protocol. A large
7 # and changing number of builtin types implement *some* flavor of
8 # iterator. Don't check the type! Use hasattr to check for both
9 # "__iter__" and "__next__" attributes instead.
10
11 def _f(): pass
12 FunctionType = type(_f)
13 LambdaType = type(lambda: None) # Same as FunctionType
14 CodeType = type(_f.__code__)
15 MappingProxyType = type(type.__dict__)
16 SimpleNamespace = type(sys.implementation)
17
18 def _cell_factory():
19 a = 1
20 def f():
21 nonlocal a
22 return f.__closure__[0]
23 CellType = type(_cell_factory())
24
25 def _g():
26 yield 1
27 GeneratorType = type(_g())
28
29 async def _c(): pass
30 _c = _c()
31 CoroutineType = type(_c)
32 _c.close() # Prevent ResourceWarning
33
34 async def _ag():
35 yield
36 _ag = _ag()
37 AsyncGeneratorType = type(_ag)
38
39 class ESC[4;38;5;81m_C:
40 def _m(self): pass
41 MethodType = type(_C()._m)
42
43 BuiltinFunctionType = type(len)
44 BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
45
46 WrapperDescriptorType = type(object.__init__)
47 MethodWrapperType = type(object().__str__)
48 MethodDescriptorType = type(str.join)
49 ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
50
51 ModuleType = type(sys)
52
53 try:
54 raise TypeError
55 except TypeError as exc:
56 TracebackType = type(exc.__traceback__)
57 FrameType = type(exc.__traceback__.tb_frame)
58
59 GetSetDescriptorType = type(FunctionType.__code__)
60 MemberDescriptorType = type(FunctionType.__globals__)
61
62 del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
63
64
65 # Provide a PEP 3115 compliant mechanism for class creation
66 def new_class(name, bases=(), kwds=None, exec_body=None):
67 """Create a class object dynamically using the appropriate metaclass."""
68 resolved_bases = resolve_bases(bases)
69 meta, ns, kwds = prepare_class(name, resolved_bases, kwds)
70 if exec_body is not None:
71 exec_body(ns)
72 if resolved_bases is not bases:
73 ns['__orig_bases__'] = bases
74 return meta(name, resolved_bases, ns, **kwds)
75
76 def resolve_bases(bases):
77 """Resolve MRO entries dynamically as specified by PEP 560."""
78 new_bases = list(bases)
79 updated = False
80 shift = 0
81 for i, base in enumerate(bases):
82 if isinstance(base, type):
83 continue
84 if not hasattr(base, "__mro_entries__"):
85 continue
86 new_base = base.__mro_entries__(bases)
87 updated = True
88 if not isinstance(new_base, tuple):
89 raise TypeError("__mro_entries__ must return a tuple")
90 else:
91 new_bases[i+shift:i+shift+1] = new_base
92 shift += len(new_base) - 1
93 if not updated:
94 return bases
95 return tuple(new_bases)
96
97 def prepare_class(name, bases=(), kwds=None):
98 """Call the __prepare__ method of the appropriate metaclass.
99
100 Returns (metaclass, namespace, kwds) as a 3-tuple
101
102 *metaclass* is the appropriate metaclass
103 *namespace* is the prepared class namespace
104 *kwds* is an updated copy of the passed in kwds argument with any
105 'metaclass' entry removed. If no kwds argument is passed in, this will
106 be an empty dict.
107 """
108 if kwds is None:
109 kwds = {}
110 else:
111 kwds = dict(kwds) # Don't alter the provided mapping
112 if 'metaclass' in kwds:
113 meta = kwds.pop('metaclass')
114 else:
115 if bases:
116 meta = type(bases[0])
117 else:
118 meta = type
119 if isinstance(meta, type):
120 # when meta is a type, we first determine the most-derived metaclass
121 # instead of invoking the initial candidate directly
122 meta = _calculate_meta(meta, bases)
123 if hasattr(meta, '__prepare__'):
124 ns = meta.__prepare__(name, bases, **kwds)
125 else:
126 ns = {}
127 return meta, ns, kwds
128
129 def _calculate_meta(meta, bases):
130 """Calculate the most derived metaclass."""
131 winner = meta
132 for base in bases:
133 base_meta = type(base)
134 if issubclass(winner, base_meta):
135 continue
136 if issubclass(base_meta, winner):
137 winner = base_meta
138 continue
139 # else:
140 raise TypeError("metaclass conflict: "
141 "the metaclass of a derived class "
142 "must be a (non-strict) subclass "
143 "of the metaclasses of all its bases")
144 return winner
145
146
147 def get_original_bases(cls, /):
148 """Return the class's "original" bases prior to modification by `__mro_entries__`.
149
150 Examples::
151
152 from typing import TypeVar, Generic, NamedTuple, TypedDict
153
154 T = TypeVar("T")
155 class Foo(Generic[T]): ...
156 class Bar(Foo[int], float): ...
157 class Baz(list[str]): ...
158 Eggs = NamedTuple("Eggs", [("a", int), ("b", str)])
159 Spam = TypedDict("Spam", {"a": int, "b": str})
160
161 assert get_original_bases(Bar) == (Foo[int], float)
162 assert get_original_bases(Baz) == (list[str],)
163 assert get_original_bases(Eggs) == (NamedTuple,)
164 assert get_original_bases(Spam) == (TypedDict,)
165 assert get_original_bases(int) == (object,)
166 """
167 try:
168 return cls.__dict__.get("__orig_bases__", cls.__bases__)
169 except AttributeError:
170 raise TypeError(
171 f"Expected an instance of type, not {type(cls).__name__!r}"
172 ) from None
173
174
175 class ESC[4;38;5;81mDynamicClassAttribute:
176 """Route attribute access on a class to __getattr__.
177
178 This is a descriptor, used to define attributes that act differently when
179 accessed through an instance and through a class. Instance access remains
180 normal, but access to an attribute through a class will be routed to the
181 class's __getattr__ method; this is done by raising AttributeError.
182
183 This allows one to have properties active on an instance, and have virtual
184 attributes on the class with the same name. (Enum used this between Python
185 versions 3.4 - 3.9 .)
186
187 Subclass from this to use a different method of accessing virtual attributes
188 and still be treated properly by the inspect module. (Enum uses this since
189 Python 3.10 .)
190
191 """
192 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
193 self.fget = fget
194 self.fset = fset
195 self.fdel = fdel
196 # next two lines make DynamicClassAttribute act the same as property
197 self.__doc__ = doc or fget.__doc__
198 self.overwrite_doc = doc is None
199 # support for abstract methods
200 self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False))
201
202 def __get__(self, instance, ownerclass=None):
203 if instance is None:
204 if self.__isabstractmethod__:
205 return self
206 raise AttributeError()
207 elif self.fget is None:
208 raise AttributeError("unreadable attribute")
209 return self.fget(instance)
210
211 def __set__(self, instance, value):
212 if self.fset is None:
213 raise AttributeError("can't set attribute")
214 self.fset(instance, value)
215
216 def __delete__(self, instance):
217 if self.fdel is None:
218 raise AttributeError("can't delete attribute")
219 self.fdel(instance)
220
221 def getter(self, fget):
222 fdoc = fget.__doc__ if self.overwrite_doc else None
223 result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__)
224 result.overwrite_doc = self.overwrite_doc
225 return result
226
227 def setter(self, fset):
228 result = type(self)(self.fget, fset, self.fdel, self.__doc__)
229 result.overwrite_doc = self.overwrite_doc
230 return result
231
232 def deleter(self, fdel):
233 result = type(self)(self.fget, self.fset, fdel, self.__doc__)
234 result.overwrite_doc = self.overwrite_doc
235 return result
236
237
238 class ESC[4;38;5;81m_GeneratorWrapper:
239 # TODO: Implement this in C.
240 def __init__(self, gen):
241 self.__wrapped = gen
242 self.__isgen = gen.__class__ is GeneratorType
243 self.__name__ = getattr(gen, '__name__', None)
244 self.__qualname__ = getattr(gen, '__qualname__', None)
245 def send(self, val):
246 return self.__wrapped.send(val)
247 def throw(self, tp, *rest):
248 return self.__wrapped.throw(tp, *rest)
249 def close(self):
250 return self.__wrapped.close()
251 @property
252 def gi_code(self):
253 return self.__wrapped.gi_code
254 @property
255 def gi_frame(self):
256 return self.__wrapped.gi_frame
257 @property
258 def gi_running(self):
259 return self.__wrapped.gi_running
260 @property
261 def gi_yieldfrom(self):
262 return self.__wrapped.gi_yieldfrom
263 cr_code = gi_code
264 cr_frame = gi_frame
265 cr_running = gi_running
266 cr_await = gi_yieldfrom
267 def __next__(self):
268 return next(self.__wrapped)
269 def __iter__(self):
270 if self.__isgen:
271 return self.__wrapped
272 return self
273 __await__ = __iter__
274
275 def coroutine(func):
276 """Convert regular generator function to a coroutine."""
277
278 if not callable(func):
279 raise TypeError('types.coroutine() expects a callable')
280
281 if (func.__class__ is FunctionType and
282 getattr(func, '__code__', None).__class__ is CodeType):
283
284 co_flags = func.__code__.co_flags
285
286 # Check if 'func' is a coroutine function.
287 # (0x180 == CO_COROUTINE | CO_ITERABLE_COROUTINE)
288 if co_flags & 0x180:
289 return func
290
291 # Check if 'func' is a generator function.
292 # (0x20 == CO_GENERATOR)
293 if co_flags & 0x20:
294 # TODO: Implement this in C.
295 co = func.__code__
296 # 0x100 == CO_ITERABLE_COROUTINE
297 func.__code__ = co.replace(co_flags=co.co_flags | 0x100)
298 return func
299
300 # The following code is primarily to support functions that
301 # return generator-like objects (for instance generators
302 # compiled with Cython).
303
304 # Delay functools and _collections_abc import for speeding up types import.
305 import functools
306 import _collections_abc
307 @functools.wraps(func)
308 def wrapped(*args, **kwargs):
309 coro = func(*args, **kwargs)
310 if (coro.__class__ is CoroutineType or
311 coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100):
312 # 'coro' is a native coroutine object or an iterable coroutine
313 return coro
314 if (isinstance(coro, _collections_abc.Generator) and
315 not isinstance(coro, _collections_abc.Coroutine)):
316 # 'coro' is either a pure Python generator iterator, or it
317 # implements collections.abc.Generator (and does not implement
318 # collections.abc.Coroutine).
319 return _GeneratorWrapper(coro)
320 # 'coro' is either an instance of collections.abc.Coroutine or
321 # some other object -- pass it through.
322 return coro
323
324 return wrapped
325
326 GenericAlias = type(list[int])
327 UnionType = type(int | str)
328
329 EllipsisType = type(Ellipsis)
330 NoneType = type(None)
331 NotImplementedType = type(NotImplemented)
332
333 __all__ = [n for n in globals() if n[:1] != '_']