diff options
Diffstat (limited to 'bindings/python')
-rw-r--r-- | bindings/python/Makefile.am | 7 | ||||
-rw-r--r-- | bindings/python/pyzmq.cpp | 528 | ||||
-rw-r--r-- | bindings/python/setup.py.in | 14 |
3 files changed, 549 insertions, 0 deletions
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am new file mode 100644 index 0000000..effe8b9 --- /dev/null +++ b/bindings/python/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/libzmq \ +-I$(top_builddir)/libzmq $(PYTHON_INCLUDES) + +pyexec_LTLIBRARIES = libpyzmq.la +libpyzmq_la_SOURCES = pyzmq.cpp +libpyzmq_la_LIBADD = $(top_builddir)/src/libzmq.la +libpyzmq_la_LDFLAGS = -avoid-version diff --git a/bindings/python/pyzmq.cpp b/bindings/python/pyzmq.cpp new file mode 100644 index 0000000..628d037 --- /dev/null +++ b/bindings/python/pyzmq.cpp @@ -0,0 +1,528 @@ +/* + Copyright (c) 2007-2009 FastMQ Inc. + + 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/>. +*/ + +#include <stddef.h> +#include <assert.h> +#include <errno.h> +#include <string.h> +#include <Python.h> + +#include "../c/zmq.h" + +#if defined _MSC_VER +#pragma warning (push) +#pragma warning (disable:4996) +#endif + +struct context_t +{ + PyObject_HEAD + void *handle; +}; + +PyObject *context_new (PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + context_t *self = (context_t*) type->tp_alloc (type, 0); + + if (self) + self->handle = NULL; + + return (PyObject*) self; +} + + +int context_init (context_t *self, PyObject *args, PyObject *kwdict) +{ + int app_threads; + int io_threads; + static const char *kwlist [] = {"app_threads", "io_threads", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "ii", (char**) kwlist, + &app_threads, &io_threads)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return -1; // ? + } + + assert (!self->handle); + self->handle = zmq_init (app_threads, io_threads); + if (!self->handle) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return -1; // ? + } + + return 0; +} + +void context_dealloc (context_t *self) +{ + if (self->handle) { + int rc = zmq_term (self->handle); + if (rc != 0) + PyErr_SetString (PyExc_SystemError, strerror (errno)); + } + + self->ob_type->tp_free ((PyObject*) self); +} + +struct socket_t +{ + PyObject_HEAD + void *handle; +}; + +PyObject *socket_new (PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + socket_t *self = (socket_t*) type->tp_alloc (type, 0); + + if (self) + self->handle = NULL; + + return (PyObject*) self; +} + +int socket_init (socket_t *self, PyObject *args, PyObject *kwdict) +{ + context_t *context; + int socket_type; + static const char *kwlist [] = {"context", "type", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "Oi", (char**) kwlist, + &context, &socket_type)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + // TODO: Check whether 'context' is really a libpyzmq.Context object. + + assert (!self->handle); + self->handle = zmq_socket (context->handle, socket_type); + if (!self->handle) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return -1; // ? + } + + return 0; +} + +void socket_dealloc (socket_t *self) +{ + if (self->handle) { + int rc = zmq_close (self->handle); + if (rc != 0) + PyErr_SetString (PyExc_SystemError, strerror (errno)); + } + + self->ob_type->tp_free ((PyObject*) self); +} + +PyObject *socket_setsockopt (socket_t *self, PyObject *args, PyObject *kwdict) +{ + int option; + PyObject* optval; + static const char *kwlist [] = {"option", "optval", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "iO", (char**) kwlist, + &option, &optval)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + int rc = 0; + + switch (option) { + case ZMQ_HWM: + case ZMQ_LWM: + case ZMQ_SWAP: + case ZMQ_AFFINITY: + case ZMQ_RATE: + case ZMQ_RECOVERY_IVL: + case ZMQ_MCAST_LOOP: + { + int val = PyInt_AsLong (optval); + rc = zmq_setsockopt (self->handle, option, &val, sizeof (int)); + break; + } + case ZMQ_IDENTITY: + case ZMQ_SUBSCRIBE: + case ZMQ_UNSUBSCRIBE: + + rc = zmq_setsockopt (self->handle, option, PyString_AsString (optval), + PyString_Size (optval)); + break; + + default: + rc = -1; + errno = EINVAL; + } + + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +PyObject *socket_bind (socket_t *self, PyObject *args, PyObject *kwdict) +{ + char const *addr; + static const char *kwlist [] = {"addr", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "s", (char**) kwlist, + &addr)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + int rc = zmq_bind (self->handle, addr); + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +PyObject *socket_connect (socket_t *self, PyObject *args, PyObject *kwdict) +{ + char const *addr; + static const char *kwlist [] = {"addr", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "s", (char**) kwlist, + &addr)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + int rc = zmq_connect (self->handle, addr); + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +PyObject *socket_send (socket_t *self, PyObject *args, PyObject *kwdict) +{ + PyObject *msg; /* = PyString_FromStringAndSize (NULL, 0); */ + int flags = 0; + static const char *kwlist [] = {"msg", "flags", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "S|i", (char**) kwlist, + &msg, &flags)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + zmq_msg_t data; + int rc = zmq_msg_init_size (&data, PyString_Size (msg)); + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return NULL; + } + memcpy (zmq_msg_data (&data), PyString_AsString (msg), + zmq_msg_size (&data)); + + rc = zmq_send (self->handle, &data, flags); + int rc2 = zmq_msg_close (&data); + assert (rc2 == 0); + + if (rc != 0 && errno == EAGAIN) + return PyBool_FromLong (0); + + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return NULL; + } + + return PyBool_FromLong (1); +} + +PyObject *socket_flush (socket_t *self, PyObject *args, PyObject *kwdict) +{ + static const char *kwlist [] = {NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "", (char**) kwlist)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + int rc = zmq_flush (self->handle); + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, strerror (errno)); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +PyObject *socket_recv (socket_t *self, PyObject *args, PyObject *kwdict) +{ + int flags = 0; + static const char *kwlist [] = {"flags", NULL}; + if (!PyArg_ParseTupleAndKeywords (args, kwdict, "|i", (char**) kwlist, + &flags)) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + zmq_msg_t msg; + int rc = zmq_msg_init (&msg); + assert (rc == 0); + + rc = zmq_recv (self->handle, &msg, flags); + + if (rc != 0 && errno == EAGAIN) { + Py_INCREF (Py_None); + return Py_None; + } + + if (rc != 0) { + PyErr_SetString (PyExc_SystemError, "invalid arguments"); + return NULL; + } + + PyObject *result = PyString_FromStringAndSize ((char*) zmq_msg_data (&msg), + zmq_msg_size (&msg)); + rc = zmq_msg_close (&msg); + assert (rc == 0); + return result; +} + +static PyMethodDef context_methods [] = +{ + { + NULL + } +}; + +static PyTypeObject context_type = +{ + PyObject_HEAD_INIT (NULL) + 0, + "libpyzmq.Context", /* tp_name */ + sizeof (context_t), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) context_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + context_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc) context_init, /* tp_init */ + 0, /* tp_alloc */ + context_new /* tp_new */ +}; + +static PyMethodDef socket_methods [] = +{ + { + "setsockopt", + (PyCFunction) socket_setsockopt, + METH_VARARGS | METH_KEYWORDS, + "setsockopt (option, optval) -> None\n\n" + }, + { + "bind", + (PyCFunction) socket_bind, + METH_VARARGS | METH_KEYWORDS, + "bind (addr) -> None\n\n" + }, + { + "connect", + (PyCFunction) socket_connect, + METH_VARARGS | METH_KEYWORDS, + "connect (addr) -> None\n\n" + }, + { + "send", + (PyCFunction) socket_send, + METH_VARARGS | METH_KEYWORDS, + "send (msg, [flags]) -> Bool\n\n" + }, + { + "flush", + (PyCFunction) socket_flush, + METH_VARARGS | METH_KEYWORDS, + "flush () -> None\n\n" + }, + { + "recv", + (PyCFunction) socket_recv, + METH_VARARGS | METH_KEYWORDS, + "recv ([flags]) -> String\n\n" + }, + { + NULL + } +}; + +static PyTypeObject socket_type = +{ + PyObject_HEAD_INIT (NULL) + 0, + "libpyzmq.Socket", /* tp_name */ + sizeof (socket_t), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) socket_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + socket_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc) socket_init, /* tp_init */ + 0, /* tp_alloc */ + socket_new /* tp_new */ +}; + +static PyMethodDef module_methods [] = {{ NULL, NULL, 0, NULL }}; + +static const char* libpyzmq_doc = + "Python API for 0MQ lightweight messaging kernel.\n" + "For more information see http://www.zeromq.org.\n" + "0MQ is distributed under GNU Lesser General Public License v3.\n"; + +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC void +#endif + +PyMODINIT_FUNC initlibpyzmq () +{ + int rc = PyType_Ready (&context_type); + assert (rc == 0); + rc = PyType_Ready (&socket_type); + assert (rc == 0); + + PyObject *module = Py_InitModule3 ("libpyzmq", module_methods, + libpyzmq_doc); + if (!module) + return; + + Py_INCREF (&context_type); + PyModule_AddObject (module, "Context", (PyObject*) &context_type); + Py_INCREF (&socket_type); + PyModule_AddObject (module, "Socket", (PyObject*) &socket_type); + + PyObject *dict = PyModule_GetDict (module); + assert (dict); + PyObject *t; + t = PyInt_FromLong (ZMQ_NOBLOCK); + PyDict_SetItemString (dict, "NOBLOCK", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_NOFLUSH); + PyDict_SetItemString (dict, "NOFLUSH", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_P2P); + PyDict_SetItemString (dict, "P2P", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_PUB); + PyDict_SetItemString (dict, "PUB", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_SUB); + PyDict_SetItemString (dict, "SUB", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_REQ); + PyDict_SetItemString (dict, "REQ", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_REP); + PyDict_SetItemString (dict, "REP", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_HWM); + PyDict_SetItemString (dict, "HWM", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_LWM); + PyDict_SetItemString (dict, "LWM", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_SWAP); + PyDict_SetItemString (dict, "SWAP", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_AFFINITY); + PyDict_SetItemString (dict, "AFFINITY", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_IDENTITY); + PyDict_SetItemString (dict, "IDENTITY", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_SUBSCRIBE); + PyDict_SetItemString (dict, "SUBSCRIBE", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_UNSUBSCRIBE); + PyDict_SetItemString (dict, "UNSUBSCRIBE", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_RATE); + PyDict_SetItemString (dict, "RATE", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_RECOVERY_IVL); + PyDict_SetItemString (dict, "RECOVERY_IVL", t); + Py_DECREF (t); + t = PyInt_FromLong (ZMQ_MCAST_LOOP); + PyDict_SetItemString (dict, "MCAST_LOOP", t); + Py_DECREF (t); + +} + +#if defined _MSC_VER +#pragma warning (pop) +#endif diff --git a/bindings/python/setup.py.in b/bindings/python/setup.py.in new file mode 100644 index 0000000..f7055d5 --- /dev/null +++ b/bindings/python/setup.py.in @@ -0,0 +1,14 @@ +from distutils.core import setup, Extension + +module1 = Extension('libpyzmq', + libraries = ['zmq'], + library_dirs = ['@prefix@/lib'], + include_dirs = ['@PYTHON_SETUP_INCLUDES@','@prefix@/include'], + sources = ['pyzmq.cpp']) + +setup (name = 'libyzmq', + version = '@VERSION@', + description = '0MQ Python library', + ext_modules = [module1]) + + |