You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					90 lines
				
				2.2 KiB
			
		
		
			
		
	
	
					90 lines
				
				2.2 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								import abc
							 | 
						||
| 
								 | 
							
								import functools
							 | 
						||
| 
								 | 
							
								import weakref
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from . import exc as async_exc
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ReversibleProxy:
							 | 
						||
| 
								 | 
							
								    # weakref.ref(async proxy object) -> weakref.ref(sync proxied object)
							 | 
						||
| 
								 | 
							
								    _proxy_objects = {}
							 | 
						||
| 
								 | 
							
								    __slots__ = ("__weakref__",)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _assign_proxied(self, target):
							 | 
						||
| 
								 | 
							
								        if target is not None:
							 | 
						||
| 
								 | 
							
								            target_ref = weakref.ref(target, ReversibleProxy._target_gced)
							 | 
						||
| 
								 | 
							
								            proxy_ref = weakref.ref(
							 | 
						||
| 
								 | 
							
								                self,
							 | 
						||
| 
								 | 
							
								                functools.partial(ReversibleProxy._target_gced, target_ref),
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            ReversibleProxy._proxy_objects[target_ref] = proxy_ref
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return target
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _target_gced(cls, ref, proxy_ref=None):
							 | 
						||
| 
								 | 
							
								        cls._proxy_objects.pop(ref, None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _regenerate_proxy_for_target(cls, target):
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _retrieve_proxy_for_target(cls, target, regenerate=True):
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            proxy_ref = cls._proxy_objects[weakref.ref(target)]
							 | 
						||
| 
								 | 
							
								        except KeyError:
							 | 
						||
| 
								 | 
							
								            pass
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            proxy = proxy_ref()
							 | 
						||
| 
								 | 
							
								            if proxy is not None:
							 | 
						||
| 
								 | 
							
								                return proxy
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if regenerate:
							 | 
						||
| 
								 | 
							
								            return cls._regenerate_proxy_for_target(target)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class StartableContext(abc.ABC):
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @abc.abstractmethod
							 | 
						||
| 
								 | 
							
								    async def start(self, is_ctxmanager=False):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __await__(self):
							 | 
						||
| 
								 | 
							
								        return self.start().__await__()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def __aenter__(self):
							 | 
						||
| 
								 | 
							
								        return await self.start(is_ctxmanager=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @abc.abstractmethod
							 | 
						||
| 
								 | 
							
								    async def __aexit__(self, type_, value, traceback):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _raise_for_not_started(self):
							 | 
						||
| 
								 | 
							
								        raise async_exc.AsyncContextNotStarted(
							 | 
						||
| 
								 | 
							
								            "%s context has not been started and object has not been awaited."
							 | 
						||
| 
								 | 
							
								            % (self.__class__.__name__)
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ProxyComparable(ReversibleProxy):
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __hash__(self):
							 | 
						||
| 
								 | 
							
								        return id(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __eq__(self, other):
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            isinstance(other, self.__class__)
							 | 
						||
| 
								 | 
							
								            and self._proxied == other._proxied
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __ne__(self, other):
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            not isinstance(other, self.__class__)
							 | 
						||
| 
								 | 
							
								            or self._proxied != other._proxied
							 | 
						||
| 
								 | 
							
								        )
							 |