asm
This commit is contained in:
25
asm/venv/lib/python3.11/site-packages/zmq/sugar/__init__.py
Normal file
25
asm/venv/lib/python3.11/site-packages/zmq/sugar/__init__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""pure-Python sugar wrappers for core 0MQ objects."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
from zmq import error
|
||||
from zmq.sugar import context, frame, poll, socket, tracker, version
|
||||
|
||||
__all__ = []
|
||||
for submod in (context, error, frame, poll, socket, tracker, version):
|
||||
__all__.extend(submod.__all__)
|
||||
|
||||
from zmq.error import * # noqa
|
||||
from zmq.sugar.context import * # noqa
|
||||
from zmq.sugar.frame import * # noqa
|
||||
from zmq.sugar.poll import * # noqa
|
||||
from zmq.sugar.socket import * # noqa
|
||||
|
||||
# deprecated:
|
||||
from zmq.sugar.stopwatch import Stopwatch # noqa
|
||||
from zmq.sugar.tracker import * # noqa
|
||||
from zmq.sugar.version import * # noqa
|
||||
|
||||
__all__.append('Stopwatch')
|
||||
10
asm/venv/lib/python3.11/site-packages/zmq/sugar/__init__.pyi
Normal file
10
asm/venv/lib/python3.11/site-packages/zmq/sugar/__init__.pyi
Normal file
@@ -0,0 +1,10 @@
|
||||
from zmq.error import *
|
||||
|
||||
from . import constants as constants
|
||||
from .constants import *
|
||||
from .context import *
|
||||
from .frame import *
|
||||
from .poll import *
|
||||
from .socket import *
|
||||
from .tracker import *
|
||||
from .version import *
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
78
asm/venv/lib/python3.11/site-packages/zmq/sugar/attrsettr.py
Normal file
78
asm/venv/lib/python3.11/site-packages/zmq/sugar/attrsettr.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""Mixin for mapping set/getattr to self.set/get"""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import errno
|
||||
from typing import TypeVar, Union
|
||||
|
||||
from .. import constants
|
||||
|
||||
T = TypeVar("T")
|
||||
OptValT = Union[str, bytes, int]
|
||||
|
||||
|
||||
class AttributeSetter:
|
||||
def __setattr__(self, key: str, value: OptValT) -> None:
|
||||
"""set zmq options by attribute"""
|
||||
|
||||
if key in self.__dict__:
|
||||
object.__setattr__(self, key, value)
|
||||
return
|
||||
# regular setattr only allowed for class-defined attributes
|
||||
for cls in self.__class__.mro():
|
||||
if key in cls.__dict__ or key in getattr(cls, "__annotations__", {}):
|
||||
object.__setattr__(self, key, value)
|
||||
return
|
||||
|
||||
upper_key = key.upper()
|
||||
try:
|
||||
opt = getattr(constants, upper_key)
|
||||
except AttributeError:
|
||||
raise AttributeError(
|
||||
f"{self.__class__.__name__} has no such option: {upper_key}"
|
||||
)
|
||||
else:
|
||||
self._set_attr_opt(upper_key, opt, value)
|
||||
|
||||
def _set_attr_opt(self, name: str, opt: int, value: OptValT) -> None:
|
||||
"""override if setattr should do something other than call self.set"""
|
||||
self.set(opt, value)
|
||||
|
||||
def __getattr__(self, key: str) -> OptValT:
|
||||
"""get zmq options by attribute"""
|
||||
upper_key = key.upper()
|
||||
try:
|
||||
opt = getattr(constants, upper_key)
|
||||
except AttributeError:
|
||||
raise AttributeError(
|
||||
f"{self.__class__.__name__} has no such option: {upper_key}"
|
||||
) from None
|
||||
else:
|
||||
from zmq import ZMQError
|
||||
|
||||
try:
|
||||
return self._get_attr_opt(upper_key, opt)
|
||||
except ZMQError as e:
|
||||
# EINVAL will be raised on access for write-only attributes.
|
||||
# Turn that into an AttributeError
|
||||
# necessary for mocking
|
||||
if e.errno in {errno.EINVAL, errno.EFAULT}:
|
||||
raise AttributeError(f"{key} attribute is write-only")
|
||||
else:
|
||||
raise
|
||||
|
||||
def _get_attr_opt(self, name, opt) -> OptValT:
|
||||
"""override if getattr should do something other than call self.get"""
|
||||
return self.get(opt)
|
||||
|
||||
def get(self, opt: int) -> OptValT:
|
||||
"""Override in subclass"""
|
||||
raise NotImplementedError("override in subclass")
|
||||
|
||||
def set(self, opt: int, val: OptValT) -> None:
|
||||
"""Override in subclass"""
|
||||
raise NotImplementedError("override in subclass")
|
||||
|
||||
|
||||
__all__ = ['AttributeSetter']
|
||||
426
asm/venv/lib/python3.11/site-packages/zmq/sugar/context.py
Normal file
426
asm/venv/lib/python3.11/site-packages/zmq/sugar/context.py
Normal file
@@ -0,0 +1,426 @@
|
||||
"""Python bindings for 0MQ."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import atexit
|
||||
import os
|
||||
from threading import Lock
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Generic,
|
||||
List,
|
||||
Optional,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
from warnings import warn
|
||||
from weakref import WeakSet
|
||||
|
||||
from zmq.backend import Context as ContextBase
|
||||
from zmq.constants import ContextOption, Errno, SocketOption
|
||||
from zmq.error import ZMQError
|
||||
from zmq.utils.interop import cast_int_addr
|
||||
|
||||
from .attrsettr import AttributeSetter, OptValT
|
||||
from .socket import Socket
|
||||
|
||||
# notice when exiting, to avoid triggering term on exit
|
||||
_exiting = False
|
||||
|
||||
|
||||
def _notice_atexit() -> None:
|
||||
global _exiting
|
||||
_exiting = True
|
||||
|
||||
|
||||
atexit.register(_notice_atexit)
|
||||
|
||||
T = TypeVar('T', bound='Context')
|
||||
ST = TypeVar('ST', bound='Socket', covariant=True)
|
||||
|
||||
|
||||
class Context(ContextBase, AttributeSetter, Generic[ST]):
|
||||
"""Create a zmq Context
|
||||
|
||||
A zmq Context creates sockets via its ``ctx.socket`` method.
|
||||
|
||||
.. versionchanged:: 24
|
||||
|
||||
When using a Context as a context manager (``with zmq.Context()``),
|
||||
or deleting a context without closing it first,
|
||||
``ctx.destroy()`` is called,
|
||||
closing any leftover sockets,
|
||||
instead of `ctx.term()` which requires sockets to be closed first.
|
||||
|
||||
This prevents hangs caused by `ctx.term()` if sockets are left open,
|
||||
but means that unclean destruction of contexts
|
||||
(with sockets left open) is not safe
|
||||
if sockets are managed in other threads.
|
||||
|
||||
.. versionadded:: 25
|
||||
|
||||
Contexts can now be shadowed by passing another Context.
|
||||
This helps in creating an async copy of a sync context or vice versa::
|
||||
|
||||
ctx = zmq.Context(async_ctx)
|
||||
|
||||
Which previously had to be::
|
||||
|
||||
ctx = zmq.Context.shadow(async_ctx.underlying)
|
||||
"""
|
||||
|
||||
sockopts: Dict[int, Any]
|
||||
_instance: Any = None
|
||||
_instance_lock = Lock()
|
||||
_instance_pid: Optional[int] = None
|
||||
_shadow = False
|
||||
_shadow_obj = None
|
||||
_warn_destroy_close = False
|
||||
_sockets: WeakSet
|
||||
# mypy doesn't like a default value here
|
||||
_socket_class: Type[ST] = Socket # type: ignore
|
||||
|
||||
@overload
|
||||
def __init__(self: "Context[Socket]", io_threads: int = 1):
|
||||
...
|
||||
|
||||
@overload
|
||||
def __init__(self: "Context[Socket]", io_threads: "Context"):
|
||||
# this should be positional-only, but that requires 3.8
|
||||
...
|
||||
|
||||
@overload
|
||||
def __init__(self: "Context[Socket]", *, shadow: Union["Context", int]):
|
||||
...
|
||||
|
||||
def __init__(
|
||||
self: "Context[Socket]",
|
||||
io_threads: Union[int, "Context"] = 1,
|
||||
shadow: Union["Context", int] = 0,
|
||||
) -> None:
|
||||
if isinstance(io_threads, Context):
|
||||
# allow positional shadow `zmq.Context(zmq.asyncio.Context())`
|
||||
# this s
|
||||
shadow = io_threads
|
||||
io_threads = 1
|
||||
|
||||
shadow_address: int = 0
|
||||
if shadow:
|
||||
self._shadow = True
|
||||
# hold a reference to the shadow object
|
||||
self._shadow_obj = shadow
|
||||
if not isinstance(shadow, int):
|
||||
try:
|
||||
shadow = shadow.underlying
|
||||
except AttributeError:
|
||||
pass
|
||||
shadow_address = cast_int_addr(shadow)
|
||||
else:
|
||||
self._shadow = False
|
||||
super().__init__(io_threads=io_threads, shadow=shadow_address)
|
||||
self.sockopts = {}
|
||||
self._sockets = WeakSet()
|
||||
|
||||
def __del__(self) -> None:
|
||||
"""Deleting a Context without closing it destroys it and all sockets.
|
||||
|
||||
.. versionchanged:: 24
|
||||
Switch from threadsafe `term()` which hangs in the event of open sockets
|
||||
to less safe `destroy()` which
|
||||
warns about any leftover sockets and closes them.
|
||||
"""
|
||||
|
||||
# Calling locals() here conceals issue #1167 on Windows CPython 3.5.4.
|
||||
locals()
|
||||
|
||||
if not self._shadow and not _exiting and not self.closed:
|
||||
self._warn_destroy_close = True
|
||||
if warn is not None and getattr(self, "_sockets", None) is not None:
|
||||
# warn can be None during process teardown
|
||||
warn(
|
||||
f"Unclosed context {self}",
|
||||
ResourceWarning,
|
||||
stacklevel=2,
|
||||
source=self,
|
||||
)
|
||||
self.destroy()
|
||||
|
||||
_repr_cls = "zmq.Context"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
cls = self.__class__
|
||||
# look up _repr_cls on exact class, not inherited
|
||||
_repr_cls = cls.__dict__.get("_repr_cls", None)
|
||||
if _repr_cls is None:
|
||||
_repr_cls = f"{cls.__module__}.{cls.__name__}"
|
||||
|
||||
closed = ' closed' if self.closed else ''
|
||||
if getattr(self, "_sockets", None):
|
||||
n_sockets = len(self._sockets)
|
||||
s = 's' if n_sockets > 1 else ''
|
||||
sockets = f"{n_sockets} socket{s}"
|
||||
else:
|
||||
sockets = ""
|
||||
return f"<{_repr_cls}({sockets}) at {hex(id(self))}{closed}>"
|
||||
|
||||
def __enter__(self: T) -> T:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
||||
# warn about any leftover sockets before closing them
|
||||
self._warn_destroy_close = True
|
||||
self.destroy()
|
||||
|
||||
def __copy__(self: T, memo: Any = None) -> T:
|
||||
"""Copying a Context creates a shadow copy"""
|
||||
return self.__class__.shadow(self.underlying)
|
||||
|
||||
__deepcopy__ = __copy__
|
||||
|
||||
@classmethod
|
||||
def shadow(cls: Type[T], address: Union[int, "Context"]) -> T:
|
||||
"""Shadow an existing libzmq context
|
||||
|
||||
address is a zmq.Context or an integer (or FFI pointer)
|
||||
representing the address of the libzmq context.
|
||||
|
||||
.. versionadded:: 14.1
|
||||
|
||||
.. versionadded:: 25
|
||||
Support for shadowing `zmq.Context` objects,
|
||||
instead of just integer addresses.
|
||||
"""
|
||||
return cls(shadow=address)
|
||||
|
||||
@classmethod
|
||||
def shadow_pyczmq(cls: Type[T], ctx: Any) -> T:
|
||||
"""Shadow an existing pyczmq context
|
||||
|
||||
ctx is the FFI `zctx_t *` pointer
|
||||
|
||||
.. versionadded:: 14.1
|
||||
"""
|
||||
from pyczmq import zctx # type: ignore
|
||||
|
||||
from zmq.utils.interop import cast_int_addr
|
||||
|
||||
underlying = zctx.underlying(ctx)
|
||||
address = cast_int_addr(underlying)
|
||||
return cls(shadow=address)
|
||||
|
||||
# static method copied from tornado IOLoop.instance
|
||||
@classmethod
|
||||
def instance(cls: Type[T], io_threads: int = 1) -> T:
|
||||
"""Returns a global Context instance.
|
||||
|
||||
Most single-threaded applications have a single, global Context.
|
||||
Use this method instead of passing around Context instances
|
||||
throughout your code.
|
||||
|
||||
A common pattern for classes that depend on Contexts is to use
|
||||
a default argument to enable programs with multiple Contexts
|
||||
but not require the argument for simpler applications::
|
||||
|
||||
class MyClass(object):
|
||||
def __init__(self, context=None):
|
||||
self.context = context or Context.instance()
|
||||
|
||||
.. versionchanged:: 18.1
|
||||
|
||||
When called in a subprocess after forking,
|
||||
a new global instance is created instead of inheriting
|
||||
a Context that won't work from the parent process.
|
||||
"""
|
||||
if (
|
||||
cls._instance is None
|
||||
or cls._instance_pid != os.getpid()
|
||||
or cls._instance.closed
|
||||
):
|
||||
with cls._instance_lock:
|
||||
if (
|
||||
cls._instance is None
|
||||
or cls._instance_pid != os.getpid()
|
||||
or cls._instance.closed
|
||||
):
|
||||
cls._instance = cls(io_threads=io_threads)
|
||||
cls._instance_pid = os.getpid()
|
||||
return cls._instance
|
||||
|
||||
def term(self) -> None:
|
||||
"""Close or terminate the context.
|
||||
|
||||
Context termination is performed in the following steps:
|
||||
|
||||
- Any blocking operations currently in progress on sockets open within context shall
|
||||
raise :class:`zmq.ContextTerminated`.
|
||||
With the exception of socket.close(), any further operations on sockets open within this context
|
||||
shall raise :class:`zmq.ContextTerminated`.
|
||||
- After interrupting all blocking calls, term shall block until the following conditions are satisfied:
|
||||
- All sockets open within context have been closed.
|
||||
- For each socket within context, all messages sent on the socket have either been
|
||||
physically transferred to a network peer,
|
||||
or the socket's linger period set with the zmq.LINGER socket option has expired.
|
||||
|
||||
For further details regarding socket linger behaviour refer to libzmq documentation for ZMQ_LINGER.
|
||||
|
||||
This can be called to close the context by hand. If this is not called,
|
||||
the context will automatically be closed when it is garbage collected,
|
||||
in which case you may see a ResourceWarning about the unclosed context.
|
||||
"""
|
||||
super().term()
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Hooks for ctxopt completion
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def __dir__(self) -> List[str]:
|
||||
keys = dir(self.__class__)
|
||||
keys.extend(ContextOption.__members__)
|
||||
return keys
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Creating Sockets
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def _add_socket(self, socket: Any) -> None:
|
||||
"""Add a weakref to a socket for Context.destroy / reference counting"""
|
||||
self._sockets.add(socket)
|
||||
|
||||
def _rm_socket(self, socket: Any) -> None:
|
||||
"""Remove a socket for Context.destroy / reference counting"""
|
||||
# allow _sockets to be None in case of process teardown
|
||||
if getattr(self, "_sockets", None) is not None:
|
||||
self._sockets.discard(socket)
|
||||
|
||||
def destroy(self, linger: Optional[int] = None) -> None:
|
||||
"""Close all sockets associated with this context and then terminate
|
||||
the context.
|
||||
|
||||
.. warning::
|
||||
|
||||
destroy involves calling ``zmq_close()``, which is **NOT** threadsafe.
|
||||
If there are active sockets in other threads, this must not be called.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
linger : int, optional
|
||||
If specified, set LINGER on sockets prior to closing them.
|
||||
"""
|
||||
if self.closed:
|
||||
return
|
||||
|
||||
sockets: List[ST] = list(getattr(self, "_sockets", None) or [])
|
||||
for s in sockets:
|
||||
if s and not s.closed:
|
||||
if self._warn_destroy_close and warn is not None:
|
||||
# warn can be None during process teardown
|
||||
warn(
|
||||
f"Destroying context with unclosed socket {s}",
|
||||
ResourceWarning,
|
||||
stacklevel=3,
|
||||
source=s,
|
||||
)
|
||||
if linger is not None:
|
||||
s.setsockopt(SocketOption.LINGER, linger)
|
||||
s.close()
|
||||
|
||||
self.term()
|
||||
|
||||
def socket(
|
||||
self: T,
|
||||
socket_type: int,
|
||||
socket_class: Optional[Callable[[T, int], ST]] = None,
|
||||
**kwargs: Any,
|
||||
) -> ST:
|
||||
"""Create a Socket associated with this Context.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
socket_type : int
|
||||
The socket type, which can be any of the 0MQ socket types:
|
||||
REQ, REP, PUB, SUB, PAIR, DEALER, ROUTER, PULL, PUSH, etc.
|
||||
|
||||
socket_class: zmq.Socket or a subclass
|
||||
The socket class to instantiate, if different from the default for this Context.
|
||||
e.g. for creating an asyncio socket attached to a default Context or vice versa.
|
||||
|
||||
.. versionadded:: 25
|
||||
|
||||
kwargs:
|
||||
will be passed to the __init__ method of the socket class.
|
||||
"""
|
||||
if self.closed:
|
||||
raise ZMQError(Errno.ENOTSUP)
|
||||
if socket_class is None:
|
||||
socket_class = self._socket_class
|
||||
s: ST = socket_class( # set PYTHONTRACEMALLOC=2 to get the calling frame
|
||||
self, socket_type, **kwargs
|
||||
)
|
||||
for opt, value in self.sockopts.items():
|
||||
try:
|
||||
s.setsockopt(opt, value)
|
||||
except ZMQError:
|
||||
# ignore ZMQErrors, which are likely for socket options
|
||||
# that do not apply to a particular socket type, e.g.
|
||||
# SUBSCRIBE for non-SUB sockets.
|
||||
pass
|
||||
self._add_socket(s)
|
||||
return s
|
||||
|
||||
def setsockopt(self, opt: int, value: Any) -> None:
|
||||
"""set default socket options for new sockets created by this Context
|
||||
|
||||
.. versionadded:: 13.0
|
||||
"""
|
||||
self.sockopts[opt] = value
|
||||
|
||||
def getsockopt(self, opt: int) -> OptValT:
|
||||
"""get default socket options for new sockets created by this Context
|
||||
|
||||
.. versionadded:: 13.0
|
||||
"""
|
||||
return self.sockopts[opt]
|
||||
|
||||
def _set_attr_opt(self, name: str, opt: int, value: OptValT) -> None:
|
||||
"""set default sockopts as attributes"""
|
||||
if name in ContextOption.__members__:
|
||||
return self.set(opt, value)
|
||||
elif name in SocketOption.__members__:
|
||||
self.sockopts[opt] = value
|
||||
else:
|
||||
raise AttributeError(f"No such context or socket option: {name}")
|
||||
|
||||
def _get_attr_opt(self, name: str, opt: int) -> OptValT:
|
||||
"""get default sockopts as attributes"""
|
||||
if name in ContextOption.__members__:
|
||||
return self.get(opt)
|
||||
else:
|
||||
if opt not in self.sockopts:
|
||||
raise AttributeError(name)
|
||||
else:
|
||||
return self.sockopts[opt]
|
||||
|
||||
def __delattr__(self, key: str) -> None:
|
||||
"""delete default sockopts as attributes"""
|
||||
if key in self.__dict__:
|
||||
self.__dict__.pop(key)
|
||||
return
|
||||
key = key.upper()
|
||||
try:
|
||||
opt = getattr(SocketOption, key)
|
||||
except AttributeError:
|
||||
raise AttributeError(f"No such socket option: {key!r}")
|
||||
else:
|
||||
if opt not in self.sockopts:
|
||||
raise AttributeError(key)
|
||||
else:
|
||||
del self.sockopts[opt]
|
||||
|
||||
|
||||
__all__ = ['Context']
|
||||
106
asm/venv/lib/python3.11/site-packages/zmq/sugar/frame.py
Normal file
106
asm/venv/lib/python3.11/site-packages/zmq/sugar/frame.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""0MQ Frame pure Python methods."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import zmq
|
||||
from zmq.backend import Frame as FrameBase
|
||||
|
||||
from .attrsettr import AttributeSetter
|
||||
|
||||
|
||||
def _draft(v, feature):
|
||||
zmq.error._check_version(v, feature)
|
||||
if not zmq.DRAFT_API:
|
||||
raise RuntimeError(
|
||||
"libzmq and pyzmq must be built with draft support for %s" % feature
|
||||
)
|
||||
|
||||
|
||||
class Frame(FrameBase, AttributeSetter):
|
||||
"""Frame(data=None, track=False, copy=None, copy_threshold=zmq.COPY_THRESHOLD)
|
||||
|
||||
A zmq message Frame class for non-copying send/recvs and access to message properties.
|
||||
|
||||
A ``zmq.Frame`` wraps an underlying ``zmq_msg_t``.
|
||||
|
||||
Message *properties* can be accessed by treating a Frame like a dictionary (``frame["User-Id"]``).
|
||||
|
||||
.. versionadded:: 14.4, libzmq 4
|
||||
|
||||
Frames created by ``recv(copy=False)`` can be used to access message properties and attributes,
|
||||
such as the CURVE User-Id.
|
||||
|
||||
For example::
|
||||
|
||||
frames = socket.recv_multipart(copy=False)
|
||||
user_id = frames[0]["User-Id"]
|
||||
|
||||
This class is used if you want to do non-copying send and recvs.
|
||||
When you pass a chunk of bytes to this class, e.g. ``Frame(buf)``, the
|
||||
ref-count of `buf` is increased by two: once because the Frame saves `buf` as
|
||||
an instance attribute and another because a ZMQ message is created that
|
||||
points to the buffer of `buf`. This second ref-count increase makes sure
|
||||
that `buf` lives until all messages that use it have been sent.
|
||||
Once 0MQ sends all the messages and it doesn't need the buffer of ``buf``,
|
||||
0MQ will call ``Py_DECREF(s)``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
data : object, optional
|
||||
any object that provides the buffer interface will be used to
|
||||
construct the 0MQ message data.
|
||||
track : bool [default: False]
|
||||
whether a MessageTracker_ should be created to track this object.
|
||||
Tracking a message has a cost at creation, because it creates a threadsafe
|
||||
Event object.
|
||||
copy : bool [default: use copy_threshold]
|
||||
Whether to create a copy of the data to pass to libzmq
|
||||
or share the memory with libzmq.
|
||||
If unspecified, copy_threshold is used.
|
||||
copy_threshold: int [default: zmq.COPY_THRESHOLD]
|
||||
If copy is unspecified, messages smaller than this many bytes
|
||||
will be copied and messages larger than this will be shared with libzmq.
|
||||
"""
|
||||
|
||||
def __getitem__(self, key):
|
||||
# map Frame['User-Id'] to Frame.get('User-Id')
|
||||
return self.get(key)
|
||||
|
||||
@property
|
||||
def group(self):
|
||||
"""The RADIO-DISH group of the message.
|
||||
|
||||
Requires libzmq >= 4.2 and pyzmq built with draft APIs enabled.
|
||||
|
||||
.. versionadded:: 17
|
||||
"""
|
||||
_draft((4, 2), "RADIO-DISH")
|
||||
return self.get('group')
|
||||
|
||||
@group.setter
|
||||
def group(self, group):
|
||||
_draft((4, 2), "RADIO-DISH")
|
||||
self.set('group', group)
|
||||
|
||||
@property
|
||||
def routing_id(self):
|
||||
"""The CLIENT-SERVER routing id of the message.
|
||||
|
||||
Requires libzmq >= 4.2 and pyzmq built with draft APIs enabled.
|
||||
|
||||
.. versionadded:: 17
|
||||
"""
|
||||
_draft((4, 2), "CLIENT-SERVER")
|
||||
return self.get('routing_id')
|
||||
|
||||
@routing_id.setter
|
||||
def routing_id(self, routing_id):
|
||||
_draft((4, 2), "CLIENT-SERVER")
|
||||
self.set('routing_id', routing_id)
|
||||
|
||||
|
||||
# keep deprecated alias
|
||||
Message = Frame
|
||||
__all__ = ['Frame', 'Message']
|
||||
164
asm/venv/lib/python3.11/site-packages/zmq/sugar/poll.py
Normal file
164
asm/venv/lib/python3.11/site-packages/zmq/sugar/poll.py
Normal file
@@ -0,0 +1,164 @@
|
||||
"""0MQ polling related functions and classes."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from zmq.backend import zmq_poll
|
||||
from zmq.constants import POLLERR, POLLIN, POLLOUT
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Polling related methods
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Poller:
|
||||
"""A stateful poll interface that mirrors Python's built-in poll."""
|
||||
|
||||
sockets: List[Tuple[Any, int]]
|
||||
_map: Dict
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.sockets = []
|
||||
self._map = {}
|
||||
|
||||
def __contains__(self, socket: Any) -> bool:
|
||||
return socket in self._map
|
||||
|
||||
def register(self, socket: Any, flags: int = POLLIN | POLLOUT):
|
||||
"""p.register(socket, flags=POLLIN|POLLOUT)
|
||||
|
||||
Register a 0MQ socket or native fd for I/O monitoring.
|
||||
|
||||
register(s,0) is equivalent to unregister(s).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
socket : zmq.Socket or native socket
|
||||
A zmq.Socket or any Python object having a ``fileno()``
|
||||
method that returns a valid file descriptor.
|
||||
flags : int
|
||||
The events to watch for. Can be POLLIN, POLLOUT or POLLIN|POLLOUT.
|
||||
If `flags=0`, socket will be unregistered.
|
||||
"""
|
||||
if flags:
|
||||
if socket in self._map:
|
||||
idx = self._map[socket]
|
||||
self.sockets[idx] = (socket, flags)
|
||||
else:
|
||||
idx = len(self.sockets)
|
||||
self.sockets.append((socket, flags))
|
||||
self._map[socket] = idx
|
||||
elif socket in self._map:
|
||||
# uregister sockets registered with no events
|
||||
self.unregister(socket)
|
||||
else:
|
||||
# ignore new sockets with no events
|
||||
pass
|
||||
|
||||
def modify(self, socket, flags=POLLIN | POLLOUT):
|
||||
"""Modify the flags for an already registered 0MQ socket or native fd."""
|
||||
self.register(socket, flags)
|
||||
|
||||
def unregister(self, socket: Any):
|
||||
"""Remove a 0MQ socket or native fd for I/O monitoring.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
socket : Socket
|
||||
The socket instance to stop polling.
|
||||
"""
|
||||
idx = self._map.pop(socket)
|
||||
self.sockets.pop(idx)
|
||||
# shift indices after deletion
|
||||
for socket, flags in self.sockets[idx:]:
|
||||
self._map[socket] -= 1
|
||||
|
||||
def poll(self, timeout: Optional[int] = None) -> List[Tuple[Any, int]]:
|
||||
"""Poll the registered 0MQ or native fds for I/O.
|
||||
|
||||
If there are currently events ready to be processed, this function will return immediately.
|
||||
Otherwise, this function will return as soon the first event is available or after timeout
|
||||
milliseconds have elapsed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
timeout : int
|
||||
The timeout in milliseconds. If None, no `timeout` (infinite). This
|
||||
is in milliseconds to be compatible with ``select.poll()``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
events : list of tuples
|
||||
The list of events that are ready to be processed.
|
||||
This is a list of tuples of the form ``(socket, event_mask)``, where the 0MQ Socket
|
||||
or integer fd is the first element, and the poll event mask (POLLIN, POLLOUT) is the second.
|
||||
It is common to call ``events = dict(poller.poll())``,
|
||||
which turns the list of tuples into a mapping of ``socket : event_mask``.
|
||||
"""
|
||||
if timeout is None or timeout < 0:
|
||||
timeout = -1
|
||||
elif isinstance(timeout, float):
|
||||
timeout = int(timeout)
|
||||
return zmq_poll(self.sockets, timeout=timeout)
|
||||
|
||||
|
||||
def select(rlist: List, wlist: List, xlist: List, timeout: Optional[float] = None):
|
||||
"""select(rlist, wlist, xlist, timeout=None) -> (rlist, wlist, xlist)
|
||||
|
||||
Return the result of poll as a lists of sockets ready for r/w/exception.
|
||||
|
||||
This has the same interface as Python's built-in ``select.select()`` function.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
timeout : float, int, optional
|
||||
The timeout in seconds. If None, no timeout (infinite). This is in seconds to be
|
||||
compatible with ``select.select()``.
|
||||
rlist : list of sockets/FDs
|
||||
sockets/FDs to be polled for read events
|
||||
wlist : list of sockets/FDs
|
||||
sockets/FDs to be polled for write events
|
||||
xlist : list of sockets/FDs
|
||||
sockets/FDs to be polled for error events
|
||||
|
||||
Returns
|
||||
-------
|
||||
(rlist, wlist, xlist) : tuple of lists of sockets (length 3)
|
||||
Lists correspond to sockets available for read/write/error events respectively.
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = -1
|
||||
# Convert from sec -> ms for zmq_poll.
|
||||
# zmq_poll accepts 3.x style timeout in ms
|
||||
timeout = int(timeout * 1000.0)
|
||||
if timeout < 0:
|
||||
timeout = -1
|
||||
sockets = []
|
||||
for s in set(rlist + wlist + xlist):
|
||||
flags = 0
|
||||
if s in rlist:
|
||||
flags |= POLLIN
|
||||
if s in wlist:
|
||||
flags |= POLLOUT
|
||||
if s in xlist:
|
||||
flags |= POLLERR
|
||||
sockets.append((s, flags))
|
||||
return_sockets = zmq_poll(sockets, timeout)
|
||||
rlist, wlist, xlist = [], [], []
|
||||
for s, flags in return_sockets:
|
||||
if flags & POLLIN:
|
||||
rlist.append(s)
|
||||
if flags & POLLOUT:
|
||||
wlist.append(s)
|
||||
if flags & POLLERR:
|
||||
xlist.append(s)
|
||||
return rlist, wlist, xlist
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Symbols to export
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
__all__ = ['Poller', 'select']
|
||||
1106
asm/venv/lib/python3.11/site-packages/zmq/sugar/socket.py
Normal file
1106
asm/venv/lib/python3.11/site-packages/zmq/sugar/socket.py
Normal file
File diff suppressed because it is too large
Load Diff
36
asm/venv/lib/python3.11/site-packages/zmq/sugar/stopwatch.py
Normal file
36
asm/venv/lib/python3.11/site-packages/zmq/sugar/stopwatch.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Deprecated Stopwatch implementation"""
|
||||
|
||||
# Copyright (c) PyZMQ Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
class Stopwatch:
|
||||
"""Deprecated zmq.Stopwatch implementation
|
||||
|
||||
You can use Python's builtin timers (time.monotonic, etc.).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
import warnings
|
||||
|
||||
warnings.warn(
|
||||
"zmq.Stopwatch is deprecated. Use stdlib time.monotonic and friends instead",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self._start = 0
|
||||
import time
|
||||
|
||||
try:
|
||||
self._monotonic = time.monotonic
|
||||
except AttributeError:
|
||||
self._monotonic = time.time
|
||||
|
||||
def start(self):
|
||||
"""Start the counter"""
|
||||
self._start = self._monotonic()
|
||||
|
||||
def stop(self):
|
||||
"""Return time since start in microseconds"""
|
||||
stop = self._monotonic()
|
||||
return int(1e6 * (stop - self._start))
|
||||
120
asm/venv/lib/python3.11/site-packages/zmq/sugar/tracker.py
Normal file
120
asm/venv/lib/python3.11/site-packages/zmq/sugar/tracker.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""Tracker for zero-copy messages with 0MQ."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import time
|
||||
from threading import Event
|
||||
from typing import Set, Tuple, Union
|
||||
|
||||
from zmq.backend import Frame
|
||||
from zmq.error import NotDone
|
||||
|
||||
|
||||
class MessageTracker:
|
||||
"""MessageTracker(*towatch)
|
||||
|
||||
A class for tracking if 0MQ is done using one or more messages.
|
||||
|
||||
When you send a 0MQ message, it is not sent immediately. The 0MQ IO thread
|
||||
sends the message at some later time. Often you want to know when 0MQ has
|
||||
actually sent the message though. This is complicated by the fact that
|
||||
a single 0MQ message can be sent multiple times using different sockets.
|
||||
This class allows you to track all of the 0MQ usages of a message.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
towatch : Event, MessageTracker, Message instances.
|
||||
This objects to track. This class can track the low-level
|
||||
Events used by the Message class, other MessageTrackers or
|
||||
actual Messages.
|
||||
"""
|
||||
|
||||
events: Set[Event]
|
||||
peers: Set["MessageTracker"]
|
||||
|
||||
def __init__(self, *towatch: Tuple[Union["MessageTracker", Event, Frame]]):
|
||||
"""MessageTracker(*towatch)
|
||||
|
||||
Create a message tracker to track a set of messages.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
*towatch : tuple of Event, MessageTracker, Message instances.
|
||||
This list of objects to track. This class can track the low-level
|
||||
Events used by the Message class, other MessageTrackers or
|
||||
actual Messages.
|
||||
"""
|
||||
self.events = set()
|
||||
self.peers = set()
|
||||
for obj in towatch:
|
||||
if isinstance(obj, Event):
|
||||
self.events.add(obj)
|
||||
elif isinstance(obj, MessageTracker):
|
||||
self.peers.add(obj)
|
||||
elif isinstance(obj, Frame):
|
||||
if not obj.tracker:
|
||||
raise ValueError("Not a tracked message")
|
||||
self.peers.add(obj.tracker)
|
||||
else:
|
||||
raise TypeError("Require Events or Message Frames, not %s" % type(obj))
|
||||
|
||||
@property
|
||||
def done(self):
|
||||
"""Is 0MQ completely done with the message(s) being tracked?"""
|
||||
for evt in self.events:
|
||||
if not evt.is_set():
|
||||
return False
|
||||
for pm in self.peers:
|
||||
if not pm.done:
|
||||
return False
|
||||
return True
|
||||
|
||||
def wait(self, timeout: Union[float, int] = -1):
|
||||
"""mt.wait(timeout=-1)
|
||||
|
||||
Wait for 0MQ to be done with the message or until `timeout`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
timeout : float [default: -1, wait forever]
|
||||
Maximum time in (s) to wait before raising NotDone.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
if done before `timeout`
|
||||
|
||||
Raises
|
||||
------
|
||||
NotDone
|
||||
if `timeout` reached before I am done.
|
||||
"""
|
||||
tic = time.time()
|
||||
remaining: float
|
||||
if timeout is False or timeout < 0:
|
||||
remaining = 3600 * 24 * 7 # a week
|
||||
else:
|
||||
remaining = timeout
|
||||
for evt in self.events:
|
||||
if remaining < 0:
|
||||
raise NotDone
|
||||
evt.wait(timeout=remaining)
|
||||
if not evt.is_set():
|
||||
raise NotDone
|
||||
toc = time.time()
|
||||
remaining -= toc - tic
|
||||
tic = toc
|
||||
|
||||
for peer in self.peers:
|
||||
if remaining < 0:
|
||||
raise NotDone
|
||||
peer.wait(timeout=remaining)
|
||||
toc = time.time()
|
||||
remaining -= toc - tic
|
||||
tic = toc
|
||||
|
||||
|
||||
_FINISHED_TRACKER = MessageTracker()
|
||||
|
||||
__all__ = ['MessageTracker', '_FINISHED_TRACKER']
|
||||
66
asm/venv/lib/python3.11/site-packages/zmq/sugar/version.py
Normal file
66
asm/venv/lib/python3.11/site-packages/zmq/sugar/version.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""PyZMQ and 0MQ version functions."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import re
|
||||
from typing import Match, Tuple, Union, cast
|
||||
|
||||
from zmq.backend import zmq_version_info
|
||||
|
||||
__version__: str = "25.1.2"
|
||||
_version_pat = re.compile(r"(\d+)\.(\d+)\.(\d+)(.*)")
|
||||
_match = cast(Match, _version_pat.match(__version__))
|
||||
_version_groups = _match.groups()
|
||||
|
||||
VERSION_MAJOR = int(_version_groups[0])
|
||||
VERSION_MINOR = int(_version_groups[1])
|
||||
VERSION_PATCH = int(_version_groups[2])
|
||||
VERSION_EXTRA = _version_groups[3].lstrip(".")
|
||||
|
||||
version_info: Union[Tuple[int, int, int], Tuple[int, int, int, float]] = (
|
||||
VERSION_MAJOR,
|
||||
VERSION_MINOR,
|
||||
VERSION_PATCH,
|
||||
)
|
||||
|
||||
if VERSION_EXTRA:
|
||||
version_info = (
|
||||
VERSION_MAJOR,
|
||||
VERSION_MINOR,
|
||||
VERSION_PATCH,
|
||||
float('inf'),
|
||||
)
|
||||
|
||||
__revision__: str = ''
|
||||
|
||||
|
||||
def pyzmq_version() -> str:
|
||||
"""return the version of pyzmq as a string"""
|
||||
if __revision__:
|
||||
return '+'.join([__version__, __revision__[:6]])
|
||||
else:
|
||||
return __version__
|
||||
|
||||
|
||||
def pyzmq_version_info() -> Union[Tuple[int, int, int], Tuple[int, int, int, float]]:
|
||||
"""return the pyzmq version as a tuple of at least three numbers
|
||||
|
||||
If pyzmq is a development version, `inf` will be appended after the third integer.
|
||||
"""
|
||||
return version_info
|
||||
|
||||
|
||||
def zmq_version() -> str:
|
||||
"""return the version of libzmq as a string"""
|
||||
return "%i.%i.%i" % zmq_version_info()
|
||||
|
||||
|
||||
__all__ = [
|
||||
'zmq_version',
|
||||
'zmq_version_info',
|
||||
'pyzmq_version',
|
||||
'pyzmq_version_info',
|
||||
'__version__',
|
||||
'__revision__',
|
||||
]
|
||||
Reference in New Issue
Block a user