| 
									
										
										
										
											2024-07-15 13:43:59 -06:00
										 |  |  | """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'): | 
					
						
							| 
									
										
										
										
											2025-07-11 15:31:59 +03:00
										 |  |  |         doc = cls.__doc__ | 
					
						
							|  |  |  |         if doc: | 
					
						
							|  |  |  |             doc = doc.replace( | 
					
						
							|  |  |  |                 'cross-interpreter container', kind, | 
					
						
							|  |  |  |             ).replace( | 
					
						
							|  |  |  |                 'cross-interpreter', kind, | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-07-15 13:43:59 -06:00
										 |  |  |         subclass = type( | 
					
						
							|  |  |  |             f'Unbound{kind.capitalize()}Item', | 
					
						
							|  |  |  |             (cls,), | 
					
						
							| 
									
										
										
										
											2025-07-11 15:31:59 +03:00
										 |  |  |             { | 
					
						
							|  |  |  |                 "_MODULE": module, | 
					
						
							|  |  |  |                 "_NAME": name, | 
					
						
							|  |  |  |                 "__doc__": doc, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2024-07-15 13:43:59 -06:00
										 |  |  |         ) | 
					
						
							|  |  |  |         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}' | 
					
						
							| 
									
										
										
										
											2025-06-11 17:35:48 -06:00
										 |  |  | #        return f'interpreters._queues.UNBOUND' | 
					
						
							| 
									
										
										
										
											2024-07-15 13:43:59 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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)) |