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