import pickle
import queue
import time
import weakref
import _interpqueues as _queues
from . import _crossinterp
from _interpqueues import (
QueueError, QueueNotFoundError,
)
from ._crossinterp import (
UNBOUND_ERROR, UNBOUND_REMOVE,
)
__all__ = [
'UNBOUND', 'UNBOUND_ERROR', 'UNBOUND_REMOVE',
'create', 'list_all',
'Queue',
'QueueError', 'QueueNotFoundError', 'QueueEmpty', 'QueueFull',
'ItemInterpreterDestroyed',
]
class QueueEmpty(QueueError, queue.Empty):
class QueueFull(QueueError, queue.Full):
class ItemInterpreterDestroyed(QueueError,
_crossinterp.ItemInterpreterDestroyed):
_SHARED_ONLY = 0
_PICKLED = 1
UNBOUND = _crossinterp.UnboundItem.singleton('queue', __name__)
def _serialize_unbound(unbound):
if unbound is UNBOUND:
unbound = _crossinterp.UNBOUND
return _crossinterp.serialize_unbound(unbound)
def _resolve_unbound(flag):
resolved = _crossinterp.resolve_unbound(flag, ItemInterpreterDestroyed)
if resolved is _crossinterp.UNBOUND:
resolved = UNBOUND
return resolved
def create(maxsize=0, *, unbounditems=UNBOUND):
unbound = _serialize_unbound(unbounditems)
unboundop, = unbound
qid = _queues.create(maxsize, unboundop, -1)
self = Queue(qid)
self._set_unbound(unboundop, unbounditems)
return self
def list_all():
queues = []
for qid, unboundop, _ in _queues.list_all():
self = Queue(qid)
if not hasattr(self, '_unbound'):
self._set_unbound(unboundop)
else:
assert self._unbound[0] == unboundop
queues.append(self)
return queues
_known_queues = weakref.WeakValueDictionary()
class Queue:
def __new__(cls, id, /):
if isinstance(id, int):
id = int(id)
else:
raise TypeError(f'id must be an int, got {id!r}')
try:
self = _known_queues[id]
except KeyError:
self = super().__new__(cls)
self._id = id
_known_queues[id] = self
_queues.bind(id)
return self
def __del__(self):
try:
_queues.release(self._id)
except QueueNotFoundError:
pass
try:
del _known_queues[self._id]
except KeyError:
pass
def __repr__(self):
return f'{type(self).__name__}({self.id})'
def __hash__(self):
return hash(self._id)
def __reduce__(self):
return (type(self), (self._id,))
def _set_unbound(self, op, items=None):
assert not hasattr(self, '_unbound')
if items is None:
items = _resolve_unbound(op)
unbound = (op, items)
self._unbound = unbound
return unbound
@property
def id(self):
return self._id
@property
def unbounditems(self):
try:
_, items = self._unbound
except AttributeError:
op, _ = _queues.get_queue_defaults(self._id)
_, items = self._set_unbound(op)
return items
@property
def maxsize(self):
try:
return self._maxsize
except AttributeError:
self._maxsize = _queues.get_maxsize(self._id)
return self._maxsize
def empty(self):
return self.qsize() == 0
def full(self):
return _queues.is_full(self._id)
def qsize(self):
return _queues.get_count(self._id)
def put(self, obj, block=True, timeout=None, *,
unbounditems=None,
_delay=10 / 1000, ):
if not block:
return self.put_nowait(obj, unbounditems=unbounditems)
if unbounditems is None:
unboundop = -1
else:
unboundop, = _serialize_unbound(unbounditems)
if timeout is not None:
timeout = int(timeout)
if timeout < 0:
raise ValueError(f'timeout value must be non-negative')
end = time.time() + timeout
while True:
try:
_queues.put(self._id, obj, unboundop)
except QueueFull as exc:
if timeout is not None and time.time() >= end:
raise time.sleep(_delay)
else:
break
def put_nowait(self, obj, *, unbounditems=None):
if unbounditems is None:
unboundop = -1
else:
unboundop, = _serialize_unbound(unbounditems)
_queues.put(self._id, obj, unboundop)
def get(self, block=True, timeout=None, *,
_delay=10 / 1000, ):
if not block:
return self.get_nowait()
if timeout is not None:
timeout = int(timeout)
if timeout < 0:
raise ValueError(f'timeout value must be non-negative')
end = time.time() + timeout
while True:
try:
obj, unboundop = _queues.get(self._id)
except QueueEmpty as exc:
if timeout is not None and time.time() >= end:
raise time.sleep(_delay)
else:
break
if unboundop is not None:
assert obj is None, repr(obj)
return _resolve_unbound(unboundop)
return obj
def get_nowait(self):
try:
obj, unboundop = _queues.get(self._id)
except QueueEmpty as exc:
raise if unboundop is not None:
assert obj is None, repr(obj)
return _resolve_unbound(unboundop)
return obj
_queues._register_heap_types(Queue, QueueEmpty, QueueFull)