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 # For Jython, the following two types are identical
60 GetSetDescriptorType = type(FunctionType.__code__)
61 MemberDescriptorType = type(FunctionType.__globals__)
62
63 del sys, _f, _g, _C, _c, _ag # Not for export
64
65
66 # Provide a PEP 3115 compliant mechanism for class creation
67 def new_class(name, bases=(), kwds=None, exec_body=None):
68 """Create a class object dynamically using the appropriate metaclass."""
69 resolved_bases = resolve_bases(bases)
70 meta, ns, kwds = prepare_class(name, resolved_bases, kwds)
71 if exec_body is not None:
72 exec_body(ns)
73 if resolved_bases is not bases:
74 ns['__orig_bases__'] = bases
75 return meta(name, resolved_bases, ns, **kwds)
76
77 def resolve_bases(bases):
78 """Resolve MRO entries dynamically as specified by PEP 560."""
79 new_bases = list(bases)
80 updated = False
81 shift = 0
82 for i, base in enumerate(bases):
83 if isinstance(base, type):
84 continue
85 if not hasattr(base, "__mro_entries__"):
86 continue
87 new_base = base.__mro_entries__(bases)
88 updated = True
89 if not isinstance(new_base, tuple):
90 raise TypeError("__mro_entries__ must return a tuple")
91 else:
92 new_bases[i+shift:i+shift+1] = new_base
93 shift += len(new_base) - 1
94 if not updated:
95 return bases
96 return tuple(new_bases)
97
98 def prepare_class(name, bases=(), kwds=None):
99 """Call the __prepare__ method of the appropriate metaclass.
100
101 Returns (metaclass, namespace, kwds) as a 3-tuple
102
103 *metaclass* is the appropriate metaclass
104 *namespace* is the prepared class namespace
105 *kwds* is an updated copy of the passed in kwds argument with any
106 'metaclass' entry removed. If no kwds argument is passed in, this will
107 be an empty dict.
108 """
109 if kwds is None:
110 kwds = {}
111 else:
112 kwds = dict(kwds) # Don't alter the provided mapping
113 if 'metaclass' in kwds:
114 meta = kwds.pop('metaclass')
115 else:
116 if bases:
117 meta = type(bases[0])
118 else:
119 meta = type
120 if isinstance(meta, type):
121 # when meta is a type, we first determine the most-derived metaclass
122 # instead of invoking the initial candidate directly
123 meta = _calculate_meta(meta, bases)
124 if hasattr(meta, '__prepare__'):
125 ns = meta.__prepare__(name, bases, **kwds)
126 else:
127 ns = {}
128 return meta, ns, kwds
129
130 def _calculate_meta(meta, bases):
131 """Calculate the most derived metaclass."""
132 winner = meta
133 for base in bases:
134 base_meta = type(base)
135 if issubclass(winner, base_meta):
136 continue
137 if issubclass(base_meta, winner):
138 winner = base_meta
139 continue
140 # else:
141 raise TypeError("metaclass conflict: "
142 "the metaclass of a derived class "
143 "must be a (non-strict) subclass "
144 "of the metaclasses of all its bases")
145 return winner
146
147 class ESC[4;38;5;81mDynamicClassAttribute:
148 """Route attribute access on a class to __getattr__.
149
150 This is a descriptor, used to define attributes that act differently when
151 accessed through an instance and through a class. Instance access remains
152 normal, but access to an attribute through a class will be routed to the
153 class's __getattr__ method; this is done by raising AttributeError.
154
155 This allows one to have properties active on an instance, and have virtual
156 attributes on the class with the same name. (Enum used this between Python
157 versions 3.4 - 3.9 .)
158
159 Subclass from this to use a different method of accessing virtual attributes
160 and still be treated properly by the inspect module. (Enum uses this since
161 Python 3.10 .)
162
163 """
164 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
165 self.fget = fget
166 self.fset = fset
167 self.fdel = fdel
168 # next two lines make DynamicClassAttribute act the same as property
169 self.__doc__ = doc or fget.__doc__
170 self.overwrite_doc = doc is None
171 # support for abstract methods
172 self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False))
173
174 def __get__(self, instance, ownerclass=None):
175 if instance is None:
176 if self.__isabstractmethod__:
177 return self
178 raise AttributeError()
179 elif self.fget is None:
180 raise AttributeError("unreadable attribute")
181 return self.fget(instance)
182
183 def __set__(self, instance, value):
184 if self.fset is None:
185 raise AttributeError("can't set attribute")
186 self.fset(instance, value)
187
188 def __delete__(self, instance):
189 if self.fdel is None:
190 raise AttributeError("can't delete attribute")
191 self.fdel(instance)
192
193 def getter(self, fget):
194 fdoc = fget.__doc__ if self.overwrite_doc else None
195 result = type(self)(fget, self.fset, self.fdel, fdoc or self.__doc__)
196 result.overwrite_doc = self.overwrite_doc
197 return result
198
199 def setter(self, fset):
200 result = type(self)(self.fget, fset, self.fdel, self.__doc__)
201 result.overwrite_doc = self.overwrite_doc
202 return result
203
204 def deleter(self, fdel):
205 result = type(self)(self.fget, self.fset, fdel, self.__doc__)
206 result.overwrite_doc = self.overwrite_doc
207 return result
208
209
210 class ESC[4;38;5;81m_GeneratorWrapper:
211 # TODO: Implement this in C.
212 def __init__(self, gen):
213 self.__wrapped = gen
214 self.__isgen = gen.__class__ is GeneratorType
215 self.__name__ = getattr(gen, '__name__', None)
216 self.__qualname__ = getattr(gen, '__qualname__', None)
217 def send(self, val):
218 return self.__wrapped.send(val)
219 def throw(self, tp, *rest):
220 return self.__wrapped.throw(tp, *rest)
221 def close(self):
222 return self.__wrapped.close()
223 @property
224 def gi_code(self):
225 return self.__wrapped.gi_code
226 @property
227 def gi_frame(self):
228 return self.__wrapped.gi_frame
229 @property
230 def gi_running(self):
231 return self.__wrapped.gi_running
232 @property
233 def gi_yieldfrom(self):
234 return self.__wrapped.gi_yieldfrom
235 cr_code = gi_code
236 cr_frame = gi_frame
237 cr_running = gi_running
238 cr_await = gi_yieldfrom
239 def __next__(self):
240 return next(self.__wrapped)
241 def __iter__(self):
242 if self.__isgen:
243 return self.__wrapped
244 return self
245 __await__ = __iter__
246
247 def coroutine(func):
248 """Convert regular generator function to a coroutine."""
249
250 if not callable(func):
251 raise TypeError('types.coroutine() expects a callable')
252
253 if (func.__class__ is FunctionType and
254 getattr(func, '__code__', None).__class__ is CodeType):
255
256 co_flags = func.__code__.co_flags
257
258 # Check if 'func' is a coroutine function.
259 # (0x180 == CO_COROUTINE | CO_ITERABLE_COROUTINE)
260 if co_flags & 0x180:
261 return func
262
263 # Check if 'func' is a generator function.
264 # (0x20 == CO_GENERATOR)
265 if co_flags & 0x20:
266 # TODO: Implement this in C.
267 co = func.__code__
268 # 0x100 == CO_ITERABLE_COROUTINE
269 func.__code__ = co.replace(co_flags=co.co_flags | 0x100)
270 return func
271
272 # The following code is primarily to support functions that
273 # return generator-like objects (for instance generators
274 # compiled with Cython).
275
276 # Delay functools and _collections_abc import for speeding up types import.
277 import functools
278 import _collections_abc
279 @functools.wraps(func)
280 def wrapped(*args, **kwargs):
281 coro = func(*args, **kwargs)
282 if (coro.__class__ is CoroutineType or
283 coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100):
284 # 'coro' is a native coroutine object or an iterable coroutine
285 return coro
286 if (isinstance(coro, _collections_abc.Generator) and
287 not isinstance(coro, _collections_abc.Coroutine)):
288 # 'coro' is either a pure Python generator iterator, or it
289 # implements collections.abc.Generator (and does not implement
290 # collections.abc.Coroutine).
291 return _GeneratorWrapper(coro)
292 # 'coro' is either an instance of collections.abc.Coroutine or
293 # some other object -- pass it through.
294 return coro
295
296 return wrapped
297
298 GenericAlias = type(list[int])
299 UnionType = type(int | str)
300
301 EllipsisType = type(Ellipsis)
302 NoneType = type(None)
303 NotImplementedType = type(NotImplemented)
304
305 __all__ = [n for n in globals() if n[:1] != '_']