Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
29
venv/Lib/site-packages/zmq/sugar/__init__.py
Normal file
29
venv/Lib/site-packages/zmq/sugar/__init__.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
"""pure-Python sugar wrappers for core 0MQ objects."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
from zmq.sugar import (
|
||||
constants, context, frame, poll, socket, tracker, version
|
||||
)
|
||||
from zmq import error
|
||||
|
||||
__all__ = ['constants']
|
||||
for submod in (
|
||||
constants, context, error, frame, poll, socket, tracker, version
|
||||
):
|
||||
__all__.extend(submod.__all__)
|
||||
|
||||
from zmq.error import *
|
||||
from zmq.sugar.context import *
|
||||
from zmq.sugar.tracker import *
|
||||
from zmq.sugar.socket import *
|
||||
from zmq.sugar.constants import *
|
||||
from zmq.sugar.frame import *
|
||||
from zmq.sugar.poll import *
|
||||
from zmq.sugar.version import *
|
||||
|
||||
# deprecated:
|
||||
from zmq.sugar.stopwatch import Stopwatch
|
||||
__all__.append('Stopwatch')
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
venv/Lib/site-packages/zmq/sugar/__pycache__/poll.cpython-36.pyc
Normal file
BIN
venv/Lib/site-packages/zmq/sugar/__pycache__/poll.cpython-36.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
66
venv/Lib/site-packages/zmq/sugar/attrsettr.py
Normal file
66
venv/Lib/site-packages/zmq/sugar/attrsettr.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
# coding: utf-8
|
||||
"""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 . import constants
|
||||
|
||||
class AttributeSetter(object):
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
"""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 obj in self.__class__.mro():
|
||||
if key in obj.__dict__:
|
||||
object.__setattr__(self, key, value)
|
||||
return
|
||||
|
||||
upper_key = key.upper()
|
||||
try:
|
||||
opt = getattr(constants, upper_key)
|
||||
except AttributeError:
|
||||
raise AttributeError("%s has no such option: %s" % (
|
||||
self.__class__.__name__, upper_key)
|
||||
)
|
||||
else:
|
||||
self._set_attr_opt(upper_key, opt, value)
|
||||
|
||||
def _set_attr_opt(self, name, opt, value):
|
||||
"""override if setattr should do something other than call self.set"""
|
||||
self.set(opt, value)
|
||||
|
||||
def __getattr__(self, key):
|
||||
"""get zmq options by attribute"""
|
||||
upper_key = key.upper()
|
||||
try:
|
||||
opt = getattr(constants, upper_key)
|
||||
except AttributeError:
|
||||
raise AttributeError("%s has no such option: %s" % (
|
||||
self.__class__.__name__, upper_key)
|
||||
)
|
||||
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 == errno.EINVAL:
|
||||
raise AttributeError("{} attribute is write-only".format(key))
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def _get_attr_opt(self, name, opt):
|
||||
"""override if getattr should do something other than call self.get"""
|
||||
return self.get(opt)
|
||||
|
||||
|
||||
__all__ = ['AttributeSetter']
|
108
venv/Lib/site-packages/zmq/sugar/constants.py
Normal file
108
venv/Lib/site-packages/zmq/sugar/constants.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
"""0MQ Constants."""
|
||||
|
||||
# Copyright (c) PyZMQ Developers.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
from zmq.backend import constants
|
||||
from zmq.backend import has
|
||||
from zmq.utils.constant_names import (
|
||||
base_names,
|
||||
switched_sockopt_names,
|
||||
int_sockopt_names,
|
||||
int64_sockopt_names,
|
||||
bytes_sockopt_names,
|
||||
fd_sockopt_names,
|
||||
ctx_opt_names,
|
||||
msg_opt_names,
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Python module level constants
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
__all__ = [
|
||||
'int_sockopts',
|
||||
'int64_sockopts',
|
||||
'bytes_sockopts',
|
||||
'ctx_opts',
|
||||
'ctx_opt_names',
|
||||
'DRAFT_API',
|
||||
]
|
||||
|
||||
if constants.VERSION < 40200:
|
||||
DRAFT_API = False
|
||||
else:
|
||||
DRAFT_API = bool(has('draft') and constants.DRAFT_API)
|
||||
|
||||
int_sockopts = set()
|
||||
int64_sockopts = set()
|
||||
bytes_sockopts = set()
|
||||
fd_sockopts = set()
|
||||
ctx_opts = set()
|
||||
msg_opts = set()
|
||||
|
||||
|
||||
if constants.VERSION < 30000:
|
||||
int64_sockopt_names.extend(switched_sockopt_names)
|
||||
else:
|
||||
int_sockopt_names.extend(switched_sockopt_names)
|
||||
|
||||
_UNDEFINED = -9999
|
||||
|
||||
|
||||
def _add_constant(name, container=None):
|
||||
"""add a constant to be defined
|
||||
|
||||
optionally add it to one of the sets for use in get/setopt checkers
|
||||
"""
|
||||
c = getattr(constants, name, _UNDEFINED)
|
||||
if c == _UNDEFINED:
|
||||
return
|
||||
globals()[name] = c
|
||||
__all__.append(name)
|
||||
if container is not None:
|
||||
container.add(c)
|
||||
return c
|
||||
|
||||
for name in base_names:
|
||||
_add_constant(name)
|
||||
|
||||
for name in int_sockopt_names:
|
||||
_add_constant(name, int_sockopts)
|
||||
|
||||
for name in int64_sockopt_names:
|
||||
_add_constant(name, int64_sockopts)
|
||||
|
||||
for name in bytes_sockopt_names:
|
||||
_add_constant(name, bytes_sockopts)
|
||||
|
||||
for name in fd_sockopt_names:
|
||||
_add_constant(name, fd_sockopts)
|
||||
|
||||
for name in ctx_opt_names:
|
||||
_add_constant(name, ctx_opts)
|
||||
|
||||
for name in msg_opt_names:
|
||||
_add_constant(name, msg_opts)
|
||||
|
||||
|
||||
# ensure some aliases are always defined
|
||||
aliases = [
|
||||
('DONTWAIT', 'NOBLOCK'),
|
||||
('XREQ', 'DEALER'),
|
||||
('XREP', 'ROUTER'),
|
||||
]
|
||||
for group in aliases:
|
||||
undefined = set()
|
||||
found = None
|
||||
for name in group:
|
||||
value = getattr(constants, name, -1)
|
||||
if value != -1:
|
||||
found = value
|
||||
else:
|
||||
undefined.add(name)
|
||||
if found is not None:
|
||||
for name in undefined:
|
||||
globals()[name] = found
|
||||
__all__.append(name)
|
282
venv/Lib/site-packages/zmq/sugar/context.py
Normal file
282
venv/Lib/site-packages/zmq/sugar/context.py
Normal file
|
@ -0,0 +1,282 @@
|
|||
# coding: utf-8
|
||||
"""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 weakref import WeakSet
|
||||
|
||||
from zmq.backend import Context as ContextBase
|
||||
from . import constants
|
||||
from .attrsettr import AttributeSetter
|
||||
from .constants import ENOTSUP, LINGER, ctx_opt_names
|
||||
from .socket import Socket
|
||||
from zmq.error import ZMQError
|
||||
|
||||
# notice when exiting, to avoid triggering term on exit
|
||||
_exiting = False
|
||||
def _notice_atexit():
|
||||
global _exiting
|
||||
_exiting = True
|
||||
atexit.register(_notice_atexit)
|
||||
|
||||
class Context(ContextBase, AttributeSetter):
|
||||
"""Create a zmq Context
|
||||
|
||||
A zmq Context creates sockets via its ``ctx.socket`` method.
|
||||
"""
|
||||
sockopts = None
|
||||
_instance = None
|
||||
_instance_lock = Lock()
|
||||
_instance_pid = None
|
||||
_shadow = False
|
||||
_sockets = None
|
||||
|
||||
def __init__(self, io_threads=1, **kwargs):
|
||||
super(Context, self).__init__(io_threads=io_threads, **kwargs)
|
||||
if kwargs.get('shadow', False):
|
||||
self._shadow = True
|
||||
else:
|
||||
self._shadow = False
|
||||
self.sockopts = {}
|
||||
self._sockets = WeakSet()
|
||||
|
||||
def __del__(self):
|
||||
"""deleting a Context should terminate it, without trying non-threadsafe destroy"""
|
||||
|
||||
# Calling locals() here conceals issue #1167 on Windows CPython 3.5.4.
|
||||
locals()
|
||||
|
||||
if not self._shadow and not _exiting:
|
||||
self.term()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *args, **kwargs):
|
||||
self.term()
|
||||
|
||||
def __copy__(self, memo=None):
|
||||
"""Copying a Context creates a shadow copy"""
|
||||
return self.__class__.shadow(self.underlying)
|
||||
|
||||
__deepcopy__ = __copy__
|
||||
|
||||
@classmethod
|
||||
def shadow(cls, address):
|
||||
"""Shadow an existing libzmq context
|
||||
|
||||
address is the integer address of the libzmq context
|
||||
or an FFI pointer to it.
|
||||
|
||||
.. versionadded:: 14.1
|
||||
"""
|
||||
from zmq.utils.interop import cast_int_addr
|
||||
address = cast_int_addr(address)
|
||||
return cls(shadow=address)
|
||||
|
||||
@classmethod
|
||||
def shadow_pyczmq(cls, ctx):
|
||||
"""Shadow an existing pyczmq context
|
||||
|
||||
ctx is the FFI `zctx_t *` pointer
|
||||
|
||||
.. versionadded:: 14.1
|
||||
"""
|
||||
from pyczmq import zctx
|
||||
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, io_threads=1):
|
||||
"""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):
|
||||
"""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.
|
||||
"""
|
||||
return super(Context, self).term()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Hooks for ctxopt completion
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
def __dir__(self):
|
||||
keys = dir(self.__class__)
|
||||
|
||||
for collection in (
|
||||
ctx_opt_names,
|
||||
):
|
||||
keys.extend(collection)
|
||||
return keys
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Creating Sockets
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
def _add_socket(self, socket):
|
||||
self._sockets.add(socket)
|
||||
|
||||
def _rm_socket(self, socket):
|
||||
if self._sockets:
|
||||
self._sockets.discard(socket)
|
||||
|
||||
def destroy(self, linger=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 = self._sockets
|
||||
self._sockets = WeakSet()
|
||||
for s in sockets:
|
||||
if s and not s.closed:
|
||||
if linger is not None:
|
||||
s.setsockopt(LINGER, linger)
|
||||
s.close()
|
||||
|
||||
self.term()
|
||||
|
||||
@property
|
||||
def _socket_class(self):
|
||||
return Socket
|
||||
|
||||
def socket(self, socket_type, **kwargs):
|
||||
"""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.
|
||||
|
||||
kwargs:
|
||||
will be passed to the __init__ method of the socket class.
|
||||
"""
|
||||
if self.closed:
|
||||
raise ZMQError(ENOTSUP)
|
||||
s = self._socket_class(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, value):
|
||||
"""set default socket options for new sockets created by this Context
|
||||
|
||||
.. versionadded:: 13.0
|
||||
"""
|
||||
self.sockopts[opt] = value
|
||||
|
||||
def getsockopt(self, opt):
|
||||
"""get default socket options for new sockets created by this Context
|
||||
|
||||
.. versionadded:: 13.0
|
||||
"""
|
||||
return self.sockopts[opt]
|
||||
|
||||
def _set_attr_opt(self, name, opt, value):
|
||||
"""set default sockopts as attributes"""
|
||||
if name in constants.ctx_opt_names:
|
||||
return self.set(opt, value)
|
||||
else:
|
||||
self.sockopts[opt] = value
|
||||
|
||||
def _get_attr_opt(self, name, opt):
|
||||
"""get default sockopts as attributes"""
|
||||
if name in constants.ctx_opt_names:
|
||||
return self.get(opt)
|
||||
else:
|
||||
if opt not in self.sockopts:
|
||||
raise AttributeError(name)
|
||||
else:
|
||||
return self.sockopts[opt]
|
||||
|
||||
def __delattr__(self, key):
|
||||
"""delete default sockopts as attributes"""
|
||||
key = key.upper()
|
||||
try:
|
||||
opt = getattr(constants, key)
|
||||
except AttributeError:
|
||||
raise AttributeError("no such socket option: %s" % key)
|
||||
else:
|
||||
if opt not in self.sockopts:
|
||||
raise AttributeError(key)
|
||||
else:
|
||||
del self.sockopts[opt]
|
||||
|
||||
__all__ = ['Context']
|
88
venv/Lib/site-packages/zmq/sugar/frame.py
Normal file
88
venv/Lib/site-packages/zmq/sugar/frame.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
# coding: utf-8
|
||||
"""0MQ Frame pure Python methods."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
from .attrsettr import AttributeSetter
|
||||
from zmq.backend import Frame as FrameBase
|
||||
import zmq
|
||||
|
||||
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-copy send/recvs.
|
||||
|
||||
This class is only needed if you want to do non-copying send and recvs.
|
||||
When you pass a string to this class, like ``Frame(s)``, the
|
||||
ref-count of `s` is increased by two: once because the Frame saves `s` as
|
||||
an instance attribute and another because a ZMQ message is created that
|
||||
points to the buffer of `s`. This second ref-count increase makes sure
|
||||
that `s` lives until all messages that use it have been sent. Once 0MQ
|
||||
sends all the messages and it doesn't need the buffer of s, 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']
|
162
venv/Lib/site-packages/zmq/sugar/poll.py
Normal file
162
venv/Lib/site-packages/zmq/sugar/poll.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
"""0MQ polling related functions and classes."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
import zmq
|
||||
from zmq.backend import zmq_poll
|
||||
from .constants import POLLIN, POLLOUT, POLLERR
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Polling related methods
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class Poller(object):
|
||||
"""A stateful poll interface that mirrors Python's built-in poll."""
|
||||
sockets = None
|
||||
_map = {}
|
||||
|
||||
def __init__(self):
|
||||
self.sockets = []
|
||||
self._map = {}
|
||||
|
||||
def __contains__(self, socket):
|
||||
return socket in self._map
|
||||
|
||||
def register(self, socket, flags=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):
|
||||
"""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=None):
|
||||
"""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 : float, 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, wlist, xlist, timeout=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 -> us 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' ]
|
774
venv/Lib/site-packages/zmq/sugar/socket.py
Normal file
774
venv/Lib/site-packages/zmq/sugar/socket.py
Normal file
|
@ -0,0 +1,774 @@
|
|||
# coding: utf-8
|
||||
"""0MQ Socket pure Python methods."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
import errno
|
||||
import random
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import zmq
|
||||
from zmq.backend import Socket as SocketBase
|
||||
from .poll import Poller
|
||||
from . import constants
|
||||
from .attrsettr import AttributeSetter
|
||||
from zmq.error import ZMQError, ZMQBindError
|
||||
from zmq.utils import jsonapi
|
||||
from zmq.utils.strtypes import bytes, unicode, basestring
|
||||
|
||||
|
||||
from .constants import (
|
||||
SNDMORE, ENOTSUP, POLLIN,
|
||||
int64_sockopt_names,
|
||||
int_sockopt_names,
|
||||
bytes_sockopt_names,
|
||||
fd_sockopt_names,
|
||||
)
|
||||
try:
|
||||
import cPickle
|
||||
pickle = cPickle
|
||||
except:
|
||||
cPickle = None
|
||||
import pickle
|
||||
|
||||
try:
|
||||
DEFAULT_PROTOCOL = pickle.DEFAULT_PROTOCOL
|
||||
except AttributeError:
|
||||
DEFAULT_PROTOCOL = pickle.HIGHEST_PROTOCOL
|
||||
|
||||
|
||||
class Socket(SocketBase, AttributeSetter):
|
||||
"""The ZMQ socket object
|
||||
|
||||
To create a Socket, first create a Context::
|
||||
|
||||
ctx = zmq.Context.instance()
|
||||
|
||||
then call ``ctx.socket(socket_type)``::
|
||||
|
||||
s = ctx.socket(zmq.ROUTER)
|
||||
|
||||
"""
|
||||
_shadow = False
|
||||
_monitor_socket = None
|
||||
|
||||
def __init__(self, *a, **kw):
|
||||
super(Socket, self).__init__(*a, **kw)
|
||||
if 'shadow' in kw:
|
||||
self._shadow = True
|
||||
else:
|
||||
self._shadow = False
|
||||
|
||||
def __del__(self):
|
||||
if not self._shadow:
|
||||
self.close()
|
||||
|
||||
# socket as context manager:
|
||||
def __enter__(self):
|
||||
"""Sockets are context managers
|
||||
|
||||
.. versionadded:: 14.4
|
||||
"""
|
||||
return self
|
||||
|
||||
def __exit__(self, *args, **kwargs):
|
||||
self.close()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Socket creation
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
def __copy__(self, memo=None):
|
||||
"""Copying a Socket creates a shadow copy"""
|
||||
return self.__class__.shadow(self.underlying)
|
||||
|
||||
__deepcopy__ = __copy__
|
||||
|
||||
@classmethod
|
||||
def shadow(cls, address):
|
||||
"""Shadow an existing libzmq socket
|
||||
|
||||
address is the integer address of the libzmq socket
|
||||
or an FFI pointer to it.
|
||||
|
||||
.. versionadded:: 14.1
|
||||
"""
|
||||
from zmq.utils.interop import cast_int_addr
|
||||
address = cast_int_addr(address)
|
||||
return cls(shadow=address)
|
||||
|
||||
def close(self, linger=None):
|
||||
"""
|
||||
Close the socket.
|
||||
|
||||
If linger is specified, LINGER sockopt will be set prior to closing.
|
||||
|
||||
Note: closing a zmq Socket may not close the underlying sockets
|
||||
if there are undelivered messages.
|
||||
Only after all messages are delivered or discarded by reaching the socket's LINGER timeout
|
||||
(default: forever)
|
||||
will the underlying sockets be closed.
|
||||
|
||||
This can be called to close the socket by hand. If this is not
|
||||
called, the socket will automatically be closed when it is
|
||||
garbage collected.
|
||||
"""
|
||||
if self.context:
|
||||
self.context._rm_socket(self)
|
||||
super(Socket, self).close(linger=linger)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Deprecated aliases
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def socket_type(self):
|
||||
warnings.warn("Socket.socket_type is deprecated, use Socket.type",
|
||||
DeprecationWarning
|
||||
)
|
||||
return self.type
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Hooks for sockopt completion
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
def __dir__(self):
|
||||
keys = dir(self.__class__)
|
||||
for collection in (
|
||||
bytes_sockopt_names,
|
||||
int_sockopt_names,
|
||||
int64_sockopt_names,
|
||||
fd_sockopt_names,
|
||||
):
|
||||
keys.extend(collection)
|
||||
return keys
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Getting/Setting options
|
||||
#-------------------------------------------------------------------------
|
||||
setsockopt = SocketBase.set
|
||||
getsockopt = SocketBase.get
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
"""Override to allow setting zmq.[UN]SUBSCRIBE even though we have a subscribe method"""
|
||||
if key in self.__dict__:
|
||||
object.__setattr__(self, key, value)
|
||||
return
|
||||
_key = key.lower()
|
||||
if _key in ('subscribe', 'unsubscribe'):
|
||||
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode('utf8')
|
||||
if _key == 'subscribe':
|
||||
self.set(zmq.SUBSCRIBE, value)
|
||||
else:
|
||||
self.set(zmq.UNSUBSCRIBE, value)
|
||||
return
|
||||
super(Socket, self).__setattr__(key, value)
|
||||
|
||||
def fileno(self):
|
||||
"""Return edge-triggered file descriptor for this socket.
|
||||
|
||||
This is a read-only edge-triggered file descriptor for both read and write events on this socket.
|
||||
It is important that all available events be consumed when an event is detected,
|
||||
otherwise the read event will not trigger again.
|
||||
|
||||
.. versionadded:: 17.0
|
||||
"""
|
||||
return self.FD
|
||||
|
||||
def subscribe(self, topic):
|
||||
"""Subscribe to a topic
|
||||
|
||||
Only for SUB sockets.
|
||||
|
||||
.. versionadded:: 15.3
|
||||
"""
|
||||
if isinstance(topic, unicode):
|
||||
topic = topic.encode('utf8')
|
||||
self.set(zmq.SUBSCRIBE, topic)
|
||||
|
||||
def unsubscribe(self, topic):
|
||||
"""Unsubscribe from a topic
|
||||
|
||||
Only for SUB sockets.
|
||||
|
||||
.. versionadded:: 15.3
|
||||
"""
|
||||
if isinstance(topic, unicode):
|
||||
topic = topic.encode('utf8')
|
||||
self.set(zmq.UNSUBSCRIBE, topic)
|
||||
|
||||
def set_string(self, option, optval, encoding='utf-8'):
|
||||
"""Set socket options with a unicode object.
|
||||
|
||||
This is simply a wrapper for setsockopt to protect from encoding ambiguity.
|
||||
|
||||
See the 0MQ documentation for details on specific options.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
option : int
|
||||
The name of the option to set. Can be any of: SUBSCRIBE,
|
||||
UNSUBSCRIBE, IDENTITY
|
||||
optval : unicode string (unicode on py2, str on py3)
|
||||
The value of the option to set.
|
||||
encoding : str
|
||||
The encoding to be used, default is utf8
|
||||
"""
|
||||
if not isinstance(optval, unicode):
|
||||
raise TypeError("unicode strings only")
|
||||
return self.set(option, optval.encode(encoding))
|
||||
|
||||
setsockopt_unicode = setsockopt_string = set_string
|
||||
|
||||
def get_string(self, option, encoding='utf-8'):
|
||||
"""Get the value of a socket option.
|
||||
|
||||
See the 0MQ documentation for details on specific options.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
option : int
|
||||
The option to retrieve.
|
||||
|
||||
Returns
|
||||
-------
|
||||
optval : unicode string (unicode on py2, str on py3)
|
||||
The value of the option as a unicode string.
|
||||
"""
|
||||
|
||||
if option not in constants.bytes_sockopts:
|
||||
raise TypeError("option %i will not return a string to be decoded"%option)
|
||||
return self.getsockopt(option).decode(encoding)
|
||||
|
||||
getsockopt_unicode = getsockopt_string = get_string
|
||||
|
||||
def bind_to_random_port(self, addr, min_port=49152, max_port=65536, max_tries=100):
|
||||
"""Bind this socket to a random port in a range.
|
||||
|
||||
If the port range is unspecified, the system will choose the port.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
addr : str
|
||||
The address string without the port to pass to ``Socket.bind()``.
|
||||
min_port : int, optional
|
||||
The minimum port in the range of ports to try (inclusive).
|
||||
max_port : int, optional
|
||||
The maximum port in the range of ports to try (exclusive).
|
||||
max_tries : int, optional
|
||||
The maximum number of bind attempts to make.
|
||||
|
||||
Returns
|
||||
-------
|
||||
port : int
|
||||
The port the socket was bound to.
|
||||
|
||||
Raises
|
||||
------
|
||||
ZMQBindError
|
||||
if `max_tries` reached before successful bind
|
||||
"""
|
||||
if hasattr(constants, 'LAST_ENDPOINT') and min_port == 49152 and max_port == 65536:
|
||||
# if LAST_ENDPOINT is supported, and min_port / max_port weren't specified,
|
||||
# we can bind to port 0 and let the OS do the work
|
||||
self.bind("%s:*" % addr)
|
||||
url = self.last_endpoint.decode('ascii', 'replace')
|
||||
_, port_s = url.rsplit(':', 1)
|
||||
return int(port_s)
|
||||
|
||||
for i in range(max_tries):
|
||||
try:
|
||||
port = random.randrange(min_port, max_port)
|
||||
self.bind('%s:%s' % (addr, port))
|
||||
except ZMQError as exception:
|
||||
en = exception.errno
|
||||
if en == zmq.EADDRINUSE:
|
||||
continue
|
||||
elif sys.platform == 'win32' and en == errno.EACCES:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
return port
|
||||
raise ZMQBindError("Could not bind socket to random port.")
|
||||
|
||||
def get_hwm(self):
|
||||
"""Get the High Water Mark.
|
||||
|
||||
On libzmq ≥ 3, this gets SNDHWM if available, otherwise RCVHWM
|
||||
"""
|
||||
major = zmq.zmq_version_info()[0]
|
||||
if major >= 3:
|
||||
# return sndhwm, fallback on rcvhwm
|
||||
try:
|
||||
return self.getsockopt(zmq.SNDHWM)
|
||||
except zmq.ZMQError:
|
||||
pass
|
||||
|
||||
return self.getsockopt(zmq.RCVHWM)
|
||||
else:
|
||||
return self.getsockopt(zmq.HWM)
|
||||
|
||||
def set_hwm(self, value):
|
||||
"""Set the High Water Mark.
|
||||
|
||||
On libzmq ≥ 3, this sets both SNDHWM and RCVHWM
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
New values only take effect for subsequent socket
|
||||
bind/connects.
|
||||
"""
|
||||
major = zmq.zmq_version_info()[0]
|
||||
if major >= 3:
|
||||
raised = None
|
||||
try:
|
||||
self.sndhwm = value
|
||||
except Exception as e:
|
||||
raised = e
|
||||
try:
|
||||
self.rcvhwm = value
|
||||
except Exception as e:
|
||||
raised = e
|
||||
|
||||
if raised:
|
||||
raise raised
|
||||
else:
|
||||
return self.setsockopt(zmq.HWM, value)
|
||||
|
||||
hwm = property(get_hwm, set_hwm,
|
||||
"""Property for High Water Mark.
|
||||
|
||||
Setting hwm sets both SNDHWM and RCVHWM as appropriate.
|
||||
It gets SNDHWM if available, otherwise RCVHWM.
|
||||
"""
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Sending and receiving messages
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
def send(self, data, flags=0, copy=True, track=False, routing_id=None, group=None):
|
||||
"""Send a single zmq message frame on this socket.
|
||||
|
||||
This queues the message to be sent by the IO thread at a later time.
|
||||
|
||||
With flags=NOBLOCK, this raises :class:`ZMQError` if the queue is full;
|
||||
otherwise, this waits until space is available.
|
||||
See :class:`Poller` for more general non-blocking I/O.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : bytes, Frame, memoryview
|
||||
The content of the message. This can be any object that provides
|
||||
the Python buffer API (i.e. `memoryview(data)` can be called).
|
||||
flags : int
|
||||
0, NOBLOCK, SNDMORE, or NOBLOCK|SNDMORE.
|
||||
copy : bool
|
||||
Should the message be sent in a copying or non-copying manner.
|
||||
track : bool
|
||||
Should the message be tracked for notification that ZMQ has
|
||||
finished with it? (ignored if copy=True)
|
||||
routing_id : int
|
||||
For use with SERVER sockets
|
||||
group : str
|
||||
For use with RADIO sockets
|
||||
|
||||
Returns
|
||||
-------
|
||||
None : if `copy` or not track
|
||||
None if message was sent, raises an exception otherwise.
|
||||
MessageTracker : if track and not copy
|
||||
a MessageTracker object, whose `pending` property will
|
||||
be True until the send is completed.
|
||||
|
||||
Raises
|
||||
------
|
||||
TypeError
|
||||
If a unicode object is passed
|
||||
ValueError
|
||||
If `track=True`, but an untracked Frame is passed.
|
||||
ZMQError
|
||||
If the send does not succeed for any reason (including
|
||||
if NOBLOCK is set and the outgoing queue is full).
|
||||
|
||||
|
||||
.. versionchanged:: 17.0
|
||||
|
||||
DRAFT support for routing_id and group arguments.
|
||||
"""
|
||||
if routing_id is not None:
|
||||
if not isinstance(data, zmq.Frame):
|
||||
data = zmq.Frame(data, track=track, copy=copy or None,
|
||||
copy_threshold=self.copy_threshold)
|
||||
data.routing_id = routing_id
|
||||
if group is not None:
|
||||
if not isinstance(data, zmq.Frame):
|
||||
data = zmq.Frame(data, track=track, copy=copy or None,
|
||||
copy_threshold=self.copy_threshold)
|
||||
data.group = group
|
||||
return super(Socket, self).send(data, flags=flags, copy=copy, track=track)
|
||||
|
||||
def send_multipart(self, msg_parts, flags=0, copy=True, track=False, **kwargs):
|
||||
"""Send a sequence of buffers as a multipart message.
|
||||
|
||||
The zmq.SNDMORE flag is added to all msg parts before the last.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
msg_parts : iterable
|
||||
A sequence of objects to send as a multipart message. Each element
|
||||
can be any sendable object (Frame, bytes, buffer-providers)
|
||||
flags : int, optional
|
||||
Any valid flags for :func:`Socket.send`.
|
||||
SNDMORE is added automatically for frames before the last.
|
||||
copy : bool, optional
|
||||
Should the frame(s) be sent in a copying or non-copying manner.
|
||||
If copy=False, frames smaller than self.copy_threshold bytes
|
||||
will be copied anyway.
|
||||
track : bool, optional
|
||||
Should the frame(s) be tracked for notification that ZMQ has
|
||||
finished with it (ignored if copy=True).
|
||||
|
||||
Returns
|
||||
-------
|
||||
None : if copy or not track
|
||||
MessageTracker : if track and not copy
|
||||
a MessageTracker object, whose `pending` property will
|
||||
be True until the last send is completed.
|
||||
"""
|
||||
# typecheck parts before sending:
|
||||
for i,msg in enumerate(msg_parts):
|
||||
if isinstance(msg, (zmq.Frame, bytes, memoryview)):
|
||||
continue
|
||||
try:
|
||||
memoryview(msg)
|
||||
except Exception:
|
||||
rmsg = repr(msg)
|
||||
if len(rmsg) > 32:
|
||||
rmsg = rmsg[:32] + '...'
|
||||
raise TypeError(
|
||||
"Frame %i (%s) does not support the buffer interface." % (
|
||||
i, rmsg,
|
||||
))
|
||||
for msg in msg_parts[:-1]:
|
||||
self.send(msg, SNDMORE|flags, copy=copy, track=track)
|
||||
# Send the last part without the extra SNDMORE flag.
|
||||
return self.send(msg_parts[-1], flags, copy=copy, track=track)
|
||||
|
||||
def recv_multipart(self, flags=0, copy=True, track=False):
|
||||
"""Receive a multipart message as a list of bytes or Frame objects
|
||||
|
||||
Parameters
|
||||
----------
|
||||
flags : int, optional
|
||||
Any valid flags for :func:`Socket.recv`.
|
||||
copy : bool, optional
|
||||
Should the message frame(s) be received in a copying or non-copying manner?
|
||||
If False a Frame object is returned for each part, if True a copy of
|
||||
the bytes is made for each frame.
|
||||
track : bool, optional
|
||||
Should the message frame(s) be tracked for notification that ZMQ has
|
||||
finished with it? (ignored if copy=True)
|
||||
|
||||
Returns
|
||||
-------
|
||||
msg_parts : list
|
||||
A list of frames in the multipart message; either Frames or bytes,
|
||||
depending on `copy`.
|
||||
|
||||
Raises
|
||||
------
|
||||
ZMQError
|
||||
for any of the reasons :func:`~Socket.recv` might fail
|
||||
"""
|
||||
parts = [self.recv(flags, copy=copy, track=track)]
|
||||
# have first part already, only loop while more to receive
|
||||
while self.getsockopt(zmq.RCVMORE):
|
||||
part = self.recv(flags, copy=copy, track=track)
|
||||
parts.append(part)
|
||||
|
||||
return parts
|
||||
|
||||
def _deserialize(self, recvd, load):
|
||||
"""Deserialize a received message
|
||||
|
||||
Override in subclass (e.g. Futures) if recvd is not the raw bytes.
|
||||
|
||||
The default implementation expects bytes and returns the deserialized message immediately.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
load: callable
|
||||
Callable that deserializes bytes
|
||||
recvd:
|
||||
The object returned by self.recv
|
||||
|
||||
"""
|
||||
return load(recvd)
|
||||
|
||||
def send_serialized(self, msg, serialize, flags=0, copy=True, **kwargs):
|
||||
"""Send a message with a custom serialization function.
|
||||
|
||||
.. versionadded:: 17
|
||||
|
||||
Parameters
|
||||
----------
|
||||
msg : The message to be sent. Can be any object serializable by `serialize`.
|
||||
serialize : callable
|
||||
The serialization function to use.
|
||||
serialize(msg) should return an iterable of sendable message frames
|
||||
(e.g. bytes objects), which will be passed to send_multipart.
|
||||
flags : int, optional
|
||||
Any valid flags for :func:`Socket.send`.
|
||||
copy : bool, optional
|
||||
Whether to copy the frames.
|
||||
|
||||
"""
|
||||
frames = serialize(msg)
|
||||
return self.send_multipart(frames, flags=flags, copy=copy, **kwargs)
|
||||
|
||||
def recv_serialized(self, deserialize, flags=0, copy=True):
|
||||
"""Receive a message with a custom deserialization function.
|
||||
|
||||
.. versionadded:: 17
|
||||
|
||||
Parameters
|
||||
----------
|
||||
deserialize : callable
|
||||
The deserialization function to use.
|
||||
deserialize will be called with one argument: the list of frames
|
||||
returned by recv_multipart() and can return any object.
|
||||
flags : int, optional
|
||||
Any valid flags for :func:`Socket.recv`.
|
||||
copy : bool, optional
|
||||
Whether to recv bytes or Frame objects.
|
||||
|
||||
Returns
|
||||
-------
|
||||
obj : object
|
||||
The object returned by the deserialization function.
|
||||
|
||||
Raises
|
||||
------
|
||||
ZMQError
|
||||
for any of the reasons :func:`~Socket.recv` might fail
|
||||
"""
|
||||
frames = self.recv_multipart(flags=flags, copy=copy)
|
||||
return self._deserialize(frames, deserialize)
|
||||
|
||||
def send_string(self, u, flags=0, copy=True, encoding='utf-8', **kwargs):
|
||||
"""Send a Python unicode string as a message with an encoding.
|
||||
|
||||
0MQ communicates with raw bytes, so you must encode/decode
|
||||
text (unicode on py2, str on py3) around 0MQ.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
u : Python unicode string (unicode on py2, str on py3)
|
||||
The unicode string to send.
|
||||
flags : int, optional
|
||||
Any valid flags for :func:`Socket.send`.
|
||||
encoding : str [default: 'utf-8']
|
||||
The encoding to be used
|
||||
"""
|
||||
if not isinstance(u, basestring):
|
||||
raise TypeError("unicode/str objects only")
|
||||
return self.send(u.encode(encoding), flags=flags, copy=copy, **kwargs)
|
||||
|
||||
send_unicode = send_string
|
||||
|
||||
def recv_string(self, flags=0, encoding='utf-8'):
|
||||
"""Receive a unicode string, as sent by send_string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
flags : int
|
||||
Any valid flags for :func:`Socket.recv`.
|
||||
encoding : str [default: 'utf-8']
|
||||
The encoding to be used
|
||||
|
||||
Returns
|
||||
-------
|
||||
s : unicode string (unicode on py2, str on py3)
|
||||
The Python unicode string that arrives as encoded bytes.
|
||||
|
||||
Raises
|
||||
------
|
||||
ZMQError
|
||||
for any of the reasons :func:`~Socket.recv` might fail
|
||||
"""
|
||||
msg = self.recv(flags=flags)
|
||||
return self._deserialize(msg, lambda buf: buf.decode(encoding))
|
||||
|
||||
recv_unicode = recv_string
|
||||
|
||||
def send_pyobj(self, obj, flags=0, protocol=DEFAULT_PROTOCOL, **kwargs):
|
||||
"""Send a Python object as a message using pickle to serialize.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
obj : Python object
|
||||
The Python object to send.
|
||||
flags : int
|
||||
Any valid flags for :func:`Socket.send`.
|
||||
protocol : int
|
||||
The pickle protocol number to use. The default is pickle.DEFAULT_PROTOCOL
|
||||
where defined, and pickle.HIGHEST_PROTOCOL elsewhere.
|
||||
"""
|
||||
msg = pickle.dumps(obj, protocol)
|
||||
return self.send(msg, flags=flags, **kwargs)
|
||||
|
||||
def recv_pyobj(self, flags=0):
|
||||
"""Receive a Python object as a message using pickle to serialize.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
flags : int
|
||||
Any valid flags for :func:`Socket.recv`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
obj : Python object
|
||||
The Python object that arrives as a message.
|
||||
|
||||
Raises
|
||||
------
|
||||
ZMQError
|
||||
for any of the reasons :func:`~Socket.recv` might fail
|
||||
"""
|
||||
msg = self.recv(flags)
|
||||
return self._deserialize(msg, pickle.loads)
|
||||
|
||||
def send_json(self, obj, flags=0, **kwargs):
|
||||
"""Send a Python object as a message using json to serialize.
|
||||
|
||||
Keyword arguments are passed on to json.dumps
|
||||
|
||||
Parameters
|
||||
----------
|
||||
obj : Python object
|
||||
The Python object to send
|
||||
flags : int
|
||||
Any valid flags for :func:`Socket.send`
|
||||
"""
|
||||
send_kwargs = {}
|
||||
for key in ('routing_id', 'group'):
|
||||
if key in kwargs:
|
||||
send_kwargs[key] = kwargs.pop(key)
|
||||
msg = jsonapi.dumps(obj, **kwargs)
|
||||
return self.send(msg, flags=flags, **send_kwargs)
|
||||
|
||||
def recv_json(self, flags=0, **kwargs):
|
||||
"""Receive a Python object as a message using json to serialize.
|
||||
|
||||
Keyword arguments are passed on to json.loads
|
||||
|
||||
Parameters
|
||||
----------
|
||||
flags : int
|
||||
Any valid flags for :func:`Socket.recv`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
obj : Python object
|
||||
The Python object that arrives as a message.
|
||||
|
||||
Raises
|
||||
------
|
||||
ZMQError
|
||||
for any of the reasons :func:`~Socket.recv` might fail
|
||||
"""
|
||||
msg = self.recv(flags)
|
||||
return self._deserialize(msg, lambda buf: jsonapi.loads(buf, **kwargs))
|
||||
|
||||
_poller_class = Poller
|
||||
|
||||
def poll(self, timeout=None, flags=POLLIN):
|
||||
"""Poll the socket for events.
|
||||
See :class:`Poller` to wait for multiple sockets at once.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
timeout : int [default: None]
|
||||
The timeout (in milliseconds) to wait for an event. If unspecified
|
||||
(or specified None), will wait forever for an event.
|
||||
flags : int [default: POLLIN]
|
||||
POLLIN, POLLOUT, or POLLIN|POLLOUT. The event flags to poll for.
|
||||
|
||||
Returns
|
||||
-------
|
||||
event_mask : int
|
||||
The poll event mask (POLLIN, POLLOUT),
|
||||
0 if the timeout was reached without an event.
|
||||
"""
|
||||
|
||||
if self.closed:
|
||||
raise ZMQError(ENOTSUP)
|
||||
|
||||
p = self._poller_class()
|
||||
p.register(self, flags)
|
||||
evts = dict(p.poll(timeout))
|
||||
# return 0 if no events, otherwise return event bitfield
|
||||
return evts.get(self, 0)
|
||||
|
||||
def get_monitor_socket(self, events=None, addr=None):
|
||||
"""Return a connected PAIR socket ready to receive the event notifications.
|
||||
|
||||
.. versionadded:: libzmq-4.0
|
||||
.. versionadded:: 14.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
events : int [default: ZMQ_EVENT_ALL]
|
||||
The bitmask defining which events are wanted.
|
||||
addr : string [default: None]
|
||||
The optional endpoint for the monitoring sockets.
|
||||
|
||||
Returns
|
||||
-------
|
||||
socket : (PAIR)
|
||||
The socket is already connected and ready to receive messages.
|
||||
"""
|
||||
# safe-guard, method only available on libzmq >= 4
|
||||
if zmq.zmq_version_info() < (4,):
|
||||
raise NotImplementedError("get_monitor_socket requires libzmq >= 4, have %s" % zmq.zmq_version())
|
||||
|
||||
# if already monitoring, return existing socket
|
||||
if self._monitor_socket:
|
||||
if self._monitor_socket.closed:
|
||||
self._monitor_socket = None
|
||||
else:
|
||||
return self._monitor_socket
|
||||
|
||||
if addr is None:
|
||||
# create endpoint name from internal fd
|
||||
addr = "inproc://monitor.s-%d" % self.FD
|
||||
if events is None:
|
||||
# use all events
|
||||
events = zmq.EVENT_ALL
|
||||
# attach monitoring socket
|
||||
self.monitor(addr, events)
|
||||
# create new PAIR socket and connect it
|
||||
self._monitor_socket = self.context.socket(zmq.PAIR)
|
||||
self._monitor_socket.connect(addr)
|
||||
return self._monitor_socket
|
||||
|
||||
def disable_monitor(self):
|
||||
"""Shutdown the PAIR socket (created using get_monitor_socket)
|
||||
that is serving socket events.
|
||||
|
||||
.. versionadded:: 14.4
|
||||
"""
|
||||
self._monitor_socket = None
|
||||
self.monitor(None, 0)
|
||||
|
||||
|
||||
__all__ = ['Socket']
|
31
venv/Lib/site-packages/zmq/sugar/stopwatch.py
Normal file
31
venv/Lib/site-packages/zmq/sugar/stopwatch.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
"""Deprecated Stopwatch implementation"""
|
||||
|
||||
# Copyright (c) PyZMQ Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
class Stopwatch(object):
|
||||
"""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))
|
||||
|
122
venv/Lib/site-packages/zmq/sugar/tracker.py
Normal file
122
venv/Lib/site-packages/zmq/sugar/tracker.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
"""Tracker for zero-copy messages with 0MQ."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import time
|
||||
|
||||
try:
|
||||
# below 3.3
|
||||
from threading import _Event as Event
|
||||
except (ImportError, AttributeError):
|
||||
# python throws ImportError, cython throws AttributeError
|
||||
from threading import Event
|
||||
|
||||
from zmq.error import NotDone
|
||||
from zmq.backend import Frame
|
||||
|
||||
class MessageTracker(object):
|
||||
"""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 = None
|
||||
peers = None
|
||||
|
||||
def __init__(self, *towatch):
|
||||
"""MessageTracker(*towatch)
|
||||
|
||||
Create a message tracker to track a set of mesages.
|
||||
|
||||
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=-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()
|
||||
if timeout is False or timeout < 0:
|
||||
remaining = 3600*24*7 # a week
|
||||
else:
|
||||
remaining = timeout
|
||||
done = False
|
||||
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']
|
48
venv/Lib/site-packages/zmq/sugar/version.py
Normal file
48
venv/Lib/site-packages/zmq/sugar/version.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
"""PyZMQ and 0MQ version functions."""
|
||||
|
||||
# Copyright (C) PyZMQ Developers
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
|
||||
from zmq.backend import zmq_version_info
|
||||
|
||||
|
||||
VERSION_MAJOR = 19
|
||||
VERSION_MINOR = 0
|
||||
VERSION_PATCH = 2
|
||||
VERSION_EXTRA = ""
|
||||
__version__ = '%i.%i.%i' % (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
|
||||
|
||||
if VERSION_EXTRA:
|
||||
__version__ = "%s.%s" % (__version__, VERSION_EXTRA)
|
||||
version_info = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, float('inf'))
|
||||
else:
|
||||
version_info = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
|
||||
|
||||
__revision__ = ''
|
||||
|
||||
def pyzmq_version():
|
||||
"""return the version of pyzmq as a string"""
|
||||
if __revision__:
|
||||
return '@'.join([__version__,__revision__[:6]])
|
||||
else:
|
||||
return __version__
|
||||
|
||||
def pyzmq_version_info():
|
||||
"""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():
|
||||
"""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__'
|
||||
]
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue