Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_threading_local.py121 linesDownload Raw Back to Lib
1"""Thread-local objects.2 3(Note that this module provides a Python version of the threading.local4 class.  Depending on the version of Python you're using, there may be a5 faster one available.  You should always import the `local` class from6 `threading`.)7"""8 9from weakref import ref10from contextlib import contextmanager11 12__all__ = ["local"]13 14# We need to use objects from the threading module, but the threading15# module may also want to use our `local` class, if support for locals16# isn't compiled in to the `thread` module.  This creates potential problems17# with circular imports.  For that reason, we don't import `threading`18# until the bottom of this file (a hack sufficient to worm around the19# potential problems).  Note that all platforms on CPython do have support20# for locals in the `thread` module, and there is no circular import problem21# then, so problems introduced by fiddling the order of imports here won't22# manifest.23 24class _localimpl:25    """A class managing thread-local dicts"""26    __slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__'27 28    def __init__(self):29        # The key used in the Thread objects' attribute dicts.30        # We keep it a string for speed but make it unlikely to clash with31        # a "real" attribute.32        self.key = '_threading_local._localimpl.' + str(id(self))33        # { id(Thread) -> (ref(Thread), thread-local dict) }34        self.dicts = {}35 36    def get_dict(self):37        """Return the dict for the current thread. Raises KeyError if none38        defined."""39        thread = current_thread()40        return self.dicts[id(thread)][1]41 42    def create_dict(self):43        """Create a new dict for the current thread, and return it."""44        localdict = {}45        key = self.key46        thread = current_thread()47        idt = id(thread)48        def local_deleted(_, key=key):49            # When the localimpl is deleted, remove the thread attribute.50            thread = wrthread()51            if thread is not None:52                del thread.__dict__[key]53        def thread_deleted(_, idt=idt):54            # When the thread is deleted, remove the local dict.55            # Note that this is suboptimal if the thread object gets56            # caught in a reference loop. We would like to be called57            # as soon as the OS-level thread ends instead.58            local = wrlocal()59            if local is not None:60                dct = local.dicts.pop(idt)61        wrlocal = ref(self, local_deleted)62        wrthread = ref(thread, thread_deleted)63        thread.__dict__[key] = wrlocal64        self.dicts[idt] = wrthread, localdict65        return localdict66 67 68@contextmanager69def _patch(self):70    impl = object.__getattribute__(self, '_local__impl')71    try:72        dct = impl.get_dict()73    except KeyError:74        dct = impl.create_dict()75        args, kw = impl.localargs76        self.__init__(*args, **kw)77    with impl.locallock:78        object.__setattr__(self, '__dict__', dct)79        yield80 81 82class local:83    __slots__ = '_local__impl', '__dict__'84 85    def __new__(cls, /, *args, **kw):86        if (args or kw) and (cls.__init__ is object.__init__):87            raise TypeError("Initialization arguments are not supported")88        self = object.__new__(cls)89        impl = _localimpl()90        impl.localargs = (args, kw)91        impl.locallock = RLock()92        object.__setattr__(self, '_local__impl', impl)93        # We need to create the thread dict in anticipation of94        # __init__ being called, to make sure we don't call it95        # again ourselves.96        impl.create_dict()97        return self98 99    def __getattribute__(self, name):100        with _patch(self):101            return object.__getattribute__(self, name)102 103    def __setattr__(self, name, value):104        if name == '__dict__':105            raise AttributeError(106                "%r object attribute '__dict__' is read-only"107                % self.__class__.__name__)108        with _patch(self):109            return object.__setattr__(self, name, value)110 111    def __delattr__(self, name):112        if name == '__dict__':113            raise AttributeError(114                "%r object attribute '__dict__' is read-only"115                % self.__class__.__name__)116        with _patch(self):117            return object.__delattr__(self, name)118 119 120from threading import current_thread, RLock121 
codekingpro/portable-devtools · Team Ai