blob: f4c1c7f4388437aeaef692f4c7c990b795c31c68 [file] [log] [blame]
diff --git a/buildutils/config.py b/buildutils/config.py
--- 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
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[bdist_egg]
+plat-name = pnacl
+
diff --git a/setup.py b/setup.py
--- 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],
},
)
diff --git a/zmq/__init__.py b/zmq/__init__.py
--- 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
--- 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
--- /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
--- /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
--- /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
--- 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
--- 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
--- 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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- /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
--- /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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- /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
--- /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
--- 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
--- 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