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