mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 18:07:37 +00:00 
			
		
		
		
	 8b209fd4f8
			
		
	
	
		8b209fd4f8
		
			
		
	
	
	
	
		
			
			See 6b98b274b6 for an explanation of the problem and solution.  Here I've applied the solution to channels.
		
	
			
		
			
				
	
	
		
			102 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """Common code between queues and channels."""
 | |
| 
 | |
| 
 | |
| class ItemInterpreterDestroyed(Exception):
 | |
|     """Raised when trying to get an item whose interpreter was destroyed."""
 | |
| 
 | |
| 
 | |
| class classonly:
 | |
|     """A non-data descriptor that makes a value only visible on the class.
 | |
| 
 | |
|     This is like the "classmethod" builtin, but does not show up on
 | |
|     instances of the class.  It may be used as a decorator.
 | |
|     """
 | |
| 
 | |
|     def __init__(self, value):
 | |
|         self.value = value
 | |
|         self.getter = classmethod(value).__get__
 | |
|         self.name = None
 | |
| 
 | |
|     def __set_name__(self, cls, name):
 | |
|         if self.name is not None:
 | |
|             raise TypeError('already used')
 | |
|         self.name = name
 | |
| 
 | |
|     def __get__(self, obj, cls):
 | |
|         if obj is not None:
 | |
|             raise AttributeError(self.name)
 | |
|         # called on the class
 | |
|         return self.getter(None, cls)
 | |
| 
 | |
| 
 | |
| class UnboundItem:
 | |
|     """Represents a cross-interpreter item no longer bound to an interpreter.
 | |
| 
 | |
|     An item is unbound when the interpreter that added it to the
 | |
|     cross-interpreter container is destroyed.
 | |
|     """
 | |
| 
 | |
|     __slots__ = ()
 | |
| 
 | |
|     @classonly
 | |
|     def singleton(cls, kind, module, name='UNBOUND'):
 | |
|         doc = cls.__doc__.replace('cross-interpreter container', kind)
 | |
|         doc = doc.replace('cross-interpreter', kind)
 | |
|         subclass = type(
 | |
|             f'Unbound{kind.capitalize()}Item',
 | |
|             (cls,),
 | |
|             dict(
 | |
|                 _MODULE=module,
 | |
|                 _NAME=name,
 | |
|                 __doc__=doc,
 | |
|             ),
 | |
|         )
 | |
|         return object.__new__(subclass)
 | |
| 
 | |
|     _MODULE = __name__
 | |
|     _NAME = 'UNBOUND'
 | |
| 
 | |
|     def __new__(cls):
 | |
|         raise Exception(f'use {cls._MODULE}.{cls._NAME}')
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return f'{self._MODULE}.{self._NAME}'
 | |
| #        return f'interpreters.queues.UNBOUND'
 | |
| 
 | |
| 
 | |
| UNBOUND = object.__new__(UnboundItem)
 | |
| UNBOUND_ERROR = object()
 | |
| UNBOUND_REMOVE = object()
 | |
| 
 | |
| _UNBOUND_CONSTANT_TO_FLAG = {
 | |
|     UNBOUND_REMOVE: 1,
 | |
|     UNBOUND_ERROR: 2,
 | |
|     UNBOUND: 3,
 | |
| }
 | |
| _UNBOUND_FLAG_TO_CONSTANT = {v: k
 | |
|                              for k, v in _UNBOUND_CONSTANT_TO_FLAG.items()}
 | |
| 
 | |
| 
 | |
| def serialize_unbound(unbound):
 | |
|     op = unbound
 | |
|     try:
 | |
|         flag = _UNBOUND_CONSTANT_TO_FLAG[op]
 | |
|     except KeyError:
 | |
|         raise NotImplementedError(f'unsupported unbound replacement op {op!r}')
 | |
|     return flag,
 | |
| 
 | |
| 
 | |
| def resolve_unbound(flag, exctype_destroyed):
 | |
|     try:
 | |
|         op = _UNBOUND_FLAG_TO_CONSTANT[flag]
 | |
|     except KeyError:
 | |
|         raise NotImplementedError(f'unsupported unbound replacement op {flag!r}')
 | |
|     if op is UNBOUND_REMOVE:
 | |
|         # "remove" not possible here
 | |
|         raise NotImplementedError
 | |
|     elif op is UNBOUND_ERROR:
 | |
|         raise exctype_destroyed("item's original interpreter destroyed")
 | |
|     elif op is UNBOUND:
 | |
|         return UNBOUND
 | |
|     else:
 | |
|         raise NotImplementedError(repr(op))
 |