| Index: ports/python_modules/pyzmq/nacl.patch
|
| ===================================================================
|
| new file mode 100644
|
|
|
| --- /dev/null
|
| +++ b/ports/python_modules/pyzmq/nacl.patch
|
| @@ -0,0 +1,5159 @@
|
| +diff --git a/buildutils/config.py b/buildutils/config.py
|
| +index 66f61e3..de2cd6e 100644
|
| +--- a/buildutils/config.py
|
| ++++ b/buildutils/config.py
|
| +@@ -87,6 +87,11 @@ def get_cfg_args():
|
| + cfg = cfg2dict(cfg)
|
| +
|
| + g = cfg.setdefault('global', {})
|
| ++ if "NACL_BUILD_TREE" in os.environ:
|
| ++ NACL_TREE = os.environ["NACL_BUILD_TREE"]
|
| ++ cfg["global"]["zmq_prefix"] = NACL_TREE
|
| ++ cfg["global"]["have_sys_un_h"] = "False"
|
| ++
|
| + # boolean keys:
|
| + for key in ['libzmq_extension',
|
| + 'bundle_libzmq_dylib',
|
| +diff --git a/setup.cfg b/setup.cfg
|
| +new file mode 100644
|
| +index 0000000..15686fc
|
| +--- /dev/null
|
| ++++ b/setup.cfg
|
| +@@ -0,0 +1,3 @@
|
| ++[bdist_egg]
|
| ++plat-name = pnacl
|
| ++
|
| +diff --git a/setup.py b/setup.py
|
| +index 5348c61..a204e23 100755
|
| +--- a/setup.py
|
| ++++ b/setup.py
|
| +@@ -270,6 +270,10 @@ class Configure(build_ext):
|
| + # include internal directories
|
| + settings.setdefault('include_dirs', [])
|
| + settings['include_dirs'] += [pjoin('zmq', sub) for sub in ('utils','core','devices')]
|
| ++ if "NACL_BUILD_TREE" in os.environ:
|
| ++ settings['include_dirs'].append(pjoin(
|
| ++ os.environ["NACL_BUILD_TREE"],
|
| ++ "include", "glibc-compat"))
|
| +
|
| + for ext in self.distribution.ext_modules:
|
| + if ext.name == 'zmq.libzmq':
|
| +@@ -826,29 +830,29 @@ def dotc(subdir, name):
|
| +
|
| + libzmq = pxd('core', 'libzmq')
|
| + buffers = pxd('utils', 'buffers')
|
| +-message = pxd('core', 'message')
|
| +-context = pxd('core', 'context')
|
| +-socket = pxd('core', 'socket')
|
| ++message = pxd('core', '_zmessage')
|
| ++context = pxd('core', '_zcontext')
|
| ++socket = pxd('core', '_zsocket')
|
| + checkrc = pxd('core', 'checkrc')
|
| +-monqueue = pxd('devices', 'monitoredqueue')
|
| ++monqueue = pxd('devices', '_zmonitoredqueue')
|
| +
|
| + submodules = dict(
|
| +- core = {'constants': [libzmq],
|
| +- 'error':[libzmq, checkrc],
|
| +- '_poll':[libzmq, socket, context, checkrc],
|
| +- 'stopwatch':[libzmq, pxd('core','stopwatch'), checkrc],
|
| +- 'context':[context, libzmq, checkrc],
|
| +- 'message':[libzmq, buffers, message, checkrc],
|
| +- 'socket':[context, message, socket, libzmq, buffers, checkrc],
|
| +- '_device':[libzmq, socket, context, checkrc],
|
| +- '_version':[libzmq],
|
| ++ core = {'_zconstants': [libzmq],
|
| ++ '_zerror':[libzmq, checkrc],
|
| ++ '__zpoll':[libzmq, socket, context, checkrc],
|
| ++ '_zstopwatch':[libzmq, pxd('core','_zstopwatch'), checkrc],
|
| ++ '_zcontext':[context, libzmq, checkrc],
|
| ++ '_zmessage':[libzmq, buffers, message, checkrc],
|
| ++ '_zsocket':[context, message, socket, libzmq, buffers, checkrc],
|
| ++ '__zdevice':[libzmq, socket, context, checkrc],
|
| ++ '__zversion':[libzmq],
|
| + },
|
| + devices = {
|
| +- 'monitoredqueue':[buffers, libzmq, monqueue, socket, context, checkrc],
|
| ++ '_zmonitoredqueue':[buffers, libzmq, monqueue, socket, context, checkrc],
|
| + },
|
| + utils = {
|
| +- 'initthreads':[libzmq],
|
| +- 'rebuffer':[buffers],
|
| ++ '_zinitthreads':[libzmq],
|
| ++ '_zrebuffer':[buffers],
|
| + },
|
| + )
|
| +
|
| + #-----------------------------------------------------------------------------
|
| + # Main setup
|
| + #-----------------------------------------------------------------------------
|
| +diff --git a/zmq/__init__.py b/zmq/__init__.py
|
| +index 19cb4a9..c55ac5c 100644
|
| +--- a/zmq/__init__.py
|
| ++++ b/zmq/__init__.py
|
| +@@ -39,7 +39,7 @@ if bundled:
|
| +
|
| + if 'PyPy' not in sys.version:
|
| + try:
|
| +- from zmq.utils import initthreads # initialize threads
|
| ++ from zmq.utils import _zinitthreads as initthreads # initialize threads
|
| + except ImportError as e:
|
| + raise ImportError("%s\nAre you trying to `import zmq` from the pyzmq source dir?" % e)
|
| + else:
|
| +diff --git a/zmq/core/__init__.py b/zmq/core/__init__.py
|
| +index 862f1d5..275e47a 100644
|
| +--- a/zmq/core/__init__.py
|
| ++++ b/zmq/core/__init__.py
|
| +@@ -23,21 +23,21 @@
|
| + # Imports
|
| + #-----------------------------------------------------------------------------
|
| +
|
| +-from zmq.core import (constants, error, message, context,
|
| +- socket, stopwatch, _poll, _version, _device )
|
| ++from zmq.core import (_zconstants, _zerror, _zmessage, _zcontext,
|
| ++ _zsocket, _zstopwatch, __zpoll, __zversion, __zdevice )
|
| +
|
| + __all__ = []
|
| +-for submod in (constants, error, message, context,
|
| +- socket, stopwatch, _poll, _version, _device):
|
| ++for submod in (_zconstants, _zerror, _zmessage, _zcontext,
|
| ++ _zsocket, _zstopwatch, __zpoll, __zversion, __zdevice):
|
| + __all__.extend(submod.__all__)
|
| +
|
| +-from zmq.core.constants import *
|
| +-from zmq.core.error import *
|
| +-from zmq.core.message import *
|
| +-from zmq.core.context import *
|
| +-from zmq.core.socket import *
|
| +-from zmq.core._poll import *
|
| +-from zmq.core.stopwatch import *
|
| +-from zmq.core._device import *
|
| +-from zmq.core._version import *
|
| ++from zmq.core._zconstants import *
|
| ++from zmq.core._zerror import *
|
| ++from zmq.core._zmessage import *
|
| ++from zmq.core._zcontext import *
|
| ++from zmq.core._zsocket import *
|
| ++from zmq.core.__zpoll import *
|
| ++from zmq.core._zstopwatch import *
|
| ++from zmq.core.__zdevice import *
|
| ++from zmq.core.__zversion import *
|
| +
|
| +diff --git a/zmq/core/__zdevice.pyx b/zmq/core/__zdevice.pyx
|
| +new file mode 100644
|
| +index 0000000..99bcc27
|
| +--- /dev/null
|
| ++++ b/zmq/core/__zdevice.pyx
|
| +@@ -0,0 +1,86 @@
|
| ++"""Python binding for 0MQ device function."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libzmq cimport zmq_device, zmq_proxy, ZMQ_VERSION_MAJOR
|
| ++from zmq.core._zsocket cimport Socket as cSocket
|
| ++from zmq.core.checkrc cimport _check_rc
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Basic device API
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++def device(int device_type, cSocket frontend, cSocket backend=None):
|
| ++ """device(device_type, frontend, backend)
|
| ++
|
| ++ Start a zeromq device.
|
| ++
|
| ++ WARNING: zmq.device is deprecated as of libzmq-3.2,
|
| ++ in favor of zmq.proxy.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ device_type : (QUEUE, FORWARDER, STREAMER)
|
| ++ The type of device to start.
|
| ++ frontend : Socket
|
| ++ The Socket instance for the incoming traffic.
|
| ++ backend : Socket
|
| ++ The Socket instance for the outbound traffic.
|
| ++ """
|
| ++ if ZMQ_VERSION_MAJOR >= 3:
|
| ++ return proxy(frontend, backend)
|
| ++
|
| ++ cdef int rc = 0
|
| ++ with nogil:
|
| ++ rc = zmq_device(device_type, frontend.handle, backend.handle)
|
| ++ _check_rc(rc)
|
| ++ return rc
|
| ++
|
| ++def proxy(cSocket frontend, cSocket backend, cSocket capture=None):
|
| ++ """proxy(frontend, backend, capture)
|
| ++
|
| ++ Start a zeromq proxy (replacement for device).
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ frontend : Socket
|
| ++ The Socket instance for the incoming traffic.
|
| ++ backend : Socket
|
| ++ The Socket instance for the outbound traffic.
|
| ++ capture : Socket
|
| ++ The Socket instance for capturing traffic.
|
| ++ """
|
| ++ cdef int rc = 0
|
| ++ cdef void* capture_handle
|
| ++ if isinstance(capture, cSocket):
|
| ++ capture_handle = capture.handle
|
| ++ else:
|
| ++ capture_handle = NULL
|
| ++ with nogil:
|
| ++ rc = zmq_proxy(frontend.handle, backend.handle, capture_handle)
|
| ++ _check_rc(rc)
|
| ++ return rc
|
| ++
|
| ++__all__ = ['device', 'proxy']
|
| ++
|
| +diff --git a/zmq/core/__zpoll.pyx b/zmq/core/__zpoll.pyx
|
| +new file mode 100644
|
| +index 0000000..799b20b
|
| +--- /dev/null
|
| ++++ b/zmq/core/__zpoll.pyx
|
| +@@ -0,0 +1,136 @@
|
| ++"""0MQ polling related functions and classes."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libc.stdlib cimport free, malloc
|
| ++
|
| ++from libzmq cimport zmq_pollitem_t, ZMQ_VERSION_MAJOR
|
| ++from libzmq cimport zmq_poll as zmq_poll_c
|
| ++from _zsocket cimport Socket
|
| ++
|
| ++import sys
|
| ++
|
| ++from zmq.core.checkrc cimport _check_rc
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Polling related methods
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++# version-independent typecheck for int/long
|
| ++if sys.version_info[0] >= 3:
|
| ++ int_t = int
|
| ++else:
|
| ++ int_t = (int,long)
|
| ++
|
| ++def zmq_poll(sockets, long timeout=-1):
|
| ++ """zmq_poll(sockets, timeout=-1)
|
| ++
|
| ++ Poll a set of 0MQ sockets, native file descs. or sockets.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ sockets : list of tuples of (socket, flags)
|
| ++ Each element of this list is a two-tuple containing a socket
|
| ++ and a flags. The socket may be a 0MQ socket or any object with
|
| ++ a ``fileno()`` method. The flags can be zmq.POLLIN (for detecting
|
| ++ for incoming messages), zmq.POLLOUT (for detecting that send is OK)
|
| ++ or zmq.POLLIN|zmq.POLLOUT for detecting both.
|
| ++ timeout : int
|
| ++ The number of milliseconds to poll for. Negative means no timeout.
|
| ++ """
|
| ++ cdef int rc, i
|
| ++ cdef zmq_pollitem_t *pollitems = NULL
|
| ++ cdef int nsockets = <int>len(sockets)
|
| ++ cdef Socket current_socket
|
| ++
|
| ++ if nsockets == 0:
|
| ++ return []
|
| ++
|
| ++ pollitems = <zmq_pollitem_t *>malloc(nsockets*sizeof(zmq_pollitem_t))
|
| ++ if pollitems == NULL:
|
| ++ raise MemoryError("Could not allocate poll items")
|
| ++
|
| ++ if ZMQ_VERSION_MAJOR < 3:
|
| ++ # timeout is us in 2.x, ms in 3.x
|
| ++ # expected input is ms (matches 3.x)
|
| ++ timeout = 1000*timeout
|
| ++
|
| ++ for i in range(nsockets):
|
| ++ s = sockets[i][0]
|
| ++ events = sockets[i][1]
|
| ++ if isinstance(s, Socket):
|
| ++ current_socket = s
|
| ++ pollitems[i].socket = current_socket.handle
|
| ++ pollitems[i].events = events
|
| ++ pollitems[i].revents = 0
|
| ++ elif isinstance(s, int_t):
|
| ++ pollitems[i].socket = NULL
|
| ++ pollitems[i].fd = s
|
| ++ pollitems[i].events = events
|
| ++ pollitems[i].revents = 0
|
| ++ elif hasattr(s, 'fileno'):
|
| ++ try:
|
| ++ fileno = int(s.fileno())
|
| ++ except:
|
| ++ free(pollitems)
|
| ++ raise ValueError('fileno() must return an valid integer fd')
|
| ++ else:
|
| ++ pollitems[i].socket = NULL
|
| ++ pollitems[i].fd = fileno
|
| ++ pollitems[i].events = events
|
| ++ pollitems[i].revents = 0
|
| ++ else:
|
| ++ free(pollitems)
|
| ++ raise TypeError(
|
| ++ "Socket must be a 0MQ socket, an integer fd or have "
|
| ++ "a fileno() method: %r" % s
|
| ++ )
|
| ++
|
| ++
|
| ++ with nogil:
|
| ++ rc = zmq_poll_c(pollitems, nsockets, timeout)
|
| ++
|
| ++ if rc < 0:
|
| ++ free(pollitems)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ results = []
|
| ++ for i in range(nsockets):
|
| ++ s = sockets[i][0]
|
| ++ # Return the fd for sockets, for compat. with select.poll.
|
| ++ if hasattr(s, 'fileno'):
|
| ++ s = s.fileno()
|
| ++ revents = pollitems[i].revents
|
| ++ # Only return sockets with non-zero status for compat. with select.poll.
|
| ++ if revents > 0:
|
| ++ results.append((s, revents))
|
| ++
|
| ++ free(pollitems)
|
| ++ return results
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Symbols to export
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++__all__ = [ 'zmq_poll' ]
|
| +diff --git a/zmq/core/__zversion.pyx b/zmq/core/__zversion.pyx
|
| +new file mode 100644
|
| +index 0000000..02cf6fc
|
| +--- /dev/null
|
| ++++ b/zmq/core/__zversion.pyx
|
| +@@ -0,0 +1,43 @@
|
| ++"""PyZMQ and 0MQ version functions."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libzmq cimport _zmq_version
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++def zmq_version_info():
|
| ++ """zmq_version_info()
|
| ++
|
| ++ Return the version of ZeroMQ itself as a 3-tuple of ints.
|
| ++ """
|
| ++ cdef int major, minor, patch
|
| ++ _zmq_version(&major, &minor, &patch)
|
| ++ return (major, minor, patch)
|
| ++
|
| ++
|
| ++__all__ = ['zmq_version_info']
|
| ++
|
| +diff --git a/zmq/core/_device.pyx b/zmq/core/_device.pyx
|
| +deleted file mode 100644
|
| +index 5471e73..0000000
|
| +--- a/zmq/core/_device.pyx
|
| ++++ /dev/null
|
| +@@ -1,86 +0,0 @@
|
| +-"""Python binding for 0MQ device function."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libzmq cimport zmq_device, zmq_proxy, ZMQ_VERSION_MAJOR
|
| +-from zmq.core.socket cimport Socket as cSocket
|
| +-from zmq.core.checkrc cimport _check_rc
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Basic device API
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-def device(int device_type, cSocket frontend, cSocket backend=None):
|
| +- """device(device_type, frontend, backend)
|
| +-
|
| +- Start a zeromq device.
|
| +-
|
| +- WARNING: zmq.device is deprecated as of libzmq-3.2,
|
| +- in favor of zmq.proxy.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- device_type : (QUEUE, FORWARDER, STREAMER)
|
| +- The type of device to start.
|
| +- frontend : Socket
|
| +- The Socket instance for the incoming traffic.
|
| +- backend : Socket
|
| +- The Socket instance for the outbound traffic.
|
| +- """
|
| +- if ZMQ_VERSION_MAJOR >= 3:
|
| +- return proxy(frontend, backend)
|
| +-
|
| +- cdef int rc = 0
|
| +- with nogil:
|
| +- rc = zmq_device(device_type, frontend.handle, backend.handle)
|
| +- _check_rc(rc)
|
| +- return rc
|
| +-
|
| +-def proxy(cSocket frontend, cSocket backend, cSocket capture=None):
|
| +- """proxy(frontend, backend, capture)
|
| +-
|
| +- Start a zeromq proxy (replacement for device).
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- frontend : Socket
|
| +- The Socket instance for the incoming traffic.
|
| +- backend : Socket
|
| +- The Socket instance for the outbound traffic.
|
| +- capture : Socket
|
| +- The Socket instance for capturing traffic.
|
| +- """
|
| +- cdef int rc = 0
|
| +- cdef void* capture_handle
|
| +- if isinstance(capture, cSocket):
|
| +- capture_handle = capture.handle
|
| +- else:
|
| +- capture_handle = NULL
|
| +- with nogil:
|
| +- rc = zmq_proxy(frontend.handle, backend.handle, capture_handle)
|
| +- _check_rc(rc)
|
| +- return rc
|
| +-
|
| +-__all__ = ['device', 'proxy']
|
| +-
|
| +diff --git a/zmq/core/_poll.pyx b/zmq/core/_poll.pyx
|
| +deleted file mode 100644
|
| +index 9db19e1..0000000
|
| +--- a/zmq/core/_poll.pyx
|
| ++++ /dev/null
|
| +@@ -1,136 +0,0 @@
|
| +-"""0MQ polling related functions and classes."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libc.stdlib cimport free, malloc
|
| +-
|
| +-from libzmq cimport zmq_pollitem_t, ZMQ_VERSION_MAJOR
|
| +-from libzmq cimport zmq_poll as zmq_poll_c
|
| +-from socket cimport Socket
|
| +-
|
| +-import sys
|
| +-
|
| +-from zmq.core.checkrc cimport _check_rc
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Polling related methods
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-# version-independent typecheck for int/long
|
| +-if sys.version_info[0] >= 3:
|
| +- int_t = int
|
| +-else:
|
| +- int_t = (int,long)
|
| +-
|
| +-def zmq_poll(sockets, long timeout=-1):
|
| +- """zmq_poll(sockets, timeout=-1)
|
| +-
|
| +- Poll a set of 0MQ sockets, native file descs. or sockets.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- sockets : list of tuples of (socket, flags)
|
| +- Each element of this list is a two-tuple containing a socket
|
| +- and a flags. The socket may be a 0MQ socket or any object with
|
| +- a ``fileno()`` method. The flags can be zmq.POLLIN (for detecting
|
| +- for incoming messages), zmq.POLLOUT (for detecting that send is OK)
|
| +- or zmq.POLLIN|zmq.POLLOUT for detecting both.
|
| +- timeout : int
|
| +- The number of milliseconds to poll for. Negative means no timeout.
|
| +- """
|
| +- cdef int rc, i
|
| +- cdef zmq_pollitem_t *pollitems = NULL
|
| +- cdef int nsockets = <int>len(sockets)
|
| +- cdef Socket current_socket
|
| +-
|
| +- if nsockets == 0:
|
| +- return []
|
| +-
|
| +- pollitems = <zmq_pollitem_t *>malloc(nsockets*sizeof(zmq_pollitem_t))
|
| +- if pollitems == NULL:
|
| +- raise MemoryError("Could not allocate poll items")
|
| +-
|
| +- if ZMQ_VERSION_MAJOR < 3:
|
| +- # timeout is us in 2.x, ms in 3.x
|
| +- # expected input is ms (matches 3.x)
|
| +- timeout = 1000*timeout
|
| +-
|
| +- for i in range(nsockets):
|
| +- s = sockets[i][0]
|
| +- events = sockets[i][1]
|
| +- if isinstance(s, Socket):
|
| +- current_socket = s
|
| +- pollitems[i].socket = current_socket.handle
|
| +- pollitems[i].events = events
|
| +- pollitems[i].revents = 0
|
| +- elif isinstance(s, int_t):
|
| +- pollitems[i].socket = NULL
|
| +- pollitems[i].fd = s
|
| +- pollitems[i].events = events
|
| +- pollitems[i].revents = 0
|
| +- elif hasattr(s, 'fileno'):
|
| +- try:
|
| +- fileno = int(s.fileno())
|
| +- except:
|
| +- free(pollitems)
|
| +- raise ValueError('fileno() must return an valid integer fd')
|
| +- else:
|
| +- pollitems[i].socket = NULL
|
| +- pollitems[i].fd = fileno
|
| +- pollitems[i].events = events
|
| +- pollitems[i].revents = 0
|
| +- else:
|
| +- free(pollitems)
|
| +- raise TypeError(
|
| +- "Socket must be a 0MQ socket, an integer fd or have "
|
| +- "a fileno() method: %r" % s
|
| +- )
|
| +-
|
| +-
|
| +- with nogil:
|
| +- rc = zmq_poll_c(pollitems, nsockets, timeout)
|
| +-
|
| +- if rc < 0:
|
| +- free(pollitems)
|
| +- _check_rc(rc)
|
| +-
|
| +- results = []
|
| +- for i in range(nsockets):
|
| +- s = sockets[i][0]
|
| +- # Return the fd for sockets, for compat. with select.poll.
|
| +- if hasattr(s, 'fileno'):
|
| +- s = s.fileno()
|
| +- revents = pollitems[i].revents
|
| +- # Only return sockets with non-zero status for compat. with select.poll.
|
| +- if revents > 0:
|
| +- results.append((s, revents))
|
| +-
|
| +- free(pollitems)
|
| +- return results
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Symbols to export
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-__all__ = [ 'zmq_poll' ]
|
| +diff --git a/zmq/core/_version.pyx b/zmq/core/_version.pyx
|
| +deleted file mode 100644
|
| +index 02cf6fc..0000000
|
| +--- a/zmq/core/_version.pyx
|
| ++++ /dev/null
|
| +@@ -1,43 +0,0 @@
|
| +-"""PyZMQ and 0MQ version functions."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libzmq cimport _zmq_version
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-def zmq_version_info():
|
| +- """zmq_version_info()
|
| +-
|
| +- Return the version of ZeroMQ itself as a 3-tuple of ints.
|
| +- """
|
| +- cdef int major, minor, patch
|
| +- _zmq_version(&major, &minor, &patch)
|
| +- return (major, minor, patch)
|
| +-
|
| +-
|
| +-__all__ = ['zmq_version_info']
|
| +-
|
| +diff --git a/zmq/core/_zconstants.pyx b/zmq/core/_zconstants.pyx
|
| +new file mode 100644
|
| +index 0000000..fa2695d
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zconstants.pyx
|
| +@@ -0,0 +1,190 @@
|
| ++"""0MQ Constants."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libzmq cimport *
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Python module level constants
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++_optionals = []
|
| ++
|
| ++if ZMQ_VERSION < 30000:
|
| ++ # backport DONTWAIT as alias to NOBLOCK
|
| ++ NOBLOCK = ZMQ_NOBLOCK
|
| ++ DONTWAIT = ZMQ_NOBLOCK
|
| ++else:
|
| ++ # keep NOBLOCK as alias for new DONTWAIT
|
| ++ NOBLOCK = ZMQ_DONTWAIT
|
| ++ DONTWAIT = ZMQ_DONTWAIT
|
| ++
|
| ++VERSION = ZMQ_VERSION
|
| ++
|
| ++# socket types
|
| ++PAIR = ZMQ_PAIR
|
| ++PUB = ZMQ_PUB
|
| ++SUB = ZMQ_SUB
|
| ++REQ = ZMQ_REQ
|
| ++REP = ZMQ_REP
|
| ++DEALER = ZMQ_DEALER
|
| ++ROUTER = ZMQ_ROUTER
|
| ++PULL = ZMQ_PULL
|
| ++PUSH = ZMQ_PUSH
|
| ++XPUB = ZMQ_XPUB
|
| ++XSUB = ZMQ_XSUB
|
| ++
|
| ++# keep deprecated aliases
|
| ++XREQ = DEALER
|
| ++XREP = ROUTER
|
| ++UPSTREAM = PULL
|
| ++DOWNSTREAM = PUSH
|
| ++
|
| ++
|
| ++# socket options
|
| ++AFFINITY = ZMQ_AFFINITY
|
| ++IDENTITY = ZMQ_IDENTITY
|
| ++SUBSCRIBE = ZMQ_SUBSCRIBE
|
| ++UNSUBSCRIBE = ZMQ_UNSUBSCRIBE
|
| ++RATE = ZMQ_RATE
|
| ++RECOVERY_IVL = ZMQ_RECOVERY_IVL
|
| ++RECONNECT_IVL_MAX = ZMQ_RECONNECT_IVL_MAX
|
| ++SNDBUF = ZMQ_SNDBUF
|
| ++RCVBUF = ZMQ_RCVBUF
|
| ++RCVMORE = ZMQ_RCVMORE
|
| ++SNDMORE = ZMQ_SNDMORE
|
| ++POLLIN = ZMQ_POLLIN
|
| ++POLLOUT = ZMQ_POLLOUT
|
| ++POLLERR = ZMQ_POLLERR
|
| ++
|
| ++STREAMER = ZMQ_STREAMER
|
| ++FORWARDER = ZMQ_FORWARDER
|
| ++QUEUE = ZMQ_QUEUE
|
| ++
|
| ++# sockopts new in 2.2.0
|
| ++SNDTIMEO = ZMQ_SNDTIMEO
|
| ++RCVTIMEO = ZMQ_RCVTIMEO
|
| ++
|
| ++# sockopts removed in 3.0.0
|
| ++HWM = ZMQ_HWM
|
| ++SWAP = ZMQ_SWAP
|
| ++MCAST_LOOP = ZMQ_MCAST_LOOP
|
| ++RECOVERY_IVL_MSEC = ZMQ_RECOVERY_IVL_MSEC
|
| ++
|
| ++# new in 3.x
|
| ++IO_THREADS = ZMQ_IO_THREADS
|
| ++MAX_SOCKETS = ZMQ_MAX_SOCKETS
|
| ++
|
| ++MORE = ZMQ_MORE
|
| ++
|
| ++MAXMSGSIZE = ZMQ_MAXMSGSIZE
|
| ++SNDHWM = ZMQ_SNDHWM
|
| ++RCVHWM = ZMQ_RCVHWM
|
| ++MULTICAST_HOPS = ZMQ_MULTICAST_HOPS
|
| ++IPV4ONLY = ZMQ_IPV4ONLY
|
| ++LAST_ENDPOINT = ZMQ_LAST_ENDPOINT
|
| ++
|
| ++ROUTER_MANDATORY = ZMQ_ROUTER_MANDATORY
|
| ++# aliases
|
| ++ROUTER_BEHAVIOR = ROUTER_MANDATORY
|
| ++FAIL_UNROUTABLE = ROUTER_MANDATORY
|
| ++
|
| ++TCP_KEEPALIVE = ZMQ_TCP_KEEPALIVE
|
| ++TCP_KEEPALIVE_CNT = ZMQ_TCP_KEEPALIVE_CNT
|
| ++TCP_KEEPALIVE_IDLE = ZMQ_TCP_KEEPALIVE_IDLE
|
| ++TCP_KEEPALIVE_INTVL = ZMQ_TCP_KEEPALIVE_INTVL
|
| ++TCP_ACCEPT_FILTER = ZMQ_TCP_ACCEPT_FILTER
|
| ++DELAY_ATTACH_ON_CONNECT = ZMQ_DELAY_ATTACH_ON_CONNECT
|
| ++XPUB_VERBOSE = ZMQ_XPUB_VERBOSE
|
| ++ROUTER_RAW = ZMQ_ROUTER_RAW
|
| ++
|
| ++EVENT_CONNECTED = ZMQ_EVENT_CONNECTED
|
| ++EVENT_CONNECT_DELAYED = ZMQ_EVENT_CONNECT_DELAYED
|
| ++EVENT_CONNECT_RETRIED = ZMQ_EVENT_CONNECT_RETRIED
|
| ++EVENT_LISTENING = ZMQ_EVENT_LISTENING
|
| ++EVENT_BIND_FAILED = ZMQ_EVENT_BIND_FAILED
|
| ++EVENT_ACCEPTED = ZMQ_EVENT_ACCEPTED
|
| ++EVENT_ACCEPT_FAILED = ZMQ_EVENT_ACCEPT_FAILED
|
| ++EVENT_CLOSED = ZMQ_EVENT_CLOSED
|
| ++EVENT_CLOSE_FAILED = ZMQ_EVENT_CLOSE_FAILED
|
| ++EVENT_DISCONNECTED = ZMQ_EVENT_DISCONNECTED
|
| ++
|
| ++FD = ZMQ_FD
|
| ++EVENTS = ZMQ_EVENTS
|
| ++TYPE = ZMQ_TYPE
|
| ++LINGER = ZMQ_LINGER
|
| ++RECONNECT_IVL = ZMQ_RECONNECT_IVL
|
| ++BACKLOG = ZMQ_BACKLOG
|
| ++
|
| ++# As new constants are added in future versions, add a new block here
|
| ++# like the two above, checking agains the relevant value for ZMQ_VERSION.
|
| ++# The constants will need to be added to libzmq.pxd and utils/zmq_compat.h
|
| ++# as well.
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Error handling
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++# Often used standard errnos
|
| ++from errno import (
|
| ++ EAGAIN,
|
| ++ EINVAL,
|
| ++ EFAULT,
|
| ++ ENOMEM,
|
| ++ ENODEV
|
| ++)
|
| ++
|
| ++# For Windows compatability
|
| ++ENOTSUP = ZMQ_ENOTSUP
|
| ++EPROTONOSUPPORT = ZMQ_EPROTONOSUPPORT
|
| ++ENOBUFS = ZMQ_ENOBUFS
|
| ++ENETDOWN = ZMQ_ENETDOWN
|
| ++EADDRINUSE = ZMQ_EADDRINUSE
|
| ++EADDRNOTAVAIL = ZMQ_EADDRNOTAVAIL
|
| ++ECONNREFUSED = ZMQ_ECONNREFUSED
|
| ++EINPROGRESS = ZMQ_EINPROGRESS
|
| ++ENOTSOCK = ZMQ_ENOTSOCK
|
| ++
|
| ++# new errnos in zmq3
|
| ++EMSGSIZE = ZMQ_EMSGSIZE
|
| ++EAFNOSUPPORT = ZMQ_EAFNOSUPPORT
|
| ++ENETUNREACH = ZMQ_ENETUNREACH
|
| ++ECONNABORTED = ZMQ_ECONNABORTED
|
| ++ECONNRESET = ZMQ_ECONNRESET
|
| ++ENOTCONN = ZMQ_ENOTCONN
|
| ++ETIMEDOUT = ZMQ_ETIMEDOUT
|
| ++EHOSTUNREACH = ZMQ_EHOSTUNREACH
|
| ++ENETRESET = ZMQ_ENETRESET
|
| ++
|
| ++# 0MQ Native
|
| ++EFSM = ZMQ_EFSM
|
| ++ENOCOMPATPROTO = ZMQ_ENOCOMPATPROTO
|
| ++ETERM = ZMQ_ETERM
|
| ++EMTHREAD = ZMQ_EMTHREAD
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Symbols to export
|
| ++#-----------------------------------------------------------------------------
|
| ++_names = list(locals().keys())
|
| ++__all__ = [ key for key in _names if not key.startswith('_') ]
|
| +diff --git a/zmq/core/_zcontext.pxd b/zmq/core/_zcontext.pxd
|
| +new file mode 100644
|
| +index 0000000..e399de5
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zcontext.pxd
|
| +@@ -0,0 +1,40 @@
|
| ++"""0MQ Context class declaration."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++cdef class Context:
|
| ++ """Manage the lifecycle of a 0MQ context."""
|
| ++
|
| ++ cdef object __weakref__ # enable weakref
|
| ++ cdef void *handle # The C handle for the underlying zmq object.
|
| ++ cdef void **_sockets # A C-array containg socket handles
|
| ++ cdef size_t _n_sockets # the number of sockets
|
| ++ cdef size_t _max_sockets # the size of the _sockets array
|
| ++ cdef int _pid # the pid of the process which created me (for fork safety)
|
| ++
|
| ++ cdef public object closed # bool property for a closed context.
|
| ++ # helpers for events on _sockets in Socket.__cinit__()/close()
|
| ++ cdef inline void _add_socket(self, void* handle)
|
| ++ cdef inline void _remove_socket(self, void* handle)
|
| ++
|
| +diff --git a/zmq/core/_zcontext.pyx b/zmq/core/_zcontext.pyx
|
| +new file mode 100644
|
| +index 0000000..0917c66
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zcontext.pyx
|
| +@@ -0,0 +1,254 @@
|
| ++"""0MQ Context class."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libc.stdlib cimport free, malloc, realloc
|
| ++
|
| ++from libzmq cimport *
|
| ++
|
| ++cdef extern from "getpid_compat.h":
|
| ++ int getpid()
|
| ++
|
| ++from zmq.error import ZMQError
|
| ++from zmq.core.checkrc cimport _check_rc
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++_instance = None
|
| ++
|
| ++cdef class Context:
|
| ++ """Context(io_threads=1)
|
| ++
|
| ++ Manage the lifecycle of a 0MQ context.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ io_threads : int
|
| ++ The number of IO threads.
|
| ++ """
|
| ++
|
| ++ def __cinit__(self, int io_threads = 1, **kwargs):
|
| ++ self.handle = NULL
|
| ++ self._sockets = NULL
|
| ++
|
| ++ if ZMQ_VERSION_MAJOR >= 3:
|
| ++ self.handle = zmq_ctx_new()
|
| ++ else:
|
| ++ self.handle = zmq_init(io_threads)
|
| ++
|
| ++ if self.handle == NULL:
|
| ++ raise ZMQError()
|
| ++
|
| ++ cdef int rc = 0
|
| ++ if ZMQ_VERSION_MAJOR >= 3:
|
| ++ rc = zmq_ctx_set(self.handle, ZMQ_IO_THREADS, io_threads)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ self.closed = False
|
| ++ self._n_sockets = 0
|
| ++ self._max_sockets = 32
|
| ++
|
| ++ self._sockets = <void **>malloc(self._max_sockets*sizeof(void *))
|
| ++ if self._sockets == NULL:
|
| ++ raise MemoryError("Could not allocate _sockets array")
|
| ++
|
| ++ self._pid = getpid()
|
| ++
|
| ++ def __init__(self, io_threads=1):
|
| ++ # no-op
|
| ++ pass
|
| ++
|
| ++
|
| ++ def __del__(self):
|
| ++ """deleting a Context should terminate it, without trying non-threadsafe destroy"""
|
| ++ self.term()
|
| ++
|
| ++ def __dealloc__(self):
|
| ++ """don't touch members in dealloc, just cleanup allocations"""
|
| ++ cdef int rc
|
| ++ if self._sockets != NULL:
|
| ++ free(self._sockets)
|
| ++ self._sockets = NULL
|
| ++ self._n_sockets = 0
|
| ++ self.term()
|
| ++
|
| ++ cdef inline void _add_socket(self, void* handle):
|
| ++ """Add a socket handle to be closed when Context terminates.
|
| ++
|
| ++ This is to be called in the Socket constructor.
|
| ++ """
|
| ++ # print self._n_sockets, self._max_sockets
|
| ++ if self._n_sockets >= self._max_sockets:
|
| ++ self._max_sockets *= 2
|
| ++ self._sockets = <void **>realloc(self._sockets, self._max_sockets*sizeof(void *))
|
| ++ if self._sockets == NULL:
|
| ++ raise MemoryError("Could not reallocate _sockets array")
|
| ++
|
| ++ self._sockets[self._n_sockets] = handle
|
| ++ self._n_sockets += 1
|
| ++ # print self._n_sockets, self._max_sockets
|
| ++
|
| ++ cdef inline void _remove_socket(self, void* handle):
|
| ++ """Remove a socket from the collected handles.
|
| ++
|
| ++ This should be called by Socket.close, to prevent trying to
|
| ++ close a socket a second time.
|
| ++ """
|
| ++ cdef bint found = False
|
| ++
|
| ++ for idx in range(self._n_sockets):
|
| ++ if self._sockets[idx] == handle:
|
| ++ found=True
|
| ++ break
|
| ++
|
| ++ if found:
|
| ++ self._n_sockets -= 1
|
| ++ if self._n_sockets:
|
| ++ # move last handle to closed socket's index
|
| ++ self._sockets[idx] = self._sockets[self._n_sockets]
|
| ++
|
| ++ @property
|
| ++ def _handle(self):
|
| ++ return <Py_ssize_t> self.handle
|
| ++
|
| ++ def term(self):
|
| ++ """ctx.term()
|
| ++
|
| ++ Close or terminate the context.
|
| ++
|
| ++ 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.
|
| ++ """
|
| ++ cdef int rc
|
| ++ cdef int i=-1
|
| ++
|
| ++ if self.handle != NULL and not self.closed and getpid() == self._pid:
|
| ++ with nogil:
|
| ++ rc = zmq_ctx_destroy(self.handle)
|
| ++ _check_rc(rc)
|
| ++ self.handle = NULL
|
| ++ self.closed = True
|
| ++
|
| ++ def set(self, int option, optval):
|
| ++ """ctx.set(option, optval)
|
| ++
|
| ++ Set context options.
|
| ++
|
| ++ See the 0MQ API documentation for zmq_ctx_set
|
| ++ for details on specific options.
|
| ++
|
| ++ New in libzmq-3.2
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ option : int
|
| ++ The option to set. Available values will depend on your
|
| ++ version of libzmq. Examples include::
|
| ++
|
| ++ zmq.IO_THREADS, zmq.MAX_SOCKETS
|
| ++
|
| ++ optval : int
|
| ++ The value of the option to set.
|
| ++ """
|
| ++ cdef int optval_int_c
|
| ++ cdef int rc
|
| ++ cdef char* optval_c
|
| ++
|
| ++ if self.closed:
|
| ++ raise RuntimeError("Context has been destroyed")
|
| ++
|
| ++ if not isinstance(optval, int):
|
| ++ raise TypeError('expected int, got: %r' % optval)
|
| ++ optval_int_c = optval
|
| ++ rc = zmq_ctx_set(self.handle, option, optval_int_c)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ def get(self, int option):
|
| ++ """ctx.get(option)
|
| ++
|
| ++ Get the value of a context option.
|
| ++
|
| ++ See the 0MQ API documentation for zmq_ctx_get
|
| ++ for details on specific options.
|
| ++
|
| ++ New in libzmq-3.2
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ option : int
|
| ++ The option to get. Available values will depend on your
|
| ++ version of libzmq. Examples include::
|
| ++
|
| ++ zmq.IO_THREADS, zmq.MAX_SOCKETS
|
| ++
|
| ++ Returns
|
| ++ -------
|
| ++ optval : int
|
| ++ The value of the option as an integer.
|
| ++ """
|
| ++ cdef int optval_int_c
|
| ++ cdef size_t sz
|
| ++ cdef int rc
|
| ++
|
| ++ if self.closed:
|
| ++ raise RuntimeError("Context has been destroyed")
|
| ++
|
| ++ rc = zmq_ctx_get(self.handle, option)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ return rc
|
| ++
|
| ++ def destroy(self, linger=None):
|
| ++ """ctx.destroy(linger=None)
|
| ++
|
| ++ Close all sockets associated with this context, and then terminate
|
| ++ the context. If linger is specified,
|
| ++ the LINGER sockopt of the sockets will be set prior to closing.
|
| ++
|
| ++ WARNING:
|
| ++
|
| ++ destroy involves calling zmq_close(), which is *NOT* threadsafe.
|
| ++ If there are active sockets in other threads, this must not be called.
|
| ++ """
|
| ++
|
| ++ cdef int linger_c
|
| ++ cdef bint setlinger=False
|
| ++
|
| ++ if linger is not None:
|
| ++ linger_c = linger
|
| ++ setlinger=True
|
| ++ if self.handle != NULL and not self.closed and self._n_sockets:
|
| ++ while self._n_sockets:
|
| ++ if setlinger:
|
| ++ zmq_setsockopt(self._sockets[0], ZMQ_LINGER, &linger_c, sizeof(int))
|
| ++ rc = zmq_close(self._sockets[0])
|
| ++ if rc < 0 and zmq_errno() != ZMQ_ENOTSOCK:
|
| ++ raise ZMQError()
|
| ++ self._n_sockets -= 1
|
| ++ self._sockets[0] = self._sockets[self._n_sockets]
|
| ++ self.term()
|
| ++
|
| ++__all__ = ['Context']
|
| +diff --git a/zmq/core/_zerror.pyx b/zmq/core/_zerror.pyx
|
| +new file mode 100644
|
| +index 0000000..85e785f
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zerror.pyx
|
| +@@ -0,0 +1,56 @@
|
| ++"""0MQ Error classes and functions."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++# allow const char*
|
| ++cdef extern from *:
|
| ++ ctypedef char* const_char_ptr "const char*"
|
| ++
|
| ++from libzmq cimport zmq_strerror, zmq_errno as zmq_errno_c
|
| ++
|
| ++from zmq.utils.strtypes import bytes
|
| ++
|
| ++def strerror(int errno):
|
| ++ """strerror(errno)
|
| ++
|
| ++ Return the error string given the error number.
|
| ++ """
|
| ++ cdef const_char_ptr str_e
|
| ++ # char * will be a bytes object:
|
| ++ str_e = zmq_strerror(errno)
|
| ++ if str is bytes:
|
| ++ # Python 2: str is bytes, so we already have the right type
|
| ++ return str_e
|
| ++ else:
|
| ++ # Python 3: decode bytes to unicode str
|
| ++ return str_e.decode()
|
| ++
|
| ++def zmq_errno():
|
| ++ """zmq_errno()
|
| ++
|
| ++ Return the integer errno of the most recent zmq error.
|
| ++ """
|
| ++ return zmq_errno_c()
|
| ++
|
| ++__all__ = ['strerror', 'zmq_errno']
|
| +diff --git a/zmq/core/_zmessage.pxd b/zmq/core/_zmessage.pxd
|
| +new file mode 100644
|
| +index 0000000..a86a8e0
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zmessage.pxd
|
| +@@ -0,0 +1,66 @@
|
| ++"""0MQ Message related class declarations."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from cpython cimport PyBytes_FromStringAndSize
|
| ++
|
| ++from libzmq cimport zmq_msg_t, zmq_msg_data, zmq_msg_size
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++cdef class MessageTracker(object):
|
| ++ """A class for tracking if 0MQ is done using one or more messages."""
|
| ++
|
| ++ cdef set events # Message Event objects to track.
|
| ++ cdef set peers # Other Message or MessageTracker objects.
|
| ++
|
| ++
|
| ++cdef class Frame:
|
| ++ """A Message Frame class for non-copy send/recvs."""
|
| ++
|
| ++ cdef zmq_msg_t zmq_msg
|
| ++ cdef object _data # The actual message data as a Python object.
|
| ++ cdef object _buffer # A Python Buffer/View of the message contents
|
| ++ cdef object _bytes # A bytes/str copy of the message.
|
| ++ cdef bint _failed_init # Flag to handle failed zmq_msg_init
|
| ++ cdef public object tracker_event # Event for use with zmq_free_fn.
|
| ++ cdef public object tracker # MessageTracker object.
|
| ++ cdef public bint more # whether RCVMORE was set
|
| ++
|
| ++ cdef Frame fast_copy(self) # Create shallow copy of Message object.
|
| ++ cdef object _getbuffer(self) # Construct self._buffer.
|
| ++
|
| ++
|
| ++cdef inline object copy_zmq_msg_bytes(zmq_msg_t *zmq_msg):
|
| ++ """ Copy the data from a zmq_msg_t """
|
| ++ cdef char *data_c = NULL
|
| ++ cdef Py_ssize_t data_len_c
|
| ++ with nogil:
|
| ++ data_c = <char *>zmq_msg_data(zmq_msg)
|
| ++ data_len_c = zmq_msg_size(zmq_msg)
|
| ++ return PyBytes_FromStringAndSize(data_c, data_len_c)
|
| ++
|
| ++
|
| +diff --git a/zmq/core/_zmessage.pyx b/zmq/core/_zmessage.pyx
|
| +new file mode 100644
|
| +index 0000000..1d358ab
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zmessage.pyx
|
| +@@ -0,0 +1,297 @@
|
| ++"""0MQ Message related classes."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2013 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++# get version-independent aliases:
|
| ++cdef extern from "pyversion_compat.h":
|
| ++ pass
|
| ++
|
| ++from cpython cimport Py_DECREF, Py_INCREF
|
| ++
|
| ++from buffers cimport asbuffer_r, viewfromobject_r
|
| ++
|
| ++cdef extern from "Python.h":
|
| ++ ctypedef int Py_ssize_t
|
| ++
|
| ++from libzmq cimport *
|
| ++
|
| ++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
|
| ++
|
| ++import zmq
|
| ++from zmq.core.checkrc cimport _check_rc
|
| ++from zmq.utils.strtypes import bytes,unicode,basestring
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++
|
| ++cdef void free_python_msg(void *data, void *hint) with gil:
|
| ++ """A function for DECREF'ing Python based messages."""
|
| ++ if hint != NULL:
|
| ++ tracker_event = (<tuple>hint)[1]
|
| ++ Py_DECREF(<object>hint)
|
| ++ if isinstance(tracker_event, Event):
|
| ++ # don't assert before DECREF:
|
| ++ # assert tracker_queue.empty(), "somebody else wrote to my Queue!"
|
| ++ tracker_event.set()
|
| ++ tracker_event = None
|
| ++
|
| ++
|
| ++cdef class Frame:
|
| ++ """Frame(data=None, track=False)
|
| ++
|
| ++ 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.
|
| ++
|
| ++ """
|
| ++
|
| ++ def __cinit__(self, object data=None, track=False, **kwargs):
|
| ++ cdef int rc
|
| ++ cdef char *data_c = NULL
|
| ++ cdef Py_ssize_t data_len_c=0
|
| ++ cdef object hint
|
| ++
|
| ++ # init more as False
|
| ++ self.more = False
|
| ++
|
| ++ # Save the data object in case the user wants the the data as a str.
|
| ++ self._data = data
|
| ++ self._failed_init = True # bool switch for dealloc
|
| ++ self._buffer = None # buffer view of data
|
| ++ self._bytes = None # bytes copy of data
|
| ++
|
| ++ # Event and MessageTracker for monitoring when zmq is done with data:
|
| ++ if track:
|
| ++ evt = Event()
|
| ++ self.tracker_event = evt
|
| ++ self.tracker = zmq.MessageTracker(evt)
|
| ++ else:
|
| ++ self.tracker_event = None
|
| ++ self.tracker = None
|
| ++
|
| ++ if isinstance(data, unicode):
|
| ++ raise TypeError("Unicode objects not allowed. Only: str/bytes, buffer interfaces.")
|
| ++
|
| ++ if data is None:
|
| ++ with nogil:
|
| ++ rc = zmq_msg_init(&self.zmq_msg)
|
| ++ _check_rc(rc)
|
| ++ self._failed_init = False
|
| ++ return
|
| ++ else:
|
| ++ asbuffer_r(data, <void **>&data_c, &data_len_c)
|
| ++ # We INCREF the *original* Python object (not self) and pass it
|
| ++ # as the hint below. This allows other copies of this Frame
|
| ++ # object to take over the ref counting of data properly.
|
| ++ hint = (data, self.tracker_event)
|
| ++ Py_INCREF(hint)
|
| ++ with nogil:
|
| ++ rc = zmq_msg_init_data(
|
| ++ &self.zmq_msg, <void *>data_c, data_len_c,
|
| ++ <zmq_free_fn *>free_python_msg, <void *>hint
|
| ++ )
|
| ++ if rc != 0:
|
| ++ Py_DECREF(hint)
|
| ++ _check_rc(rc)
|
| ++ self._failed_init = False
|
| ++
|
| ++ def __init__(self, object data=None, track=False):
|
| ++ """Enforce signature"""
|
| ++ pass
|
| ++
|
| ++ def __dealloc__(self):
|
| ++ cdef int rc
|
| ++ if self._failed_init:
|
| ++ return
|
| ++ # This simply decreases the 0MQ ref-count of zmq_msg.
|
| ++ with nogil:
|
| ++ rc = zmq_msg_close(&self.zmq_msg)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ # buffer interface code adapted from petsc4py by Lisandro Dalcin, a BSD project
|
| ++
|
| ++ def __getbuffer__(self, Py_buffer* buffer, int flags):
|
| ++ # new-style (memoryview) buffer interface
|
| ++ with nogil:
|
| ++ buffer.buf = zmq_msg_data(&self.zmq_msg)
|
| ++ buffer.len = zmq_msg_size(&self.zmq_msg)
|
| ++
|
| ++ buffer.obj = self
|
| ++ buffer.readonly = 1
|
| ++ buffer.format = "B"
|
| ++ buffer.ndim = 0
|
| ++ buffer.shape = NULL
|
| ++ buffer.strides = NULL
|
| ++ buffer.suboffsets = NULL
|
| ++ buffer.itemsize = 1
|
| ++ buffer.internal = NULL
|
| ++
|
| ++ def __getsegcount__(self, Py_ssize_t *lenp):
|
| ++ # required for getreadbuffer
|
| ++ if lenp != NULL:
|
| ++ with nogil:
|
| ++ lenp[0] = zmq_msg_size(&self.zmq_msg)
|
| ++ return 1
|
| ++
|
| ++ def __getreadbuffer__(self, Py_ssize_t idx, void **p):
|
| ++ # old-style (buffer) interface
|
| ++ cdef char *data_c = NULL
|
| ++ cdef Py_ssize_t data_len_c
|
| ++ if idx != 0:
|
| ++ raise SystemError("accessing non-existent buffer segment")
|
| ++ # read-only, because we don't want to allow
|
| ++ # editing of the message in-place
|
| ++ with nogil:
|
| ++ data_c = <char *>zmq_msg_data(&self.zmq_msg)
|
| ++ data_len_c = zmq_msg_size(&self.zmq_msg)
|
| ++ if p != NULL:
|
| ++ p[0] = <void*>data_c
|
| ++ return data_len_c
|
| ++
|
| ++ # end buffer interface
|
| ++
|
| ++ def __copy__(self):
|
| ++ """Create a shallow copy of the message.
|
| ++
|
| ++ This does not copy the contents of the Frame, just the pointer.
|
| ++ This will increment the 0MQ ref count of the message, but not
|
| ++ the ref count of the Python object. That is only done once when
|
| ++ the Python is first turned into a 0MQ message.
|
| ++ """
|
| ++ return self.fast_copy()
|
| ++
|
| ++ cdef Frame fast_copy(self):
|
| ++ """Fast, cdef'd version of shallow copy of the Frame."""
|
| ++ cdef Frame new_msg
|
| ++ new_msg = Frame()
|
| ++ # This does not copy the contents, but just increases the ref-count
|
| ++ # of the zmq_msg by one.
|
| ++ with nogil:
|
| ++ zmq_msg_copy(&new_msg.zmq_msg, &self.zmq_msg)
|
| ++ # Copy the ref to data so the copy won't create a copy when str is
|
| ++ # called.
|
| ++ if self._data is not None:
|
| ++ new_msg._data = self._data
|
| ++ if self._buffer is not None:
|
| ++ new_msg._buffer = self._buffer
|
| ++ if self._bytes is not None:
|
| ++ new_msg._bytes = self._bytes
|
| ++
|
| ++ # Frame copies share the tracker and tracker_event
|
| ++ new_msg.tracker_event = self.tracker_event
|
| ++ new_msg.tracker = self.tracker
|
| ++
|
| ++ return new_msg
|
| ++
|
| ++ def __len__(self):
|
| ++ """Return the length of the message in bytes."""
|
| ++ cdef size_t sz
|
| ++ with nogil:
|
| ++ sz = zmq_msg_size(&self.zmq_msg)
|
| ++ return sz
|
| ++ # return <int>zmq_msg_size(&self.zmq_msg)
|
| ++
|
| ++ def __str__(self):
|
| ++ """Return the str form of the message."""
|
| ++ if isinstance(self._data, bytes):
|
| ++ b = self._data
|
| ++ else:
|
| ++ b = self.bytes
|
| ++ if str is unicode:
|
| ++ return b.decode()
|
| ++ else:
|
| ++ return b
|
| ++
|
| ++ cdef inline object _getbuffer(self):
|
| ++ """Create a Python buffer/view of the message data.
|
| ++
|
| ++ This will be called only once, the first time the `buffer` property
|
| ++ is accessed. Subsequent calls use a cached copy.
|
| ++ """
|
| ++ if self._data is None:
|
| ++ return viewfromobject_r(self)
|
| ++ else:
|
| ++ return viewfromobject_r(self._data)
|
| ++
|
| ++ @property
|
| ++ def buffer(self):
|
| ++ """Get a read-only buffer view of the message contents."""
|
| ++ if self._buffer is None:
|
| ++ self._buffer = self._getbuffer()
|
| ++ return self._buffer
|
| ++
|
| ++ @property
|
| ++ def bytes(self):
|
| ++ """Get the message content as a Python str/bytes object.
|
| ++
|
| ++ The first time this property is accessed, a copy of the message
|
| ++ contents is made. From then on that same copy of the message is
|
| ++ returned.
|
| ++ """
|
| ++ if self._bytes is None:
|
| ++ self._bytes = copy_zmq_msg_bytes(&self.zmq_msg)
|
| ++ return self._bytes
|
| ++
|
| ++ def set(self, int option, int value):
|
| ++ """Set a message property"""
|
| ++ cdef int rc = zmq_msg_set(&self.zmq_msg, option, value)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ def get(self, int option):
|
| ++ """Get a message property"""
|
| ++ cdef int rc = zmq_msg_get(&self.zmq_msg, option)
|
| ++ _check_rc(rc)
|
| ++ return rc
|
| ++
|
| ++# legacy Message name
|
| ++Message = Frame
|
| ++
|
| ++__all__ = ['Frame', 'Message']
|
| +diff --git a/zmq/core/_zsocket.pxd b/zmq/core/_zsocket.pxd
|
| +new file mode 100644
|
| +index 0000000..68f96c8
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zsocket.pxd
|
| +@@ -0,0 +1,48 @@
|
| ++"""0MQ Socket class declaration."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from _zcontext cimport Context
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++
|
| ++cdef class Socket:
|
| ++ """A 0MQ socket."""
|
| ++
|
| ++ cdef object __weakref__ # enable weakref
|
| ++ cdef void *handle # The C handle for the underlying zmq object.
|
| ++ cdef public int socket_type # The 0MQ socket type - REQ,REP, etc.
|
| ++ # Hold on to a reference to the context to make sure it is not garbage
|
| ++ # collected until the socket it done with it.
|
| ++ cdef public Context context # The zmq Context object that owns this.
|
| ++ cdef public bint _closed # bool property for a closed socket.
|
| ++ cdef int _pid # the pid of the process which created me (for fork safety)
|
| ++
|
| ++ # cpdef methods for direct-cython access:
|
| ++ cpdef object send(self, object data, int flags=*, copy=*, track=*)
|
| ++ cpdef object recv(self, int flags=*, copy=*, track=*)
|
| ++
|
| +diff --git a/zmq/core/_zsocket.pyx b/zmq/core/_zsocket.pyx
|
| +new file mode 100644
|
| +index 0000000..a5e507d
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zsocket.pyx
|
| +@@ -0,0 +1,628 @@
|
| ++"""0MQ Socket class."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Cython Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++# get version-independent aliases:
|
| ++cdef extern from "pyversion_compat.h":
|
| ++ pass
|
| ++
|
| ++from libc.errno cimport ENAMETOOLONG
|
| ++from libc.string cimport memcpy
|
| ++
|
| ++from cpython cimport PyBytes_FromStringAndSize
|
| ++from cpython cimport PyBytes_AsString, PyBytes_Size
|
| ++from cpython cimport Py_DECREF, Py_INCREF
|
| ++
|
| ++from buffers cimport asbuffer_r, viewfromobject_r
|
| ++
|
| ++from libzmq cimport *
|
| ++from _zmessage cimport Frame, copy_zmq_msg_bytes
|
| ++
|
| ++from _zcontext cimport Context
|
| ++
|
| ++cdef extern from "Python.h":
|
| ++ ctypedef int Py_ssize_t
|
| ++
|
| ++cdef extern from "ipcmaxlen.h":
|
| ++ int get_ipc_path_max_len()
|
| ++
|
| ++cdef extern from "getpid_compat.h":
|
| ++ int getpid()
|
| ++
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Python Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++import copy as copy_mod
|
| ++import time
|
| ++import sys
|
| ++import random
|
| ++import struct
|
| ++import codecs
|
| ++
|
| ++from zmq.utils import jsonapi
|
| ++
|
| ++try:
|
| ++ import cPickle
|
| ++ pickle = cPickle
|
| ++except:
|
| ++ cPickle = None
|
| ++ import pickle
|
| ++
|
| ++import zmq
|
| ++from zmq.core import _zconstants as constants
|
| ++from zmq.core._zconstants import *
|
| ++from zmq.core.checkrc cimport _check_rc
|
| ++from zmq.error import ZMQError, ZMQBindError
|
| ++from zmq.utils.strtypes import bytes,unicode,basestring
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++IPC_PATH_MAX_LEN = get_ipc_path_max_len()
|
| ++
|
| ++# inline some small socket submethods:
|
| ++# true methods frequently cannot be inlined, acc. Cython docs
|
| ++
|
| ++cdef inline _check_closed(Socket s, bint raise_notsup):
|
| ++ cdef int rc
|
| ++ cdef int errno
|
| ++ cdef int stype
|
| ++ cdef size_t sz=sizeof(int)
|
| ++ if s._closed:
|
| ++ if raise_notsup:
|
| ++ raise ZMQError(ENOTSUP)
|
| ++ else:
|
| ++ return True
|
| ++ else:
|
| ++ rc = zmq_getsockopt(s.handle, ZMQ_TYPE, <void *>&stype, &sz)
|
| ++ if rc < 0 and zmq_errno() == ENOTSOCK:
|
| ++ s._closed = True
|
| ++ if raise_notsup:
|
| ++ raise ZMQError(ENOTSUP)
|
| ++ else:
|
| ++ return True
|
| ++ else:
|
| ++ _check_rc(rc)
|
| ++ return False
|
| ++
|
| ++cdef inline Frame _recv_frame(void *handle, int flags=0, track=False):
|
| ++ """Receive a message in a non-copying manner and return a Frame."""
|
| ++ cdef int rc
|
| ++ cdef Frame msg
|
| ++ msg = Frame(track=track)
|
| ++
|
| ++ with nogil:
|
| ++ rc = zmq_msg_recv(&msg.zmq_msg, handle, flags)
|
| ++
|
| ++ _check_rc(rc)
|
| ++ return msg
|
| ++
|
| ++cdef inline object _recv_copy(void *handle, int flags=0):
|
| ++ """Receive a message and return a copy"""
|
| ++ cdef zmq_msg_t zmq_msg
|
| ++ with nogil:
|
| ++ zmq_msg_init (&zmq_msg)
|
| ++ rc = zmq_msg_recv(&zmq_msg, handle, flags)
|
| ++ _check_rc(rc)
|
| ++ msg_bytes = copy_zmq_msg_bytes(&zmq_msg)
|
| ++ with nogil:
|
| ++ zmq_msg_close(&zmq_msg)
|
| ++ return msg_bytes
|
| ++
|
| ++cdef inline object _send_frame(void *handle, Frame msg, int flags=0):
|
| ++ """Send a Frame on this socket in a non-copy manner."""
|
| ++ cdef int rc
|
| ++ cdef Frame msg_copy
|
| ++
|
| ++ # Always copy so the original message isn't garbage collected.
|
| ++ # This doesn't do a real copy, just a reference.
|
| ++ msg_copy = msg.fast_copy()
|
| ++
|
| ++ with nogil:
|
| ++ rc = zmq_msg_send(&msg_copy.zmq_msg, handle, flags)
|
| ++
|
| ++ _check_rc(rc)
|
| ++ return msg.tracker
|
| ++
|
| ++
|
| ++cdef inline object _send_copy(void *handle, object msg, int flags=0):
|
| ++ """Send a message on this socket by copying its content."""
|
| ++ cdef int rc, rc2
|
| ++ cdef zmq_msg_t data
|
| ++ cdef char *msg_c
|
| ++ cdef Py_ssize_t msg_c_len=0
|
| ++
|
| ++ # copy to c array:
|
| ++ asbuffer_r(msg, <void **>&msg_c, &msg_c_len)
|
| ++
|
| ++ # Copy the msg before sending. This avoids any complications with
|
| ++ # the GIL, etc.
|
| ++ # If zmq_msg_init_* fails we must not call zmq_msg_close (Bus Error)
|
| ++ with nogil:
|
| ++ rc = zmq_msg_init_size(&data, msg_c_len)
|
| ++
|
| ++ _check_rc(rc)
|
| ++
|
| ++ with nogil:
|
| ++ memcpy(zmq_msg_data(&data), msg_c, zmq_msg_size(&data))
|
| ++ rc = zmq_msg_send(&data, handle, flags)
|
| ++ rc2 = zmq_msg_close(&data)
|
| ++ _check_rc(rc)
|
| ++ _check_rc(rc2)
|
| ++
|
| ++
|
| ++cdef class Socket:
|
| ++ """Socket(context, socket_type)
|
| ++
|
| ++ A 0MQ socket.
|
| ++
|
| ++ These objects will generally be constructed via the socket() method of a Context object.
|
| ++
|
| ++ Note: 0MQ Sockets are *not* threadsafe. **DO NOT** share them across threads.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ context : Context
|
| ++ The 0MQ Context this Socket belongs to.
|
| ++ socket_type : int
|
| ++ The socket type, which can be any of the 0MQ socket types:
|
| ++ REQ, REP, PUB, SUB, PAIR, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
|
| ++
|
| ++ See Also
|
| ++ --------
|
| ++ .Context.socket : method for creating a socket bound to a Context.
|
| ++ """
|
| ++
|
| ++ def __cinit__(self, Context context, int socket_type, *args, **kwrags):
|
| ++ cdef Py_ssize_t c_handle
|
| ++ c_handle = context._handle
|
| ++
|
| ++ self.handle = NULL
|
| ++ self.context = context
|
| ++ self.socket_type = socket_type
|
| ++ with nogil:
|
| ++ self.handle = zmq_socket(<void *>c_handle, socket_type)
|
| ++ if self.handle == NULL:
|
| ++ raise ZMQError()
|
| ++ self._closed = False
|
| ++ self._pid = getpid()
|
| ++ context._add_socket(self.handle)
|
| ++
|
| ++ def __dealloc__(self):
|
| ++ """close *and* remove from context's list
|
| ++
|
| ++ But be careful that context might not exist if called during gc
|
| ++ """
|
| ++ if self.handle != NULL and getpid() == self._pid:
|
| ++ rc = zmq_close(self.handle)
|
| ++ if rc != 0 and zmq_errno() != ENOTSOCK:
|
| ++ # ignore ENOTSOCK (closed by Context)
|
| ++ _check_rc(rc)
|
| ++ # during gc, self.context might be NULL
|
| ++ if self.context:
|
| ++ self.context._remove_socket(self.handle)
|
| ++
|
| ++ def __init__(self, context, socket_type):
|
| ++ pass
|
| ++
|
| ++ @property
|
| ++ def closed(self):
|
| ++ return _check_closed(self, False)
|
| ++
|
| ++ def close(self, linger=None):
|
| ++ """s.close(linger=None)
|
| ++
|
| ++ Close the socket.
|
| ++
|
| ++ If linger is specified, LINGER sockopt will be set prior to closing.
|
| ++
|
| ++ 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.
|
| ++ """
|
| ++ cdef int rc=0
|
| ++ cdef int linger_c
|
| ++ cdef bint setlinger=False
|
| ++
|
| ++ if linger is not None:
|
| ++ linger_c = linger
|
| ++ setlinger=True
|
| ++
|
| ++ if self.handle != NULL and not self._closed and getpid() == self._pid:
|
| ++ if setlinger:
|
| ++ zmq_setsockopt(self.handle, ZMQ_LINGER, &linger_c, sizeof(int))
|
| ++ rc = zmq_close(self.handle)
|
| ++ if rc != 0 and zmq_errno() != ENOTSOCK:
|
| ++ # ignore ENOTSOCK (closed by Context)
|
| ++ _check_rc(rc)
|
| ++ self._closed = True
|
| ++ # during gc, self.context might be NULL
|
| ++ if self.context:
|
| ++ self.context._remove_socket(self.handle)
|
| ++ self.handle = NULL
|
| ++
|
| ++ def set(self, int option, optval):
|
| ++ """s.set(option, optval)
|
| ++
|
| ++ Set socket options.
|
| ++
|
| ++ See the 0MQ API documentation for details on specific options.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ option : int
|
| ++ The option to set. Available values will depend on your
|
| ++ version of libzmq. Examples include::
|
| ++
|
| ++ zmq.SUBSCRIBE, UNSUBSCRIBE, IDENTITY, HWM, LINGER, FD
|
| ++
|
| ++ optval : int or bytes
|
| ++ The value of the option to set.
|
| ++ """
|
| ++ cdef int64_t optval_int64_c
|
| ++ cdef int optval_int_c
|
| ++ cdef int rc
|
| ++ cdef char* optval_c
|
| ++ cdef Py_ssize_t sz
|
| ++
|
| ++ _check_closed(self, True)
|
| ++ if isinstance(optval, unicode):
|
| ++ raise TypeError("unicode not allowed, use setsockopt_string")
|
| ++
|
| ++ if option in zmq.constants.bytes_sockopts:
|
| ++ if not isinstance(optval, bytes):
|
| ++ raise TypeError('expected bytes, got: %r' % optval)
|
| ++ optval_c = PyBytes_AsString(optval)
|
| ++ sz = PyBytes_Size(optval)
|
| ++ with nogil:
|
| ++ rc = zmq_setsockopt(
|
| ++ self.handle, option,
|
| ++ optval_c, sz
|
| ++ )
|
| ++ elif option in zmq.constants.int64_sockopts:
|
| ++ if not isinstance(optval, int):
|
| ++ raise TypeError('expected int, got: %r' % optval)
|
| ++ optval_int64_c = optval
|
| ++ with nogil:
|
| ++ rc = zmq_setsockopt(
|
| ++ self.handle, option,
|
| ++ &optval_int64_c, sizeof(int64_t)
|
| ++ )
|
| ++ else:
|
| ++ # default is to assume int, which is what most new sockopts will be
|
| ++ # this lets pyzmq work with newer libzmq which may add constants
|
| ++ # pyzmq has not yet added, rather than artificially raising. Invalid
|
| ++ # sockopts will still raise just the same, but it will be libzmq doing
|
| ++ # the raising.
|
| ++ if not isinstance(optval, int):
|
| ++ raise TypeError('expected int, got: %r' % optval)
|
| ++ optval_int_c = optval
|
| ++ with nogil:
|
| ++ rc = zmq_setsockopt(
|
| ++ self.handle, option,
|
| ++ &optval_int_c, sizeof(int)
|
| ++ )
|
| ++
|
| ++ _check_rc(rc)
|
| ++
|
| ++ def get(self, int option):
|
| ++ """s.get(option)
|
| ++
|
| ++ Get the value of a socket option.
|
| ++
|
| ++ See the 0MQ API documentation for details on specific options.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ option : int
|
| ++ The option to get. Available values will depend on your
|
| ++ version of libzmq. Examples include::
|
| ++
|
| ++ zmq.IDENTITY, HWM, LINGER, FD, EVENTS
|
| ++
|
| ++ Returns
|
| ++ -------
|
| ++ optval : int or bytes
|
| ++ The value of the option as a bytestring or int.
|
| ++ """
|
| ++ cdef int64_t optval_int64_c
|
| ++ cdef int optval_int_c
|
| ++ cdef fd_t optval_fd_c
|
| ++ cdef char identity_str_c [255]
|
| ++ cdef size_t sz
|
| ++ cdef int rc
|
| ++
|
| ++ _check_closed(self, True)
|
| ++
|
| ++ if option in zmq.constants.bytes_sockopts:
|
| ++ sz = 255
|
| ++ with nogil:
|
| ++ rc = zmq_getsockopt(self.handle, option, <void *>identity_str_c, &sz)
|
| ++ _check_rc(rc)
|
| ++ result = PyBytes_FromStringAndSize(<char *>identity_str_c, sz)
|
| ++ elif option in zmq.constants.int64_sockopts:
|
| ++ sz = sizeof(int64_t)
|
| ++ with nogil:
|
| ++ rc = zmq_getsockopt(self.handle, option, <void *>&optval_int64_c, &sz)
|
| ++ _check_rc(rc)
|
| ++ result = optval_int64_c
|
| ++ elif option == ZMQ_FD:
|
| ++ sz = sizeof(fd_t)
|
| ++ with nogil:
|
| ++ rc = zmq_getsockopt(self.handle, option, <void *>&optval_fd_c, &sz)
|
| ++ _check_rc(rc)
|
| ++ result = optval_fd_c
|
| ++ else:
|
| ++ # default is to assume int, which is what most new sockopts will be
|
| ++ # this lets pyzmq work with newer libzmq which may add constants
|
| ++ # pyzmq has not yet added, rather than artificially raising. Invalid
|
| ++ # sockopts will still raise just the same, but it will be libzmq doing
|
| ++ # the raising.
|
| ++ sz = sizeof(int)
|
| ++ with nogil:
|
| ++ rc = zmq_getsockopt(self.handle, option, <void *>&optval_int_c, &sz)
|
| ++ _check_rc(rc)
|
| ++ result = optval_int_c
|
| ++
|
| ++ return result
|
| ++
|
| ++ def bind(self, addr):
|
| ++ """s.bind(addr)
|
| ++
|
| ++ Bind the socket to an address.
|
| ++
|
| ++ This causes the socket to listen on a network port. Sockets on the
|
| ++ other side of this connection will use ``Socket.connect(addr)`` to
|
| ++ connect to this socket.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ addr : str
|
| ++ The address string. This has the form 'protocol://interface:port',
|
| ++ for example 'tcp://127.0.0.1:5555'. Protocols supported include
|
| ++ tcp, udp, pgm, epgm, inproc and ipc. If the address is unicode, it is
|
| ++ encoded to utf-8 first.
|
| ++ """
|
| ++ cdef int rc
|
| ++ cdef char* c_addr
|
| ++
|
| ++ _check_closed(self, True)
|
| ++ if isinstance(addr, unicode):
|
| ++ addr = addr.encode('utf-8')
|
| ++ if not isinstance(addr, bytes):
|
| ++ raise TypeError('expected str, got: %r' % addr)
|
| ++ c_addr = addr
|
| ++ rc = zmq_bind(self.handle, c_addr)
|
| ++ if rc != 0:
|
| ++ if IPC_PATH_MAX_LEN and zmq_errno() == ENAMETOOLONG:
|
| ++ # py3compat: addr is bytes, but msg wants str
|
| ++ if str is unicode:
|
| ++ addr = addr.decode('utf-8', 'replace')
|
| ++ path = addr.split('://', 1)[-1]
|
| ++ msg = ('ipc path "{0}" is longer than {1} '
|
| ++ 'characters (sizeof(sockaddr_un.sun_path)). '
|
| ++ 'zmq.IPC_PATH_MAX_LEN constant can be used '
|
| ++ 'to check addr length (if it is defined).'
|
| ++ .format(path, IPC_PATH_MAX_LEN))
|
| ++ raise ZMQError(msg=msg)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ def connect(self, addr):
|
| ++ """s.connect(addr)
|
| ++
|
| ++ Connect to a remote 0MQ socket.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ addr : str
|
| ++ The address string. This has the form 'protocol://interface:port',
|
| ++ for example 'tcp://127.0.0.1:5555'. Protocols supported are
|
| ++ tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
|
| ++ encoded to utf-8 first.
|
| ++ """
|
| ++ cdef int rc
|
| ++ cdef char* c_addr
|
| ++
|
| ++ _check_closed(self, True)
|
| ++ if isinstance(addr, unicode):
|
| ++ addr = addr.encode('utf-8')
|
| ++ if not isinstance(addr, bytes):
|
| ++ raise TypeError('expected str, got: %r' % addr)
|
| ++ c_addr = addr
|
| ++
|
| ++ rc = zmq_connect(self.handle, c_addr)
|
| ++ if rc != 0:
|
| ++ raise ZMQError()
|
| ++
|
| ++ def unbind(self, addr):
|
| ++ """s.unbind(addr)
|
| ++
|
| ++ Unbind from an address (undoes a call to bind).
|
| ++
|
| ++ This feature requires libzmq-3
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ addr : str
|
| ++ The address string. This has the form 'protocol://interface:port',
|
| ++ for example 'tcp://127.0.0.1:5555'. Protocols supported are
|
| ++ tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
|
| ++ encoded to utf-8 first.
|
| ++ """
|
| ++ cdef int rc
|
| ++ cdef char* c_addr
|
| ++
|
| ++ if ZMQ_VERSION_MAJOR < 3:
|
| ++ raise NotImplementedError("unbind requires libzmq >= 3.0, have %s" % zmq.zmq_version())
|
| ++
|
| ++
|
| ++ _check_closed(self, True)
|
| ++ if isinstance(addr, unicode):
|
| ++ addr = addr.encode('utf-8')
|
| ++ if not isinstance(addr, bytes):
|
| ++ raise TypeError('expected str, got: %r' % addr)
|
| ++ c_addr = addr
|
| ++
|
| ++ rc = zmq_unbind(self.handle, c_addr)
|
| ++ if rc != 0:
|
| ++ raise ZMQError()
|
| ++
|
| ++ def disconnect(self, addr):
|
| ++ """s.disconnect(addr)
|
| ++
|
| ++ Disconnect from a remote 0MQ socket (undoes a call to connect).
|
| ++
|
| ++ This feature requires libzmq-3
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ addr : str
|
| ++ The address string. This has the form 'protocol://interface:port',
|
| ++ for example 'tcp://127.0.0.1:5555'. Protocols supported are
|
| ++ tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
|
| ++ encoded to utf-8 first.
|
| ++ """
|
| ++ cdef int rc
|
| ++ cdef char* c_addr
|
| ++
|
| ++ if ZMQ_VERSION_MAJOR < 3:
|
| ++ raise NotImplementedError("disconnect requires libzmq >= 3.0, have %s" % zmq.zmq_version())
|
| ++
|
| ++ _check_closed(self, True)
|
| ++ if isinstance(addr, unicode):
|
| ++ addr = addr.encode('utf-8')
|
| ++ if not isinstance(addr, bytes):
|
| ++ raise TypeError('expected str, got: %r' % addr)
|
| ++ c_addr = addr
|
| ++
|
| ++ rc = zmq_disconnect(self.handle, c_addr)
|
| ++ if rc != 0:
|
| ++ raise ZMQError()
|
| ++
|
| ++ #-------------------------------------------------------------------------
|
| ++ # Sending and receiving messages
|
| ++ #-------------------------------------------------------------------------
|
| ++
|
| ++ cpdef object send(self, object data, int flags=0, copy=True, track=False):
|
| ++ """s.send(data, flags=0, copy=True, track=False)
|
| ++
|
| ++ Send a message on this socket.
|
| ++
|
| ++ This queues the message to be sent by the IO thread at a later time.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ data : object, str, Frame
|
| ++ The content of the message.
|
| ++ flags : int
|
| ++ Any supported flag: 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)
|
| ++
|
| ++ 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.
|
| ++
|
| ++ """
|
| ++ _check_closed(self, True)
|
| ++
|
| ++ if isinstance(data, unicode):
|
| ++ raise TypeError("unicode not allowed, use send_unicode")
|
| ++
|
| ++ if copy:
|
| ++ # msg.bytes never returns the input data object
|
| ++ # it is always a copy, but always the same copy
|
| ++ if isinstance(data, Frame):
|
| ++ data = data.buffer
|
| ++ return _send_copy(self.handle, data, flags)
|
| ++ else:
|
| ++ if isinstance(data, Frame):
|
| ++ if track and not data.tracker:
|
| ++ raise ValueError('Not a tracked message')
|
| ++ msg = data
|
| ++ else:
|
| ++ msg = Frame(data, track=track)
|
| ++ return _send_frame(self.handle, msg, flags)
|
| ++
|
| ++ cpdef object recv(self, int flags=0, copy=True, track=False):
|
| ++ """s.recv(flags=0, copy=True, track=False)
|
| ++
|
| ++ Receive a message.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ flags : int
|
| ++ Any supported flag: NOBLOCK. If NOBLOCK is set, this method
|
| ++ will raise a ZMQError with EAGAIN if a message is not ready.
|
| ++ If NOBLOCK is not set, then this method will block until a
|
| ++ message arrives.
|
| ++ copy : bool
|
| ++ Should the message be received in a copying or non-copying manner?
|
| ++ If False a Frame object is returned, if True a string copy of
|
| ++ message is returned.
|
| ++ track : bool
|
| ++ Should the message be tracked for notification that ZMQ has
|
| ++ finished with it? (ignored if copy=True)
|
| ++
|
| ++ Returns
|
| ++ -------
|
| ++ msg : bytes, Frame
|
| ++ The received message frame. If `copy` is False, then it will be a Frame,
|
| ++ otherwise it will be bytes.
|
| ++
|
| ++ Raises
|
| ++ ------
|
| ++ ZMQError
|
| ++ for any of the reasons zmq_msg_recv might fail.
|
| ++ """
|
| ++ _check_closed(self, True)
|
| ++
|
| ++ if copy:
|
| ++ return _recv_copy(self.handle, flags)
|
| ++ else:
|
| ++ frame = _recv_frame(self.handle, flags, track)
|
| ++ frame.more = self.getsockopt(zmq.RCVMORE)
|
| ++ return frame
|
| ++
|
| ++
|
| ++__all__ = ['Socket', 'IPC_PATH_MAX_LEN']
|
| +diff --git a/zmq/core/_zstopwatch.pxd b/zmq/core/_zstopwatch.pxd
|
| +new file mode 100644
|
| +index 0000000..5d56166
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zstopwatch.pxd
|
| +@@ -0,0 +1,31 @@
|
| ++"""0MQ Stopwatch class declaration."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++
|
| ++cdef class Stopwatch:
|
| ++ """A simple stopwatch based on zmq_stopwatch_start/stop."""
|
| ++
|
| ++ cdef void *watch # The C handle for the underlying zmq object
|
| ++
|
| +diff --git a/zmq/core/_zstopwatch.pyx b/zmq/core/_zstopwatch.pyx
|
| +new file mode 100644
|
| +index 0000000..6d2fd61
|
| +--- /dev/null
|
| ++++ b/zmq/core/_zstopwatch.pyx
|
| +@@ -0,0 +1,90 @@
|
| ++"""0MQ Stopwatch class."""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq.
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libzmq cimport zmq_stopwatch_start, zmq_stopwatch_stop, zmq_sleep
|
| ++
|
| ++from zmq.error import ZMQError
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Code
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++cdef class Stopwatch:
|
| ++ """Stopwatch()
|
| ++
|
| ++ A simple stopwatch based on zmq_stopwatch_start/stop.
|
| ++
|
| ++ This class should be used for benchmarking and timing 0MQ code.
|
| ++ """
|
| ++
|
| ++ def __cinit__(self):
|
| ++ self.watch = NULL
|
| ++
|
| ++ def __dealloc__(self):
|
| ++ try:
|
| ++ self.stop()
|
| ++ except ZMQError:
|
| ++ pass
|
| ++
|
| ++ def start(self):
|
| ++ """s.start()
|
| ++
|
| ++ Start the stopwatch.
|
| ++ """
|
| ++ if self.watch == NULL:
|
| ++ with nogil:
|
| ++ self.watch = zmq_stopwatch_start()
|
| ++ else:
|
| ++ raise ZMQError('Stopwatch is already runing.')
|
| ++
|
| ++ def stop(self):
|
| ++ """s.stop()
|
| ++
|
| ++ Stop the stopwatch.
|
| ++
|
| ++ Returns
|
| ++ -------
|
| ++ t : unsigned long int
|
| ++ the number of microseconds since ``start()`` was called.
|
| ++ """
|
| ++ cdef unsigned long time
|
| ++ if self.watch == NULL:
|
| ++ raise ZMQError('Must start the Stopwatch before calling stop.')
|
| ++ else:
|
| ++ with nogil:
|
| ++ time = zmq_stopwatch_stop(self.watch)
|
| ++ self.watch = NULL
|
| ++ return time
|
| ++
|
| ++ def sleep(self, int seconds):
|
| ++ """s.sleep(seconds)
|
| ++
|
| ++ Sleep for an integer number of seconds.
|
| ++ """
|
| ++ with nogil:
|
| ++ zmq_sleep(seconds)
|
| ++
|
| ++
|
| ++__all__ = ['Stopwatch']
|
| +diff --git a/zmq/core/constants.pyx b/zmq/core/constants.pyx
|
| +deleted file mode 100644
|
| +index fa2695d..0000000
|
| +--- a/zmq/core/constants.pyx
|
| ++++ /dev/null
|
| +@@ -1,190 +0,0 @@
|
| +-"""0MQ Constants."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libzmq cimport *
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Python module level constants
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-_optionals = []
|
| +-
|
| +-if ZMQ_VERSION < 30000:
|
| +- # backport DONTWAIT as alias to NOBLOCK
|
| +- NOBLOCK = ZMQ_NOBLOCK
|
| +- DONTWAIT = ZMQ_NOBLOCK
|
| +-else:
|
| +- # keep NOBLOCK as alias for new DONTWAIT
|
| +- NOBLOCK = ZMQ_DONTWAIT
|
| +- DONTWAIT = ZMQ_DONTWAIT
|
| +-
|
| +-VERSION = ZMQ_VERSION
|
| +-
|
| +-# socket types
|
| +-PAIR = ZMQ_PAIR
|
| +-PUB = ZMQ_PUB
|
| +-SUB = ZMQ_SUB
|
| +-REQ = ZMQ_REQ
|
| +-REP = ZMQ_REP
|
| +-DEALER = ZMQ_DEALER
|
| +-ROUTER = ZMQ_ROUTER
|
| +-PULL = ZMQ_PULL
|
| +-PUSH = ZMQ_PUSH
|
| +-XPUB = ZMQ_XPUB
|
| +-XSUB = ZMQ_XSUB
|
| +-
|
| +-# keep deprecated aliases
|
| +-XREQ = DEALER
|
| +-XREP = ROUTER
|
| +-UPSTREAM = PULL
|
| +-DOWNSTREAM = PUSH
|
| +-
|
| +-
|
| +-# socket options
|
| +-AFFINITY = ZMQ_AFFINITY
|
| +-IDENTITY = ZMQ_IDENTITY
|
| +-SUBSCRIBE = ZMQ_SUBSCRIBE
|
| +-UNSUBSCRIBE = ZMQ_UNSUBSCRIBE
|
| +-RATE = ZMQ_RATE
|
| +-RECOVERY_IVL = ZMQ_RECOVERY_IVL
|
| +-RECONNECT_IVL_MAX = ZMQ_RECONNECT_IVL_MAX
|
| +-SNDBUF = ZMQ_SNDBUF
|
| +-RCVBUF = ZMQ_RCVBUF
|
| +-RCVMORE = ZMQ_RCVMORE
|
| +-SNDMORE = ZMQ_SNDMORE
|
| +-POLLIN = ZMQ_POLLIN
|
| +-POLLOUT = ZMQ_POLLOUT
|
| +-POLLERR = ZMQ_POLLERR
|
| +-
|
| +-STREAMER = ZMQ_STREAMER
|
| +-FORWARDER = ZMQ_FORWARDER
|
| +-QUEUE = ZMQ_QUEUE
|
| +-
|
| +-# sockopts new in 2.2.0
|
| +-SNDTIMEO = ZMQ_SNDTIMEO
|
| +-RCVTIMEO = ZMQ_RCVTIMEO
|
| +-
|
| +-# sockopts removed in 3.0.0
|
| +-HWM = ZMQ_HWM
|
| +-SWAP = ZMQ_SWAP
|
| +-MCAST_LOOP = ZMQ_MCAST_LOOP
|
| +-RECOVERY_IVL_MSEC = ZMQ_RECOVERY_IVL_MSEC
|
| +-
|
| +-# new in 3.x
|
| +-IO_THREADS = ZMQ_IO_THREADS
|
| +-MAX_SOCKETS = ZMQ_MAX_SOCKETS
|
| +-
|
| +-MORE = ZMQ_MORE
|
| +-
|
| +-MAXMSGSIZE = ZMQ_MAXMSGSIZE
|
| +-SNDHWM = ZMQ_SNDHWM
|
| +-RCVHWM = ZMQ_RCVHWM
|
| +-MULTICAST_HOPS = ZMQ_MULTICAST_HOPS
|
| +-IPV4ONLY = ZMQ_IPV4ONLY
|
| +-LAST_ENDPOINT = ZMQ_LAST_ENDPOINT
|
| +-
|
| +-ROUTER_MANDATORY = ZMQ_ROUTER_MANDATORY
|
| +-# aliases
|
| +-ROUTER_BEHAVIOR = ROUTER_MANDATORY
|
| +-FAIL_UNROUTABLE = ROUTER_MANDATORY
|
| +-
|
| +-TCP_KEEPALIVE = ZMQ_TCP_KEEPALIVE
|
| +-TCP_KEEPALIVE_CNT = ZMQ_TCP_KEEPALIVE_CNT
|
| +-TCP_KEEPALIVE_IDLE = ZMQ_TCP_KEEPALIVE_IDLE
|
| +-TCP_KEEPALIVE_INTVL = ZMQ_TCP_KEEPALIVE_INTVL
|
| +-TCP_ACCEPT_FILTER = ZMQ_TCP_ACCEPT_FILTER
|
| +-DELAY_ATTACH_ON_CONNECT = ZMQ_DELAY_ATTACH_ON_CONNECT
|
| +-XPUB_VERBOSE = ZMQ_XPUB_VERBOSE
|
| +-ROUTER_RAW = ZMQ_ROUTER_RAW
|
| +-
|
| +-EVENT_CONNECTED = ZMQ_EVENT_CONNECTED
|
| +-EVENT_CONNECT_DELAYED = ZMQ_EVENT_CONNECT_DELAYED
|
| +-EVENT_CONNECT_RETRIED = ZMQ_EVENT_CONNECT_RETRIED
|
| +-EVENT_LISTENING = ZMQ_EVENT_LISTENING
|
| +-EVENT_BIND_FAILED = ZMQ_EVENT_BIND_FAILED
|
| +-EVENT_ACCEPTED = ZMQ_EVENT_ACCEPTED
|
| +-EVENT_ACCEPT_FAILED = ZMQ_EVENT_ACCEPT_FAILED
|
| +-EVENT_CLOSED = ZMQ_EVENT_CLOSED
|
| +-EVENT_CLOSE_FAILED = ZMQ_EVENT_CLOSE_FAILED
|
| +-EVENT_DISCONNECTED = ZMQ_EVENT_DISCONNECTED
|
| +-
|
| +-FD = ZMQ_FD
|
| +-EVENTS = ZMQ_EVENTS
|
| +-TYPE = ZMQ_TYPE
|
| +-LINGER = ZMQ_LINGER
|
| +-RECONNECT_IVL = ZMQ_RECONNECT_IVL
|
| +-BACKLOG = ZMQ_BACKLOG
|
| +-
|
| +-# As new constants are added in future versions, add a new block here
|
| +-# like the two above, checking agains the relevant value for ZMQ_VERSION.
|
| +-# The constants will need to be added to libzmq.pxd and utils/zmq_compat.h
|
| +-# as well.
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Error handling
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-# Often used standard errnos
|
| +-from errno import (
|
| +- EAGAIN,
|
| +- EINVAL,
|
| +- EFAULT,
|
| +- ENOMEM,
|
| +- ENODEV
|
| +-)
|
| +-
|
| +-# For Windows compatability
|
| +-ENOTSUP = ZMQ_ENOTSUP
|
| +-EPROTONOSUPPORT = ZMQ_EPROTONOSUPPORT
|
| +-ENOBUFS = ZMQ_ENOBUFS
|
| +-ENETDOWN = ZMQ_ENETDOWN
|
| +-EADDRINUSE = ZMQ_EADDRINUSE
|
| +-EADDRNOTAVAIL = ZMQ_EADDRNOTAVAIL
|
| +-ECONNREFUSED = ZMQ_ECONNREFUSED
|
| +-EINPROGRESS = ZMQ_EINPROGRESS
|
| +-ENOTSOCK = ZMQ_ENOTSOCK
|
| +-
|
| +-# new errnos in zmq3
|
| +-EMSGSIZE = ZMQ_EMSGSIZE
|
| +-EAFNOSUPPORT = ZMQ_EAFNOSUPPORT
|
| +-ENETUNREACH = ZMQ_ENETUNREACH
|
| +-ECONNABORTED = ZMQ_ECONNABORTED
|
| +-ECONNRESET = ZMQ_ECONNRESET
|
| +-ENOTCONN = ZMQ_ENOTCONN
|
| +-ETIMEDOUT = ZMQ_ETIMEDOUT
|
| +-EHOSTUNREACH = ZMQ_EHOSTUNREACH
|
| +-ENETRESET = ZMQ_ENETRESET
|
| +-
|
| +-# 0MQ Native
|
| +-EFSM = ZMQ_EFSM
|
| +-ENOCOMPATPROTO = ZMQ_ENOCOMPATPROTO
|
| +-ETERM = ZMQ_ETERM
|
| +-EMTHREAD = ZMQ_EMTHREAD
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Symbols to export
|
| +-#-----------------------------------------------------------------------------
|
| +-_names = list(locals().keys())
|
| +-__all__ = [ key for key in _names if not key.startswith('_') ]
|
| +diff --git a/zmq/core/context.pxd b/zmq/core/context.pxd
|
| +deleted file mode 100644
|
| +index e399de5..0000000
|
| +--- a/zmq/core/context.pxd
|
| ++++ /dev/null
|
| +@@ -1,40 +0,0 @@
|
| +-"""0MQ Context class declaration."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-cdef class Context:
|
| +- """Manage the lifecycle of a 0MQ context."""
|
| +-
|
| +- cdef object __weakref__ # enable weakref
|
| +- cdef void *handle # The C handle for the underlying zmq object.
|
| +- cdef void **_sockets # A C-array containg socket handles
|
| +- cdef size_t _n_sockets # the number of sockets
|
| +- cdef size_t _max_sockets # the size of the _sockets array
|
| +- cdef int _pid # the pid of the process which created me (for fork safety)
|
| +-
|
| +- cdef public object closed # bool property for a closed context.
|
| +- # helpers for events on _sockets in Socket.__cinit__()/close()
|
| +- cdef inline void _add_socket(self, void* handle)
|
| +- cdef inline void _remove_socket(self, void* handle)
|
| +-
|
| +diff --git a/zmq/core/context.pyx b/zmq/core/context.pyx
|
| +deleted file mode 100644
|
| +index 0917c66..0000000
|
| +--- a/zmq/core/context.pyx
|
| ++++ /dev/null
|
| +@@ -1,254 +0,0 @@
|
| +-"""0MQ Context class."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libc.stdlib cimport free, malloc, realloc
|
| +-
|
| +-from libzmq cimport *
|
| +-
|
| +-cdef extern from "getpid_compat.h":
|
| +- int getpid()
|
| +-
|
| +-from zmq.error import ZMQError
|
| +-from zmq.core.checkrc cimport _check_rc
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-_instance = None
|
| +-
|
| +-cdef class Context:
|
| +- """Context(io_threads=1)
|
| +-
|
| +- Manage the lifecycle of a 0MQ context.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- io_threads : int
|
| +- The number of IO threads.
|
| +- """
|
| +-
|
| +- def __cinit__(self, int io_threads = 1, **kwargs):
|
| +- self.handle = NULL
|
| +- self._sockets = NULL
|
| +-
|
| +- if ZMQ_VERSION_MAJOR >= 3:
|
| +- self.handle = zmq_ctx_new()
|
| +- else:
|
| +- self.handle = zmq_init(io_threads)
|
| +-
|
| +- if self.handle == NULL:
|
| +- raise ZMQError()
|
| +-
|
| +- cdef int rc = 0
|
| +- if ZMQ_VERSION_MAJOR >= 3:
|
| +- rc = zmq_ctx_set(self.handle, ZMQ_IO_THREADS, io_threads)
|
| +- _check_rc(rc)
|
| +-
|
| +- self.closed = False
|
| +- self._n_sockets = 0
|
| +- self._max_sockets = 32
|
| +-
|
| +- self._sockets = <void **>malloc(self._max_sockets*sizeof(void *))
|
| +- if self._sockets == NULL:
|
| +- raise MemoryError("Could not allocate _sockets array")
|
| +-
|
| +- self._pid = getpid()
|
| +-
|
| +- def __init__(self, io_threads=1):
|
| +- # no-op
|
| +- pass
|
| +-
|
| +-
|
| +- def __del__(self):
|
| +- """deleting a Context should terminate it, without trying non-threadsafe destroy"""
|
| +- self.term()
|
| +-
|
| +- def __dealloc__(self):
|
| +- """don't touch members in dealloc, just cleanup allocations"""
|
| +- cdef int rc
|
| +- if self._sockets != NULL:
|
| +- free(self._sockets)
|
| +- self._sockets = NULL
|
| +- self._n_sockets = 0
|
| +- self.term()
|
| +-
|
| +- cdef inline void _add_socket(self, void* handle):
|
| +- """Add a socket handle to be closed when Context terminates.
|
| +-
|
| +- This is to be called in the Socket constructor.
|
| +- """
|
| +- # print self._n_sockets, self._max_sockets
|
| +- if self._n_sockets >= self._max_sockets:
|
| +- self._max_sockets *= 2
|
| +- self._sockets = <void **>realloc(self._sockets, self._max_sockets*sizeof(void *))
|
| +- if self._sockets == NULL:
|
| +- raise MemoryError("Could not reallocate _sockets array")
|
| +-
|
| +- self._sockets[self._n_sockets] = handle
|
| +- self._n_sockets += 1
|
| +- # print self._n_sockets, self._max_sockets
|
| +-
|
| +- cdef inline void _remove_socket(self, void* handle):
|
| +- """Remove a socket from the collected handles.
|
| +-
|
| +- This should be called by Socket.close, to prevent trying to
|
| +- close a socket a second time.
|
| +- """
|
| +- cdef bint found = False
|
| +-
|
| +- for idx in range(self._n_sockets):
|
| +- if self._sockets[idx] == handle:
|
| +- found=True
|
| +- break
|
| +-
|
| +- if found:
|
| +- self._n_sockets -= 1
|
| +- if self._n_sockets:
|
| +- # move last handle to closed socket's index
|
| +- self._sockets[idx] = self._sockets[self._n_sockets]
|
| +-
|
| +- @property
|
| +- def _handle(self):
|
| +- return <Py_ssize_t> self.handle
|
| +-
|
| +- def term(self):
|
| +- """ctx.term()
|
| +-
|
| +- Close or terminate the context.
|
| +-
|
| +- 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.
|
| +- """
|
| +- cdef int rc
|
| +- cdef int i=-1
|
| +-
|
| +- if self.handle != NULL and not self.closed and getpid() == self._pid:
|
| +- with nogil:
|
| +- rc = zmq_ctx_destroy(self.handle)
|
| +- _check_rc(rc)
|
| +- self.handle = NULL
|
| +- self.closed = True
|
| +-
|
| +- def set(self, int option, optval):
|
| +- """ctx.set(option, optval)
|
| +-
|
| +- Set context options.
|
| +-
|
| +- See the 0MQ API documentation for zmq_ctx_set
|
| +- for details on specific options.
|
| +-
|
| +- New in libzmq-3.2
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- option : int
|
| +- The option to set. Available values will depend on your
|
| +- version of libzmq. Examples include::
|
| +-
|
| +- zmq.IO_THREADS, zmq.MAX_SOCKETS
|
| +-
|
| +- optval : int
|
| +- The value of the option to set.
|
| +- """
|
| +- cdef int optval_int_c
|
| +- cdef int rc
|
| +- cdef char* optval_c
|
| +-
|
| +- if self.closed:
|
| +- raise RuntimeError("Context has been destroyed")
|
| +-
|
| +- if not isinstance(optval, int):
|
| +- raise TypeError('expected int, got: %r' % optval)
|
| +- optval_int_c = optval
|
| +- rc = zmq_ctx_set(self.handle, option, optval_int_c)
|
| +- _check_rc(rc)
|
| +-
|
| +- def get(self, int option):
|
| +- """ctx.get(option)
|
| +-
|
| +- Get the value of a context option.
|
| +-
|
| +- See the 0MQ API documentation for zmq_ctx_get
|
| +- for details on specific options.
|
| +-
|
| +- New in libzmq-3.2
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- option : int
|
| +- The option to get. Available values will depend on your
|
| +- version of libzmq. Examples include::
|
| +-
|
| +- zmq.IO_THREADS, zmq.MAX_SOCKETS
|
| +-
|
| +- Returns
|
| +- -------
|
| +- optval : int
|
| +- The value of the option as an integer.
|
| +- """
|
| +- cdef int optval_int_c
|
| +- cdef size_t sz
|
| +- cdef int rc
|
| +-
|
| +- if self.closed:
|
| +- raise RuntimeError("Context has been destroyed")
|
| +-
|
| +- rc = zmq_ctx_get(self.handle, option)
|
| +- _check_rc(rc)
|
| +-
|
| +- return rc
|
| +-
|
| +- def destroy(self, linger=None):
|
| +- """ctx.destroy(linger=None)
|
| +-
|
| +- Close all sockets associated with this context, and then terminate
|
| +- the context. If linger is specified,
|
| +- the LINGER sockopt of the sockets will be set prior to closing.
|
| +-
|
| +- WARNING:
|
| +-
|
| +- destroy involves calling zmq_close(), which is *NOT* threadsafe.
|
| +- If there are active sockets in other threads, this must not be called.
|
| +- """
|
| +-
|
| +- cdef int linger_c
|
| +- cdef bint setlinger=False
|
| +-
|
| +- if linger is not None:
|
| +- linger_c = linger
|
| +- setlinger=True
|
| +- if self.handle != NULL and not self.closed and self._n_sockets:
|
| +- while self._n_sockets:
|
| +- if setlinger:
|
| +- zmq_setsockopt(self._sockets[0], ZMQ_LINGER, &linger_c, sizeof(int))
|
| +- rc = zmq_close(self._sockets[0])
|
| +- if rc < 0 and zmq_errno() != ZMQ_ENOTSOCK:
|
| +- raise ZMQError()
|
| +- self._n_sockets -= 1
|
| +- self._sockets[0] = self._sockets[self._n_sockets]
|
| +- self.term()
|
| +-
|
| +-__all__ = ['Context']
|
| +diff --git a/zmq/core/error.pyx b/zmq/core/error.pyx
|
| +deleted file mode 100644
|
| +index 85e785f..0000000
|
| +--- a/zmq/core/error.pyx
|
| ++++ /dev/null
|
| +@@ -1,56 +0,0 @@
|
| +-"""0MQ Error classes and functions."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-# allow const char*
|
| +-cdef extern from *:
|
| +- ctypedef char* const_char_ptr "const char*"
|
| +-
|
| +-from libzmq cimport zmq_strerror, zmq_errno as zmq_errno_c
|
| +-
|
| +-from zmq.utils.strtypes import bytes
|
| +-
|
| +-def strerror(int errno):
|
| +- """strerror(errno)
|
| +-
|
| +- Return the error string given the error number.
|
| +- """
|
| +- cdef const_char_ptr str_e
|
| +- # char * will be a bytes object:
|
| +- str_e = zmq_strerror(errno)
|
| +- if str is bytes:
|
| +- # Python 2: str is bytes, so we already have the right type
|
| +- return str_e
|
| +- else:
|
| +- # Python 3: decode bytes to unicode str
|
| +- return str_e.decode()
|
| +-
|
| +-def zmq_errno():
|
| +- """zmq_errno()
|
| +-
|
| +- Return the integer errno of the most recent zmq error.
|
| +- """
|
| +- return zmq_errno_c()
|
| +-
|
| +-__all__ = ['strerror', 'zmq_errno']
|
| +diff --git a/zmq/core/message.pxd b/zmq/core/message.pxd
|
| +deleted file mode 100644
|
| +index a86a8e0..0000000
|
| +--- a/zmq/core/message.pxd
|
| ++++ /dev/null
|
| +@@ -1,66 +0,0 @@
|
| +-"""0MQ Message related class declarations."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from cpython cimport PyBytes_FromStringAndSize
|
| +-
|
| +-from libzmq cimport zmq_msg_t, zmq_msg_data, zmq_msg_size
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-cdef class MessageTracker(object):
|
| +- """A class for tracking if 0MQ is done using one or more messages."""
|
| +-
|
| +- cdef set events # Message Event objects to track.
|
| +- cdef set peers # Other Message or MessageTracker objects.
|
| +-
|
| +-
|
| +-cdef class Frame:
|
| +- """A Message Frame class for non-copy send/recvs."""
|
| +-
|
| +- cdef zmq_msg_t zmq_msg
|
| +- cdef object _data # The actual message data as a Python object.
|
| +- cdef object _buffer # A Python Buffer/View of the message contents
|
| +- cdef object _bytes # A bytes/str copy of the message.
|
| +- cdef bint _failed_init # Flag to handle failed zmq_msg_init
|
| +- cdef public object tracker_event # Event for use with zmq_free_fn.
|
| +- cdef public object tracker # MessageTracker object.
|
| +- cdef public bint more # whether RCVMORE was set
|
| +-
|
| +- cdef Frame fast_copy(self) # Create shallow copy of Message object.
|
| +- cdef object _getbuffer(self) # Construct self._buffer.
|
| +-
|
| +-
|
| +-cdef inline object copy_zmq_msg_bytes(zmq_msg_t *zmq_msg):
|
| +- """ Copy the data from a zmq_msg_t """
|
| +- cdef char *data_c = NULL
|
| +- cdef Py_ssize_t data_len_c
|
| +- with nogil:
|
| +- data_c = <char *>zmq_msg_data(zmq_msg)
|
| +- data_len_c = zmq_msg_size(zmq_msg)
|
| +- return PyBytes_FromStringAndSize(data_c, data_len_c)
|
| +-
|
| +-
|
| +diff --git a/zmq/core/message.pyx b/zmq/core/message.pyx
|
| +deleted file mode 100644
|
| +index 1d358ab..0000000
|
| +--- a/zmq/core/message.pyx
|
| ++++ /dev/null
|
| +@@ -1,297 +0,0 @@
|
| +-"""0MQ Message related classes."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2013 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-# get version-independent aliases:
|
| +-cdef extern from "pyversion_compat.h":
|
| +- pass
|
| +-
|
| +-from cpython cimport Py_DECREF, Py_INCREF
|
| +-
|
| +-from buffers cimport asbuffer_r, viewfromobject_r
|
| +-
|
| +-cdef extern from "Python.h":
|
| +- ctypedef int Py_ssize_t
|
| +-
|
| +-from libzmq cimport *
|
| +-
|
| +-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
|
| +-
|
| +-import zmq
|
| +-from zmq.core.checkrc cimport _check_rc
|
| +-from zmq.utils.strtypes import bytes,unicode,basestring
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-
|
| +-cdef void free_python_msg(void *data, void *hint) with gil:
|
| +- """A function for DECREF'ing Python based messages."""
|
| +- if hint != NULL:
|
| +- tracker_event = (<tuple>hint)[1]
|
| +- Py_DECREF(<object>hint)
|
| +- if isinstance(tracker_event, Event):
|
| +- # don't assert before DECREF:
|
| +- # assert tracker_queue.empty(), "somebody else wrote to my Queue!"
|
| +- tracker_event.set()
|
| +- tracker_event = None
|
| +-
|
| +-
|
| +-cdef class Frame:
|
| +- """Frame(data=None, track=False)
|
| +-
|
| +- 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.
|
| +-
|
| +- """
|
| +-
|
| +- def __cinit__(self, object data=None, track=False, **kwargs):
|
| +- cdef int rc
|
| +- cdef char *data_c = NULL
|
| +- cdef Py_ssize_t data_len_c=0
|
| +- cdef object hint
|
| +-
|
| +- # init more as False
|
| +- self.more = False
|
| +-
|
| +- # Save the data object in case the user wants the the data as a str.
|
| +- self._data = data
|
| +- self._failed_init = True # bool switch for dealloc
|
| +- self._buffer = None # buffer view of data
|
| +- self._bytes = None # bytes copy of data
|
| +-
|
| +- # Event and MessageTracker for monitoring when zmq is done with data:
|
| +- if track:
|
| +- evt = Event()
|
| +- self.tracker_event = evt
|
| +- self.tracker = zmq.MessageTracker(evt)
|
| +- else:
|
| +- self.tracker_event = None
|
| +- self.tracker = None
|
| +-
|
| +- if isinstance(data, unicode):
|
| +- raise TypeError("Unicode objects not allowed. Only: str/bytes, buffer interfaces.")
|
| +-
|
| +- if data is None:
|
| +- with nogil:
|
| +- rc = zmq_msg_init(&self.zmq_msg)
|
| +- _check_rc(rc)
|
| +- self._failed_init = False
|
| +- return
|
| +- else:
|
| +- asbuffer_r(data, <void **>&data_c, &data_len_c)
|
| +- # We INCREF the *original* Python object (not self) and pass it
|
| +- # as the hint below. This allows other copies of this Frame
|
| +- # object to take over the ref counting of data properly.
|
| +- hint = (data, self.tracker_event)
|
| +- Py_INCREF(hint)
|
| +- with nogil:
|
| +- rc = zmq_msg_init_data(
|
| +- &self.zmq_msg, <void *>data_c, data_len_c,
|
| +- <zmq_free_fn *>free_python_msg, <void *>hint
|
| +- )
|
| +- if rc != 0:
|
| +- Py_DECREF(hint)
|
| +- _check_rc(rc)
|
| +- self._failed_init = False
|
| +-
|
| +- def __init__(self, object data=None, track=False):
|
| +- """Enforce signature"""
|
| +- pass
|
| +-
|
| +- def __dealloc__(self):
|
| +- cdef int rc
|
| +- if self._failed_init:
|
| +- return
|
| +- # This simply decreases the 0MQ ref-count of zmq_msg.
|
| +- with nogil:
|
| +- rc = zmq_msg_close(&self.zmq_msg)
|
| +- _check_rc(rc)
|
| +-
|
| +- # buffer interface code adapted from petsc4py by Lisandro Dalcin, a BSD project
|
| +-
|
| +- def __getbuffer__(self, Py_buffer* buffer, int flags):
|
| +- # new-style (memoryview) buffer interface
|
| +- with nogil:
|
| +- buffer.buf = zmq_msg_data(&self.zmq_msg)
|
| +- buffer.len = zmq_msg_size(&self.zmq_msg)
|
| +-
|
| +- buffer.obj = self
|
| +- buffer.readonly = 1
|
| +- buffer.format = "B"
|
| +- buffer.ndim = 0
|
| +- buffer.shape = NULL
|
| +- buffer.strides = NULL
|
| +- buffer.suboffsets = NULL
|
| +- buffer.itemsize = 1
|
| +- buffer.internal = NULL
|
| +-
|
| +- def __getsegcount__(self, Py_ssize_t *lenp):
|
| +- # required for getreadbuffer
|
| +- if lenp != NULL:
|
| +- with nogil:
|
| +- lenp[0] = zmq_msg_size(&self.zmq_msg)
|
| +- return 1
|
| +-
|
| +- def __getreadbuffer__(self, Py_ssize_t idx, void **p):
|
| +- # old-style (buffer) interface
|
| +- cdef char *data_c = NULL
|
| +- cdef Py_ssize_t data_len_c
|
| +- if idx != 0:
|
| +- raise SystemError("accessing non-existent buffer segment")
|
| +- # read-only, because we don't want to allow
|
| +- # editing of the message in-place
|
| +- with nogil:
|
| +- data_c = <char *>zmq_msg_data(&self.zmq_msg)
|
| +- data_len_c = zmq_msg_size(&self.zmq_msg)
|
| +- if p != NULL:
|
| +- p[0] = <void*>data_c
|
| +- return data_len_c
|
| +-
|
| +- # end buffer interface
|
| +-
|
| +- def __copy__(self):
|
| +- """Create a shallow copy of the message.
|
| +-
|
| +- This does not copy the contents of the Frame, just the pointer.
|
| +- This will increment the 0MQ ref count of the message, but not
|
| +- the ref count of the Python object. That is only done once when
|
| +- the Python is first turned into a 0MQ message.
|
| +- """
|
| +- return self.fast_copy()
|
| +-
|
| +- cdef Frame fast_copy(self):
|
| +- """Fast, cdef'd version of shallow copy of the Frame."""
|
| +- cdef Frame new_msg
|
| +- new_msg = Frame()
|
| +- # This does not copy the contents, but just increases the ref-count
|
| +- # of the zmq_msg by one.
|
| +- with nogil:
|
| +- zmq_msg_copy(&new_msg.zmq_msg, &self.zmq_msg)
|
| +- # Copy the ref to data so the copy won't create a copy when str is
|
| +- # called.
|
| +- if self._data is not None:
|
| +- new_msg._data = self._data
|
| +- if self._buffer is not None:
|
| +- new_msg._buffer = self._buffer
|
| +- if self._bytes is not None:
|
| +- new_msg._bytes = self._bytes
|
| +-
|
| +- # Frame copies share the tracker and tracker_event
|
| +- new_msg.tracker_event = self.tracker_event
|
| +- new_msg.tracker = self.tracker
|
| +-
|
| +- return new_msg
|
| +-
|
| +- def __len__(self):
|
| +- """Return the length of the message in bytes."""
|
| +- cdef size_t sz
|
| +- with nogil:
|
| +- sz = zmq_msg_size(&self.zmq_msg)
|
| +- return sz
|
| +- # return <int>zmq_msg_size(&self.zmq_msg)
|
| +-
|
| +- def __str__(self):
|
| +- """Return the str form of the message."""
|
| +- if isinstance(self._data, bytes):
|
| +- b = self._data
|
| +- else:
|
| +- b = self.bytes
|
| +- if str is unicode:
|
| +- return b.decode()
|
| +- else:
|
| +- return b
|
| +-
|
| +- cdef inline object _getbuffer(self):
|
| +- """Create a Python buffer/view of the message data.
|
| +-
|
| +- This will be called only once, the first time the `buffer` property
|
| +- is accessed. Subsequent calls use a cached copy.
|
| +- """
|
| +- if self._data is None:
|
| +- return viewfromobject_r(self)
|
| +- else:
|
| +- return viewfromobject_r(self._data)
|
| +-
|
| +- @property
|
| +- def buffer(self):
|
| +- """Get a read-only buffer view of the message contents."""
|
| +- if self._buffer is None:
|
| +- self._buffer = self._getbuffer()
|
| +- return self._buffer
|
| +-
|
| +- @property
|
| +- def bytes(self):
|
| +- """Get the message content as a Python str/bytes object.
|
| +-
|
| +- The first time this property is accessed, a copy of the message
|
| +- contents is made. From then on that same copy of the message is
|
| +- returned.
|
| +- """
|
| +- if self._bytes is None:
|
| +- self._bytes = copy_zmq_msg_bytes(&self.zmq_msg)
|
| +- return self._bytes
|
| +-
|
| +- def set(self, int option, int value):
|
| +- """Set a message property"""
|
| +- cdef int rc = zmq_msg_set(&self.zmq_msg, option, value)
|
| +- _check_rc(rc)
|
| +-
|
| +- def get(self, int option):
|
| +- """Get a message property"""
|
| +- cdef int rc = zmq_msg_get(&self.zmq_msg, option)
|
| +- _check_rc(rc)
|
| +- return rc
|
| +-
|
| +-# legacy Message name
|
| +-Message = Frame
|
| +-
|
| +-__all__ = ['Frame', 'Message']
|
| +diff --git a/zmq/core/socket.pxd b/zmq/core/socket.pxd
|
| +deleted file mode 100644
|
| +index 92253eb..0000000
|
| +--- a/zmq/core/socket.pxd
|
| ++++ /dev/null
|
| +@@ -1,48 +0,0 @@
|
| +-"""0MQ Socket class declaration."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from context cimport Context
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-
|
| +-cdef class Socket:
|
| +- """A 0MQ socket."""
|
| +-
|
| +- cdef object __weakref__ # enable weakref
|
| +- cdef void *handle # The C handle for the underlying zmq object.
|
| +- cdef public int socket_type # The 0MQ socket type - REQ,REP, etc.
|
| +- # Hold on to a reference to the context to make sure it is not garbage
|
| +- # collected until the socket it done with it.
|
| +- cdef public Context context # The zmq Context object that owns this.
|
| +- cdef public bint _closed # bool property for a closed socket.
|
| +- cdef int _pid # the pid of the process which created me (for fork safety)
|
| +-
|
| +- # cpdef methods for direct-cython access:
|
| +- cpdef object send(self, object data, int flags=*, copy=*, track=*)
|
| +- cpdef object recv(self, int flags=*, copy=*, track=*)
|
| +-
|
| +diff --git a/zmq/core/socket.pyx b/zmq/core/socket.pyx
|
| +deleted file mode 100644
|
| +index 16fbf7f..0000000
|
| +--- a/zmq/core/socket.pyx
|
| ++++ /dev/null
|
| +@@ -1,628 +0,0 @@
|
| +-"""0MQ Socket class."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Cython Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-# get version-independent aliases:
|
| +-cdef extern from "pyversion_compat.h":
|
| +- pass
|
| +-
|
| +-from libc.errno cimport ENAMETOOLONG
|
| +-from libc.string cimport memcpy
|
| +-
|
| +-from cpython cimport PyBytes_FromStringAndSize
|
| +-from cpython cimport PyBytes_AsString, PyBytes_Size
|
| +-from cpython cimport Py_DECREF, Py_INCREF
|
| +-
|
| +-from buffers cimport asbuffer_r, viewfromobject_r
|
| +-
|
| +-from libzmq cimport *
|
| +-from message cimport Frame, copy_zmq_msg_bytes
|
| +-
|
| +-from context cimport Context
|
| +-
|
| +-cdef extern from "Python.h":
|
| +- ctypedef int Py_ssize_t
|
| +-
|
| +-cdef extern from "ipcmaxlen.h":
|
| +- int get_ipc_path_max_len()
|
| +-
|
| +-cdef extern from "getpid_compat.h":
|
| +- int getpid()
|
| +-
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Python Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-import copy as copy_mod
|
| +-import time
|
| +-import sys
|
| +-import random
|
| +-import struct
|
| +-import codecs
|
| +-
|
| +-from zmq.utils import jsonapi
|
| +-
|
| +-try:
|
| +- import cPickle
|
| +- pickle = cPickle
|
| +-except:
|
| +- cPickle = None
|
| +- import pickle
|
| +-
|
| +-import zmq
|
| +-from zmq.core import constants
|
| +-from zmq.core.constants import *
|
| +-from zmq.core.checkrc cimport _check_rc
|
| +-from zmq.error import ZMQError, ZMQBindError
|
| +-from zmq.utils.strtypes import bytes,unicode,basestring
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-IPC_PATH_MAX_LEN = get_ipc_path_max_len()
|
| +-
|
| +-# inline some small socket submethods:
|
| +-# true methods frequently cannot be inlined, acc. Cython docs
|
| +-
|
| +-cdef inline _check_closed(Socket s, bint raise_notsup):
|
| +- cdef int rc
|
| +- cdef int errno
|
| +- cdef int stype
|
| +- cdef size_t sz=sizeof(int)
|
| +- if s._closed:
|
| +- if raise_notsup:
|
| +- raise ZMQError(ENOTSUP)
|
| +- else:
|
| +- return True
|
| +- else:
|
| +- rc = zmq_getsockopt(s.handle, ZMQ_TYPE, <void *>&stype, &sz)
|
| +- if rc < 0 and zmq_errno() == ENOTSOCK:
|
| +- s._closed = True
|
| +- if raise_notsup:
|
| +- raise ZMQError(ENOTSUP)
|
| +- else:
|
| +- return True
|
| +- else:
|
| +- _check_rc(rc)
|
| +- return False
|
| +-
|
| +-cdef inline Frame _recv_frame(void *handle, int flags=0, track=False):
|
| +- """Receive a message in a non-copying manner and return a Frame."""
|
| +- cdef int rc
|
| +- cdef Frame msg
|
| +- msg = Frame(track=track)
|
| +-
|
| +- with nogil:
|
| +- rc = zmq_msg_recv(&msg.zmq_msg, handle, flags)
|
| +-
|
| +- _check_rc(rc)
|
| +- return msg
|
| +-
|
| +-cdef inline object _recv_copy(void *handle, int flags=0):
|
| +- """Receive a message and return a copy"""
|
| +- cdef zmq_msg_t zmq_msg
|
| +- with nogil:
|
| +- zmq_msg_init (&zmq_msg)
|
| +- rc = zmq_msg_recv(&zmq_msg, handle, flags)
|
| +- _check_rc(rc)
|
| +- msg_bytes = copy_zmq_msg_bytes(&zmq_msg)
|
| +- with nogil:
|
| +- zmq_msg_close(&zmq_msg)
|
| +- return msg_bytes
|
| +-
|
| +-cdef inline object _send_frame(void *handle, Frame msg, int flags=0):
|
| +- """Send a Frame on this socket in a non-copy manner."""
|
| +- cdef int rc
|
| +- cdef Frame msg_copy
|
| +-
|
| +- # Always copy so the original message isn't garbage collected.
|
| +- # This doesn't do a real copy, just a reference.
|
| +- msg_copy = msg.fast_copy()
|
| +-
|
| +- with nogil:
|
| +- rc = zmq_msg_send(&msg_copy.zmq_msg, handle, flags)
|
| +-
|
| +- _check_rc(rc)
|
| +- return msg.tracker
|
| +-
|
| +-
|
| +-cdef inline object _send_copy(void *handle, object msg, int flags=0):
|
| +- """Send a message on this socket by copying its content."""
|
| +- cdef int rc, rc2
|
| +- cdef zmq_msg_t data
|
| +- cdef char *msg_c
|
| +- cdef Py_ssize_t msg_c_len=0
|
| +-
|
| +- # copy to c array:
|
| +- asbuffer_r(msg, <void **>&msg_c, &msg_c_len)
|
| +-
|
| +- # Copy the msg before sending. This avoids any complications with
|
| +- # the GIL, etc.
|
| +- # If zmq_msg_init_* fails we must not call zmq_msg_close (Bus Error)
|
| +- with nogil:
|
| +- rc = zmq_msg_init_size(&data, msg_c_len)
|
| +-
|
| +- _check_rc(rc)
|
| +-
|
| +- with nogil:
|
| +- memcpy(zmq_msg_data(&data), msg_c, zmq_msg_size(&data))
|
| +- rc = zmq_msg_send(&data, handle, flags)
|
| +- rc2 = zmq_msg_close(&data)
|
| +- _check_rc(rc)
|
| +- _check_rc(rc2)
|
| +-
|
| +-
|
| +-cdef class Socket:
|
| +- """Socket(context, socket_type)
|
| +-
|
| +- A 0MQ socket.
|
| +-
|
| +- These objects will generally be constructed via the socket() method of a Context object.
|
| +-
|
| +- Note: 0MQ Sockets are *not* threadsafe. **DO NOT** share them across threads.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- context : Context
|
| +- The 0MQ Context this Socket belongs to.
|
| +- socket_type : int
|
| +- The socket type, which can be any of the 0MQ socket types:
|
| +- REQ, REP, PUB, SUB, PAIR, DEALER, ROUTER, PULL, PUSH, XPUB, XSUB.
|
| +-
|
| +- See Also
|
| +- --------
|
| +- .Context.socket : method for creating a socket bound to a Context.
|
| +- """
|
| +-
|
| +- def __cinit__(self, Context context, int socket_type, *args, **kwrags):
|
| +- cdef Py_ssize_t c_handle
|
| +- c_handle = context._handle
|
| +-
|
| +- self.handle = NULL
|
| +- self.context = context
|
| +- self.socket_type = socket_type
|
| +- with nogil:
|
| +- self.handle = zmq_socket(<void *>c_handle, socket_type)
|
| +- if self.handle == NULL:
|
| +- raise ZMQError()
|
| +- self._closed = False
|
| +- self._pid = getpid()
|
| +- context._add_socket(self.handle)
|
| +-
|
| +- def __dealloc__(self):
|
| +- """close *and* remove from context's list
|
| +-
|
| +- But be careful that context might not exist if called during gc
|
| +- """
|
| +- if self.handle != NULL and getpid() == self._pid:
|
| +- rc = zmq_close(self.handle)
|
| +- if rc != 0 and zmq_errno() != ENOTSOCK:
|
| +- # ignore ENOTSOCK (closed by Context)
|
| +- _check_rc(rc)
|
| +- # during gc, self.context might be NULL
|
| +- if self.context:
|
| +- self.context._remove_socket(self.handle)
|
| +-
|
| +- def __init__(self, context, socket_type):
|
| +- pass
|
| +-
|
| +- @property
|
| +- def closed(self):
|
| +- return _check_closed(self, False)
|
| +-
|
| +- def close(self, linger=None):
|
| +- """s.close(linger=None)
|
| +-
|
| +- Close the socket.
|
| +-
|
| +- If linger is specified, LINGER sockopt will be set prior to closing.
|
| +-
|
| +- 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.
|
| +- """
|
| +- cdef int rc=0
|
| +- cdef int linger_c
|
| +- cdef bint setlinger=False
|
| +-
|
| +- if linger is not None:
|
| +- linger_c = linger
|
| +- setlinger=True
|
| +-
|
| +- if self.handle != NULL and not self._closed and getpid() == self._pid:
|
| +- if setlinger:
|
| +- zmq_setsockopt(self.handle, ZMQ_LINGER, &linger_c, sizeof(int))
|
| +- rc = zmq_close(self.handle)
|
| +- if rc != 0 and zmq_errno() != ENOTSOCK:
|
| +- # ignore ENOTSOCK (closed by Context)
|
| +- _check_rc(rc)
|
| +- self._closed = True
|
| +- # during gc, self.context might be NULL
|
| +- if self.context:
|
| +- self.context._remove_socket(self.handle)
|
| +- self.handle = NULL
|
| +-
|
| +- def set(self, int option, optval):
|
| +- """s.set(option, optval)
|
| +-
|
| +- Set socket options.
|
| +-
|
| +- See the 0MQ API documentation for details on specific options.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- option : int
|
| +- The option to set. Available values will depend on your
|
| +- version of libzmq. Examples include::
|
| +-
|
| +- zmq.SUBSCRIBE, UNSUBSCRIBE, IDENTITY, HWM, LINGER, FD
|
| +-
|
| +- optval : int or bytes
|
| +- The value of the option to set.
|
| +- """
|
| +- cdef int64_t optval_int64_c
|
| +- cdef int optval_int_c
|
| +- cdef int rc
|
| +- cdef char* optval_c
|
| +- cdef Py_ssize_t sz
|
| +-
|
| +- _check_closed(self, True)
|
| +- if isinstance(optval, unicode):
|
| +- raise TypeError("unicode not allowed, use setsockopt_string")
|
| +-
|
| +- if option in zmq.constants.bytes_sockopts:
|
| +- if not isinstance(optval, bytes):
|
| +- raise TypeError('expected bytes, got: %r' % optval)
|
| +- optval_c = PyBytes_AsString(optval)
|
| +- sz = PyBytes_Size(optval)
|
| +- with nogil:
|
| +- rc = zmq_setsockopt(
|
| +- self.handle, option,
|
| +- optval_c, sz
|
| +- )
|
| +- elif option in zmq.constants.int64_sockopts:
|
| +- if not isinstance(optval, int):
|
| +- raise TypeError('expected int, got: %r' % optval)
|
| +- optval_int64_c = optval
|
| +- with nogil:
|
| +- rc = zmq_setsockopt(
|
| +- self.handle, option,
|
| +- &optval_int64_c, sizeof(int64_t)
|
| +- )
|
| +- else:
|
| +- # default is to assume int, which is what most new sockopts will be
|
| +- # this lets pyzmq work with newer libzmq which may add constants
|
| +- # pyzmq has not yet added, rather than artificially raising. Invalid
|
| +- # sockopts will still raise just the same, but it will be libzmq doing
|
| +- # the raising.
|
| +- if not isinstance(optval, int):
|
| +- raise TypeError('expected int, got: %r' % optval)
|
| +- optval_int_c = optval
|
| +- with nogil:
|
| +- rc = zmq_setsockopt(
|
| +- self.handle, option,
|
| +- &optval_int_c, sizeof(int)
|
| +- )
|
| +-
|
| +- _check_rc(rc)
|
| +-
|
| +- def get(self, int option):
|
| +- """s.get(option)
|
| +-
|
| +- Get the value of a socket option.
|
| +-
|
| +- See the 0MQ API documentation for details on specific options.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- option : int
|
| +- The option to get. Available values will depend on your
|
| +- version of libzmq. Examples include::
|
| +-
|
| +- zmq.IDENTITY, HWM, LINGER, FD, EVENTS
|
| +-
|
| +- Returns
|
| +- -------
|
| +- optval : int or bytes
|
| +- The value of the option as a bytestring or int.
|
| +- """
|
| +- cdef int64_t optval_int64_c
|
| +- cdef int optval_int_c
|
| +- cdef fd_t optval_fd_c
|
| +- cdef char identity_str_c [255]
|
| +- cdef size_t sz
|
| +- cdef int rc
|
| +-
|
| +- _check_closed(self, True)
|
| +-
|
| +- if option in zmq.constants.bytes_sockopts:
|
| +- sz = 255
|
| +- with nogil:
|
| +- rc = zmq_getsockopt(self.handle, option, <void *>identity_str_c, &sz)
|
| +- _check_rc(rc)
|
| +- result = PyBytes_FromStringAndSize(<char *>identity_str_c, sz)
|
| +- elif option in zmq.constants.int64_sockopts:
|
| +- sz = sizeof(int64_t)
|
| +- with nogil:
|
| +- rc = zmq_getsockopt(self.handle, option, <void *>&optval_int64_c, &sz)
|
| +- _check_rc(rc)
|
| +- result = optval_int64_c
|
| +- elif option == ZMQ_FD:
|
| +- sz = sizeof(fd_t)
|
| +- with nogil:
|
| +- rc = zmq_getsockopt(self.handle, option, <void *>&optval_fd_c, &sz)
|
| +- _check_rc(rc)
|
| +- result = optval_fd_c
|
| +- else:
|
| +- # default is to assume int, which is what most new sockopts will be
|
| +- # this lets pyzmq work with newer libzmq which may add constants
|
| +- # pyzmq has not yet added, rather than artificially raising. Invalid
|
| +- # sockopts will still raise just the same, but it will be libzmq doing
|
| +- # the raising.
|
| +- sz = sizeof(int)
|
| +- with nogil:
|
| +- rc = zmq_getsockopt(self.handle, option, <void *>&optval_int_c, &sz)
|
| +- _check_rc(rc)
|
| +- result = optval_int_c
|
| +-
|
| +- return result
|
| +-
|
| +- def bind(self, addr):
|
| +- """s.bind(addr)
|
| +-
|
| +- Bind the socket to an address.
|
| +-
|
| +- This causes the socket to listen on a network port. Sockets on the
|
| +- other side of this connection will use ``Socket.connect(addr)`` to
|
| +- connect to this socket.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- addr : str
|
| +- The address string. This has the form 'protocol://interface:port',
|
| +- for example 'tcp://127.0.0.1:5555'. Protocols supported include
|
| +- tcp, udp, pgm, epgm, inproc and ipc. If the address is unicode, it is
|
| +- encoded to utf-8 first.
|
| +- """
|
| +- cdef int rc
|
| +- cdef char* c_addr
|
| +-
|
| +- _check_closed(self, True)
|
| +- if isinstance(addr, unicode):
|
| +- addr = addr.encode('utf-8')
|
| +- if not isinstance(addr, bytes):
|
| +- raise TypeError('expected str, got: %r' % addr)
|
| +- c_addr = addr
|
| +- rc = zmq_bind(self.handle, c_addr)
|
| +- if rc != 0:
|
| +- if IPC_PATH_MAX_LEN and zmq_errno() == ENAMETOOLONG:
|
| +- # py3compat: addr is bytes, but msg wants str
|
| +- if str is unicode:
|
| +- addr = addr.decode('utf-8', 'replace')
|
| +- path = addr.split('://', 1)[-1]
|
| +- msg = ('ipc path "{0}" is longer than {1} '
|
| +- 'characters (sizeof(sockaddr_un.sun_path)). '
|
| +- 'zmq.IPC_PATH_MAX_LEN constant can be used '
|
| +- 'to check addr length (if it is defined).'
|
| +- .format(path, IPC_PATH_MAX_LEN))
|
| +- raise ZMQError(msg=msg)
|
| +- _check_rc(rc)
|
| +-
|
| +- def connect(self, addr):
|
| +- """s.connect(addr)
|
| +-
|
| +- Connect to a remote 0MQ socket.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- addr : str
|
| +- The address string. This has the form 'protocol://interface:port',
|
| +- for example 'tcp://127.0.0.1:5555'. Protocols supported are
|
| +- tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
|
| +- encoded to utf-8 first.
|
| +- """
|
| +- cdef int rc
|
| +- cdef char* c_addr
|
| +-
|
| +- _check_closed(self, True)
|
| +- if isinstance(addr, unicode):
|
| +- addr = addr.encode('utf-8')
|
| +- if not isinstance(addr, bytes):
|
| +- raise TypeError('expected str, got: %r' % addr)
|
| +- c_addr = addr
|
| +-
|
| +- rc = zmq_connect(self.handle, c_addr)
|
| +- if rc != 0:
|
| +- raise ZMQError()
|
| +-
|
| +- def unbind(self, addr):
|
| +- """s.unbind(addr)
|
| +-
|
| +- Unbind from an address (undoes a call to bind).
|
| +-
|
| +- This feature requires libzmq-3
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- addr : str
|
| +- The address string. This has the form 'protocol://interface:port',
|
| +- for example 'tcp://127.0.0.1:5555'. Protocols supported are
|
| +- tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
|
| +- encoded to utf-8 first.
|
| +- """
|
| +- cdef int rc
|
| +- cdef char* c_addr
|
| +-
|
| +- if ZMQ_VERSION_MAJOR < 3:
|
| +- raise NotImplementedError("unbind requires libzmq >= 3.0, have %s" % zmq.zmq_version())
|
| +-
|
| +-
|
| +- _check_closed(self, True)
|
| +- if isinstance(addr, unicode):
|
| +- addr = addr.encode('utf-8')
|
| +- if not isinstance(addr, bytes):
|
| +- raise TypeError('expected str, got: %r' % addr)
|
| +- c_addr = addr
|
| +-
|
| +- rc = zmq_unbind(self.handle, c_addr)
|
| +- if rc != 0:
|
| +- raise ZMQError()
|
| +-
|
| +- def disconnect(self, addr):
|
| +- """s.disconnect(addr)
|
| +-
|
| +- Disconnect from a remote 0MQ socket (undoes a call to connect).
|
| +-
|
| +- This feature requires libzmq-3
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- addr : str
|
| +- The address string. This has the form 'protocol://interface:port',
|
| +- for example 'tcp://127.0.0.1:5555'. Protocols supported are
|
| +- tcp, upd, pgm, inproc and ipc. If the address is unicode, it is
|
| +- encoded to utf-8 first.
|
| +- """
|
| +- cdef int rc
|
| +- cdef char* c_addr
|
| +-
|
| +- if ZMQ_VERSION_MAJOR < 3:
|
| +- raise NotImplementedError("disconnect requires libzmq >= 3.0, have %s" % zmq.zmq_version())
|
| +-
|
| +- _check_closed(self, True)
|
| +- if isinstance(addr, unicode):
|
| +- addr = addr.encode('utf-8')
|
| +- if not isinstance(addr, bytes):
|
| +- raise TypeError('expected str, got: %r' % addr)
|
| +- c_addr = addr
|
| +-
|
| +- rc = zmq_disconnect(self.handle, c_addr)
|
| +- if rc != 0:
|
| +- raise ZMQError()
|
| +-
|
| +- #-------------------------------------------------------------------------
|
| +- # Sending and receiving messages
|
| +- #-------------------------------------------------------------------------
|
| +-
|
| +- cpdef object send(self, object data, int flags=0, copy=True, track=False):
|
| +- """s.send(data, flags=0, copy=True, track=False)
|
| +-
|
| +- Send a message on this socket.
|
| +-
|
| +- This queues the message to be sent by the IO thread at a later time.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- data : object, str, Frame
|
| +- The content of the message.
|
| +- flags : int
|
| +- Any supported flag: 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)
|
| +-
|
| +- 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.
|
| +-
|
| +- """
|
| +- _check_closed(self, True)
|
| +-
|
| +- if isinstance(data, unicode):
|
| +- raise TypeError("unicode not allowed, use send_unicode")
|
| +-
|
| +- if copy:
|
| +- # msg.bytes never returns the input data object
|
| +- # it is always a copy, but always the same copy
|
| +- if isinstance(data, Frame):
|
| +- data = data.buffer
|
| +- return _send_copy(self.handle, data, flags)
|
| +- else:
|
| +- if isinstance(data, Frame):
|
| +- if track and not data.tracker:
|
| +- raise ValueError('Not a tracked message')
|
| +- msg = data
|
| +- else:
|
| +- msg = Frame(data, track=track)
|
| +- return _send_frame(self.handle, msg, flags)
|
| +-
|
| +- cpdef object recv(self, int flags=0, copy=True, track=False):
|
| +- """s.recv(flags=0, copy=True, track=False)
|
| +-
|
| +- Receive a message.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- flags : int
|
| +- Any supported flag: NOBLOCK. If NOBLOCK is set, this method
|
| +- will raise a ZMQError with EAGAIN if a message is not ready.
|
| +- If NOBLOCK is not set, then this method will block until a
|
| +- message arrives.
|
| +- copy : bool
|
| +- Should the message be received in a copying or non-copying manner?
|
| +- If False a Frame object is returned, if True a string copy of
|
| +- message is returned.
|
| +- track : bool
|
| +- Should the message be tracked for notification that ZMQ has
|
| +- finished with it? (ignored if copy=True)
|
| +-
|
| +- Returns
|
| +- -------
|
| +- msg : bytes, Frame
|
| +- The received message frame. If `copy` is False, then it will be a Frame,
|
| +- otherwise it will be bytes.
|
| +-
|
| +- Raises
|
| +- ------
|
| +- ZMQError
|
| +- for any of the reasons zmq_msg_recv might fail.
|
| +- """
|
| +- _check_closed(self, True)
|
| +-
|
| +- if copy:
|
| +- return _recv_copy(self.handle, flags)
|
| +- else:
|
| +- frame = _recv_frame(self.handle, flags, track)
|
| +- frame.more = self.getsockopt(zmq.RCVMORE)
|
| +- return frame
|
| +-
|
| +-
|
| +-__all__ = ['Socket', 'IPC_PATH_MAX_LEN']
|
| +diff --git a/zmq/core/stopwatch.pxd b/zmq/core/stopwatch.pxd
|
| +deleted file mode 100644
|
| +index 5d56166..0000000
|
| +--- a/zmq/core/stopwatch.pxd
|
| ++++ /dev/null
|
| +@@ -1,31 +0,0 @@
|
| +-"""0MQ Stopwatch class declaration."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-
|
| +-cdef class Stopwatch:
|
| +- """A simple stopwatch based on zmq_stopwatch_start/stop."""
|
| +-
|
| +- cdef void *watch # The C handle for the underlying zmq object
|
| +-
|
| +diff --git a/zmq/core/stopwatch.pyx b/zmq/core/stopwatch.pyx
|
| +deleted file mode 100644
|
| +index 6d2fd61..0000000
|
| +--- a/zmq/core/stopwatch.pyx
|
| ++++ /dev/null
|
| +@@ -1,90 +0,0 @@
|
| +-"""0MQ Stopwatch class."""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq.
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libzmq cimport zmq_stopwatch_start, zmq_stopwatch_stop, zmq_sleep
|
| +-
|
| +-from zmq.error import ZMQError
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Code
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-cdef class Stopwatch:
|
| +- """Stopwatch()
|
| +-
|
| +- A simple stopwatch based on zmq_stopwatch_start/stop.
|
| +-
|
| +- This class should be used for benchmarking and timing 0MQ code.
|
| +- """
|
| +-
|
| +- def __cinit__(self):
|
| +- self.watch = NULL
|
| +-
|
| +- def __dealloc__(self):
|
| +- try:
|
| +- self.stop()
|
| +- except ZMQError:
|
| +- pass
|
| +-
|
| +- def start(self):
|
| +- """s.start()
|
| +-
|
| +- Start the stopwatch.
|
| +- """
|
| +- if self.watch == NULL:
|
| +- with nogil:
|
| +- self.watch = zmq_stopwatch_start()
|
| +- else:
|
| +- raise ZMQError('Stopwatch is already runing.')
|
| +-
|
| +- def stop(self):
|
| +- """s.stop()
|
| +-
|
| +- Stop the stopwatch.
|
| +-
|
| +- Returns
|
| +- -------
|
| +- t : unsigned long int
|
| +- the number of microseconds since ``start()`` was called.
|
| +- """
|
| +- cdef unsigned long time
|
| +- if self.watch == NULL:
|
| +- raise ZMQError('Must start the Stopwatch before calling stop.')
|
| +- else:
|
| +- with nogil:
|
| +- time = zmq_stopwatch_stop(self.watch)
|
| +- self.watch = NULL
|
| +- return time
|
| +-
|
| +- def sleep(self, int seconds):
|
| +- """s.sleep(seconds)
|
| +-
|
| +- Sleep for an integer number of seconds.
|
| +- """
|
| +- with nogil:
|
| +- zmq_sleep(seconds)
|
| +-
|
| +-
|
| +-__all__ = ['Stopwatch']
|
| +diff --git a/zmq/devices/__init__.py b/zmq/devices/__init__.py
|
| +index b5c8eb3..dcae13d 100644
|
| +--- a/zmq/devices/__init__.py
|
| ++++ b/zmq/devices/__init__.py
|
| +@@ -14,11 +14,12 @@
|
| + #-----------------------------------------------------------------------------
|
| +
|
| + from zmq import device
|
| +-from zmq.devices import basedevice, proxydevice, monitoredqueue, monitoredqueuedevice
|
| ++from zmq.devices import basedevice, proxydevice, monitoredqueuedevice
|
| ++from zmq.devices import _zmonitoredqueue as monitoredqueue
|
| +
|
| + from zmq.devices.basedevice import *
|
| + from zmq.devices.proxydevice import *
|
| +-from zmq.devices.monitoredqueue import *
|
| ++from zmq.devices._zmonitoredqueue import *
|
| + from zmq.devices.monitoredqueuedevice import *
|
| +
|
| + __all__ = ['device']
|
| +diff --git a/zmq/devices/_zmonitoredqueue.pxd b/zmq/devices/_zmonitoredqueue.pxd
|
| +new file mode 100644
|
| +index 0000000..e04354a
|
| +--- /dev/null
|
| ++++ b/zmq/devices/_zmonitoredqueue.pxd
|
| +@@ -0,0 +1,166 @@
|
| ++"""MonitoredQueue class declarations.
|
| ++
|
| ++Authors
|
| ++-------
|
| ++* MinRK
|
| ++* Brian Granger
|
| ++"""
|
| ++
|
| ++#
|
| ++# Copyright (c) 2010 Min Ragan-Kelley, Brian Granger
|
| ++#
|
| ++# This file is part of pyzmq, but is derived and adapted from zmq_queue.cpp
|
| ++# originally from libzmq-2.1.6, used under LGPLv3
|
| ++#
|
| ++# pyzmq is free software; you can redistribute it and/or modify it under
|
| ++# the terms of the Lesser GNU General Public License as published by
|
| ++# the Free Software Foundation; either version 3 of the License, or
|
| ++# (at your option) any later version.
|
| ++#
|
| ++# pyzmq is distributed in the hope that it will be useful,
|
| ++# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| ++# Lesser GNU General Public License for more details.
|
| ++#
|
| ++# You should have received a copy of the Lesser GNU General Public License
|
| ++# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| ++#
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libzmq cimport *
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# MonitoredQueue C functions
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++cdef inline int _relay(void *insocket_, void *outsocket_, void *sidesocket_,
|
| ++ zmq_msg_t msg, zmq_msg_t side_msg, zmq_msg_t id_msg,
|
| ++ bint swap_ids) nogil:
|
| ++ cdef int rc
|
| ++ cdef int64_t flag_2
|
| ++ cdef int flag_3
|
| ++ cdef int flags
|
| ++ cdef bint more
|
| ++ cdef size_t flagsz
|
| ++ cdef void * flag_ptr
|
| ++
|
| ++ if ZMQ_VERSION_MAJOR < 3:
|
| ++ flagsz = sizeof (int64_t)
|
| ++ flag_ptr = &flag_2
|
| ++ else:
|
| ++ flagsz = sizeof (int)
|
| ++ flag_ptr = &flag_3
|
| ++
|
| ++ if swap_ids:# both router, must send second identity first
|
| ++ # recv two ids into msg, id_msg
|
| ++ rc = zmq_msg_recv(&msg, insocket_, 0)
|
| ++ rc = zmq_msg_recv(&id_msg, insocket_, 0)
|
| ++
|
| ++ # send second id (id_msg) first
|
| ++ #!!!! always send a copy before the original !!!!
|
| ++ rc = zmq_msg_copy(&side_msg, &id_msg)
|
| ++ rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
|
| ++ rc = zmq_msg_send(&id_msg, sidesocket_, ZMQ_SNDMORE)
|
| ++ # send first id (msg) second
|
| ++ rc = zmq_msg_copy(&side_msg, &msg)
|
| ++ rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
|
| ++ rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
|
| ++ if rc < 0:
|
| ++ return rc
|
| ++ while (True):
|
| ++ rc = zmq_msg_recv(&msg, insocket_, 0)
|
| ++ # assert (rc == 0)
|
| ++ rc = zmq_getsockopt (insocket_, ZMQ_RCVMORE, flag_ptr, &flagsz)
|
| ++ flags = 0
|
| ++ if ZMQ_VERSION_MAJOR < 3:
|
| ++ if flag_2:
|
| ++ flags |= ZMQ_SNDMORE
|
| ++ else:
|
| ++ if flag_3:
|
| ++ flags |= ZMQ_SNDMORE
|
| ++ # LABEL has been removed:
|
| ++ # rc = zmq_getsockopt (insocket_, ZMQ_RCVLABEL, flag_ptr, &flagsz)
|
| ++ # if flag_3:
|
| ++ # flags |= ZMQ_SNDLABEL
|
| ++ # assert (rc == 0)
|
| ++
|
| ++ rc = zmq_msg_copy(&side_msg, &msg)
|
| ++ if flags:
|
| ++ rc = zmq_msg_send(&side_msg, outsocket_, flags)
|
| ++ # only SNDMORE for side-socket
|
| ++ rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
|
| ++ else:
|
| ++ rc = zmq_msg_send(&side_msg, outsocket_, 0)
|
| ++ rc = zmq_msg_send(&msg, sidesocket_, 0)
|
| ++ break
|
| ++ return rc
|
| ++
|
| ++# the MonitoredQueue C function, adapted from zmq::queue.cpp :
|
| ++cdef inline int c_monitored_queue (void *insocket_, void *outsocket_,
|
| ++ void *sidesocket_, zmq_msg_t *in_msg_ptr,
|
| ++ zmq_msg_t *out_msg_ptr, int swap_ids) nogil:
|
| ++ """The actual C function for a monitored queue device.
|
| ++
|
| ++ See ``monitored_queue()`` for details.
|
| ++ """
|
| ++
|
| ++ cdef zmq_msg_t msg
|
| ++ cdef int rc = zmq_msg_init (&msg)
|
| ++ cdef zmq_msg_t id_msg
|
| ++ rc = zmq_msg_init (&id_msg)
|
| ++ cdef zmq_msg_t side_msg
|
| ++ rc = zmq_msg_init (&side_msg)
|
| ++ # assert (rc == 0)
|
| ++
|
| ++
|
| ++ cdef zmq_pollitem_t items [2]
|
| ++ items [0].socket = insocket_
|
| ++ items [0].fd = 0
|
| ++ items [0].events = ZMQ_POLLIN
|
| ++ items [0].revents = 0
|
| ++ items [1].socket = outsocket_
|
| ++ items [1].fd = 0
|
| ++ items [1].events = ZMQ_POLLIN
|
| ++ items [1].revents = 0
|
| ++ # I don't think sidesocket should be polled?
|
| ++ # items [2].socket = sidesocket_
|
| ++ # items [2].fd = 0
|
| ++ # items [2].events = ZMQ_POLLIN
|
| ++ # items [2].revents = 0
|
| ++
|
| ++ while (True):
|
| ++
|
| ++ # // Wait while there are either requests or replies to process.
|
| ++ rc = zmq_poll (&items [0], 2, -1)
|
| ++ if rc < 0:
|
| ++ return rc
|
| ++ # // The algorithm below asumes ratio of request and replies processed
|
| ++ # // under full load to be 1:1. Although processing requests replies
|
| ++ # // first is tempting it is suspectible to DoS attacks (overloading
|
| ++ # // the system with unsolicited replies).
|
| ++ #
|
| ++ # // Process a request.
|
| ++ if (items [0].revents & ZMQ_POLLIN):
|
| ++ # send in_prefix to side socket
|
| ++ rc = zmq_msg_copy(&side_msg, in_msg_ptr)
|
| ++ rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
|
| ++ if rc < 0:
|
| ++ return rc
|
| ++ # relay the rest of the message
|
| ++ rc = _relay(insocket_, outsocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
|
| ++ if rc < 0:
|
| ++ return rc
|
| ++ if (items [1].revents & ZMQ_POLLIN):
|
| ++ # send out_prefix to side socket
|
| ++ rc = zmq_msg_copy(&side_msg, out_msg_ptr)
|
| ++ rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
|
| ++ if rc < 0:
|
| ++ return rc
|
| ++ # relay the rest of the message
|
| ++ rc = _relay(outsocket_, insocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
|
| ++ if rc < 0:
|
| ++ return rc
|
| ++ return 0
|
| +diff --git a/zmq/devices/_zmonitoredqueue.pyx b/zmq/devices/_zmonitoredqueue.pyx
|
| +new file mode 100644
|
| +index 0000000..a74ae8e
|
| +--- /dev/null
|
| ++++ b/zmq/devices/_zmonitoredqueue.pyx
|
| +@@ -0,0 +1,108 @@
|
| ++"""MonitoredQueue classes and functions.
|
| ++
|
| ++Authors
|
| ++-------
|
| ++* MinRK
|
| ++* Brian Granger
|
| ++"""
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq
|
| ++#
|
| ++# Distributed under the terms of the New BSD License. The full license is in
|
| ++# the file COPYING.BSD, distributed as part of this software.
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++cdef extern from "Python.h":
|
| ++ ctypedef int Py_ssize_t
|
| ++
|
| ++from libc.string cimport memcpy
|
| ++
|
| ++from buffers cimport asbuffer_r
|
| ++from libzmq cimport *
|
| ++
|
| ++from zmq.core._zsocket cimport Socket
|
| ++from zmq.core.checkrc cimport _check_rc
|
| ++
|
| ++from zmq import ROUTER, ZMQError
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# MonitoredQueue functions
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++
|
| ++def monitored_queue(Socket in_socket, Socket out_socket, Socket mon_socket,
|
| ++ bytes in_prefix=b'in', bytes out_prefix=b'out'):
|
| ++ """monitored_queue(in_socket, out_socket, mon_socket,
|
| ++ in_prefix='in', out_prefix='out')
|
| ++
|
| ++ Start a monitored queue device.
|
| ++
|
| ++ A monitored queue behaves just like a zmq QUEUE device as far as in_socket
|
| ++ and out_socket are concerned, except that all messages *also* go out on
|
| ++ mon_socket. mon_socket also prefixes the messages coming from each with a
|
| ++ prefix, by default 'in' and 'out', so all messages sent by mon_socket are
|
| ++ multipart.
|
| ++
|
| ++ The only difference between this and a QUEUE as far as in/out are
|
| ++ concerned is that it works with two ROUTER sockets by swapping the IDENT
|
| ++ prefixes.
|
| ++
|
| ++ Parameters
|
| ++ ----------
|
| ++ in_socket : Socket
|
| ++ One of the sockets to the Queue. Its messages will be prefixed with
|
| ++ 'in'.
|
| ++ out_socket : Socket
|
| ++ One of the sockets to the Queue. Its messages will be prefixed with
|
| ++ 'out'. The only difference between in/out socket is this prefix.
|
| ++ mon_socket : Socket
|
| ++ This socket sends out every message received by each of the others
|
| ++ with an in/out prefix specifying which one it was.
|
| ++ in_prefix : str
|
| ++ Prefix added to broadcast messages from in_socket.
|
| ++ out_prefix : str
|
| ++ Prefix added to broadcast messages from out_socket.
|
| ++ """
|
| ++
|
| ++ cdef void *ins=in_socket.handle
|
| ++ cdef void *outs=out_socket.handle
|
| ++ cdef void *mons=mon_socket.handle
|
| ++ cdef zmq_msg_t in_msg
|
| ++ cdef zmq_msg_t out_msg
|
| ++ cdef bint swap_ids
|
| ++ cdef char *msg_c = NULL
|
| ++ cdef Py_ssize_t msg_c_len
|
| ++ cdef int rc
|
| ++
|
| ++ # force swap_ids if both ROUTERs
|
| ++ swap_ids = (in_socket.socket_type == ROUTER and
|
| ++ out_socket.socket_type == ROUTER)
|
| ++
|
| ++ # build zmq_msg objects from str prefixes
|
| ++ asbuffer_r(in_prefix, <void **>&msg_c, &msg_c_len)
|
| ++ with nogil:
|
| ++ rc = zmq_msg_init_size(&in_msg, msg_c_len)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ with nogil:
|
| ++ memcpy(zmq_msg_data(&in_msg), msg_c, zmq_msg_size(&in_msg))
|
| ++
|
| ++ asbuffer_r(out_prefix, <void **>&msg_c, &msg_c_len)
|
| ++
|
| ++ with nogil:
|
| ++ rc = zmq_msg_init_size(&out_msg, msg_c_len)
|
| ++ _check_rc(rc)
|
| ++
|
| ++ with nogil:
|
| ++ memcpy(zmq_msg_data(&out_msg), msg_c, zmq_msg_size(&out_msg))
|
| ++ rc = c_monitored_queue(ins, outs, mons, &in_msg, &out_msg, swap_ids)
|
| ++ return rc
|
| ++
|
| ++__all__ = ['monitored_queue']
|
| +diff --git a/zmq/devices/basedevice.py b/zmq/devices/basedevice.py
|
| +index f65ba1f..4b2c42b 100644
|
| +--- a/zmq/devices/basedevice.py
|
| ++++ b/zmq/devices/basedevice.py
|
| +@@ -20,8 +20,15 @@ Authors
|
| + #-----------------------------------------------------------------------------
|
| +
|
| + import time
|
| +-from threading import Thread
|
| +-from multiprocessing import Process
|
| ++try:
|
| ++ from threading import Thread
|
| ++except ImportError:
|
| ++ Thread = None
|
| ++
|
| ++try:
|
| ++ from multiprocessing import Process
|
| ++except ImportError:
|
| ++ Process = None
|
| +
|
| + from zmq import device, QUEUE, Context
|
| +
|
| +diff --git a/zmq/devices/monitoredqueue.pxd b/zmq/devices/monitoredqueue.pxd
|
| +deleted file mode 100644
|
| +index e04354a..0000000
|
| +--- a/zmq/devices/monitoredqueue.pxd
|
| ++++ /dev/null
|
| +@@ -1,166 +0,0 @@
|
| +-"""MonitoredQueue class declarations.
|
| +-
|
| +-Authors
|
| +--------
|
| +-* MinRK
|
| +-* Brian Granger
|
| +-"""
|
| +-
|
| +-#
|
| +-# Copyright (c) 2010 Min Ragan-Kelley, Brian Granger
|
| +-#
|
| +-# This file is part of pyzmq, but is derived and adapted from zmq_queue.cpp
|
| +-# originally from libzmq-2.1.6, used under LGPLv3
|
| +-#
|
| +-# pyzmq is free software; you can redistribute it and/or modify it under
|
| +-# the terms of the Lesser GNU General Public License as published by
|
| +-# the Free Software Foundation; either version 3 of the License, or
|
| +-# (at your option) any later version.
|
| +-#
|
| +-# pyzmq is distributed in the hope that it will be useful,
|
| +-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| +-# Lesser GNU General Public License for more details.
|
| +-#
|
| +-# You should have received a copy of the Lesser GNU General Public License
|
| +-# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| +-#
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libzmq cimport *
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# MonitoredQueue C functions
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-cdef inline int _relay(void *insocket_, void *outsocket_, void *sidesocket_,
|
| +- zmq_msg_t msg, zmq_msg_t side_msg, zmq_msg_t id_msg,
|
| +- bint swap_ids) nogil:
|
| +- cdef int rc
|
| +- cdef int64_t flag_2
|
| +- cdef int flag_3
|
| +- cdef int flags
|
| +- cdef bint more
|
| +- cdef size_t flagsz
|
| +- cdef void * flag_ptr
|
| +-
|
| +- if ZMQ_VERSION_MAJOR < 3:
|
| +- flagsz = sizeof (int64_t)
|
| +- flag_ptr = &flag_2
|
| +- else:
|
| +- flagsz = sizeof (int)
|
| +- flag_ptr = &flag_3
|
| +-
|
| +- if swap_ids:# both router, must send second identity first
|
| +- # recv two ids into msg, id_msg
|
| +- rc = zmq_msg_recv(&msg, insocket_, 0)
|
| +- rc = zmq_msg_recv(&id_msg, insocket_, 0)
|
| +-
|
| +- # send second id (id_msg) first
|
| +- #!!!! always send a copy before the original !!!!
|
| +- rc = zmq_msg_copy(&side_msg, &id_msg)
|
| +- rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
|
| +- rc = zmq_msg_send(&id_msg, sidesocket_, ZMQ_SNDMORE)
|
| +- # send first id (msg) second
|
| +- rc = zmq_msg_copy(&side_msg, &msg)
|
| +- rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
|
| +- rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
|
| +- if rc < 0:
|
| +- return rc
|
| +- while (True):
|
| +- rc = zmq_msg_recv(&msg, insocket_, 0)
|
| +- # assert (rc == 0)
|
| +- rc = zmq_getsockopt (insocket_, ZMQ_RCVMORE, flag_ptr, &flagsz)
|
| +- flags = 0
|
| +- if ZMQ_VERSION_MAJOR < 3:
|
| +- if flag_2:
|
| +- flags |= ZMQ_SNDMORE
|
| +- else:
|
| +- if flag_3:
|
| +- flags |= ZMQ_SNDMORE
|
| +- # LABEL has been removed:
|
| +- # rc = zmq_getsockopt (insocket_, ZMQ_RCVLABEL, flag_ptr, &flagsz)
|
| +- # if flag_3:
|
| +- # flags |= ZMQ_SNDLABEL
|
| +- # assert (rc == 0)
|
| +-
|
| +- rc = zmq_msg_copy(&side_msg, &msg)
|
| +- if flags:
|
| +- rc = zmq_msg_send(&side_msg, outsocket_, flags)
|
| +- # only SNDMORE for side-socket
|
| +- rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
|
| +- else:
|
| +- rc = zmq_msg_send(&side_msg, outsocket_, 0)
|
| +- rc = zmq_msg_send(&msg, sidesocket_, 0)
|
| +- break
|
| +- return rc
|
| +-
|
| +-# the MonitoredQueue C function, adapted from zmq::queue.cpp :
|
| +-cdef inline int c_monitored_queue (void *insocket_, void *outsocket_,
|
| +- void *sidesocket_, zmq_msg_t *in_msg_ptr,
|
| +- zmq_msg_t *out_msg_ptr, int swap_ids) nogil:
|
| +- """The actual C function for a monitored queue device.
|
| +-
|
| +- See ``monitored_queue()`` for details.
|
| +- """
|
| +-
|
| +- cdef zmq_msg_t msg
|
| +- cdef int rc = zmq_msg_init (&msg)
|
| +- cdef zmq_msg_t id_msg
|
| +- rc = zmq_msg_init (&id_msg)
|
| +- cdef zmq_msg_t side_msg
|
| +- rc = zmq_msg_init (&side_msg)
|
| +- # assert (rc == 0)
|
| +-
|
| +-
|
| +- cdef zmq_pollitem_t items [2]
|
| +- items [0].socket = insocket_
|
| +- items [0].fd = 0
|
| +- items [0].events = ZMQ_POLLIN
|
| +- items [0].revents = 0
|
| +- items [1].socket = outsocket_
|
| +- items [1].fd = 0
|
| +- items [1].events = ZMQ_POLLIN
|
| +- items [1].revents = 0
|
| +- # I don't think sidesocket should be polled?
|
| +- # items [2].socket = sidesocket_
|
| +- # items [2].fd = 0
|
| +- # items [2].events = ZMQ_POLLIN
|
| +- # items [2].revents = 0
|
| +-
|
| +- while (True):
|
| +-
|
| +- # // Wait while there are either requests or replies to process.
|
| +- rc = zmq_poll (&items [0], 2, -1)
|
| +- if rc < 0:
|
| +- return rc
|
| +- # // The algorithm below asumes ratio of request and replies processed
|
| +- # // under full load to be 1:1. Although processing requests replies
|
| +- # // first is tempting it is suspectible to DoS attacks (overloading
|
| +- # // the system with unsolicited replies).
|
| +- #
|
| +- # // Process a request.
|
| +- if (items [0].revents & ZMQ_POLLIN):
|
| +- # send in_prefix to side socket
|
| +- rc = zmq_msg_copy(&side_msg, in_msg_ptr)
|
| +- rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
|
| +- if rc < 0:
|
| +- return rc
|
| +- # relay the rest of the message
|
| +- rc = _relay(insocket_, outsocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
|
| +- if rc < 0:
|
| +- return rc
|
| +- if (items [1].revents & ZMQ_POLLIN):
|
| +- # send out_prefix to side socket
|
| +- rc = zmq_msg_copy(&side_msg, out_msg_ptr)
|
| +- rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
|
| +- if rc < 0:
|
| +- return rc
|
| +- # relay the rest of the message
|
| +- rc = _relay(outsocket_, insocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
|
| +- if rc < 0:
|
| +- return rc
|
| +- return 0
|
| +diff --git a/zmq/devices/monitoredqueue.pyx b/zmq/devices/monitoredqueue.pyx
|
| +deleted file mode 100644
|
| +index 65db882..0000000
|
| +--- a/zmq/devices/monitoredqueue.pyx
|
| ++++ /dev/null
|
| +@@ -1,108 +0,0 @@
|
| +-"""MonitoredQueue classes and functions.
|
| +-
|
| +-Authors
|
| +--------
|
| +-* MinRK
|
| +-* Brian Granger
|
| +-"""
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq
|
| +-#
|
| +-# Distributed under the terms of the New BSD License. The full license is in
|
| +-# the file COPYING.BSD, distributed as part of this software.
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-cdef extern from "Python.h":
|
| +- ctypedef int Py_ssize_t
|
| +-
|
| +-from libc.string cimport memcpy
|
| +-
|
| +-from buffers cimport asbuffer_r
|
| +-from libzmq cimport *
|
| +-
|
| +-from zmq.core.socket cimport Socket
|
| +-from zmq.core.checkrc cimport _check_rc
|
| +-
|
| +-from zmq import ROUTER, ZMQError
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# MonitoredQueue functions
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-
|
| +-def monitored_queue(Socket in_socket, Socket out_socket, Socket mon_socket,
|
| +- bytes in_prefix=b'in', bytes out_prefix=b'out'):
|
| +- """monitored_queue(in_socket, out_socket, mon_socket,
|
| +- in_prefix='in', out_prefix='out')
|
| +-
|
| +- Start a monitored queue device.
|
| +-
|
| +- A monitored queue behaves just like a zmq QUEUE device as far as in_socket
|
| +- and out_socket are concerned, except that all messages *also* go out on
|
| +- mon_socket. mon_socket also prefixes the messages coming from each with a
|
| +- prefix, by default 'in' and 'out', so all messages sent by mon_socket are
|
| +- multipart.
|
| +-
|
| +- The only difference between this and a QUEUE as far as in/out are
|
| +- concerned is that it works with two ROUTER sockets by swapping the IDENT
|
| +- prefixes.
|
| +-
|
| +- Parameters
|
| +- ----------
|
| +- in_socket : Socket
|
| +- One of the sockets to the Queue. Its messages will be prefixed with
|
| +- 'in'.
|
| +- out_socket : Socket
|
| +- One of the sockets to the Queue. Its messages will be prefixed with
|
| +- 'out'. The only difference between in/out socket is this prefix.
|
| +- mon_socket : Socket
|
| +- This socket sends out every message received by each of the others
|
| +- with an in/out prefix specifying which one it was.
|
| +- in_prefix : str
|
| +- Prefix added to broadcast messages from in_socket.
|
| +- out_prefix : str
|
| +- Prefix added to broadcast messages from out_socket.
|
| +- """
|
| +-
|
| +- cdef void *ins=in_socket.handle
|
| +- cdef void *outs=out_socket.handle
|
| +- cdef void *mons=mon_socket.handle
|
| +- cdef zmq_msg_t in_msg
|
| +- cdef zmq_msg_t out_msg
|
| +- cdef bint swap_ids
|
| +- cdef char *msg_c = NULL
|
| +- cdef Py_ssize_t msg_c_len
|
| +- cdef int rc
|
| +-
|
| +- # force swap_ids if both ROUTERs
|
| +- swap_ids = (in_socket.socket_type == ROUTER and
|
| +- out_socket.socket_type == ROUTER)
|
| +-
|
| +- # build zmq_msg objects from str prefixes
|
| +- asbuffer_r(in_prefix, <void **>&msg_c, &msg_c_len)
|
| +- with nogil:
|
| +- rc = zmq_msg_init_size(&in_msg, msg_c_len)
|
| +- _check_rc(rc)
|
| +-
|
| +- with nogil:
|
| +- memcpy(zmq_msg_data(&in_msg), msg_c, zmq_msg_size(&in_msg))
|
| +-
|
| +- asbuffer_r(out_prefix, <void **>&msg_c, &msg_c_len)
|
| +-
|
| +- with nogil:
|
| +- rc = zmq_msg_init_size(&out_msg, msg_c_len)
|
| +- _check_rc(rc)
|
| +-
|
| +- with nogil:
|
| +- memcpy(zmq_msg_data(&out_msg), msg_c, zmq_msg_size(&out_msg))
|
| +- rc = c_monitored_queue(ins, outs, mons, &in_msg, &out_msg, swap_ids)
|
| +- return rc
|
| +-
|
| +-__all__ = ['monitored_queue']
|
| +diff --git a/zmq/devices/monitoredqueuedevice.py b/zmq/devices/monitoredqueuedevice.py
|
| +index a9f5c3f..422715c 100644
|
| +--- a/zmq/devices/monitoredqueuedevice.py
|
| ++++ b/zmq/devices/monitoredqueuedevice.py
|
| +@@ -24,7 +24,7 @@ import time
|
| +
|
| + from zmq import ZMQError, PUB
|
| + from zmq.devices.proxydevice import ProxyBase, Proxy, ThreadProxy, ProcessProxy
|
| +-from zmq.devices.monitoredqueue import monitored_queue
|
| ++from zmq.devices._zmonitoredqueue import monitored_queue
|
| +
|
| + #-----------------------------------------------------------------------------
|
| + # Classes
|
| +diff --git a/zmq/sugar/backend.py b/zmq/sugar/backend.py
|
| +index ad07379..6f87c1b 100644
|
| +--- a/zmq/sugar/backend.py
|
| ++++ b/zmq/sugar/backend.py
|
| +@@ -23,8 +23,9 @@ try:
|
| + strerror, zmq_errno,
|
| + zmq_poll,
|
| + zmq_version_info,
|
| +- constants,
|
| ++ _zconstants,
|
| + )
|
| ++ constants = _zconstants
|
| + except ImportError:
|
| + from zmq.cffi_core import (
|
| + Context,
|
| +diff --git a/zmq/sugar/context.py b/zmq/sugar/context.py
|
| +index bcc4686..f0f3325 100644
|
| +--- a/zmq/sugar/context.py
|
| ++++ b/zmq/sugar/context.py
|
| +@@ -128,4 +128,4 @@ class Context(ContextBase, AttributeSetter):
|
| + else:
|
| + del self.sockopts[opt]
|
| +
|
| +-__all__ = ['Context']
|
| +\ No newline at end of file
|
| ++__all__ = ['Context']
|
| +diff --git a/zmq/utils/_zinitthreads.pyx b/zmq/utils/_zinitthreads.pyx
|
| +new file mode 100644
|
| +index 0000000..6c57c9f
|
| +--- /dev/null
|
| ++++ b/zmq/utils/_zinitthreads.pyx
|
| +@@ -0,0 +1,23 @@
|
| ++"""Utility to initialize threads."""
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Copyright (c) 2010 Brian Granger, Min Ragan-Kelley
|
| ++#
|
| ++# Distributed under the terms of the New BSD License. The full license is in
|
| ++# the file COPYING.BSD, distributed as part of this software.
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Imports
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++cdef extern from "Python.h":
|
| ++ cdef void PyEval_InitThreads()
|
| ++
|
| ++# It seems that in only *some* version of Python/Cython we need to call this
|
| ++# by hand to get threads initialized. Not clear why this is the case though.
|
| ++# If we don't have this, pyzmq will segfault.
|
| ++def init_threads():
|
| ++ PyEval_InitThreads()
|
| ++
|
| ++__all__ = ['init_threads']
|
| +diff --git a/zmq/utils/_zrebuffer.pyx b/zmq/utils/_zrebuffer.pyx
|
| +new file mode 100644
|
| +index 0000000..ca240d3
|
| +--- /dev/null
|
| ++++ b/zmq/utils/_zrebuffer.pyx
|
| +@@ -0,0 +1,104 @@
|
| ++"""
|
| ++Utility for changing itemsize of memoryviews, and getting
|
| ++numpy arrays from byte-arrays that should be interpreted with a different
|
| ++itemsize.
|
| ++
|
| ++Authors
|
| ++-------
|
| ++* MinRK
|
| ++"""
|
| ++
|
| ++#-----------------------------------------------------------------------------
|
| ++# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
|
| ++#
|
| ++# This file is part of pyzmq
|
| ++#
|
| ++# Distributed under the terms of the New BSD License. The full license is in
|
| ++# the file COPYING.BSD, distributed as part of this software.
|
| ++#-----------------------------------------------------------------------------
|
| ++
|
| ++from libc.stdlib cimport malloc
|
| ++from buffers cimport *
|
| ++
|
| ++cdef inline object _rebuffer(object obj, char * format, int itemsize):
|
| ++ """clobber the format & itemsize of a 1-D
|
| ++
|
| ++ This is the Python 3 model, but will work on Python >= 2.6. Currently,
|
| ++ we use it only on >= 3.0.
|
| ++ """
|
| ++ cdef Py_buffer view
|
| ++ cdef int flags = PyBUF_SIMPLE
|
| ++ cdef int mode = 0
|
| ++ # cdef Py_ssize_t *shape, *strides, *suboffsets
|
| ++
|
| ++ mode = check_buffer(obj)
|
| ++ if mode == 0:
|
| ++ raise TypeError("%r does not provide a buffer interface."%obj)
|
| ++
|
| ++ if mode == 3:
|
| ++ flags = PyBUF_ANY_CONTIGUOUS
|
| ++ if format:
|
| ++ flags |= PyBUF_FORMAT
|
| ++ PyObject_GetBuffer(obj, &view, flags)
|
| ++ assert view.ndim <= 1, "Can only reinterpret 1-D memoryviews"
|
| ++ assert view.len % itemsize == 0, "Buffer of length %i not divisible into items of size %i"%(view.len, itemsize)
|
| ++ # hack the format
|
| ++ view.ndim = 1
|
| ++ view.format = format
|
| ++ view.itemsize = itemsize
|
| ++ view.strides = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
|
| ++ view.strides[0] = itemsize
|
| ++ view.shape = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
|
| ++ view.shape[0] = view.len/itemsize
|
| ++ view.suboffsets = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
|
| ++ view.suboffsets[0] = 0
|
| ++ # for debug: make buffer writable, for zero-copy testing
|
| ++ # view.readonly = 0
|
| ++
|
| ++ return PyMemoryView_FromBuffer(&view)
|
| ++ else:
|
| ++ raise TypeError("This funciton is only for new-style buffer objects.")
|
| ++
|
| ++def rebuffer(obj, format, itemsize):
|
| ++ """Change the itemsize of a memoryview.
|
| ++
|
| ++ Only for 1D contiguous buffers.
|
| ++ """
|
| ++ return _rebuffer(obj, format, itemsize)
|
| ++
|
| ++def array_from_buffer(view, dtype, shape):
|
| ++ """Get a numpy array from a memoryview, regardless of the itemsize of the original
|
| ++ memoryview. This is important, because pyzmq does not send memoryview shape data
|
| ++ over the wire, so we need to change the memoryview itemsize before calling
|
| ++ asarray.
|
| ++ """
|
| ++ import numpy
|
| ++ A = numpy.array([],dtype=dtype)
|
| ++ ref = viewfromobject(A,0)
|
| ++ fmt = ref.format.encode()
|
| ++ buf = viewfromobject(view, 0)
|
| ++ buf = _rebuffer(view, fmt, ref.itemsize)
|
| ++ return numpy.asarray(buf, dtype=dtype).reshape(shape)
|
| ++
|
| ++def print_view_info(obj):
|
| ++ """simple utility for printing info on a new-style buffer object"""
|
| ++ cdef Py_buffer view
|
| ++ cdef int flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT
|
| ++ cdef int mode = 0
|
| ++
|
| ++ mode = check_buffer(obj)
|
| ++ if mode == 0:
|
| ++ raise TypeError("%r does not provide a buffer interface."%obj)
|
| ++
|
| ++ if mode == 3:
|
| ++ PyObject_GetBuffer(obj, &view, flags)
|
| ++ print <Py_ssize_t>view.buf, view.len, view.format, view.ndim,
|
| ++ if view.ndim:
|
| ++ if view.shape:
|
| ++ print view.shape[0],
|
| ++ if view.strides:
|
| ++ print view.strides[0],
|
| ++ if view.suboffsets:
|
| ++ print view.suboffsets[0],
|
| ++ print
|
| ++
|
| +\ No newline at end of file
|
| +diff --git a/zmq/utils/initthreads.pyx b/zmq/utils/initthreads.pyx
|
| +deleted file mode 100644
|
| +index 6c57c9f..0000000
|
| +--- a/zmq/utils/initthreads.pyx
|
| ++++ /dev/null
|
| +@@ -1,23 +0,0 @@
|
| +-"""Utility to initialize threads."""
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Copyright (c) 2010 Brian Granger, Min Ragan-Kelley
|
| +-#
|
| +-# Distributed under the terms of the New BSD License. The full license is in
|
| +-# the file COPYING.BSD, distributed as part of this software.
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Imports
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-cdef extern from "Python.h":
|
| +- cdef void PyEval_InitThreads()
|
| +-
|
| +-# It seems that in only *some* version of Python/Cython we need to call this
|
| +-# by hand to get threads initialized. Not clear why this is the case though.
|
| +-# If we don't have this, pyzmq will segfault.
|
| +-def init_threads():
|
| +- PyEval_InitThreads()
|
| +-
|
| +-__all__ = ['init_threads']
|
| +diff --git a/zmq/utils/rebuffer.pyx b/zmq/utils/rebuffer.pyx
|
| +deleted file mode 100644
|
| +index ca240d3..0000000
|
| +--- a/zmq/utils/rebuffer.pyx
|
| ++++ /dev/null
|
| +@@ -1,104 +0,0 @@
|
| +-"""
|
| +-Utility for changing itemsize of memoryviews, and getting
|
| +-numpy arrays from byte-arrays that should be interpreted with a different
|
| +-itemsize.
|
| +-
|
| +-Authors
|
| +--------
|
| +-* MinRK
|
| +-"""
|
| +-
|
| +-#-----------------------------------------------------------------------------
|
| +-# Copyright (c) 2010-2012 Brian Granger, Min Ragan-Kelley
|
| +-#
|
| +-# This file is part of pyzmq
|
| +-#
|
| +-# Distributed under the terms of the New BSD License. The full license is in
|
| +-# the file COPYING.BSD, distributed as part of this software.
|
| +-#-----------------------------------------------------------------------------
|
| +-
|
| +-from libc.stdlib cimport malloc
|
| +-from buffers cimport *
|
| +-
|
| +-cdef inline object _rebuffer(object obj, char * format, int itemsize):
|
| +- """clobber the format & itemsize of a 1-D
|
| +-
|
| +- This is the Python 3 model, but will work on Python >= 2.6. Currently,
|
| +- we use it only on >= 3.0.
|
| +- """
|
| +- cdef Py_buffer view
|
| +- cdef int flags = PyBUF_SIMPLE
|
| +- cdef int mode = 0
|
| +- # cdef Py_ssize_t *shape, *strides, *suboffsets
|
| +-
|
| +- mode = check_buffer(obj)
|
| +- if mode == 0:
|
| +- raise TypeError("%r does not provide a buffer interface."%obj)
|
| +-
|
| +- if mode == 3:
|
| +- flags = PyBUF_ANY_CONTIGUOUS
|
| +- if format:
|
| +- flags |= PyBUF_FORMAT
|
| +- PyObject_GetBuffer(obj, &view, flags)
|
| +- assert view.ndim <= 1, "Can only reinterpret 1-D memoryviews"
|
| +- assert view.len % itemsize == 0, "Buffer of length %i not divisible into items of size %i"%(view.len, itemsize)
|
| +- # hack the format
|
| +- view.ndim = 1
|
| +- view.format = format
|
| +- view.itemsize = itemsize
|
| +- view.strides = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
|
| +- view.strides[0] = itemsize
|
| +- view.shape = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
|
| +- view.shape[0] = view.len/itemsize
|
| +- view.suboffsets = <Py_ssize_t *>malloc(sizeof(Py_ssize_t))
|
| +- view.suboffsets[0] = 0
|
| +- # for debug: make buffer writable, for zero-copy testing
|
| +- # view.readonly = 0
|
| +-
|
| +- return PyMemoryView_FromBuffer(&view)
|
| +- else:
|
| +- raise TypeError("This funciton is only for new-style buffer objects.")
|
| +-
|
| +-def rebuffer(obj, format, itemsize):
|
| +- """Change the itemsize of a memoryview.
|
| +-
|
| +- Only for 1D contiguous buffers.
|
| +- """
|
| +- return _rebuffer(obj, format, itemsize)
|
| +-
|
| +-def array_from_buffer(view, dtype, shape):
|
| +- """Get a numpy array from a memoryview, regardless of the itemsize of the original
|
| +- memoryview. This is important, because pyzmq does not send memoryview shape data
|
| +- over the wire, so we need to change the memoryview itemsize before calling
|
| +- asarray.
|
| +- """
|
| +- import numpy
|
| +- A = numpy.array([],dtype=dtype)
|
| +- ref = viewfromobject(A,0)
|
| +- fmt = ref.format.encode()
|
| +- buf = viewfromobject(view, 0)
|
| +- buf = _rebuffer(view, fmt, ref.itemsize)
|
| +- return numpy.asarray(buf, dtype=dtype).reshape(shape)
|
| +-
|
| +-def print_view_info(obj):
|
| +- """simple utility for printing info on a new-style buffer object"""
|
| +- cdef Py_buffer view
|
| +- cdef int flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT
|
| +- cdef int mode = 0
|
| +-
|
| +- mode = check_buffer(obj)
|
| +- if mode == 0:
|
| +- raise TypeError("%r does not provide a buffer interface."%obj)
|
| +-
|
| +- if mode == 3:
|
| +- PyObject_GetBuffer(obj, &view, flags)
|
| +- print <Py_ssize_t>view.buf, view.len, view.format, view.ndim,
|
| +- if view.ndim:
|
| +- if view.shape:
|
| +- print view.shape[0],
|
| +- if view.strides:
|
| +- print view.strides[0],
|
| +- if view.suboffsets:
|
| +- print view.suboffsets[0],
|
| +- print
|
| +-
|
| +\ No newline at end of file
|
|
|
|
|