this repo has no description
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] != '_']