| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | """Cross-interpreter Channels High Level Module.""" | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  | import _xxinterpchannels as _channels | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | # aliases: | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  | from _xxinterpchannels import ( | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  |     ChannelError, ChannelNotFoundError, ChannelClosedError, | 
					
						
							|  |  |  |     ChannelEmptyError, ChannelNotEmptyError, | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = [ | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     'create', 'list_all', | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |     'SendChannel', 'RecvChannel', | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  |     'ChannelError', 'ChannelNotFoundError', 'ChannelEmptyError', | 
					
						
							|  |  |  | ] | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | def create(): | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |     """Return (recv, send) for a new cross-interpreter channel.
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |     The channel may be used to pass data safely between interpreters. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  |     cid = _channels.create() | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |     recv, send = RecvChannel(cid), SendChannel(cid) | 
					
						
							|  |  |  |     return recv, send | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-12 08:24:31 -07:00
										 |  |  | def list_all(): | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |     """Return a list of (recv, send) for all open channels.""" | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |     return [(RecvChannel(cid), SendChannel(cid)) | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  |             for cid in _channels.list_all()] | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  | class _ChannelEnd: | 
					
						
							|  |  |  |     """The base class for RecvChannel and SendChannel.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  |     _end = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, cid): | 
					
						
							|  |  |  |         if self._end == 'send': | 
					
						
							|  |  |  |             cid = _channels._channel_id(cid, send=True, force=True) | 
					
						
							|  |  |  |         elif self._end == 'recv': | 
					
						
							|  |  |  |             cid = _channels._channel_id(cid, recv=True, force=True) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise NotImplementedError(self._end) | 
					
						
							|  |  |  |         self._id = cid | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return f'{type(self).__name__}(id={int(self._id)})' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __hash__(self): | 
					
						
							|  |  |  |         return hash(self._id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __eq__(self, other): | 
					
						
							|  |  |  |         if isinstance(self, RecvChannel): | 
					
						
							|  |  |  |             if not isinstance(other, RecvChannel): | 
					
						
							|  |  |  |                 return NotImplemented | 
					
						
							|  |  |  |         elif not isinstance(other, SendChannel): | 
					
						
							|  |  |  |             return NotImplemented | 
					
						
							|  |  |  |         return other._id == self._id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def id(self): | 
					
						
							|  |  |  |         return self._id | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 08:51:21 -06:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def _info(self): | 
					
						
							|  |  |  |         return _channels.get_info(self._id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def is_closed(self): | 
					
						
							|  |  |  |         return self._info.closed | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | _NOT_SET = object() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  | class RecvChannel(_ChannelEnd): | 
					
						
							|  |  |  |     """The receiving end of a cross-interpreter channel.""" | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  |     _end = 'recv' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |     def recv(self, timeout=None, *, | 
					
						
							|  |  |  |              _sentinel=object(), | 
					
						
							|  |  |  |              _delay=10 / 1000,  # 10 milliseconds | 
					
						
							|  |  |  |              ): | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         """Return the next object from the channel.
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         This blocks until an object has been sent, if none have been | 
					
						
							|  |  |  |         sent already. | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |         if timeout is not None: | 
					
						
							|  |  |  |             timeout = int(timeout) | 
					
						
							|  |  |  |             if timeout < 0: | 
					
						
							|  |  |  |                 raise ValueError(f'timeout value must be non-negative') | 
					
						
							|  |  |  |             end = time.time() + timeout | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  |         obj = _channels.recv(self._id, _sentinel) | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         while obj is _sentinel: | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |             time.sleep(_delay) | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |             if timeout is not None and time.time() >= end: | 
					
						
							|  |  |  |                 raise TimeoutError | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  |             obj = _channels.recv(self._id, _sentinel) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |         return obj | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def recv_nowait(self, default=_NOT_SET): | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         """Return the next object from the channel.
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         If none have been sent then return the default if one | 
					
						
							|  |  |  |         is provided or fail with ChannelEmptyError.  Otherwise this | 
					
						
							|  |  |  |         is the same as recv(). | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         if default is _NOT_SET: | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  |             return _channels.recv(self._id) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2023-02-03 18:14:43 -07:00
										 |  |  |             return _channels.recv(self._id, default) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  |     def close(self): | 
					
						
							|  |  |  |         _channels.close(self._id, recv=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  | class SendChannel(_ChannelEnd): | 
					
						
							|  |  |  |     """The sending end of a cross-interpreter channel.""" | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  |     _end = 'send' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-19 08:51:21 -06:00
										 |  |  |     @property | 
					
						
							|  |  |  |     def is_closed(self): | 
					
						
							|  |  |  |         info = self._info | 
					
						
							|  |  |  |         return info.closed or info.closing | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |     def send(self, obj, timeout=None): | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         """Send the object (i.e. its data) to the channel's receiving end.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This blocks until the object is received. | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |         _channels.send(self._id, obj, timeout=timeout, blocking=True) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def send_nowait(self, obj): | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         """Send the object to the channel's receiving end.
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         If the object is immediately received then return True | 
					
						
							|  |  |  |         (else False).  Otherwise this is the same as send(). | 
					
						
							| 
									
										
										
										
											2020-06-10 00:53:23 -03:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-06-16 18:24:40 -06:00
										 |  |  |         # XXX Note that at the moment channel_send() only ever returns | 
					
						
							|  |  |  |         # None.  This should be fixed when channel_send_wait() is added. | 
					
						
							|  |  |  |         # See bpo-32604 and gh-19829. | 
					
						
							| 
									
										
										
										
											2023-10-10 03:35:14 -06:00
										 |  |  |         return _channels.send(self._id, obj, blocking=False) | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |     def send_buffer(self, obj, timeout=None): | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  |         """Send the object's buffer to the channel's receiving end.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This blocks until the object is received. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |         _channels.send_buffer(self._id, obj, timeout=timeout, blocking=True) | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def send_buffer_nowait(self, obj): | 
					
						
							|  |  |  |         """Send the object's buffer to the channel's receiving end.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If the object is immediately received then return True | 
					
						
							|  |  |  |         (else False).  Otherwise this is the same as send(). | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2023-10-10 03:35:14 -06:00
										 |  |  |         return _channels.send_buffer(self._id, obj, blocking=False) | 
					
						
							| 
									
										
										
										
											2023-10-09 07:39:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-02 14:47:41 -06:00
										 |  |  |     def close(self): | 
					
						
							|  |  |  |         _channels.close(self._id, send=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-03 18:36:50 -06:00
										 |  |  | # XXX This is causing leaks (gh-110318): | 
					
						
							| 
									
										
										
										
											2023-10-19 08:52:02 -06:00
										 |  |  | _channels._register_end_types(SendChannel, RecvChannel) |