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