Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit

  • Loading branch information...
commit eb01ea096ef7c680def50a317632154f0e739c76 0 parents
Vasiliy Evseenko authored
165 COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
38 README.rst
@@ -0,0 +1,38 @@
+======================================================
+pyzmq-ctypes: Python bindings for 0MQ (ctypes version)
+======================================================
+
+This project is an attempt to build a partially-compatible version of
+PyZMQ running on pypy. Since I don't have time to write a Cython that
+compiles to Python instead of C, I decided to write some ctypes bindings
+for ZeroMQ.
+
+These bindings introspect parts of the ZeroMQ library by using the C
+compiler and a C parser, so you will still need those in order to
+use this.
+
+Authors
+=======
+
+The ctypes bindings were written by Daniel Holth <dholth@gmail.com>
+based on a copy of the original PyZMQ with the Cython bits taken out.
+
+The orginal PyZMQ was started by and continues to be led by Brian
+E. Granger (ellisonbg AT gmail DOT com).
+
+The following people have contributed to the project:
+
+* Carlos Rocha (carlos DOT rocha AT gmail DOT com)
+* Andrew Gwozdziewycz (git AT apgwoz DOT com)
+* Fernando Perez (fernando DOT perez AT berkeley DOT edu)
+* Nicholas Piel (nicholas AT nichol DOT as)
+* Eugene Chernyshov (chernyshov DOT eugene AT gmail DOT com)
+* Justin Riley (justin DOT t DOT riley AT gmail DOT com)
+* Ivo Danihelka (ivo AT denihelka DOT net)
+* Thomas Supra (tomspur AT fedoraproject DOT org)
+* Douglas Creager (dcreager AT dcreager DOT net)
+* Erick Tryzelaar (erick DOT tryzelaar AT gmail DOT com)
+* Min Ragan-Kelley (benjaminrk AT gmail DOT com)
+* Scott Sadler (github AT mashi DOT org)
+* spez (steve AT hipmunk DOT com)
+* Thomas Kluyver (takowl AT gmail DOT com)
70 perf/local_lat.py
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2007-2010 iMatix Corporation
+#
+# This file is part of 0MQ.
+#
+# 0MQ 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.
+#
+# 0MQ 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/>.
+#
+
+import sys
+import time
+import zmq
+
+def main():
+ use_poll = '-p' in sys.argv
+ use_copy = '-c' in sys.argv
+ if use_copy:
+ sys.argv.remove('-c')
+ if use_poll:
+ sys.argv.remove('-p')
+
+ if len (sys.argv) != 4:
+ print 'usage: local_lat [-c use-copy] [-p use-poll] <bind-to> <message-size> <roundtrip-count>'
+ sys.exit (1)
+
+ try:
+ bind_to = sys.argv[1]
+ message_size = int(sys.argv[2])
+ roundtrip_count = int(sys.argv[3])
+ except (ValueError, OverflowError), e:
+ print 'message-size and roundtrip-count must be integers'
+ sys.exit(1)
+
+ ctx = zmq.Context()
+ s = ctx.socket(zmq.REP)
+
+ if use_poll:
+ p = zmq.Poller()
+ p.register(s)
+
+ s.bind(bind_to)
+
+ for i in range(0, roundtrip_count):
+ if use_poll:
+ res = p.poll()
+ assert(res[0][1] & zmq.POLLIN)
+ msg = s.recv(zmq.NOBLOCK if use_poll else 0, copy=use_copy)
+ assert len(msg) == message_size
+
+ if use_poll:
+ res = p.poll()
+ assert(res[0][1] & zmq.POLLOUT)
+ s.send(msg, zmq.NOBLOCK if use_poll else 0, copy=use_copy)
+
+ # Let the context finish messaging before ending.
+ # You may need to increase this time for longer or many messages.
+ time.sleep(2.0)
+
+if __name__ == '__main__':
+ main()
96 perf/local_thr.py
@@ -0,0 +1,96 @@
+#
+# Copyright (c) 2007-2010 iMatix Corporation
+#
+# This file is part of 0MQ.
+#
+# 0MQ 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.
+#
+# 0MQ 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/>.
+#
+
+import sys
+import time
+import zmq
+
+def main ():
+ use_poll = '-p' in sys.argv
+ use_copy = '-c' in sys.argv
+ if use_copy:
+ sys.argv.remove('-c')
+ if use_poll:
+ sys.argv.remove('-p')
+
+ if len (sys.argv) != 4:
+ print 'usage: local_thr [-c use-copy] [-p use-poll] <bind-to> <message-size> <message-count>'
+ sys.exit(1)
+
+ try:
+ bind_to = sys.argv[1]
+ message_size = int(sys.argv[2])
+ message_count = int(sys.argv[3])
+ except (ValueError, OverflowError), e:
+ print 'message-size and message-count must be integers'
+ sys.exit(1)
+
+ ctx = zmq.Context()
+ s = ctx.socket(zmq.SUB)
+
+ # Add your socket options here.
+ # For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM.
+ s.setsockopt(zmq.SUBSCRIBE , "");
+
+ if use_poll:
+ p = zmq.Poller()
+ p.register(s)
+
+ s.bind(bind_to)
+
+ # Wait for the other side to connect.
+ time.sleep(2.0)
+
+ msg = s.recv()
+ assert len (msg) == message_size
+
+ clock = zmq.Stopwatch()
+ start = 0
+ clock.start()
+ # start = time.clock()
+
+ for i in range (1, message_count):
+ if use_poll:
+ res = p.poll()
+ assert(res[0][1] & zmq.POLLIN)
+ msg = s.recv(zmq.NOBLOCK if use_poll else 0, copy=use_copy)
+ assert len(msg) == message_size
+
+ end = clock.stop()
+ # end = time.clock()
+
+ elapsed = (end - start)
+ # elapsed = (end - start) * 1000000 # use with time.clock
+ if elapsed == 0:
+ elapsed = 1
+ throughput = (1000000.0 * float(message_count)) / float(elapsed)
+ megabits = float(throughput * message_size * 8) / 1000000
+
+ print "message size: %.0f [B]" % (message_size, )
+ print "message count: %.0f" % (message_count, )
+ print "mean throughput: %.0f [msg/s]" % (throughput, )
+ print "mean throughput: %.3f [Mb/s]" % (megabits, )
+
+ # Let the context finish messaging before ending.
+ # You may need to increase this time for longer or many messages.
+ time.sleep(2.0)
+
+if __name__ == "__main__":
+ main ()
+
93 perf/remote_lat.py
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2007-2010 iMatix Corporation
+#
+# This file is part of 0MQ.
+#
+# 0MQ 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.
+#
+# 0MQ 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/>.
+#
+
+import sys
+import time
+import zmq
+
+
+def main ():
+ use_poll = '-p' in sys.argv
+ use_copy = '-c' in sys.argv
+ if use_copy:
+ sys.argv.remove('-c')
+ if use_poll:
+ sys.argv.remove('-p')
+
+ if len(sys.argv) != 4:
+ print 'usage: remote_lat [-c use-copy] [-p use-poll] <connect-to> <message-size> <roundtrip-count>'
+ sys.exit(1)
+
+ try:
+ connect_to = sys.argv[1]
+ message_size = int(sys.argv[2])
+ roundtrip_count = int(sys.argv[3])
+ except (ValueError, OverflowError), e:
+ print 'message-size and message-count must be integers'
+ sys.exit(1)
+
+ ctx = zmq.Context()
+ s = ctx.socket(zmq.REQ)
+ print connect_to
+ s.connect(connect_to)
+
+ if use_poll:
+ p = zmq.Poller()
+ p.register(s)
+
+ msg = ' ' * message_size
+
+ clock = zmq.Stopwatch()
+ start = 0
+ clock.start()
+ # start = time.clock()
+
+ for i in range (0, roundtrip_count):
+ if use_poll:
+ res = p.poll()
+ assert(res[0][1] & zmq.POLLOUT)
+ s.send(msg, zmq.NOBLOCK if use_poll else 0, copy=use_copy)
+
+ if use_poll:
+ res = p.poll()
+ assert(res[0][1] & zmq.POLLIN)
+ msg = s.recv(zmq.NOBLOCK if use_poll else 0, copy=use_copy)
+ assert len (msg) == message_size
+
+ end = clock.stop()
+ # end = time.clock()
+
+ time.sleep(1)
+
+ elapsed = (end - start)
+ # elapsed = (end - start) * 1000000 # use with time.clock
+ latency = elapsed / (roundtrip_count * 2)
+
+ print "message size: %.0f [B]" % (message_size, )
+ print "roundtrip count: %.0f" % (roundtrip_count, )
+ print "mean latency: %.3f [us]" % (latency, )
+
+ # Let the context finish messaging before ending.
+ # You may need to increase this time for longer or many messages.
+ time.sleep(2.0)
+
+if __name__ == "__main__":
+ main ()
+
+
72 perf/remote_thr.py
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2007-2010 iMatix Corporation
+#
+# This file is part of 0MQ.
+#
+# 0MQ 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.
+#
+# 0MQ 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/>.
+#
+
+import sys
+import zmq
+import time
+
+def main ():
+ use_poll = '-p' in sys.argv
+ use_copy = '-c' in sys.argv
+ if use_copy:
+ sys.argv.remove('-c')
+ if use_poll:
+ sys.argv.remove('-p')
+
+ if len (sys.argv) != 4:
+ print 'usage: remote_thr [-c use-copy] [-p use-poll] <connect-to> <message-size> <message-count>'
+ sys.exit(1)
+
+ try:
+ connect_to = sys.argv[1]
+ message_size = int(sys.argv[2])
+ message_count = int(sys.argv[3])
+ except (ValueError, OverflowError), e:
+ print 'message-size and message-count must be integers'
+ sys.exit(1)
+
+ ctx = zmq.Context()
+ s = ctx.socket(zmq.PUB)
+
+ # Add your socket options here.
+ # For example ZMQ_RATE, ZMQ_RECOVERY_IVL and ZMQ_MCAST_LOOP for PGM.
+
+ if use_poll:
+ p = zmq.Poller()
+ p.register(s)
+
+ s.connect(connect_to)
+
+ # Wait for this side to connect.
+ time.sleep(2.0)
+
+ msg = ' ' * message_size
+
+ for i in range(0, message_count):
+ if use_poll:
+ res = p.poll()
+ assert(res[0][1] & zmq.POLLOUT)
+ s.send(msg, zmq.NOBLOCK if use_poll else 0, copy=use_copy)
+
+ # Let the context finish messaging before ending.
+ # You may need to increase this time for longer or many messages.
+ time.sleep(2.0)
+
+if __name__ == "__main__":
+ main ()
56 setup.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright © 2011 Daniel Holth
+#
+# Derived from original pyzmq © 2010 Brian Granger
+#
+# This file is part of pyzmq-ctypes
+#
+# pyzmq-ctypes 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-ctypes 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/>.
+
+import os, sys
+
+from distutils.core import setup
+
+long_desc = \
+"""
+pyzmq-ctypes is a ctypes binding for the ZeroMQ library
+(http://www.zeromq.org) that will run on pypy.
+"""
+
+setup(
+ name = "pyzmq-ctypes",
+ version = "2.1.0",
+ packages = ['zmq', 'zmq.core'],
+ author = "Daniel Holth",
+ author_email = "dholth@fastmail.fm",
+ url = 'http://bitbucket.org/dholth/pyzmq-ctypes',
+ download_url = 'http://python.org/pypi/pyzmq-ctypes',
+ description = "Python bindings for 0MQ (ctypes version).",
+ install_requires = ['py', 'ctypes_configure', 'pycparser'],
+ long_description = long_desc,
+ license = "LGPL",
+ classifiers = [
+ 'Development Status :: 2 - Pre-Alpha',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Financial and Insurance Industry',
+ 'Intended Audience :: Science/Research',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+ 'Operating System :: POSIX',
+ 'Topic :: System :: Networking'
+ ]
+)
+
1  zmq/__init__.py
@@ -0,0 +1 @@
+from _zmq import *
496 zmq/_zmq.py
@@ -0,0 +1,496 @@
+# -*- coding: utf-8 -*-
+"""
+Low-level ctypes binding for the ZeroMQ library.
+
+Makes an attempt to emulate pyzmq.core.
+"""
+# Copyright © 2011 Daniel Holth
+#
+# Derived from original pyzmq © 2010 Brian Granger
+#
+# This file is part of pyzmq-ctypes
+#
+# pyzmq-ctypes 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-ctypes 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/>.
+
+import random
+
+from ctypes import *
+from ctypes_configure import configure
+
+class CConfigure(object):
+ _compilation_info_ = configure.ExternalCompilationInfo(
+ includes = ['zmq.h'],
+ libraries = ['zmq']
+ )
+ size_t = configure.SimpleType('size_t', c_int)
+
+for cname in ['ZMQ_AFFINITY', 'ZMQ_DOWNSTREAM', 'EADDRINUSE',
+ 'EADDRNOTAVAIL', 'EAGAIN', 'ECONNREFUSED', 'EFAULT', 'EFSM',
+ 'EINPROGRESS', 'EINVAL', 'EMTHREAD', 'ENETDOWN', 'ENOBUFS',
+ 'ENOCOMPATPROTO', 'ENODEV', 'ENOMEM', 'ENOTSUP', 'EPROTONOSUPPORT',
+ 'ETERM', 'ZMQ_FORWARDER', 'ZMQ_HWM', 'ZMQ_IDENTITY', 'ZMQ_MCAST_LOOP',
+ 'ZMQ_NOBLOCK', 'ZMQ_PAIR', 'ZMQ_POLLERR', 'ZMQ_POLLIN', 'ZMQ_POLLOUT',
+ 'ZMQ_PUB', 'ZMQ_PULL', 'ZMQ_PUSH', 'ZMQ_QUEUE', 'ZMQ_RATE', 'ZMQ_RCVBUF',
+ 'ZMQ_RCVMORE', 'ZMQ_RECOVERY_IVL', 'ZMQ_REP', 'ZMQ_REQ', 'ZMQ_SNDBUF',
+ 'ZMQ_SNDMORE', 'ZMQ_STREAMER', 'ZMQ_SUB', 'ZMQ_SUBSCRIBE', 'ZMQ_SWAP',
+ 'ZMQ_UNSUBSCRIBE', 'ZMQ_UPSTREAM', 'ZMQ_XREP', 'ZMQ_XREQ', 'ZMQ_MAX_VSM_SIZE',
+ 'ZMQ_FD', 'ZMQ_EVENTS', 'ZMQ_TYPE', 'ZMQ_LINGER', 'ZMQ_RECONNECT_IVL',
+ 'ZMQ_BACKLOG']:
+ pyname = cname.split('_', 1)[-1]
+ setattr(CConfigure, pyname, configure.ConstantInteger(cname))
+
+info = configure.configure(CConfigure)
+globals().update(info)
+
+# collections of sockopts, based on type:
+bytes_sockopts = [SUBSCRIBE, UNSUBSCRIBE, IDENTITY]
+int64_sockopts = [HWM, SWAP, AFFINITY, RATE, RECOVERY_IVL,
+ MCAST_LOOP, SNDBUF, RCVBUF, RCVMORE]
+int_sockopts = [FD, EVENTS, TYPE, LINGER, RECONNECT_IVL, BACKLOG]
+
+class ZMQBaseError(Exception): pass
+
+class ZMQError(ZMQBaseError):
+ def __init__(self, errno=None):
+ if errno is None:
+ errno = get_errno()
+ self.strerror = zmq_strerror(errno)
+ self.errno = errno
+
+ def __str__(self):
+ return self.strerror
+
+def _check_nonzero(result, func, arguments):
+ if result != 0:
+ raise ZMQError(get_errno())
+ return result
+
+def _check_not_null(result, func, arguments):
+ if result is None:
+ raise ZMQError(get_errno())
+ return result
+
+def _check_zmq_errno(result, func, arguments):
+ errno = get_errno()
+ if errno != 0:
+ raise ZMQError(errno)
+ return result
+
+libzmq = CDLL("libzmq.so", use_errno=True)
+
+libzmq.zmq_version.restype = None
+libzmq.zmq_version.argtypes = [POINTER(c_int)]*3
+
+major = c_int()
+minor = c_int()
+patch = c_int()
+
+libzmq.zmq_version(byref(major), byref(minor), byref(patch))
+
+__zmq_version__ = tuple((x.value for x in (major, minor, patch)))
+
+def zmq_version():
+ return '.'.join(map(str, __zmq_version__))
+
+memmove.restype = c_void_p
+# Error number as known by the 0MQ library
+
+libzmq.zmq_errno.argtypes = []
+
+libzmq.zmq_strerror.restype = c_char_p
+libzmq.zmq_strerror.argtypes = [c_int]
+
+# 0MQ infrastructure
+
+libzmq.zmq_init.restype = c_void_p
+libzmq.zmq_init.argtypes = [c_int]
+
+libzmq.zmq_term.restype = c_int # the default
+libzmq.zmq_term.argtypes = [c_void_p]
+
+# 0MQ message definition
+
+class zmq_msg_t(Structure):
+ _fields_ = [
+ ('content', c_void_p),
+ ('flags', c_ubyte),
+ ('vsm_size', c_ubyte),
+ ('vsm_data', c_ubyte*MAX_VSM_SIZE)
+ ]
+
+libzmq.zmq_msg_init.argtypes = [POINTER(zmq_msg_t)]
+libzmq.zmq_msg_init.restype = c_int
+libzmq.zmq_msg_init_size.restype = c_int
+libzmq.zmq_msg_init_size.argtypes = [POINTER(zmq_msg_t), size_t]
+
+# requires a free function:
+libzmq.zmq_msg_init_data.restype = c_int
+libzmq.zmq_msg_init_data.argtypes = [POINTER(zmq_msg_t), c_void_p, size_t,
+ c_void_p, c_void_p]
+libzmq.zmq_msg_close.restype = c_int
+libzmq.zmq_msg_close.argtypes = [POINTER(zmq_msg_t)]
+libzmq.zmq_msg_move.argtypes = [POINTER(zmq_msg_t), POINTER(zmq_msg_t)]
+libzmq.zmq_msg_copy.argtypes = [POINTER(zmq_msg_t), POINTER(zmq_msg_t)]
+libzmq.zmq_msg_data.restype = c_void_p
+libzmq.zmq_msg_data.argtypes = [POINTER(zmq_msg_t)]
+libzmq.zmq_msg_size.restype = c_void_p
+libzmq.zmq_msg_size.argtypes = [POINTER(zmq_msg_t)]
+
+# 0MQ socket definition
+
+libzmq.zmq_socket.restype = c_void_p
+libzmq.zmq_socket.argtypes = [c_void_p, c_int]
+libzmq.zmq_socket.errcheck = _check_not_null
+
+libzmq.zmq_close.restype = c_int
+libzmq.zmq_close.argtypes = [c_void_p]
+
+libzmq.zmq_setsockopt.restype = c_int
+libzmq.zmq_setsockopt.argtypes = [c_void_p, c_int, c_void_p, size_t]
+libzmq.zmq_getsockopt.restype = c_int
+libzmq.zmq_getsockopt.argtypes = [c_void_p, c_int, c_void_p, POINTER(size_t)]
+libzmq.zmq_bind.restype = c_int
+libzmq.zmq_bind.argtypes = [c_void_p, c_char_p]
+libzmq.zmq_connect.restype = c_int
+libzmq.zmq_connect.argtypes = [c_void_p, c_char_p]
+libzmq.zmq_send.restype = c_int
+libzmq.zmq_send.argtypes = [c_void_p, POINTER(zmq_msg_t), c_int]
+libzmq.zmq_recv.restype = c_int
+libzmq.zmq_recv.argtypes = [c_void_p, POINTER(zmq_msg_t), c_int]
+
+def _default_errcheck():
+ for symbol in dir(libzmq):
+ if symbol.startswith('zmq_'):
+ fn = getattr(libzmq, symbol)
+ if fn.errcheck != None:
+ continue
+ if fn.restype is c_int:
+ fn.errcheck = _check_nonzero
+ elif fn.restype is c_void_p:
+ fn.errcheck = _check_not_null
+
+def _shortcuts():
+ for symbol in dir(libzmq):
+ if symbol.startswith('zmq_') and not symbol in globals():
+ fn = getattr(libzmq, symbol)
+ globals()[symbol] = fn
+
+_default_errcheck()
+_shortcuts()
+
+# Higher-level interface. Partially copied from pyzmq.
+
+class Context(object):
+ def __init__(self, io_threads=1):
+ """The io_threads argument specifies the size of the ØMQ thread pool to
+ handle I/O operations. If your application is using only the inproc
+ transport for messaging you may set this to zero, otherwise set it to
+ at least one."""
+ if not io_threads > 0:
+ raise ZMQError(EINVAL)
+ self.handle = zmq_init(io_threads)
+ self.closed = False
+
+ def socket(self, kind):
+ if self.closed:
+ raise ZMQError(ENOTSUP)
+ return Socket(self, kind)
+
+ def term(self):
+ rc = zmq_term(self.handle)
+ self.handle = None
+ self.closed = True
+ return rc
+
+class Socket(object):
+ def __init__(self, context, socket_type):
+ self.context = context
+ self.handle = zmq_socket(context.handle, socket_type)
+ self.socket_type = socket_type
+ self.closed = False
+
+ def _check_closed(self):
+ if self.closed:
+ raise ZMQError(ENOTSUP)
+
+ def close(self):
+ zmq_close(self.handle)
+ self.handle = None
+ self.closed = True
+
+ def bind(self, addr):
+ if isinstance(addr, unicode):
+ addr = addr.encode('utf-8')
+ if not isinstance(addr, bytes):
+ raise TypeError('expected str, got: %r' % addr)
+ zmq_bind(self.handle, addr)
+
+ def bind_to_random_port(self, addr, min_port=2000, max_port=20000, max_tries=100):
+ """s.bind_to_random_port(addr, min_port=2000, max_port=20000, max_tries=100)
+
+ Bind this socket to a random port in a range.
+
+ Parameters
+ ----------
+ addr : str
+ The address string without the port to pass to ``Socket.bind()``.
+ min_port : int, optional
+ The minimum port in the range of ports to try.
+ max_port : int, optional
+ The maximum port in the range of ports to try.
+ max_tries : int, optional
+ The number of attempt to bind.
+
+ Returns
+ -------
+ port : int
+ The port the socket was bound to.
+
+ Raises
+ ------
+ ZMQBindError
+ if `max_tries` reached before successful bind
+ """
+ for i in range(max_tries):
+ try:
+ port = random.randrange(min_port, max_port)
+ self.bind('%s:%s' % (addr, port))
+ except ZMQError:
+ pass
+ else:
+ return port
+ raise ZMQBindError("Could not bind socket to random port.")
+
+ 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.
+ """
+ if isinstance(addr, unicode):
+ addr = addr.encode('utf-8')
+ if not isinstance(addr, bytes):
+ raise TypeError('expected str, got: %r' % addr)
+ zmq_connect(self.handle, addr)
+
+ def rcvmore(self):
+ """s.rcvmore()
+
+ Are there more parts to a multipart message?
+
+ Returns
+ -------
+ more : bool
+ whether we are in the middle of a multipart message.
+ """
+ more = self.getsockopt(RCVMORE)
+ return bool(more)
+
+
+ def getsockopt(self, option):
+ """s.getsockopt(option)
+
+ Get the value of a socket option.
+
+ See the 0MQ documentation for details on specific options.
+
+ Parameters
+ ----------
+ option : str
+ The name of the option to set. Can be any of:
+ IDENTITY, HWM, SWAP, AFFINITY, RATE,
+ RECOVERY_IVL, MCAST_LOOP, SNDBUF, RCVBUF, RCVMORE.
+
+ Returns
+ -------
+ optval : int, str
+ The value of the option as a string or int.
+ """
+
+ self._check_closed()
+
+ optval = 0
+
+ if option in int64_sockopts:
+ optval = c_int64(optval)
+ elif option in int_sockopts:
+ optval = c_int32(optval)
+ else:
+ raise ZMQError(EINVAL)
+
+ optlen = size_t(sizeof(optval))
+ zmq_getsockopt(self.handle, option, byref(optval), byref(optlen))
+ return optval.value
+
+
+ def setsockopt(self, option, optval):
+ """s.setsockopt(option, optval)
+
+ Set socket options.
+
+ See the 0MQ documentation for details on specific options.
+
+ Parameters
+ ----------
+ option : constant
+ The name of the option to set. Can be any of: SUBSCRIBE,
+ UNSUBSCRIBE, IDENTITY, HWM, SWAP, AFFINITY, RATE,
+ RECOVERY_IVL, MCAST_LOOP, SNDBUF, RCVBUF.
+ optval : int or str
+ The value of the option to set.
+ """
+
+ self._check_closed()
+ if isinstance(optval, unicode):
+ raise TypeError("unicode not allowed, use setsockopt_unicode")
+
+ if option in bytes_sockopts:
+ if not isinstance(optval, bytes):
+ raise TypeError('expected str, got: %r' % optval)
+ zmq_setsockopt(self.handle, option, optval, len(optval))
+ elif option in int64_sockopts:
+ if not isinstance(optval, int):
+ raise TypeError('expected int, got: %r' % optval)
+ optval_int64_c = c_int64(optval)
+ zmq_setsockopt(self.handle, option,
+ byref(optval_int64_c), sizeof(optval_int64_c))
+ elif option in int_sockopts:
+ if not isinstance(optval, int):
+ raise TypeError('expected int, got: %r' % optval)
+ optval_int32_c = c_int32(optval)
+ zmq_setsockopt(self.handle, option,
+ byref(optval_int32_c), sizeof(optval_int32_c))
+
+ else:
+ raise ZMQError(EINVAL)
+
+
+ def send(self, data, 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, Message
+ 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 Message is passed.
+ ZMQError
+ If the send does not succeed for any reason.
+
+ """
+ self._check_closed()
+
+ if isinstance(data, unicode):
+ raise TypeError("unicode not allowed, use send_unicode")
+
+ if not isinstance(data, bytes):
+ raise TypeError('expected str, got: %r' % data)
+
+ flags = c_int(flags)
+
+ msg = zmq_msg_t()
+ msg_c_len = len(data)
+
+ zmq_msg_init_size(byref(msg), msg_c_len)
+
+ try:
+ msg_buf = zmq_msg_data(byref(msg))
+ msg_buf_size = zmq_msg_size(byref(msg))
+ memmove(msg_buf, data, msg_buf_size)
+ return zmq_send(self.handle, byref(msg), flags)
+ finally:
+ zmq_msg_close(byref(msg))
+
+
+
+ def recv(self, 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 Message 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 : str, Message
+ The returned message. If `copy` is False, then it will be a Message,
+ otherwise a str.
+
+ Raises
+ ------
+ ZMQError
+ for any of the reasons zmq_recvmsg might fail.
+ """
+
+ self._check_closed()
+
+ flags = c_int(flags)
+ msg = zmq_msg_t()
+
+ zmq_msg_init(byref(msg))
+ try:
+ zmq_recv(self.handle, byref(msg), flags)
+ data = zmq_msg_data(byref(msg))
+ data_size = zmq_msg_size(byref(msg))
+ return string_at(data, data_size)
+ finally:
+ zmq_msg_close(byref(msg))
+
+
+
3  zmq/core/__init__.py
@@ -0,0 +1,3 @@
+from zmq._zmq import *
+
+
3  zmq/core/constants.py
@@ -0,0 +1,3 @@
+from zmq._zmq import *
+
+
3  zmq/core/context.py
@@ -0,0 +1,3 @@
+from zmq._zmq import *
+
+
3  zmq/core/error.py
@@ -0,0 +1,3 @@
+from zmq._zmq import *
+
+
3  zmq/core/socket.py
@@ -0,0 +1,3 @@
+from zmq._zmq import *
+
+
92 zmq/tests/__init__.py
@@ -0,0 +1,92 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import sys
+
+from unittest import TestCase
+
+import zmq
+
+#-----------------------------------------------------------------------------
+# Utilities
+#-----------------------------------------------------------------------------
+
+
+class BaseZMQTestCase(TestCase):
+
+ def setUp(self):
+ self.context = zmq.Context()
+ self.sockets = []
+
+ def tearDown(self):
+ while self.sockets:
+ sock = self.sockets.pop()
+ sock.close()
+ del self.context
+
+
+ def create_bound_pair(self, type1, type2, interface='tcp://127.0.0.1'):
+ """Create a bound socket pair using a random port."""
+ s1 = zmq.Socket(self.context, type1)
+ port = s1.bind_to_random_port(interface)
+ s2 = zmq.Socket(self.context, type2)
+ s2.connect('%s:%s' % (interface, port))
+ self.sockets.extend([s1,s2])
+ return s1, s2
+
+ def ping_pong(self, s1, s2, msg):
+ s1.send(msg)
+ msg2 = s2.recv()
+ s2.send(msg2)
+ msg3 = s1.recv()
+ return msg3
+
+ def ping_pong_json(self, s1, s2, o):
+ s1.send_json(o)
+ o2 = s2.recv_json()
+ s2.send_json(o2)
+ o3 = s1.recv_json()
+ return o3
+
+ def ping_pong_pyobj(self, s1, s2, o):
+ s1.send_pyobj(o)
+ o2 = s2.recv_pyobj()
+ s2.send_pyobj(o2)
+ o3 = s1.recv_pyobj()
+ return o3
+
+ def assertRaisesErrno(self, errno, func, *args, **kwargs):
+ try:
+ func(*args, **kwargs)
+ except zmq.ZMQError:
+ e = sys.exc_info()[1]
+ self.assertEqual(e.errno, errno, "wrong error raised, expected '%s' \
+got '%s'" % (zmq.ZMQError(errno), zmq.ZMQError(e.errno)))
+ else:
+ self.fail("Function did not raise any error")
+
+
+
+class PollZMQTestCase(BaseZMQTestCase):
+ pass
+
61 zmq/tests/test_context.py
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import zmq
+from zmq.tests import BaseZMQTestCase
+
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+
+class TestContext(BaseZMQTestCase):
+
+ def test_init(self):
+ c1 = zmq.Context()
+ self.assert_(isinstance(c1, zmq.Context))
+ del c1
+ c2 = zmq.Context()
+ self.assert_(isinstance(c2, zmq.Context))
+ del c2
+ c3 = zmq.Context()
+ self.assert_(isinstance(c3, zmq.Context))
+ del c3
+
+ def test_term(self):
+ c = zmq.Context()
+ c.term()
+ self.assert_(c.closed)
+
+ def test_fail_init(self):
+ self.assertRaisesErrno(zmq.EINVAL, zmq.Context, 0)
+
+ def test_term_hang(self):
+ rep,req = self.create_bound_pair(zmq.XREP, zmq.XREQ)
+ req.setsockopt(zmq.LINGER, 0)
+ req.send('hello'.encode(), copy=False)
+ req.close()
+ rep.close()
+ self.context.term()
+
114 zmq/tests/test_device.py
@@ -0,0 +1,114 @@
+#
+# Copyright (c) 2010 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
+#-----------------------------------------------------------------------------
+
+import time
+
+import zmq
+from zmq import devices
+from zmq.tests import BaseZMQTestCase
+from zmq.utils.strtypes import (bytes,unicode,basestring)
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+
+class TestDevice(BaseZMQTestCase):
+
+ def test_device_types(self):
+ # a = self.context.socket(zmq.SUB)
+ for devtype in (zmq.STREAMER, zmq.FORWARDER, zmq.QUEUE):
+ dev = devices.Device(devtype, zmq.PAIR,zmq.PAIR)
+ self.assertEquals(dev.device_type, devtype)
+ del dev
+ # del a
+
+ def test_device_attributes(self):
+ # a = self.context.socket(zmq.SUB)
+ # b = self.context.socket(zmq.PUB)
+ dev = devices.Device(zmq.FORWARDER, zmq.SUB, zmq.PUB)
+ self.assert_(dev.in_type == zmq.SUB)
+ self.assert_(dev.out_type == zmq.PUB)
+ self.assertEquals(dev.device_type, zmq.FORWARDER)
+ self.assertEquals(dev.daemon, True)
+ # del a
+ del dev
+
+ def test_tsdevice_attributes(self):
+ dev = devices.Device(zmq.QUEUE, zmq.SUB, zmq.PUB)
+ self.assertEquals(dev.in_type, zmq.SUB)
+ self.assertEquals(dev.out_type, zmq.PUB)
+ self.assertEquals(dev.device_type, zmq.QUEUE)
+ self.assertEquals(dev.daemon, True)
+ del dev
+
+
+ def test_single_socket_forwarder_connect(self):
+ dev = devices.ThreadDevice(zmq.FORWARDER, zmq.REP, -1)
+ req = self.context.socket(zmq.REQ)
+ port = req.bind_to_random_port('tcp://127.0.0.1')
+ dev.connect_in('tcp://127.0.0.1:%i'%port)
+ dev.start()
+ time.sleep(.25)
+ msg = 'hello'.encode()
+ req.send(msg)
+ self.assertEquals(msg, req.recv())
+ del dev
+ del req
+ dev = devices.ThreadDevice(zmq.FORWARDER, zmq.REP, -1)
+ req = self.context.socket(zmq.REQ)
+ port = req.bind_to_random_port('tcp://127.0.0.1')
+ dev.connect_out('tcp://127.0.0.1:%i'%port)
+ dev.start()
+ time.sleep(.25)
+ msg = 'hello again'.encode()
+ req.send(msg)
+ self.assertEquals(msg, req.recv())
+ del dev
+ del req
+
+ def test_single_socket_forwarder_bind(self):
+ dev = devices.ThreadDevice(zmq.FORWARDER, zmq.REP, -1)
+ req = self.context.socket(zmq.REQ)
+ port = 12345
+ req.connect('tcp://127.0.0.1:%i'%port)
+ dev.bind_in('tcp://127.0.0.1:%i'%port)
+ dev.start()
+ time.sleep(.25)
+ msg = 'hello'.encode()
+ req.send(msg)
+ self.assertEquals(msg, req.recv())
+ del dev
+ del req
+ dev = devices.ThreadDevice(zmq.FORWARDER, zmq.REP, -1)
+ req = self.context.socket(zmq.REQ)
+ port = 12346
+ req.connect('tcp://127.0.0.1:%i'%port)
+ dev.bind_in('tcp://127.0.0.1:%i'%port)
+ dev.start()
+ time.sleep(.25)
+ msg = 'hello again'.encode()
+ req.send(msg)
+ self.assertEquals(msg, req.recv())
+ del dev
+ del req
128 zmq/tests/test_log.py
@@ -0,0 +1,128 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import time
+from unittest import TestCase
+
+import zmq
+from zmq.tests import BaseZMQTestCase
+
+from zmq.log import handlers
+import logging
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestPubLog(BaseZMQTestCase):
+
+ iface = 'inproc://zmqlog'
+ topic='zmq'.encode()
+
+ @property
+ def logger(self):
+ # print dir(self)
+ logger = logging.getLogger('zmqtest')
+ logger.setLevel(logging.DEBUG)
+ return logger
+
+ def connect_handler(self):
+ logger = self.logger
+ pub,sub = self.create_bound_pair(zmq.PUB, zmq.SUB)
+ handler = handlers.PUBHandler(pub)
+ handler.setLevel(logging.DEBUG)
+ handler.root_topic = self.topic
+ logger.addHandler(handler)
+ sub.setsockopt(zmq.SUBSCRIBE, self.topic)
+ time.sleep(0.1)
+ return logger, handler, sub
+
+ def test_init_iface(self):
+ logger = self.logger
+ ctx = self.context
+ handler = handlers.PUBHandler(self.iface)
+ self.assertFalse(handler.ctx is ctx)
+ handler.socket.close()
+
+ handler = handlers.PUBHandler(self.iface, self.context)
+ self.assertTrue(handler.ctx is ctx)
+
+ handler.setLevel(logging.DEBUG)
+ handler.root_topic = self.topic
+ logger.addHandler(handler)
+
+ # handler.socket.close()
+ sub = ctx.socket(zmq.SUB)
+ sub.connect(self.iface)
+ sub.setsockopt(zmq.SUBSCRIBE, self.topic)
+ import time; time.sleep(0.1)
+ msg1 = 'message'
+ logger.info(msg1)
+
+ (topic, msg2) = sub.recv_multipart()
+ self.assertEquals(topic, 'zmq.INFO'.encode())
+ self.assertEquals(msg2, (msg1+'\n').encode())
+ logger.removeHandler(handler)
+ # handler.socket.close()
+
+ def test_init_socket(self):
+ pub,sub = self.create_bound_pair(zmq.PUB, zmq.SUB)
+ logger = self.logger
+ handler = handlers.PUBHandler(pub)
+ handler.setLevel(logging.DEBUG)
+ handler.root_topic = self.topic
+ logger.addHandler(handler)
+
+ self.assertTrue(handler.socket is pub)
+ self.assertTrue(handler.ctx is pub.context)
+ self.assertTrue(handler.ctx is self.context)
+ # handler.socket.close()
+ sub.setsockopt(zmq.SUBSCRIBE, self.topic)
+ import time; time.sleep(0.1)
+ msg1 = 'message'
+ logger.info(msg1)
+
+ (topic, msg2) = sub.recv_multipart()
+ self.assertEquals(topic, 'zmq.INFO'.encode())
+ self.assertEquals(msg2, (msg1+'\n').encode())
+ logger.removeHandler(handler)
+ # handler.socket.close()
+
+ def test_root_topic(self):
+ logger, handler, sub = self.connect_handler()
+ handler.socket.bind(self.iface)
+ sub2 = sub.context.socket(zmq.SUB)
+ sub2.connect(self.iface)
+ sub2.setsockopt(zmq.SUBSCRIBE, ''.encode())
+ handler.root_topic = 'twoonly'.encode()
+ msg1 = 'ignored'
+ logger.info(msg1)
+ self.assertRaisesErrno(zmq.EAGAIN, sub.recv, zmq.NOBLOCK)
+ topic,msg2 = sub2.recv_multipart()
+ self.assertEquals(topic, 'twoonly.INFO'.encode())
+ self.assertEquals(msg2, (msg1+'\n').encode())
+
+
+
+ logger.removeHandler(handler)
+
296 zmq/tests/test_message.py
@@ -0,0 +1,296 @@
+#!/usr/bin/env python
+# -*- coding: utf8 -*-
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import copy
+import sys
+from sys import getrefcount as grc
+import time
+from pprint import pprint
+from unittest import TestCase
+
+import zmq
+from zmq.tests import BaseZMQTestCase
+from zmq.utils.strtypes import unicode,bytes
+
+try:
+ from nose import SkipTest
+except ImportError:
+ class SkipTest(Exception):
+ pass
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+x = 'x'.encode()
+
+class TestMessage(BaseZMQTestCase):
+
+ def test_above_30(self):
+ """Message above 30 bytes are never copied by 0MQ."""
+ for i in range(5, 16): # 32, 64,..., 65536
+ s = (2**i)*x
+ self.assertEquals(grc(s), 2)
+ m = zmq.Message(s)
+ self.assertEquals(grc(s), 4)
+ del m
+ self.assertEquals(grc(s), 2)
+ del s
+
+ def test_str(self):
+ """Test the str representations of the Messages."""
+ for i in range(16):
+ s = (2**i)*x
+ m = zmq.Message(s)
+ self.assertEquals(s, str(m).encode())
+
+ def test_bytes(self):
+ """Test the Message.bytes property."""
+ for i in range(1,16):
+ s = (2**i)*x
+ m = zmq.Message(s)
+ b = m.bytes
+ self.assertEquals(s, m.bytes)
+ # check that it copies
+ self.assert_(b is not s)
+ # check that it copies only once
+ self.assert_(b is m.bytes)
+
+ def test_unicode(self):
+ """Test the unicode representations of the Messages."""
+ s = unicode('asdf')
+ self.assertRaises(TypeError, zmq.Message, s)
+ u = '§'
+ if str is not unicode:
+ u = u.decode('utf8')
+ for i in range(16):
+ s = (2**i)*u
+ m = zmq.Message(s.encode('utf8'))
+ self.assertEquals(s, unicode(m.bytes,'utf8'))
+
+ def test_len(self):
+ """Test the len of the Messages."""
+ for i in range(16):
+ s = (2**i)*x
+ m = zmq.Message(s)
+ self.assertEquals(len(s), len(m))
+
+ def test_lifecycle1(self):
+ """Run through a ref counting cycle with a copy."""
+ try:
+ view = memoryview
+ except NameError:
+ view = type(None)
+ for i in range(5, 16): # 32, 64,..., 65536
+ s = (2**i)*x
+ rc = 2
+ self.assertEquals(grc(s), rc)
+ m = zmq.Message(s)
+ rc += 2
+ self.assertEquals(grc(s), rc)
+ m2 = copy.copy(m)
+ rc += 1
+ self.assertEquals(grc(s), rc)
+ b = m2.buffer
+ extra = int(isinstance(b,view))
+ # memoryview incs by 2
+ # buffer by 1
+ rc += 1+extra
+ self.assertEquals(grc(s), rc)
+
+ self.assertEquals(s, str(m).encode())
+ self.assertEquals(s, str(m2).encode())
+ self.assertEquals(s, m.bytes)
+ # self.assert_(s is str(m))
+ # self.assert_(s is str(m2))
+ del m2
+ rc -= 1
+ self.assertEquals(grc(s), rc)
+ rc -= 1+extra
+ del b
+ self.assertEquals(grc(s), rc)
+ del m
+ rc -= 2
+ self.assertEquals(grc(s), rc)
+ self.assertEquals(rc, 2)
+ del s
+
+ def test_lifecycle2(self):
+ """Run through a different ref counting cycle with a copy."""
+ try:
+ view = memoryview
+ except NameError:
+ view = type(None)
+ for i in range(5, 16): # 32, 64,..., 65536
+ s = (2**i)*x
+ rc = 2
+ self.assertEquals(grc(s), rc)
+ m = zmq.Message(s)
+ rc += 2
+ self.assertEquals(grc(s), rc)
+ m2 = copy.copy(m)
+ rc += 1
+ self.assertEquals(grc(s), rc)
+ b = m.buffer
+ extra = int(isinstance(b,view))
+ rc += 1+extra
+ self.assertEquals(grc(s), rc)
+ self.assertEquals(s, str(m).encode())
+ self.assertEquals(s, str(m2).encode())
+ self.assertEquals(s, m2.bytes)
+ self.assertEquals(s, m.bytes)
+ # self.assert_(s is str(m))
+ # self.assert_(s is str(m2))
+ del b
+ self.assertEquals(grc(s), rc)
+ del m
+ # m.buffer is kept until m is del'd
+ rc -= 1+extra
+ rc -= 1
+ self.assertEquals(grc(s), rc)
+ del m2
+ rc -= 2
+ self.assertEquals(grc(s), rc)
+ self.assertEquals(rc, 2)
+ del s
+
+ def test_tracker(self):
+ m = zmq.Message('asdf'.encode(), track=True)
+ self.assertFalse(m.done)
+ pm = zmq.MessageTracker(m)
+ self.assertFalse(pm.done)
+ del m
+ self.assertTrue(pm.done)
+
+ def test_no_tracker(self):
+ m = zmq.Message('asdf'.encode(), track=False)
+ self.assertRaises(ValueError, getattr, m, 'done')
+ m2 = copy.copy(m)
+ self.assertRaises(ValueError, getattr, m2, 'done')
+ self.assertRaises(ValueError, zmq.MessageTracker, m)
+
+ def test_multi_tracker(self):
+ m = zmq.Message('asdf'.encode(), track=True)
+ m2 = zmq.Message('whoda'.encode(), track=True)
+ mt = zmq.MessageTracker(m,m2)
+ self.assertFalse(m.done)
+ self.assertFalse(mt.done)
+ self.assertRaises(zmq.NotDone, mt.wait, 0.1)
+ del m
+ time.sleep(0.1)
+ self.assertRaises(zmq.NotDone, mt.wait, 0.1)
+ self.assertFalse(mt.done)
+ del m2
+ self.assertTrue(mt.wait() is None)
+ self.assertTrue(mt.done)
+
+
+ def test_buffer_in(self):
+ """test using a buffer as input"""
+ try:
+ view = memoryview
+ except NameError:
+ view = buffer
+ if unicode is str:
+ ins = "§§¶•ªº˜µ¬˚…∆˙åß∂©œ∑´†≈ç√".encode('utf8')
+ else:
+ ins = "§§¶•ªº˜µ¬˚…∆˙åß∂©œ∑´†≈ç√"
+ m = zmq.Message(view(ins))
+
+ def test_bad_buffer_in(self):
+ """test using a bad object"""
+ self.assertRaises(TypeError, zmq.Message, 5)
+ self.assertRaises(TypeError, zmq.Message, object())
+
+ def test_buffer_out(self):
+ """receiving buffered output"""
+ try:
+ view = memoryview
+ except NameError:
+ view = buffer
+ if unicode is str:
+ ins = "§§¶•ªº˜µ¬˚…∆˙åß∂©œ∑´†≈ç√".encode('utf8')
+ else:
+ ins = "§§¶•ªº˜µ¬˚…∆˙åß∂©œ∑´†≈ç√"
+ m = zmq.Message(ins)
+ outb = m.buffer
+ self.assertTrue(isinstance(outb, view))
+ self.assert_(outb is m.buffer)
+ self.assert_(m.buffer is m.buffer)
+
+ def test_multisend(self):
+ """ensure that a message remains intact after multiple sends"""
+ a,b = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+ s = "message".encode()
+ m = zmq.Message(s)
+ self.assertEquals(s, m.bytes)
+
+ a.send(m, copy=False)
+ time.sleep(0.1)
+ self.assertEquals(s, m.bytes)
+ a.send(m, copy=False)
+ time.sleep(0.1)
+ self.assertEquals(s, m.bytes)
+ a.send(m, copy=True)
+ time.sleep(0.1)
+ self.assertEquals(s, m.bytes)
+ a.send(m, copy=True)
+ time.sleep(0.1)
+ self.assertEquals(s, m.bytes)
+ for i in range(4):
+ r = b.recv()
+ self.assertEquals(s,r)
+ self.assertEquals(s, m.bytes)
+
+ def test_buffer_numpy(self):
+ """test non-copying numpy array messages"""
+ try:
+ import numpy
+ except ImportError:
+ raise SkipTest
+ shapes = map(numpy.random.randint, [2]*5,[16]*5)
+ for i in range(1,len(shapes)+1):
+ shape = shapes[:i]
+ A = numpy.random.random(shape)
+ m = zmq.Message(A)
+ self.assertEquals(A.data, m.buffer)
+ B = numpy.frombuffer(m.buffer,dtype=A.dtype).reshape(A.shape)
+ self.assertEquals((A==B).all(), True)
+
+ def test_memoryview(self):
+ """test messages from memoryview (only valid for python >= 2.7)"""
+ major,minor = sys.version_info[:2]
+ if not (major >= 3 or (major == 2 and minor >= 7)):
+ raise SkipTest
+
+ s = 'carrotjuice'.encode()
+ v = memoryview(s)
+ m = zmq.Message(s)
+ buf = m.buffer
+ s2 = buf.tobytes()
+ self.assertEquals(s2,s)
+ self.assertEquals(m.bytes,s)
+
+
176 zmq/tests/test_monqueue.py
@@ -0,0 +1,176 @@
+#
+# Copyright (c) 2010 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
+#-----------------------------------------------------------------------------
+
+import time
+from unittest import TestCase
+
+import zmq
+from zmq import devices
+from zmq.tests import BaseZMQTestCase
+
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestMonitoredQueue(BaseZMQTestCase):
+ sockets = []
+ pass
+
+ def build_device(self, mon_sub="".encode(), in_prefix='in'.encode(), out_prefix='out'.encode()):
+ self.device = devices.ThreadMonitoredQueue(zmq.PAIR, zmq.PAIR, zmq.PUB,
+ in_prefix, out_prefix)
+ alice = self.context.socket(zmq.PAIR)
+ bob = self.context.socket(zmq.PAIR)
+ mon = self.context.socket(zmq.SUB)
+
+ aport = alice.bind_to_random_port('tcp://127.0.0.1')
+ bport = bob.bind_to_random_port('tcp://127.0.0.1')
+ mport = mon.bind_to_random_port('tcp://127.0.0.1')
+ mon.setsockopt(zmq.SUBSCRIBE, mon_sub)
+
+ self.device.connect_in("tcp://127.0.0.1:%i"%aport)
+ self.device.connect_out("tcp://127.0.0.1:%i"%bport)
+ self.device.connect_mon("tcp://127.0.0.1:%i"%mport)
+ time.sleep(.2)
+ self.device.start()
+ self.sockets.extend([alice, bob, mon])
+ return alice, bob, mon
+
+
+ def teardown_device(self):
+ for socket in self.sockets:
+ socket.close()
+ del socket
+ del self.device
+
+ def test_reply(self):
+ alice, bob, mon = self.build_device()
+ alices = "hello bob".encode().split()
+ alice.send_multipart(alices)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices, bobs)
+ bobs = "hello alice".encode().split()
+ bob.send_multipart(bobs)
+ alices = alice.recv_multipart()
+ self.assertEquals(alices, bobs)
+ self.teardown_device()
+
+ def test_queue(self):
+ alice, bob, mon = self.build_device()
+ alices = "hello bob".encode().split()
+ alice.send_multipart(alices)
+ alices2 = "hello again".encode().split()
+ alice.send_multipart(alices2)
+ alices3 = "hello again and again".encode().split()
+ alice.send_multipart(alices3)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices, bobs)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices2, bobs)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices3, bobs)
+ bobs = "hello alice".encode().split()
+ bob.send_multipart(bobs)
+ alices = alice.recv_multipart()
+ self.assertEquals(alices, bobs)
+ self.teardown_device()
+
+ def test_monitor(self):
+ alice, bob, mon = self.build_device()
+ alices = "hello bob".encode().split()
+ alice.send_multipart(alices)
+ alices2 = "hello again".encode().split()
+ alice.send_multipart(alices2)
+ alices3 = "hello again and again".encode().split()
+ alice.send_multipart(alices3)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['in'.encode()]+bobs, mons)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices2, bobs)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices3, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['in'.encode()]+alices2, mons)
+ bobs = "hello alice".encode().split()
+ bob.send_multipart(bobs)
+ alices = alice.recv_multipart()
+ self.assertEquals(alices, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['in'.encode()]+alices3, mons)
+ mons = mon.recv_multipart()
+ self.assertEquals(['out'.encode()]+bobs, mons)
+ self.teardown_device()
+
+ def test_prefix(self):
+ alice, bob, mon = self.build_device("".encode(), 'foo'.encode(), 'bar'.encode())
+ alices = "hello bob".encode().split()
+ alice.send_multipart(alices)
+ alices2 = "hello again".encode().split()
+ alice.send_multipart(alices2)
+ alices3 = "hello again and again".encode().split()
+ alice.send_multipart(alices3)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['foo'.encode()]+bobs, mons)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices2, bobs)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices3, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['foo'.encode()]+alices2, mons)
+ bobs = "hello alice".encode().split()
+ bob.send_multipart(bobs)
+ alices = alice.recv_multipart()
+ self.assertEquals(alices, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['foo'.encode()]+alices3, mons)
+ mons = mon.recv_multipart()
+ self.assertEquals(['bar'.encode()]+bobs, mons)
+ self.teardown_device()
+
+ def test_monitor_subscribe(self):
+ alice, bob, mon = self.build_device("out".encode())
+ alices = "hello bob".encode().split()
+ alice.send_multipart(alices)
+ alices2 = "hello again".encode().split()
+ alice.send_multipart(alices2)
+ alices3 = "hello again and again".encode().split()
+ alice.send_multipart(alices3)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices, bobs)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices2, bobs)
+ bobs = bob.recv_multipart()
+ self.assertEquals(alices3, bobs)
+ bobs = "hello alice".encode().split()
+ bob.send_multipart(bobs)
+ alices = alice.recv_multipart()
+ self.assertEquals(alices, bobs)
+ mons = mon.recv_multipart()
+ self.assertEquals(['out'.encode()]+bobs, mons)
+ self.teardown_device()
+
46 zmq/tests/test_multipart.py
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import zmq
+
+from zmq.tests import BaseZMQTestCase
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestMultipart(BaseZMQTestCase):
+
+ def test_xrep_xreq(self):
+ xrep, xreq = self.create_bound_pair(zmq.XREP, zmq.XREQ)
+
+ msg1 = 'message1'.encode()
+ xreq.send(msg1)
+ ident = xrep.recv()
+ more = xrep.rcvmore()
+ self.assertEquals(more, True)
+ msg2 = xrep.recv()
+ self.assertEquals(msg1, msg2)
+ more = xrep.rcvmore()
+ self.assertEquals(more, False)
+
70 zmq/tests/test_pair.py
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import zmq
+
+from zmq.tests import BaseZMQTestCase
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+x = ' '.encode()
+class TestPair(BaseZMQTestCase):
+
+ def test_basic(self):
+ s1, s2 = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+
+ msg1 = 'message1'.encode()
+ msg2 = self.ping_pong(s1, s2, msg1)
+ self.assertEquals(msg1, msg2)
+
+ def test_multiple(self):
+ s1, s2 = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+
+ for i in range(10):
+ msg = i*x
+ s1.send(msg)
+
+ for i in range(10):
+ msg = i*x
+ s2.send(msg)
+
+ for i in range(10):
+ msg = s1.recv()
+ self.assertEquals(msg, i*x)
+
+ for i in range(10):
+ msg = s2.recv()
+ self.assertEquals(msg, i*x)
+
+ def test_json(self):
+ s1, s2 = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+ o = dict(a=10,b=list(range(10)))
+ o2 = self.ping_pong_json(s1, s2, o)
+
+ def test_pyobj(self):
+ s1, s2 = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+ o = dict(a=10,b=range(10))
+ o2 = self.ping_pong_pyobj(s1, s2, o)
+
177 zmq/tests/test_poll.py
@@ -0,0 +1,177 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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
+#-----------------------------------------------------------------------------
+
+import time
+from unittest import TestCase
+
+import zmq
+from zmq.tests import PollZMQTestCase
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+def wait():
+ time.sleep(.25)
+
+
+class TestPoll(PollZMQTestCase):
+
+ # This test is failing due to this issue:
+ # http://github.com/sustrik/zeromq2/issues#issue/26
+ def test_pair(self):
+ s1, s2 = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+
+ # Sleep to allow sockets to connect.
+ wait()
+
+ poller = zmq.Poller()
+ poller.register(s1, zmq.POLLIN|zmq.POLLOUT)
+ poller.register(s2, zmq.POLLIN|zmq.POLLOUT)
+ # Poll result should contain both sockets
+ socks = dict(poller.poll())
+ # Now make sure that both are send ready.
+ self.assertEquals(socks[s1], zmq.POLLOUT)
+ self.assertEquals(socks[s2], zmq.POLLOUT)
+ # Now do a send on both, wait and test for zmq.POLLOUT|zmq.POLLIN
+ s1.send('msg1'.encode())
+ s2.send('msg2'.encode())
+ wait()
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s1], zmq.POLLOUT|zmq.POLLIN)
+ self.assertEquals(socks[s2], zmq.POLLOUT|zmq.POLLIN)
+ # Make sure that both are in POLLOUT after recv.
+ s1.recv()
+ s2.recv()
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s1], zmq.POLLOUT)
+ self.assertEquals(socks[s2], zmq.POLLOUT)
+
+ poller.unregister(s1)
+ poller.unregister(s2)
+
+ # Wait for everything to finish.
+ wait()
+
+ def test_reqrep(self):
+ s1, s2 = self.create_bound_pair(zmq.REP, zmq.REQ)
+
+ # Sleep to allow sockets to connect.
+ wait()
+
+ poller = zmq.Poller()
+ poller.register(s1, zmq.POLLIN|zmq.POLLOUT)
+ poller.register(s2, zmq.POLLIN|zmq.POLLOUT)
+
+ # Make sure that s1 is in state 0 and s2 is in POLLOUT
+ socks = dict(poller.poll())
+ self.assertEquals(s1 in socks, 0)
+ self.assertEquals(socks[s2], zmq.POLLOUT)
+
+ # Make sure that s2 goes immediately into state 0 after send.
+ s2.send('msg1'.encode())
+ socks = dict(poller.poll())
+ self.assertEquals(s2 in socks, 0)
+
+ # Make sure that s1 goes into POLLIN state after a time.sleep().
+ time.sleep(0.5)
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s1], zmq.POLLIN)
+
+ # Make sure that s1 goes into POLLOUT after recv.
+ s1.recv()
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s1], zmq.POLLOUT)
+
+ # Make sure s1 goes into state 0 after send.
+ s1.send('msg2'.encode())
+ socks = dict(poller.poll())
+ self.assertEquals(s1 in socks, 0)
+
+ # Wait and then see that s2 is in POLLIN.
+ time.sleep(0.5)
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s2], zmq.POLLIN)
+
+ # Make sure that s2 is in POLLOUT after recv.
+ s2.recv()
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s2], zmq.POLLOUT)
+
+ poller.unregister(s1)
+ poller.unregister(s2)
+
+ # Wait for everything to finish.
+ wait()
+
+ def test_pubsub(self):
+ s1, s2 = self.create_bound_pair(zmq.PUB, zmq.SUB)
+ s2.setsockopt(zmq.SUBSCRIBE, ''.encode())
+
+ # Sleep to allow sockets to connect.
+ wait()
+
+ poller = zmq.Poller()
+ poller.register(s1, zmq.POLLIN|zmq.POLLOUT)
+ poller.register(s2, zmq.POLLIN)
+
+ # Now make sure that both are send ready.
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s1], zmq.POLLOUT)
+ self.assertEquals(s2 in socks, 0)
+ # Make sure that s1 stays in POLLOUT after a send.
+ s1.send('msg1'.encode())
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s1], zmq.POLLOUT)
+
+ # Make sure that s2 is POLLIN after waiting.
+ wait()
+ socks = dict(poller.poll())
+ self.assertEquals(socks[s2], zmq.POLLIN)
+
+ # Make sure that s2 goes into 0 after recv.
+ s2.recv()
+ socks = dict(poller.poll())
+ self.assertEquals(s2 in socks, 0)
+
+ poller.unregister(s1)
+ poller.unregister(s2)
+
+ # Wait for everything to finish.
+ wait()
+
+class TestSelect(PollZMQTestCase):
+
+ # This test is failing due to this issue:
+ # http://github.com/sustrik/zeromq2/issues#issue/26
+ def test_pair(self):
+ s1, s2 = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
+
+ # Sleep to allow sockets to connect.
+ wait()
+
+ rlist, wlist, xlist = zmq.select([s1, s2], [s1, s2], [s1, s2])
+ self.assert_(s1 in wlist)
+ self.assert_(s2 in wlist)
+ self.assert_(s1 not in rlist)
+ self.assert_(s2 not in rlist)
+
58 zmq/tests/test_pubsub.py
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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 unittest import TestCase
+
+import zmq
+from zmq.tests import BaseZMQTestCase
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestPubSub(BaseZMQTestCase):
+
+ pass
+
+ # We are disabling this test while an issue is being resolved.
+ # def test_basic(self):
+ # s1, s2 = self.create_bound_pair(zmq.PUB, zmq.SUB)
+ # s2.setsockopt(zmq.SUBSCRIBE,'')
+ # import time; time.sleep(0.5)
+ # msg1 = 'message'
+ # s1.send(msg1)
+ # msg2 = s2.recv() # This is blocking!
+ # self.assertEquals(msg1, msg2)
+
+ def test_topic(self):
+ s1, s2 = self.create_bound_pair(zmq.PUB, zmq.SUB)
+ s2.setsockopt(zmq.SUBSCRIBE, 'x'.encode())
+ import time; time.sleep(0.1)
+ msg1 = 'message'.encode()
+ s1.send(msg1)
+ self.assertRaisesErrno(zmq.EAGAIN, s2.recv, zmq.NOBLOCK)
+ msg1 = 'xmessage'.encode()
+ s1.send(msg1)
+ msg2 = s2.recv()
+ self.assertEquals(msg1, msg2)
+
78 zmq/tests/test_reqrep.py
@@ -0,0 +1,78 @@
+#
+# Copyright (c) 2010 Brian E. Granger
+#
+# 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 unittest import TestCase
+
+import zmq
+from zmq.tests import BaseZMQTestCase
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestReqRep(BaseZMQTestCase):
+
+ def test_basic(self):
+ s1, s2 = self.create_bound_pair(zmq.REQ, zmq.REP)
+
+ msg1 = 'message 1'.encode()
+ msg2 = self.ping_pong(s1, s2, msg1)
+ self.assertEquals(msg1, msg2)
+
+ def test_multiple(self):
+ s1, s2 = self.create_bound_pair(zmq.REQ, zmq.REP)
+
+ for i in range(10):
+ msg1 = i*' '.encode()
+ msg2 = self.ping_pong(s1, s2, msg1)
+ self.assertEquals(msg1, msg2)
+
+ def test_bad_send_recv(self):
+ s1, s2 = self.create_bound_pair(zmq.REQ, zmq.REP)
+ for copy in (True,False):
+ self.assertRaisesErrno(zmq.EFSM, s1.recv, copy=copy)
+ self.assertRaisesErrno(zmq.EFSM, s2.send, 'asdf'.encode(), copy=copy)
+
+ # I have to have this or we die on an Abort trap.
+ msg1 = 'asdf'.encode()
+ msg2 = self.ping_pong(s1, s2, msg1)
+ self.assertEquals(msg1, msg2)
+
+ def test_json(self):
+ s1, s2 = self.create_bound_pair(zmq.REQ, zmq.REP)
+ o = dict(a=10,b=list(range(10)))
+ o2 = self.ping_pong_json(s1, s2, o)
+
+ def test_pyobj(self):
+ s1, s2 = self.create_bound_pair(zmq.REQ, zmq.REP)
+ o = dict(a=10,b=range(10))
+ o2 = self.ping_pong_pyobj(s1, s2, o)
+
+ def test_large_msg(self):
+ s1, s2 = self.create_bound_pair(zmq.REQ, zmq.REP)
+ msg1 = 10000*'X'.encode()
+
+ for i in range(10):
+ msg2 = self.ping_pong(s1, s2, msg1)
+ self.assertEquals(msg1, msg2)
+
191 zmq/tests/test_socket.py
@@ -0,0 +1,191 @@