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