diff options
author | James Taylor <user234683@users.noreply.github.com> | 2019-09-06 16:31:13 -0700 |
---|---|---|
committer | James Taylor <user234683@users.noreply.github.com> | 2019-09-06 16:31:13 -0700 |
commit | 3d57e14df7ba5f14a634295caf3b2e60da50bfe2 (patch) | |
tree | 4903bcb79a49ad714a1a9129765b9545405c9978 /python/gevent/local.py | |
parent | ac32b24b2a011292b704a3f27e8fd08a7ae9424b (diff) | |
download | yt-local-3d57e14df7ba5f14a634295caf3b2e60da50bfe2.tar.lz yt-local-3d57e14df7ba5f14a634295caf3b2e60da50bfe2.tar.xz yt-local-3d57e14df7ba5f14a634295caf3b2e60da50bfe2.zip |
Remove windows python distribution from repo and add requirements.txt
Diffstat (limited to 'python/gevent/local.py')
-rw-r--r-- | python/gevent/local.py | 605 |
1 files changed, 0 insertions, 605 deletions
diff --git a/python/gevent/local.py b/python/gevent/local.py deleted file mode 100644 index f29bb23..0000000 --- a/python/gevent/local.py +++ /dev/null @@ -1,605 +0,0 @@ -# cython: auto_pickle=False,embedsignature=True,always_allow_keywords=False -""" -Greenlet-local objects. - -This module is based on `_threading_local.py`__ from the standard -library of Python 3.4. - -__ https://github.com/python/cpython/blob/3.4/Lib/_threading_local.py - -Greenlet-local objects support the management of greenlet-local data. -If you have data that you want to be local to a greenlet, simply create -a greenlet-local object and use its attributes: - - >>> mydata = local() - >>> mydata.number = 42 - >>> mydata.number - 42 - -You can also access the local-object's dictionary: - - >>> mydata.__dict__ - {'number': 42} - >>> mydata.__dict__.setdefault('widgets', []) - [] - >>> mydata.widgets - [] - -What's important about greenlet-local objects is that their data are -local to a greenlet. If we access the data in a different greenlet: - - >>> log = [] - >>> def f(): - ... items = list(mydata.__dict__.items()) - ... items.sort() - ... log.append(items) - ... mydata.number = 11 - ... log.append(mydata.number) - >>> greenlet = gevent.spawn(f) - >>> greenlet.join() - >>> log - [[], 11] - -we get different data. Furthermore, changes made in the other greenlet -don't affect data seen in this greenlet: - - >>> mydata.number - 42 - -Of course, values you get from a local object, including a __dict__ -attribute, are for whatever greenlet was current at the time the -attribute was read. For that reason, you generally don't want to save -these values across greenlets, as they apply only to the greenlet they -came from. - -You can create custom local objects by subclassing the local class: - - >>> class MyLocal(local): - ... number = 2 - ... initialized = False - ... def __init__(self, **kw): - ... if self.initialized: - ... raise SystemError('__init__ called too many times') - ... self.initialized = True - ... self.__dict__.update(kw) - ... def squared(self): - ... return self.number ** 2 - -This can be useful to support default values, methods and -initialization. Note that if you define an __init__ method, it will be -called each time the local object is used in a separate greenlet. This -is necessary to initialize each greenlet's dictionary. - -Now if we create a local object: - - >>> mydata = MyLocal(color='red') - -Now we have a default number: - - >>> mydata.number - 2 - -an initial color: - - >>> mydata.color - 'red' - >>> del mydata.color - -And a method that operates on the data: - - >>> mydata.squared() - 4 - -As before, we can access the data in a separate greenlet: - - >>> log = [] - >>> greenlet = gevent.spawn(f) - >>> greenlet.join() - >>> log - [[('color', 'red'), ('initialized', True)], 11] - -without affecting this greenlet's data: - - >>> mydata.number - 2 - >>> mydata.color - Traceback (most recent call last): - ... - AttributeError: 'MyLocal' object has no attribute 'color' - -Note that subclasses can define slots, but they are not greenlet -local. They are shared across greenlets:: - - >>> class MyLocal(local): - ... __slots__ = 'number' - - >>> mydata = MyLocal() - >>> mydata.number = 42 - >>> mydata.color = 'red' - -So, the separate greenlet: - - >>> greenlet = gevent.spawn(f) - >>> greenlet.join() - -affects what we see: - - >>> mydata.number - 11 - ->>> del mydata - -.. versionchanged:: 1.1a2 - Update the implementation to match Python 3.4 instead of Python 2.5. - This results in locals being eligible for garbage collection as soon - as their greenlet exits. - -.. versionchanged:: 1.2.3 - Use a weak-reference to clear the greenlet link we establish in case - the local object dies before the greenlet does. - -.. versionchanged:: 1.3a1 - Implement the methods for attribute access directly, handling - descriptors directly here. This allows removing the use of a lock - and facilitates greatly improved performance. - -.. versionchanged:: 1.3a1 - The ``__init__`` method of subclasses of ``local`` is no longer - called with a lock held. CPython does not use such a lock in its - native implementation. This could potentially show as a difference - if code that uses multiple dependent attributes in ``__slots__`` - (which are shared across all greenlets) switches during ``__init__``. - -""" -from __future__ import print_function - -from copy import copy -from weakref import ref - - -locals()['getcurrent'] = __import__('greenlet').getcurrent -locals()['greenlet_init'] = lambda: None - -__all__ = [ - "local", -] - -# The key used in the Thread objects' attribute dicts. -# We keep it a string for speed but make it unlikely to clash with -# a "real" attribute. -key_prefix = '_gevent_local_localimpl_' - -# The overall structure is as follows: -# For each local() object: -# greenlet.__dict__[key_prefix + str(id(local))] -# => _localimpl.dicts[id(greenlet)] => (ref(greenlet), {}) - -# That final tuple is actually a localimpl_dict_entry object. - -def all_local_dicts_for_greenlet(greenlet): - """ - Internal debug helper for getting the local values associated - with a greenlet. This is subject to change or removal at any time. - - :return: A list of ((type, id), {}) pairs, where the first element - is the type and id of the local object and the second object is its - instance dictionary, as seen from this greenlet. - - .. versionadded:: 1.3a2 - """ - - result = [] - id_greenlet = id(greenlet) - greenlet_dict = greenlet.__dict__ - for k, v in greenlet_dict.items(): - if not k.startswith(key_prefix): - continue - local_impl = v() - if local_impl is None: - continue - entry = local_impl.dicts.get(id_greenlet) - if entry is None: - # Not yet used in this greenlet. - continue - assert entry.wrgreenlet() is greenlet - result.append((local_impl.localtypeid, entry.localdict)) - - return result - - -class _wrefdict(dict): - """A dict that can be weak referenced""" - -class _greenlet_deleted(object): - """ - A weakref callback for when the greenlet - is deleted. - - If the greenlet is a `gevent.greenlet.Greenlet` and - supplies ``rawlink``, that will be used instead of a - weakref. - """ - __slots__ = ('idt', 'wrdicts') - - def __init__(self, idt, wrdicts): - self.idt = idt - self.wrdicts = wrdicts - - def __call__(self, _unused): - dicts = self.wrdicts() - if dicts: - dicts.pop(self.idt, None) - -class _local_deleted(object): - __slots__ = ('key', 'wrthread', 'greenlet_deleted') - - def __init__(self, key, wrthread, greenlet_deleted): - self.key = key - self.wrthread = wrthread - self.greenlet_deleted = greenlet_deleted - - def __call__(self, _unused): - thread = self.wrthread() - if thread is not None: - try: - unlink = thread.unlink - except AttributeError: - pass - else: - unlink(self.greenlet_deleted) - del thread.__dict__[self.key] - -class _localimpl(object): - """A class managing thread-local dicts""" - __slots__ = ('key', 'dicts', - 'localargs', 'localkwargs', - 'localtypeid', - '__weakref__',) - - def __init__(self, args, kwargs, local_type, id_local): - self.key = key_prefix + str(id(self)) - # { id(greenlet) -> _localimpl_dict_entry(ref(greenlet), greenlet-local dict) } - self.dicts = _wrefdict() - self.localargs = args - self.localkwargs = kwargs - self.localtypeid = local_type, id_local - - # We need to create the thread dict in anticipation of - # __init__ being called, to make sure we don't call it - # again ourselves. MUST do this before setting any attributes. - greenlet = getcurrent() # pylint:disable=undefined-variable - _localimpl_create_dict(self, greenlet, id(greenlet)) - -class _localimpl_dict_entry(object): - """ - The object that goes in the ``dicts`` of ``_localimpl`` - object for each thread. - """ - # This is a class, not just a tuple, so that cython can optimize - # attribute access - __slots__ = ('wrgreenlet', 'localdict') - - def __init__(self, wrgreenlet, localdict): - self.wrgreenlet = wrgreenlet - self.localdict = localdict - -# We use functions instead of methods so that they can be cdef'd in -# local.pxd; if they were cdef'd as methods, they would cause -# the creation of a pointer and a vtable. This happens -# even if we declare the class @cython.final. functions thus save memory overhead -# (but not pointer chasing overhead; the vtable isn't used when we declare -# the class final). - - -def _localimpl_create_dict(self, greenlet, id_greenlet): - """Create a new dict for the current thread, and return it.""" - localdict = {} - key = self.key - - wrdicts = ref(self.dicts) - - # When the greenlet is deleted, remove the local dict. - # Note that this is suboptimal if the greenlet object gets - # caught in a reference loop. We would like to be called - # as soon as the OS-level greenlet ends instead. - - # If we are working with a gevent.greenlet.Greenlet, we - # can pro-actively clear out with a link, avoiding the - # issue described above. Use rawlink to avoid spawning any - # more greenlets. - greenlet_deleted = _greenlet_deleted(id_greenlet, wrdicts) - - rawlink = getattr(greenlet, 'rawlink', None) - if rawlink is not None: - rawlink(greenlet_deleted) - wrthread = ref(greenlet) - else: - wrthread = ref(greenlet, greenlet_deleted) - - - # When the localimpl is deleted, remove the thread attribute. - local_deleted = _local_deleted(key, wrthread, greenlet_deleted) - - - wrlocal = ref(self, local_deleted) - greenlet.__dict__[key] = wrlocal - - self.dicts[id_greenlet] = _localimpl_dict_entry(wrthread, localdict) - return localdict - - -_marker = object() - -def _local_get_dict(self): - impl = self._local__impl - # Cython can optimize dict[], but not dict.get() - greenlet = getcurrent() # pylint:disable=undefined-variable - idg = id(greenlet) - try: - entry = impl.dicts[idg] - dct = entry.localdict - except KeyError: - dct = _localimpl_create_dict(impl, greenlet, idg) - self.__init__(*impl.localargs, **impl.localkwargs) - return dct - -def _init(): - greenlet_init() # pylint:disable=undefined-variable - -_local_attrs = { - '_local__impl', - '_local_type_get_descriptors', - '_local_type_set_or_del_descriptors', - '_local_type_del_descriptors', - '_local_type_set_descriptors', - '_local_type', - '_local_type_vars', - '__class__', - '__cinit__', -} - -class local(object): - """ - An object whose attributes are greenlet-local. - """ - __slots__ = tuple(_local_attrs - {'__class__', '__cinit__'}) - - def __cinit__(self, *args, **kw): - if args or kw: - if type(self).__init__ == object.__init__: - raise TypeError("Initialization arguments are not supported", args, kw) - impl = _localimpl(args, kw, type(self), id(self)) - # pylint:disable=attribute-defined-outside-init - self._local__impl = impl - get, dels, sets_or_dels, sets = _local_find_descriptors(self) - self._local_type_get_descriptors = get - self._local_type_set_or_del_descriptors = sets_or_dels - self._local_type_del_descriptors = dels - self._local_type_set_descriptors = sets - self._local_type = type(self) - self._local_type_vars = set(dir(self._local_type)) - - def __getattribute__(self, name): # pylint:disable=too-many-return-statements - if name in _local_attrs: - # The _local__impl, __cinit__, etc, won't be hit by the - # Cython version, if we've done things right. If we haven't, - # they will be, and this will produce an error. - return object.__getattribute__(self, name) - - dct = _local_get_dict(self) - - if name == '__dict__': - return dct - # If there's no possible way we can switch, because this - # attribute is *not* found in the class where it might be a - # data descriptor (property), and it *is* in the dict - # then we don't need to swizzle the dict and take the lock. - - # We don't have to worry about people overriding __getattribute__ - # because if they did, the dict-swizzling would only last as - # long as we were in here anyway. - # Similarly, a __getattr__ will still be called by _oga() if needed - # if it's not in the dict. - - # Optimization: If we're not subclassed, then - # there can be no descriptors except for methods, which will - # never need to use __dict__. - if self._local_type is local: - return dct[name] if name in dct else object.__getattribute__(self, name) - - # NOTE: If this is a descriptor, this will invoke its __get__. - # A broken descriptor that doesn't return itself when called with - # a None for the instance argument could mess us up here. - # But this is faster than a loop over mro() checking each class __dict__ - # manually. - if name in dct: - if name not in self._local_type_vars: - # If there is a dict value, and nothing in the type, - # it can't possibly be a descriptor, so it is just returned. - return dct[name] - - # It's in the type *and* in the dict. If the type value is - # a data descriptor (defines __get__ *and* either __set__ or - # __delete__), then the type wins. If it's a non-data descriptor - # (defines just __get__), then the instance wins. If it's not a - # descriptor at all (doesn't have __get__), the instance wins. - # NOTE that the docs for descriptors say that these methods must be - # defined on the *class* of the object in the type. - if name not in self._local_type_get_descriptors: - # Entirely not a descriptor. Instance wins. - return dct[name] - if name in self._local_type_set_or_del_descriptors: - # A data descriptor. - # arbitrary code execution while these run. If they touch self again, - # they'll call back into us and we'll repeat the dance. - type_attr = getattr(self._local_type, name) - return type(type_attr).__get__(type_attr, self, self._local_type) - # Last case is a non-data descriptor. Instance wins. - return dct[name] - - if name in self._local_type_vars: - # Not in the dictionary, but is found in the type. It could be - # a non-data descriptor still. Some descriptors, like @staticmethod, - # return objects (functions, in this case), that are *themselves* - # descriptors, which when invoked, again, would do the wrong thing. - # So we can't rely on getattr() on the type for them, we have to - # look through the MRO dicts ourself. - if name not in self._local_type_get_descriptors: - # Not a descriptor, can't execute code. So all we need is - # the return value of getattr() on our type. - return getattr(self._local_type, name) - - for base in self._local_type.mro(): - bd = base.__dict__ - if name in bd: - attr_on_type = bd[name] - result = type(attr_on_type).__get__(attr_on_type, self, self._local_type) - return result - - # It wasn't in the dict and it wasn't in the type. - # So the next step is to invoke type(self)__getattr__, if it - # exists, otherwise raise an AttributeError. - # we will invoke type(self).__getattr__ or raise an attribute error. - if hasattr(self._local_type, '__getattr__'): - return self._local_type.__getattr__(self, name) - raise AttributeError("%r object has no attribute '%s'" - % (self._local_type.__name__, name)) - - def __setattr__(self, name, value): - if name == '__dict__': - raise AttributeError( - "%r object attribute '__dict__' is read-only" - % type(self)) - - if name in _local_attrs: - object.__setattr__(self, name, value) - return - - dct = _local_get_dict(self) - - if self._local_type is local: - # Optimization: If we're not subclassed, we can't - # have data descriptors, so this goes right in the dict. - dct[name] = value - return - - if name in self._local_type_vars: - if name in self._local_type_set_descriptors: - type_attr = getattr(self._local_type, name, _marker) - # A data descriptor, like a property or a slot. - type(type_attr).__set__(type_attr, self, value) - return - # Otherwise it goes directly in the dict - dct[name] = value - - def __delattr__(self, name): - if name == '__dict__': - raise AttributeError( - "%r object attribute '__dict__' is read-only" - % self.__class__.__name__) - - if name in self._local_type_vars: - if name in self._local_type_del_descriptors: - # A data descriptor, like a property or a slot. - type_attr = getattr(self._local_type, name, _marker) - type(type_attr).__delete__(type_attr, self) - return - # Otherwise it goes directly in the dict - - # Begin inlined function _get_dict() - dct = _local_get_dict(self) - - try: - del dct[name] - except KeyError: - raise AttributeError(name) - - def __copy__(self): - impl = self._local__impl - entry = impl.dicts[id(getcurrent())] # pylint:disable=undefined-variable - - dct = entry.localdict - duplicate = copy(dct) - - cls = type(self) - instance = cls(*impl.localargs, **impl.localkwargs) - _local__copy_dict_from(instance, impl, duplicate) - return instance - -def _local__copy_dict_from(self, impl, duplicate): - current = getcurrent() # pylint:disable=undefined-variable - currentId = id(current) - new_impl = self._local__impl - assert new_impl is not impl - entry = new_impl.dicts[currentId] - new_impl.dicts[currentId] = _localimpl_dict_entry(entry.wrgreenlet, duplicate) - -def _local_find_descriptors(self): - type_self = type(self) - gets = set() - dels = set() - set_or_del = set() - sets = set() - mro = list(type_self.mro()) - - for attr_name in dir(type_self): - # Conventionally, descriptors when called on a class - # return themself, but not all do. Notable exceptions are - # in the zope.interface package, where things like __provides__ - # return other class attributes. So we can't use getattr, and instead - # walk up the dicts - for base in mro: - bd = base.__dict__ - if attr_name in bd: - attr = bd[attr_name] - break - else: - raise AttributeError(attr_name) - - type_attr = type(attr) - if hasattr(type_attr, '__get__'): - gets.add(attr_name) - if hasattr(type_attr, '__delete__'): - dels.add(attr_name) - set_or_del.add(attr_name) - if hasattr(type_attr, '__set__'): - sets.add(attr_name) - - return (gets, dels, set_or_del, sets) - -# Cython doesn't let us use __new__, it requires -# __cinit__. But we need __new__ if we're not compiled -# (e.g., on PyPy). So we set it at runtime. Cython -# will raise an error if we're compiled. -def __new__(cls, *args, **kw): - self = super(local, cls).__new__(cls) - # We get the cls in *args for some reason - # too when we do it this way....except on PyPy3, which does - # not *unless* it's wrapped in a classmethod (which it is) - self.__cinit__(*args[1:], **kw) - return self - -try: - # PyPy2/3 and CPython handle adding a __new__ to the class - # in different ways. In CPython and PyPy3, it must be wrapped with classmethod; - # in PyPy2, it must not. In either case, the args that get passed to - # it are stil wrong. - local.__new__ = 'None' -except TypeError: # pragma: no cover - # Must be compiled - pass -else: - from gevent._compat import PYPY - from gevent._compat import PY2 - if PYPY and PY2: - local.__new__ = __new__ - else: - local.__new__ = classmethod(__new__) - - del PYPY - del PY2 - -_init() - -from gevent._util import import_c_accel -import_c_accel(globals(), 'gevent._local') |