1""" 2Define names for built-in types that aren't directly accessible as a builtin. 3""" 4import 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 11def _f(): pass 12FunctionType = type(_f) 13LambdaType = type(lambda: None) # Same as FunctionType 14CodeType = type(_f.__code__) 15MappingProxyType = type(type.__dict__) 16SimpleNamespace = type(sys.implementation) 17 18def _cell_factory(): 19 a = 1 20 def f(): 21 nonlocal a 22 return f.__closure__[0] 23CellType = type(_cell_factory()) 24 25def _g(): 26 yield 1 27GeneratorType = type(_g()) 28 29async def _c(): pass 30_c = _c() 31CoroutineType = type(_c) 32_c.close() # Prevent ResourceWarning 33 34async def _ag(): 35 yield 36_ag = _ag() 37AsyncGeneratorType = type(_ag) 38 39class _C: 40 def _m(self): pass 41MethodType = type(_C()._m) 42 43BuiltinFunctionType = type(len) 44BuiltinMethodType = type([].append) # Same as BuiltinFunctionType 45 46WrapperDescriptorType = type(object.__init__) 47MethodWrapperType = type(object().__str__) 48MethodDescriptorType = type(str.join) 49ClassMethodDescriptorType = type(dict.__dict__['fromkeys']) 50 51ModuleType = type(sys) 52 53try: 54 raise TypeError 55except 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 60GetSetDescriptorType = type(FunctionType.__code__) 61MemberDescriptorType = type(FunctionType.__globals__) 62 63del sys, _f, _g, _C, _c, _ag # Not for export 64 65 66# Provide a PEP 3115 compliant mechanism for class creation 67def 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 77def 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 98def 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 130def _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 147class DynamicClassAttribute: 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 210class _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 247def 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 298GenericAlias = type(list[int]) 299UnionType = type(int | str) 300 301EllipsisType = type(Ellipsis) 302NoneType = type(None) 303NotImplementedType = type(NotImplemented) 304 305__all__ = [n for n in globals() if n[:1] != '_'] 306