├── .gitignore ├── .travis.yml ├── MANIFEST.in ├── Makefile ├── README.md ├── eterm.c ├── eterm.h ├── pyerl.c ├── setup.py └── tests ├── pingpong.erl ├── test_pyerl.py └── test_rpc.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | MANIFEST 3 | build/ 4 | dist/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 2.7 5 | 6 | sudo: required 7 | 8 | before_install: 9 | - sudo apt-get update -qq 10 | - sudo apt-get install -qq erlang-dev 11 | 12 | install: 13 | - pip install . 14 | 15 | script: 16 | - echo "can't test on Travis CI" 17 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Makefile 2 | include *.h 3 | include tests/*.py 4 | include tests/*.erl 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | 3 | all: build 4 | 5 | build: 6 | python setup.py build 7 | cp build/lib.*/*.so ./ 8 | 9 | clean: 10 | rm -rf build/ MANIFEST pyerl.html *.beam 11 | 12 | test: 13 | ./tests/test_pyerl.py 14 | 15 | sdist: 16 | python setup.py sdist 17 | 18 | upload: 19 | python setup.py sdist upload 20 | 21 | doc: 22 | pydoc -w pyerl 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PyErl 2 | ===== 3 | 4 | [![PyPI](https://img.shields.io/pypi/v/PyErl.svg)](https://pypi.python.org/pypi/PyErl/) 5 | [![Build Status](https://travis-ci.org/hamano/python-erlang-interface.svg?branch=master)](https://travis-ci.org/hamano/python-erlang-interface) 6 | [![GitHub license](https://img.shields.io/github/license/hamano/python-erlang-interface.svg)]() 7 | 8 | PyErl is Erlang Interface for Python. which help you integrate 9 | programs written in Python and Erlang. 10 | 11 | DEPENDENCIES 12 | ------------ 13 | 14 | This module requires these other modules and libraries: 15 | 16 | Erlang/OTP R12 or later 17 | 18 | In debian: 19 | ~~~ 20 | apt-get install erlang-dev 21 | ~~~ 22 | 23 | INSTALL 24 | ------- 25 | 26 | ~~~ 27 | python setup.py build 28 | python setup.py install 29 | ~~~ 30 | 31 | EXAMPLE 32 | ------- 33 | 34 | * make erlang terms 35 | 36 | ~~~ 37 | import pyerl 38 | atom = pyerl.mk_atom("hello") 39 | string = pyerl.mk_string("world") 40 | int = pyerl.mk_int(-1) 41 | list = pyerl.mk_list([atom, string, int]) 42 | print list 43 | ~~~ 44 | 45 | * call rpc 46 | 47 | ~~~ 48 | # just call pingpong:ping() in node2@localhost 49 | import pyerl 50 | host = "localhost" 51 | name = "node1" 52 | node = name + "@" + host 53 | cookie = "TESTCOOKIE" 54 | pyerl.connect_xinit(host, name, node, "127.0.0.1", cookie, 1) 55 | pyerl.xconnect("127.0.0.1", "node2") 56 | atom = pyerl.mk_atom("ping") 57 | args = pyerl.mk_list([atom]); 58 | eterm = pyerl.rpc(sock, "pingpong", "ping", args); 59 | pyerl.close_connection(sock); 60 | print eterm 61 | ~~~ 62 | 63 | AUTHER 64 | ------ 65 | Tsukasa Hamano 66 | -------------------------------------------------------------------------------- /eterm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "structmember.h" 3 | #include 4 | #include 5 | #include "eterm.h" 6 | 7 | static void 8 | Eterm_dealloc(EtermObject *self) 9 | { 10 | if(self->term){ 11 | if(ERL_TYPE(self->term) & ERL_COMPOUND){ 12 | erl_free_compound(self->term); 13 | }else{ 14 | erl_free_term(self->term); 15 | } 16 | } 17 | self->ob_type->tp_free((PyObject*)self); 18 | } 19 | 20 | static PyObject * 21 | Eterm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 22 | { 23 | EtermObject *self; 24 | self = (EtermObject *)type->tp_alloc(type, 0); 25 | if (self != NULL) { 26 | self->term = NULL; 27 | } 28 | return (PyObject *)self; 29 | } 30 | 31 | static int 32 | Eterm_init(EtermObject *self, PyObject *args, PyObject *kwds) 33 | { 34 | static char *kwlist[] = {"atom", "binary", "string", NULL}; 35 | const char *atom = NULL; 36 | const char *binary = NULL; 37 | int binary_size = 0; 38 | const char *string = NULL; 39 | 40 | if (!PyArg_ParseTupleAndKeywords( 41 | args, kwds, "|ss#s", kwlist, 42 | &atom, &binary, &binary_size, 43 | &string)){ 44 | return -1; 45 | } 46 | if(atom){ 47 | self->term = erl_mk_atom(atom); 48 | }else if(binary){ 49 | self->term = erl_mk_binary(binary, binary_size); 50 | }else if(string){ 51 | self->term = erl_mk_string(string); 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | static PyMemberDef Eterm_members[] = { 58 | {NULL} /* Sentinel */ 59 | }; 60 | 61 | static PyObject * 62 | Eterm_gettype(EtermObject *self, void *closure) 63 | { 64 | return Py_BuildValue("i", ERL_TYPE(self->term)); 65 | } 66 | 67 | static PyGetSetDef Eterm_getseters[] = { 68 | {"type", (getter)Eterm_gettype, NULL, NULL, NULL}, 69 | {NULL} /* Sentinel */ 70 | }; 71 | 72 | static PyObject * 73 | Eterm_print_term(EtermObject *self, PyObject *args) 74 | { 75 | int ret = 0; 76 | PyObject *stream = NULL; 77 | FILE *fp = stdout; 78 | 79 | if (!PyArg_ParseTuple(args, "|O", &stream)){ 80 | return NULL; 81 | } 82 | if(stream && PyFile_Check(stream)){ 83 | fp = PyFile_AsFile(stream); 84 | } 85 | if(self->term){ 86 | ret = erl_print_term(fp, self->term); 87 | fprintf(fp, "\n"); 88 | } 89 | return Py_BuildValue("i", ret); 90 | } 91 | 92 | static PyObject * 93 | Eterm_is_integer(EtermObject *self) 94 | { 95 | if(ERL_IS_INTEGER(self->term)){ 96 | Py_RETURN_TRUE; 97 | }else{ 98 | Py_RETURN_FALSE; 99 | } 100 | } 101 | 102 | static PyObject * 103 | Eterm_is_unsigned_integer(EtermObject *self) 104 | { 105 | if(ERL_IS_UNSIGNED_INTEGER(self->term)){ 106 | Py_RETURN_TRUE; 107 | }else{ 108 | Py_RETURN_FALSE; 109 | } 110 | } 111 | 112 | static PyObject * 113 | Eterm_is_float(EtermObject *self) 114 | { 115 | if(ERL_IS_FLOAT(self->term)){ 116 | Py_RETURN_TRUE; 117 | }else{ 118 | Py_RETURN_FALSE; 119 | } 120 | } 121 | 122 | static PyObject * 123 | Eterm_is_atom(EtermObject *self) 124 | { 125 | if(ERL_IS_ATOM(self->term)){ 126 | Py_RETURN_TRUE; 127 | }else{ 128 | Py_RETURN_FALSE; 129 | } 130 | } 131 | 132 | static PyObject * 133 | Eterm_is_pid(EtermObject *self) 134 | { 135 | if(ERL_IS_PID(self->term)){ 136 | Py_RETURN_TRUE; 137 | }else{ 138 | Py_RETURN_FALSE; 139 | } 140 | } 141 | 142 | static PyObject * 143 | Eterm_is_port(EtermObject *self) 144 | { 145 | if(ERL_IS_PORT(self->term)){ 146 | Py_RETURN_TRUE; 147 | }else{ 148 | Py_RETURN_FALSE; 149 | } 150 | } 151 | 152 | static PyObject * 153 | Eterm_is_ref(EtermObject *self) 154 | { 155 | if(ERL_IS_REF(self->term)){ 156 | Py_RETURN_TRUE; 157 | }else{ 158 | Py_RETURN_FALSE; 159 | } 160 | } 161 | 162 | static PyObject * 163 | Eterm_is_tuple(EtermObject *self) 164 | { 165 | if(ERL_IS_TUPLE(self->term)){ 166 | Py_RETURN_TRUE; 167 | }else{ 168 | Py_RETURN_FALSE; 169 | } 170 | } 171 | 172 | static PyObject * 173 | Eterm_is_binary(EtermObject *self) 174 | { 175 | if(ERL_IS_BINARY(self->term)){ 176 | Py_RETURN_TRUE; 177 | }else{ 178 | Py_RETURN_FALSE; 179 | } 180 | } 181 | 182 | static PyObject * 183 | Eterm_is_nil(EtermObject *self) 184 | { 185 | if(ERL_IS_NIL(self->term)){ 186 | Py_RETURN_TRUE; 187 | }else{ 188 | Py_RETURN_FALSE; 189 | } 190 | } 191 | 192 | static PyObject * 193 | Eterm_is_empty_list(EtermObject *self) 194 | { 195 | if(ERL_IS_LIST(self->term)){ 196 | Py_RETURN_TRUE; 197 | }else{ 198 | Py_RETURN_FALSE; 199 | } 200 | } 201 | 202 | static PyObject * 203 | Eterm_is_cons(EtermObject *self) 204 | { 205 | if(ERL_IS_CONS(self->term)){ 206 | Py_RETURN_TRUE; 207 | }else{ 208 | Py_RETURN_FALSE; 209 | } 210 | } 211 | 212 | static PyObject * 213 | Eterm_is_list(EtermObject *self) 214 | { 215 | if(ERL_IS_LIST(self->term)){ 216 | Py_RETURN_TRUE; 217 | }else{ 218 | Py_RETURN_FALSE; 219 | } 220 | } 221 | 222 | #ifdef ERL_IS_LONGLONG 223 | static PyObject * 224 | Eterm_is_longlong(EtermObject *self) 225 | { 226 | if(ERL_IS_LONGLONG(self->term)){ 227 | Py_RETURN_TRUE; 228 | }else{ 229 | Py_RETURN_FALSE; 230 | } 231 | } 232 | #endif 233 | 234 | #ifdef ERL_IS_UNSIGNED_LONGLONG 235 | static PyObject * 236 | Eterm_is_unsigned_longlong(EtermObject *self) 237 | { 238 | if(ERL_IS_UNSIGNED_LONGLONG(self->term)){ 239 | Py_RETURN_TRUE; 240 | }else{ 241 | Py_RETURN_FALSE; 242 | } 243 | } 244 | #endif 245 | 246 | static PyMethodDef Eterm_methods[] = { 247 | {"print_term", (PyCFunction)Eterm_print_term, METH_VARARGS, 248 | "print EtermObject" 249 | }, 250 | {"is_integer", (PyCFunction)Eterm_is_integer, METH_NOARGS, NULL}, 251 | {"is_unsigned_integer", (PyCFunction)Eterm_is_unsigned_integer, 252 | METH_NOARGS, NULL}, 253 | {"is_float", (PyCFunction)Eterm_is_float, METH_NOARGS, NULL}, 254 | {"is_atom", (PyCFunction)Eterm_is_atom, METH_NOARGS, NULL}, 255 | {"is_pid", (PyCFunction)Eterm_is_pid, METH_NOARGS, NULL}, 256 | {"is_port", (PyCFunction)Eterm_is_port, METH_NOARGS, NULL}, 257 | {"is_ref", (PyCFunction)Eterm_is_ref, METH_NOARGS, NULL}, 258 | {"is_tuple", (PyCFunction)Eterm_is_tuple, METH_NOARGS, NULL}, 259 | {"is_binary", (PyCFunction)Eterm_is_binary, METH_NOARGS, NULL}, 260 | {"is_nil", (PyCFunction)Eterm_is_nil, METH_NOARGS, NULL}, 261 | {"is_empty_list", (PyCFunction)Eterm_is_empty_list, METH_NOARGS, NULL}, 262 | {"is_cons", (PyCFunction)Eterm_is_cons, METH_NOARGS, NULL}, 263 | {"is_list", (PyCFunction)Eterm_is_list, METH_NOARGS, NULL}, 264 | #ifdef ERL_IS_LONGLONG 265 | {"is_longlong", (PyCFunction)Eterm_is_longlong, METH_NOARGS, NULL}, 266 | #endif 267 | #ifdef ERL_IS_UNSIGNED_LONGLONG 268 | {"is_unsigned_longlong", (PyCFunction)Eterm_is_unsigned_longlong, 269 | METH_NOARGS, NULL}, 270 | #endif 271 | {NULL} /* Sentinel */ 272 | }; 273 | 274 | static PyObject * 275 | Eterm_str(PyObject *self) 276 | { 277 | PyObject *ret; 278 | EtermObject *eterm = (EtermObject *)self; 279 | ei_x_buff buf; 280 | char *s = NULL; 281 | int i = 0; 282 | 283 | ei_x_new(&buf); 284 | ei_x_encode_term(&buf, eterm->term); 285 | ei_s_print_term(&s, buf.buff, &i); 286 | ret = PyString_FromString(s); 287 | free(s); 288 | return ret; 289 | } 290 | 291 | PyTypeObject EtermType = { 292 | PyObject_HEAD_INIT(NULL) 293 | 0, /*ob_size*/ 294 | "pyerl.Eterm", /*tp_name*/ 295 | sizeof(EtermObject), /*tp_basicsize*/ 296 | 0, /*tp_itemsize*/ 297 | (destructor)Eterm_dealloc, /*tp_dealloc*/ 298 | 0, /*tp_print*/ 299 | 0, /*tp_getattr*/ 300 | 0, /*tp_setattr*/ 301 | 0, /*tp_compare*/ 302 | 0, /*tp_repr*/ 303 | 0, /*tp_as_number*/ 304 | 0, /*tp_as_sequence*/ 305 | 0, /*tp_as_mapping*/ 306 | 0, /*tp_hash */ 307 | 0, /*tp_call*/ 308 | Eterm_str, /*tp_str*/ 309 | 0, /*tp_getattro*/ 310 | 0, /*tp_setattro*/ 311 | 0, /*tp_as_buffer*/ 312 | Py_TPFLAGS_DEFAULT, /*tp_flags*/ 313 | "Eterm objects", /* tp_doc */ 314 | 0, /* tp_traverse */ 315 | 0, /* tp_clear */ 316 | 0, /* tp_richcompare */ 317 | 0, /* tp_weaklistoffset */ 318 | 0, /* tp_iter */ 319 | 0, /* tp_iternext */ 320 | Eterm_methods, /* tp_methods */ 321 | Eterm_members, /* tp_members */ 322 | Eterm_getseters, /* tp_getset */ 323 | 0, /* tp_base */ 324 | 0, /* tp_dict */ 325 | 0, /* tp_descr_get */ 326 | 0, /* tp_descr_set */ 327 | 0, /* tp_dictoffset */ 328 | (initproc)Eterm_init, /* tp_init */ 329 | 0, /* tp_alloc */ 330 | Eterm_new, /* tp_new */ 331 | }; 332 | -------------------------------------------------------------------------------- /eterm.h: -------------------------------------------------------------------------------- 1 | #ifndef HAVE_PYERL_ETERM_H 2 | #define HAVE_PYERL_ETERM_H 3 | 4 | #include 5 | 6 | extern PyTypeObject EtermType; 7 | 8 | typedef struct { 9 | PyObject_HEAD 10 | ETERM *term; 11 | /* Type-specific fields go here. */ 12 | } EtermObject; 13 | 14 | #endif /* HAVE_PYERL_ETERM_H */ 15 | -------------------------------------------------------------------------------- /pyerl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "structmember.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "eterm.h" 9 | 10 | static char pyerl_doc[] = "Erlang Interface for Python\n"; 11 | 12 | static PyObject * 13 | pyerl_init(PyObject *self, PyObject *args) 14 | { 15 | int x = 0; 16 | int y = 0; 17 | if(!PyArg_ParseTuple(args, "|ii", &x, &y)){ 18 | return NULL; 19 | } 20 | erl_init((void *)x, y); 21 | Py_RETURN_NONE; 22 | } 23 | 24 | static PyObject * 25 | pyerl_set_compat_rel(PyObject *self, PyObject *args) 26 | { 27 | unsigned int rel; 28 | if(!PyArg_ParseTuple(args, "I", &rel)){ 29 | return NULL; 30 | } 31 | erl_set_compat_rel(rel); 32 | Py_RETURN_NONE; 33 | } 34 | 35 | static PyObject * 36 | pyerl_connect_init(PyObject *self, PyObject *args) 37 | { 38 | int ret; 39 | int number; 40 | char *cookie; 41 | short creation; 42 | 43 | if(!PyArg_ParseTuple(args, "ish", &number, &cookie, &creation)){ 44 | return NULL; 45 | } 46 | ret = erl_connect_init(number, cookie, creation); 47 | return PyInt_FromLong(ret); 48 | } 49 | 50 | static PyObject * 51 | pyerl_connect_xinit(PyObject *self, PyObject *args) 52 | { 53 | int ret; 54 | char *host, *alive, *node, *addr; 55 | char *cookie; 56 | short creation; 57 | struct in_addr ia; 58 | 59 | if(!PyArg_ParseTuple(args, "sssssh", 60 | &host, &alive, &node, &addr, &cookie, &creation)){ 61 | return NULL; 62 | } 63 | ia.s_addr = inet_addr(addr); 64 | ret = erl_connect_xinit(host ,alive, node, &ia, cookie, creation); 65 | return PyInt_FromLong(ret); 66 | } 67 | 68 | static PyObject * 69 | pyerl_connect(PyObject *self, PyObject *args) 70 | { 71 | int ret; 72 | char *node; 73 | 74 | if(!PyArg_ParseTuple(args, "s", &node)) 75 | return NULL; 76 | ret = erl_connect(node); 77 | return PyInt_FromLong(ret); 78 | } 79 | 80 | static PyObject * 81 | pyerl_xconnect(PyObject *self, PyObject *args) 82 | { 83 | int ret; 84 | char *addr, *alive; 85 | struct in_addr ia; 86 | 87 | if(!PyArg_ParseTuple(args, "ss", &addr, &alive)) 88 | return NULL; 89 | ia.s_addr = inet_addr(addr); 90 | ret = erl_xconnect(&ia, alive); 91 | return PyInt_FromLong(ret); 92 | } 93 | 94 | static PyObject * 95 | pyerl_close_connection(PyObject *self, PyObject *args) 96 | { 97 | int ret; 98 | int fd; 99 | if(!PyArg_ParseTuple(args, "i", &fd)){ 100 | return NULL; 101 | } 102 | ret = erl_close_connection(fd); 103 | return PyInt_FromLong(ret); 104 | } 105 | 106 | static PyObject * 107 | pyerl_xreceive_msg(PyObject *self, PyObject *args) 108 | { 109 | int ret; 110 | int fd; 111 | int size = 1024; 112 | unsigned char *buf = malloc(size); 113 | ErlMessage emsg; 114 | EtermObject *msg; 115 | 116 | if(!PyArg_ParseTuple(args, "i", &fd)){ 117 | return NULL; 118 | } 119 | if(fd < 0){ 120 | PyErr_SetString(PyExc_IOError, "Invalid descriptor."); 121 | return NULL; 122 | } 123 | if(!(msg = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 124 | return PyErr_NoMemory(); 125 | } 126 | ret = erl_xreceive_msg(fd, &buf, &size, &emsg); 127 | msg->term = erl_copy_term(emsg.msg); 128 | /* TODO: bad return */ 129 | return Py_BuildValue("iO", ret, msg); 130 | } 131 | 132 | static PyObject * 133 | pyerl_send(PyObject *self, PyObject *args) 134 | { 135 | int ret; 136 | int fd; 137 | PyObject *to; 138 | PyObject *msg; 139 | EtermObject *eto; 140 | EtermObject *emsg; 141 | 142 | if(!PyArg_ParseTuple(args, "iOO", &fd, &to, &msg)){ 143 | return NULL; 144 | } 145 | if(fd < 0){ 146 | PyErr_SetString(PyExc_IOError, "Invalid descriptor."); 147 | return NULL; 148 | } 149 | if(!PyObject_TypeCheck(to, &EtermType) || 150 | !PyObject_TypeCheck(msg, &EtermType)){ 151 | return NULL; 152 | } 153 | eto = (EtermObject *)to; 154 | emsg = (EtermObject *)msg; 155 | ret = erl_send(fd, eto->term, emsg->term); 156 | return PyInt_FromLong(ret); 157 | } 158 | 159 | static PyObject * 160 | pyerl_reg_send(PyObject *self, PyObject *args) 161 | { 162 | int ret; 163 | int fd; 164 | char *to; 165 | PyObject *msg; 166 | EtermObject *emsg; 167 | 168 | if(!PyArg_ParseTuple(args, "isO", &fd, &to, &msg)){ 169 | return NULL; 170 | } 171 | if(fd < 0){ 172 | PyErr_SetString(PyExc_IOError, "Invalid descriptor."); 173 | return NULL; 174 | } 175 | if(!PyObject_TypeCheck(msg, &EtermType)){ 176 | return NULL; 177 | } 178 | emsg = (EtermObject *)msg; 179 | ret = erl_reg_send(fd, to, emsg->term); 180 | return PyInt_FromLong(ret); 181 | } 182 | 183 | static PyObject * 184 | pyerl_rpc(PyObject *self, PyObject *args) 185 | { 186 | EtermObject *ret; 187 | int fd; 188 | char *mod, *fun; 189 | EtermObject *arg; 190 | 191 | if(!PyArg_ParseTuple(args, "issO", &fd, &mod, &fun, &arg)){ 192 | return NULL; 193 | } 194 | if(fd < 0){ 195 | PyErr_SetString(PyExc_IOError, "Invalid descriptor."); 196 | return NULL; 197 | } 198 | if(!PyObject_TypeCheck(arg, &EtermType)){ 199 | return NULL; 200 | } 201 | if(!(ret = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 202 | return PyErr_NoMemory(); 203 | } 204 | ret->term = erl_rpc(fd, mod, fun, arg->term); 205 | return (PyObject *)ret; 206 | } 207 | 208 | static PyObject * 209 | pyerl_publish(PyObject *self, PyObject *args) 210 | { 211 | int ret; 212 | int port; 213 | if(!PyArg_ParseTuple(args, "i", &port)){ 214 | return NULL; 215 | } 216 | ret = erl_publish(port); 217 | return PyInt_FromLong(ret); 218 | } 219 | 220 | static PyObject * 221 | pyerl_unpublish(PyObject *self, PyObject *args) 222 | { 223 | int ret; 224 | char *alive; 225 | 226 | if(!PyArg_ParseTuple(args, "s", &alive)) 227 | return NULL; 228 | ret = erl_unpublish(alive); 229 | return PyInt_FromLong(ret); 230 | } 231 | 232 | static PyObject * 233 | pyerl_thiscookie(PyObject *self, PyObject *args) 234 | { 235 | const char *ret; 236 | ret = erl_thiscookie(); 237 | return Py_BuildValue("s", ret); 238 | } 239 | 240 | static PyObject * 241 | pyerl_thisnodename(PyObject *self, PyObject *args) 242 | { 243 | const char *ret; 244 | ret = erl_thisnodename(); 245 | return Py_BuildValue("s", ret); 246 | } 247 | 248 | static PyObject * 249 | pyerl_thishostname(PyObject *self, PyObject *args) 250 | { 251 | const char *ret; 252 | ret = erl_thishostname(); 253 | return Py_BuildValue("s", ret); 254 | } 255 | 256 | static PyObject * 257 | pyerl_thisalivename(PyObject *self, PyObject *args) 258 | { 259 | const char *ret; 260 | ret = erl_thishostname(); 261 | return Py_BuildValue("s", ret); 262 | } 263 | 264 | static PyObject * 265 | pyerl_thiscreation(PyObject *self, PyObject *args) 266 | { 267 | int ret; 268 | ret = erl_thiscreation(); 269 | return PyInt_FromLong(ret); 270 | } 271 | 272 | 273 | static PyObject * 274 | pyerl_cons(PyObject *self, PyObject *args) 275 | { 276 | EtermObject *ret; 277 | PyObject *head; 278 | PyObject *tail; 279 | EtermObject *ehead; 280 | EtermObject *etail; 281 | 282 | if(!PyArg_ParseTuple(args, "OO", &head, &tail)){ 283 | return NULL; 284 | } 285 | if(!PyObject_TypeCheck(head, &EtermType)|| 286 | !PyObject_TypeCheck(tail, &EtermType)){ 287 | return NULL; 288 | } 289 | ehead = (EtermObject *)head; 290 | etail = (EtermObject *)tail; 291 | if(!ehead->term || !etail->term){ 292 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 293 | return NULL; 294 | } 295 | if(!(ret = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 296 | return PyErr_NoMemory(); 297 | } 298 | if(!(ret->term = erl_cons(ehead->term, etail->term))){ 299 | EtermType.tp_dealloc((PyObject *)ret); 300 | return PyErr_NoMemory(); 301 | } 302 | return (PyObject *)ret; 303 | } 304 | 305 | static PyObject * 306 | pyerl_copy_term(PyObject *self, PyObject *args) 307 | { 308 | EtermObject *ret; 309 | PyObject *term; 310 | EtermObject *eterm; 311 | 312 | if(!PyArg_ParseTuple(args, "O", &term)){ 313 | return NULL; 314 | } 315 | if(!PyObject_TypeCheck(term, &EtermType)){ 316 | return NULL; 317 | } 318 | 319 | if(!(ret = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 320 | return PyErr_NoMemory(); 321 | } 322 | eterm = (EtermObject *)term; 323 | if(!eterm->term){ 324 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 325 | return NULL; 326 | } 327 | if(!(ret->term = erl_copy_term(eterm->term))){ 328 | EtermType.tp_dealloc((PyObject *)ret); 329 | return PyErr_NoMemory(); 330 | } 331 | return (PyObject *)ret; 332 | } 333 | 334 | static PyObject * 335 | pyerl_element(PyObject *self, PyObject *args) 336 | { 337 | EtermObject *ret; 338 | int position; 339 | PyObject *tuple; 340 | EtermObject *etuple; 341 | int size; 342 | 343 | if(!PyArg_ParseTuple(args, "iO", &position, &tuple)){ 344 | return NULL; 345 | } 346 | if(!PyObject_TypeCheck(tuple, &EtermType)){ 347 | return NULL; 348 | } 349 | if(!(ret = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 350 | return PyErr_NoMemory(); 351 | } 352 | etuple = (EtermObject *)tuple; 353 | if(!etuple->term){ 354 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 355 | return NULL; 356 | } 357 | size = erl_size(etuple->term); 358 | if(position < 1 || position > size){ 359 | PyErr_SetString(PyExc_IndexError, "Index out of range."); 360 | return NULL; 361 | } 362 | ret->term = erl_element(position, etuple->term); 363 | return Py_BuildValue("O", ret); 364 | } 365 | 366 | static PyObject * 367 | pyerl_hd(PyObject *self, PyObject *args) 368 | { 369 | EtermObject *ret; 370 | PyObject *term; 371 | EtermObject *eterm; 372 | 373 | if(!PyArg_ParseTuple(args, "O", &term)){ 374 | return NULL; 375 | } 376 | if(!PyObject_TypeCheck(term, &EtermType)){ 377 | return NULL; 378 | } 379 | if(!(ret = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 380 | return PyErr_NoMemory(); 381 | } 382 | eterm = (EtermObject *)term; 383 | if(!eterm->term){ 384 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 385 | return NULL; 386 | } 387 | ret->term = erl_hd(eterm->term); 388 | if(!ret->term){ 389 | EtermType.tp_dealloc((PyObject *)ret); 390 | Py_RETURN_NONE; 391 | } 392 | return Py_BuildValue("O", ret); 393 | } 394 | 395 | static PyObject * 396 | pyerl_tl(PyObject *self, PyObject *args) 397 | { 398 | EtermObject *ret; 399 | PyObject *term; 400 | EtermObject *eterm; 401 | 402 | if(!PyArg_ParseTuple(args, "O", &term)){ 403 | return NULL; 404 | } 405 | if(!PyObject_TypeCheck(term, &EtermType)){ 406 | return NULL; 407 | } 408 | if(!(ret = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 409 | return PyErr_NoMemory(); 410 | } 411 | eterm = (EtermObject *)term; 412 | if(!eterm->term){ 413 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 414 | return NULL; 415 | } 416 | ret->term = erl_tl(eterm->term); 417 | if(!ret->term){ 418 | EtermType.tp_dealloc((PyObject *)ret); 419 | Py_RETURN_NONE; 420 | } 421 | return Py_BuildValue("O", ret); 422 | } 423 | 424 | static PyObject * 425 | pyerl_mk_atom(PyObject *self, PyObject *args) 426 | { 427 | EtermObject *eterm; 428 | const char *string; 429 | 430 | if(!PyArg_ParseTuple(args, "s", &string)){ 431 | return NULL; 432 | } 433 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 434 | return NULL; 435 | } 436 | if(!(eterm->term = erl_mk_atom(string))){ 437 | EtermType.tp_dealloc((PyObject *)eterm); 438 | return NULL; 439 | } 440 | return (PyObject *)eterm; 441 | } 442 | 443 | static PyObject * 444 | pyerl_mk_binary(PyObject *self, PyObject *args) 445 | { 446 | EtermObject *eterm; 447 | const char *bptr; 448 | int size; 449 | 450 | if(!PyArg_ParseTuple(args, "s#", &bptr, &size)){ 451 | return NULL; 452 | } 453 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 454 | return PyErr_NoMemory(); 455 | } 456 | if(!(eterm->term = erl_mk_binary(bptr, size))){ 457 | EtermType.tp_dealloc((PyObject *)eterm); 458 | return PyErr_NoMemory(); 459 | } 460 | return (PyObject *)eterm; 461 | } 462 | 463 | static PyObject * 464 | pyerl_mk_empty_list(PyObject *self, PyObject *args) 465 | { 466 | EtermObject *eterm; 467 | 468 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 469 | return NULL; 470 | } 471 | if(!(eterm->term = erl_mk_empty_list())){ 472 | EtermType.tp_dealloc((PyObject *)eterm); 473 | return PyErr_NoMemory(); 474 | } 475 | return (PyObject *)eterm; 476 | } 477 | 478 | static PyObject * 479 | pyerl_mk_estring(PyObject *self, PyObject *args) 480 | { 481 | EtermObject *eterm; 482 | const char *string; 483 | int len; 484 | 485 | if(!PyArg_ParseTuple(args, "s#", &string, &len)){ 486 | return NULL; 487 | } 488 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 489 | return PyErr_NoMemory(); 490 | } 491 | if(!(eterm->term = erl_mk_estring(string, len))){ 492 | EtermType.tp_dealloc((PyObject *)eterm); 493 | return PyErr_NoMemory(); 494 | } 495 | return (PyObject *)eterm; 496 | } 497 | 498 | static PyObject * 499 | pyerl_mk_float(PyObject *self, PyObject *args) 500 | { 501 | EtermObject *eterm; 502 | double f; 503 | 504 | if(!PyArg_ParseTuple(args, "d", &f)){ 505 | return NULL; 506 | } 507 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 508 | return PyErr_NoMemory(); 509 | } 510 | if(!(eterm->term = erl_mk_float(f))){ 511 | EtermType.tp_dealloc((PyObject *)eterm); 512 | return PyErr_NoMemory(); 513 | } 514 | return (PyObject *)eterm; 515 | } 516 | 517 | static PyObject * 518 | pyerl_mk_int(PyObject *self, PyObject *args) 519 | { 520 | EtermObject *eterm; 521 | int n; 522 | 523 | if(!PyArg_ParseTuple(args, "i", &n)){ 524 | return NULL; 525 | } 526 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 527 | return PyErr_NoMemory(); 528 | } 529 | if(!(eterm->term = erl_mk_int(n))){ 530 | EtermType.tp_dealloc((PyObject *)eterm); 531 | return PyErr_NoMemory(); 532 | } 533 | return (PyObject *)eterm; 534 | } 535 | 536 | static PyObject * 537 | pyerl_mk_list(PyObject *self, PyObject *args) 538 | { 539 | EtermObject *eterm; 540 | PyObject *array; 541 | Py_ssize_t size; 542 | int i; 543 | PyObject *obj; 544 | EtermObject *eobj; 545 | ETERM **eterm_array; 546 | 547 | if(!PyArg_ParseTuple(args, "O", &array)){ 548 | return NULL; 549 | } 550 | if(!PyList_Check(array)){ 551 | return NULL; 552 | } 553 | size = PyList_Size(array); 554 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 555 | return PyErr_NoMemory(); 556 | } 557 | eterm_array = (ETERM **)malloc(sizeof(ETERM *) * size); 558 | for(i=0; iterm); 565 | } 566 | 567 | if(!(eterm->term = erl_mk_list(eterm_array, size))){ 568 | free(eterm_array); 569 | EtermType.tp_dealloc((PyObject *)eterm); 570 | return PyErr_NoMemory(); 571 | } 572 | free(eterm_array); 573 | return (PyObject *)eterm; 574 | } 575 | 576 | static PyObject * 577 | pyerl_mk_pid(PyObject *self, PyObject *args) 578 | { 579 | EtermObject *eterm; 580 | const char *node; 581 | unsigned int number; 582 | unsigned int serial; 583 | unsigned int creation; 584 | 585 | if(!PyArg_ParseTuple(args, "sIII", &node, &number, &serial, &creation)){ 586 | return NULL; 587 | } 588 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 589 | return PyErr_NoMemory(); 590 | } 591 | if(!(eterm->term = erl_mk_pid(node, number, serial, creation))){ 592 | EtermType.tp_dealloc((PyObject *)eterm); 593 | return PyErr_NoMemory(); 594 | } 595 | return (PyObject *)eterm; 596 | } 597 | 598 | static PyObject * 599 | pyerl_mk_port(PyObject *self, PyObject *args) 600 | { 601 | EtermObject *eterm; 602 | const char *node; 603 | unsigned int number; 604 | unsigned int creation; 605 | 606 | if(!PyArg_ParseTuple(args, "sII", &node, &number, &creation)){ 607 | return NULL; 608 | } 609 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 610 | return PyErr_NoMemory(); 611 | } 612 | if(!(eterm->term = erl_mk_port(node, number, creation))){ 613 | EtermType.tp_dealloc((PyObject *)eterm); 614 | return PyErr_NoMemory(); 615 | } 616 | return (PyObject *)eterm; 617 | } 618 | 619 | static PyObject * 620 | pyerl_mk_ref(PyObject *self, PyObject *args) 621 | { 622 | EtermObject *eterm; 623 | const char *node; 624 | unsigned int number; 625 | unsigned int creation; 626 | 627 | if(!PyArg_ParseTuple(args, "sII", &node, &number, &creation)){ 628 | return NULL; 629 | } 630 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 631 | return PyErr_NoMemory(); 632 | } 633 | if(!(eterm->term = erl_mk_ref(node, number, creation))){ 634 | EtermType.tp_dealloc((PyObject *)eterm); 635 | return PyErr_NoMemory(); 636 | } 637 | return (PyObject *)eterm; 638 | } 639 | 640 | static PyObject * 641 | pyerl_mk_long_ref(PyObject *self, PyObject *args) 642 | { 643 | EtermObject *eterm; 644 | const char *node; 645 | unsigned int n1, n2, n3; 646 | unsigned int creation; 647 | 648 | if(!PyArg_ParseTuple(args, "sIIII", &node, &n1, &n2, &n3, &creation)){ 649 | return NULL; 650 | } 651 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 652 | return PyErr_NoMemory(); 653 | } 654 | if(!(eterm->term = erl_mk_long_ref(node, n1, n2, n3, creation))){ 655 | EtermType.tp_dealloc((PyObject *)eterm); 656 | return PyErr_NoMemory(); 657 | } 658 | return (PyObject *)eterm; 659 | } 660 | 661 | static PyObject * 662 | pyerl_mk_string(PyObject *self, PyObject *args) 663 | { 664 | EtermObject *eterm; 665 | const char *string; 666 | 667 | if(!PyArg_ParseTuple(args, "s", &string)){ 668 | return NULL; 669 | } 670 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 671 | return PyErr_NoMemory(); 672 | } 673 | if(!(eterm->term = erl_mk_string(string))){ 674 | EtermType.tp_dealloc((PyObject *)eterm); 675 | return PyErr_NoMemory(); 676 | } 677 | return (PyObject *)eterm; 678 | } 679 | 680 | static PyObject * 681 | pyerl_mk_tuple(PyObject *self, PyObject *args) 682 | { 683 | EtermObject *eterm; 684 | PyObject *array; 685 | Py_ssize_t size; 686 | int i; 687 | PyObject *obj; 688 | EtermObject *eobj; 689 | ETERM **eterm_array; 690 | 691 | if(!PyArg_ParseTuple(args, "O", &array)){ 692 | return NULL; 693 | } 694 | if(!PyTuple_Check(array)){ 695 | return NULL; 696 | } 697 | size = PyTuple_Size(array); 698 | eterm_array = (ETERM **)malloc(sizeof(ETERM *) * size); 699 | for(i=0; iterm); 706 | } 707 | 708 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 709 | free(eterm_array); 710 | return PyErr_NoMemory(); 711 | } 712 | 713 | if(!(eterm->term = erl_mk_tuple(eterm_array, size))){ 714 | free(eterm_array); 715 | EtermType.tp_dealloc((PyObject *)eterm); 716 | return PyErr_NoMemory(); 717 | } 718 | free(eterm_array); 719 | return (PyObject *)eterm; 720 | } 721 | 722 | static PyObject * 723 | pyerl_mk_uint(PyObject *self, PyObject *args) 724 | { 725 | EtermObject *eterm; 726 | unsigned int n; 727 | 728 | if(!PyArg_ParseTuple(args, "I", &n)){ 729 | return NULL; 730 | } 731 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 732 | return PyErr_NoMemory(); 733 | } 734 | if(!(eterm->term = erl_mk_uint(n))){ 735 | EtermType.tp_dealloc((PyObject *)eterm); 736 | return PyErr_NoMemory(); 737 | } 738 | return (PyObject *)eterm; 739 | } 740 | 741 | static PyObject * 742 | pyerl_mk_var(PyObject *self, PyObject *args) 743 | { 744 | EtermObject *eterm; 745 | const char *name; 746 | 747 | if(!PyArg_ParseTuple(args, "s", &name)){ 748 | return NULL; 749 | } 750 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 751 | return NULL; 752 | } 753 | if(!(eterm->term = erl_mk_var(name))){ 754 | EtermType.tp_dealloc((PyObject *)eterm); 755 | return PyErr_NoMemory(); 756 | } 757 | return (PyObject *)eterm; 758 | } 759 | 760 | #ifdef ERL_LONGLONG 761 | static PyObject * 762 | pyerl_mk_longlong(PyObject *self, PyObject *args) 763 | { 764 | EtermObject *eterm; 765 | long long ll; 766 | 767 | if(!PyArg_ParseTuple(args, "L", &ll)){ 768 | return NULL; 769 | } 770 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 771 | return PyErr_NoMemory(); 772 | } 773 | if(!(eterm->term = erl_mk_longlong(ll))){ 774 | EtermType.tp_dealloc((PyObject *)eterm); 775 | return PyErr_NoMemory(); 776 | } 777 | return (PyObject *)eterm; 778 | } 779 | #endif 780 | 781 | #ifdef ERL_U_LONGLONG 782 | static PyObject * 783 | pyerl_mk_ulonglong(PyObject *self, PyObject *args) 784 | { 785 | EtermObject *eterm; 786 | unsigned long long ll; 787 | 788 | if(!PyArg_ParseTuple(args, "K", &ll)){ 789 | return NULL; 790 | } 791 | if(!(eterm = (EtermObject *)EtermType.tp_new(&EtermType, NULL, NULL))){ 792 | return PyErr_NoMemory(); 793 | } 794 | if(!(eterm->term = erl_mk_ulonglong(ll))){ 795 | EtermType.tp_dealloc((PyObject *)eterm); 796 | return PyErr_NoMemory(); 797 | } 798 | return (PyObject *)eterm; 799 | } 800 | #endif 801 | 802 | static PyObject * 803 | pyerl_print_term(PyObject *self, PyObject *args) 804 | { 805 | int ret = 0; 806 | PyObject *stream; 807 | PyObject *term; 808 | EtermObject *eterm; 809 | FILE *fp = stdout; 810 | 811 | if(!PyArg_ParseTuple(args, "OO", &stream, &term)){ 812 | return NULL; 813 | } 814 | if(!PyFile_Check(stream)){ 815 | return NULL; 816 | } 817 | fp = PyFile_AsFile(stream); 818 | if(!PyObject_TypeCheck(term, &EtermType)){ 819 | return NULL; 820 | } 821 | eterm = (EtermObject *)term; 822 | if(!eterm->term){ 823 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 824 | return NULL; 825 | } 826 | ret = erl_print_term(fp, eterm->term); 827 | fprintf(fp, "\n"); 828 | return PyInt_FromLong(ret); 829 | } 830 | 831 | static PyObject * 832 | pyerl_size(PyObject *self, PyObject *args) 833 | { 834 | int ret = 0; 835 | PyObject *term = NULL; 836 | EtermObject *eterm; 837 | 838 | if(!PyArg_ParseTuple(args, "O", &term)){ 839 | return NULL; 840 | } 841 | 842 | if(!PyObject_TypeCheck(term, &EtermType)){ 843 | return NULL; 844 | } 845 | 846 | eterm = (EtermObject *)term; 847 | if(!eterm->term){ 848 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 849 | return NULL; 850 | } 851 | ret = erl_size(eterm->term); 852 | return PyInt_FromLong(ret); 853 | } 854 | 855 | static PyObject * 856 | pyerl_eterm_release(PyObject *self, PyObject *args) 857 | { 858 | erl_eterm_release(); 859 | Py_RETURN_NONE; 860 | } 861 | 862 | static PyObject * 863 | pyerl_eterm_statistics(PyObject *self, PyObject *args) 864 | { 865 | unsigned long allocated; 866 | unsigned long freed; 867 | erl_eterm_statistics(&allocated, &freed); 868 | return Py_BuildValue("(kk)", allocated, freed); 869 | } 870 | 871 | static PyObject * 872 | pyerl_term_len(PyObject *self, PyObject *args) 873 | { 874 | int ret = 0; 875 | PyObject *term = NULL; 876 | EtermObject *eterm; 877 | 878 | if(!PyArg_ParseTuple(args, "O", &term)){ 879 | return NULL; 880 | } 881 | 882 | if(!PyObject_TypeCheck(term, &EtermType)){ 883 | return NULL; 884 | } 885 | 886 | eterm = (EtermObject *)term; 887 | if(!eterm->term){ 888 | PyErr_SetString(PyExc_TypeError, "Invalid arguments."); 889 | return NULL; 890 | } 891 | ret = erl_term_len(eterm->term); 892 | return PyInt_FromLong(ret); 893 | } 894 | 895 | static PyMethodDef methods[] = { 896 | {"init", pyerl_init, METH_VARARGS, "\ 897 | This function must be called before any of the others in the\n\ 898 | erl_interface library in order to initialize the library functions.\n\ 899 | But It doesn't need to call this function in pyerl due to already\n\ 900 | called at import."}, 901 | {"set_compat_rel", pyerl_set_compat_rel, METH_VARARGS, "\ 902 | A call to set_compat_rel(release_number) sets the erl_interface\n\ 903 | library in compatibility mode of release release_number."}, 904 | {"connect_init", pyerl_connect_init, METH_VARARGS, "\ 905 | These functions initialize the erl_connect module.\n\ 906 | connect_init() provides an alternative interface which does not\n\ 907 | require as much information from the caller. Instead, connect_init()\n\ 908 | uses gethostbyname() to obtain default values."}, 909 | {"connect_xinit", pyerl_connect_xinit, METH_VARARGS, "\ 910 | These functions initialize the erl_connect module.\n\ 911 | connect_xinit() stores for later use information about the node's host\n\ 912 | name host, alive name alive, node name node, IP address addr, cookie\n\ 913 | cookie, and creation number creation."}, 914 | {"connect", pyerl_connect, METH_VARARGS, "\ 915 | These functions set up a connection to an Erlang node."}, 916 | {"xconnect", pyerl_xconnect, METH_VARARGS, "\ 917 | These functions set up a connection to an Erlang node."}, 918 | {"close_connection", pyerl_close_connection, METH_VARARGS, "\ 919 | This function closes an open connection to an Erlang node."}, 920 | {"xreceive_msg", pyerl_xreceive_msg, METH_VARARGS, NULL}, 921 | {"send", pyerl_send, METH_VARARGS, "\ 922 | This function sends an Erlang term to a process."}, 923 | {"reg_send", pyerl_reg_send, METH_VARARGS, "\ 924 | This function sends an Erlang term to a registered process."}, 925 | {"rpc", pyerl_rpc, METH_VARARGS, "\ 926 | These functions support calling Erlang functions on remote nodes. "}, 927 | 928 | {"publish", pyerl_publish, METH_VARARGS, NULL}, 929 | {"unpublish", pyerl_unpublish, METH_VARARGS, NULL}, 930 | /* TODO */ 931 | /* {"accept", pyerl_accept, METH_VARARGS, NULL}, */ 932 | {"thiscookie", pyerl_thiscookie, METH_VARARGS, NULL}, 933 | {"thisnodename", pyerl_thisnodename, METH_VARARGS, NULL}, 934 | {"thishostname", pyerl_thishostname, METH_VARARGS, NULL}, 935 | {"thisalivename", pyerl_thisalivename, METH_VARARGS, NULL}, 936 | {"thiscreation", pyerl_thiscreation, METH_VARARGS, NULL}, 937 | 938 | {"cons", pyerl_cons, METH_VARARGS, NULL}, 939 | {"copy_term", pyerl_copy_term, METH_VARARGS, NULL}, 940 | {"element", pyerl_element, METH_VARARGS, NULL}, 941 | {"hd", pyerl_hd, METH_VARARGS, NULL}, 942 | {"tl", pyerl_tl, METH_VARARGS, NULL}, 943 | 944 | {"mk_atom", pyerl_mk_atom, METH_VARARGS, NULL}, 945 | {"mk_binary", pyerl_mk_binary, METH_VARARGS, NULL}, 946 | {"mk_empty_list", pyerl_mk_empty_list, METH_VARARGS, NULL}, 947 | {"mk_estring", pyerl_mk_estring, METH_VARARGS, NULL}, 948 | {"mk_float", pyerl_mk_float, METH_VARARGS, NULL}, 949 | {"mk_int", pyerl_mk_int, METH_VARARGS, NULL}, 950 | {"mk_list", pyerl_mk_list, METH_VARARGS, NULL}, 951 | {"mk_pid", pyerl_mk_pid, METH_VARARGS, NULL}, 952 | {"mk_port", pyerl_mk_port, METH_VARARGS, NULL}, 953 | {"mk_ref", pyerl_mk_ref, METH_VARARGS, NULL}, 954 | {"mk_long_ref", pyerl_mk_long_ref, METH_VARARGS, NULL}, 955 | {"mk_string", pyerl_mk_string, METH_VARARGS, NULL}, 956 | {"mk_tuple", pyerl_mk_tuple, METH_VARARGS, NULL}, 957 | {"mk_uint", pyerl_mk_uint, METH_VARARGS, NULL}, 958 | {"mk_var", pyerl_mk_var, METH_VARARGS, NULL}, 959 | #ifdef ERL_LONGLONG 960 | {"mk_longlong", pyerl_mk_longlong, METH_VARARGS, NULL}, 961 | #endif 962 | #ifdef ERL_U_LONGLONG 963 | {"mk_ulonglong", pyerl_mk_ulonglong, METH_VARARGS, NULL}, 964 | #endif 965 | 966 | {"print_term", pyerl_print_term, METH_VARARGS, NULL}, 967 | {"size", pyerl_size, METH_VARARGS, NULL}, 968 | 969 | {"eterm_release", pyerl_eterm_release, METH_NOARGS, NULL}, 970 | {"eterm_statistics", pyerl_eterm_statistics, METH_NOARGS, NULL}, 971 | {"term_len", pyerl_term_len, METH_VARARGS, NULL}, 972 | {NULL, NULL} 973 | }; 974 | 975 | void initpyerl(void) 976 | { 977 | PyObject *m; 978 | 979 | erl_init(NULL, 0); 980 | if (PyType_Ready(&EtermType) < 0) 981 | return; 982 | 983 | m = Py_InitModule3("pyerl", methods, pyerl_doc); 984 | if (m == NULL) 985 | return; 986 | Py_INCREF(&EtermType); 987 | PyModule_AddObject(m, "Eterm", (PyObject *)&EtermType); 988 | 989 | PyModule_AddIntConstant(m, "COMPOUND", ERL_COMPOUND); 990 | PyModule_AddIntConstant(m, "UNDEF", ERL_UNDEF); 991 | PyModule_AddIntConstant(m, "INTEGER", ERL_INTEGER); 992 | PyModule_AddIntConstant(m, "U_INTEGER", ERL_U_INTEGER); 993 | PyModule_AddIntConstant(m, "ATOM", ERL_ATOM); 994 | PyModule_AddIntConstant(m, "PID", ERL_PID); 995 | PyModule_AddIntConstant(m, "PORT", ERL_PORT); 996 | PyModule_AddIntConstant(m, "REF", ERL_REF); 997 | PyModule_AddIntConstant(m, "CONS", ERL_CONS); 998 | PyModule_AddIntConstant(m, "LIST", ERL_LIST); 999 | PyModule_AddIntConstant(m, "NIL", ERL_NIL); 1000 | PyModule_AddIntConstant(m, "EMPTY_LIST", ERL_EMPTY_LIST); 1001 | PyModule_AddIntConstant(m, "TUPLE", ERL_TUPLE); 1002 | PyModule_AddIntConstant(m, "BINARY", ERL_BINARY); 1003 | PyModule_AddIntConstant(m, "FLOAT", ERL_FLOAT); 1004 | PyModule_AddIntConstant(m, "VARIABLE", ERL_VARIABLE); 1005 | PyModule_AddIntConstant(m, "SMALL_BIG", ERL_SMALL_BIG); 1006 | PyModule_AddIntConstant(m, "U_SMALL_BIG", ERL_U_SMALL_BIG); 1007 | PyModule_AddIntConstant(m, "FUNCTION", ERL_FUNCTION); 1008 | PyModule_AddIntConstant(m, "BIG", ERL_BIG); 1009 | #ifdef ERL_LONGLONG 1010 | PyModule_AddIntConstant(m, "LONGLONG", ERL_LONGLONG); 1011 | #endif 1012 | #ifdef ERL_U_LONGLONG 1013 | PyModule_AddIntConstant(m, "U_LONGLONG", ERL_U_LONGLONG); 1014 | #endif 1015 | } 1016 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup, Extension 4 | from os import path 5 | import os 6 | import re 7 | 8 | otp_dir = None 9 | 10 | def getSearchDir(): 11 | return os.environ.get('ERL_HOME', os.environ.get('ERLANG_HOME', '/usr')) 12 | 13 | def findInSubdirectory(filename, subdirectory=''): 14 | if subdirectory: 15 | path = subdirectory 16 | else: 17 | path = os.getcwd() 18 | for root, dirs, names in os.walk(path): 19 | if filename in names: 20 | this_path = re.sub('include/erl_interface.h', '', os.path.join(root, filename)) 21 | return this_path 22 | return None 23 | 24 | otp_dir = findInSubdirectory('erl_interface.h', getSearchDir()) 25 | 26 | if otp_dir == None: 27 | print 'Cannot find Erlang/OTP directory.' 28 | print 'You need to install Erlang/OTP.' 29 | exit(1) 30 | 31 | include_dirs = [otp_dir + 'include/'] 32 | library_dirs = [otp_dir + 'lib/'] 33 | 34 | setup(name = "PyErl", 35 | version = "0.5", 36 | description = "Erlang Interface for Python", 37 | long_description = ''' 38 | PyErl is Erlang Interface for Python. which help you integrate 39 | programs written in Python and Erlang. 40 | ''', 41 | author = "Tsukasa Hamano", 42 | author_email = "code@cuspy.org", 43 | url="http://github.com/hamano/python-erlang-interface", 44 | download_url="http://pypi.python.org/pypi/PyErl/", 45 | license="MPL", 46 | ext_modules = [ 47 | Extension( 48 | "pyerl", 49 | ["pyerl.c", "eterm.c"], 50 | libraries=["erl_interface", "ei"], 51 | include_dirs = include_dirs, 52 | library_dirs = library_dirs, 53 | ) 54 | ], 55 | classifiers = [ 56 | 'Programming Language :: Python', 57 | 'Programming Language :: Erlang', 58 | 'Topic :: Software Development :: Libraries :: Python Modules', 59 | ], 60 | ) 61 | -------------------------------------------------------------------------------- /tests/pingpong.erl: -------------------------------------------------------------------------------- 1 | -module(pingpong). 2 | -compile(export_all). 3 | 4 | start() -> register(pingpong, spawn(?MODULE, loop, [])). 5 | stop() -> pingpong ! stop. 6 | 7 | loop() -> 8 | receive 9 | stop -> 10 | io:fwrite("Stop: ~w~n", [self()]), 11 | exit(ok); 12 | {ping, Pid, Message} -> 13 | io:fwrite("Pid: ~w, Message:~s~n", [Pid, Message]), 14 | Pid ! {pong, self(), Message}; 15 | Other -> 16 | io:fwrite("Other: ~w~n", [Other]) 17 | end, 18 | loop(). 19 | 20 | ping(Arg) -> 21 | case Arg of 22 | ping -> pong; 23 | stop -> exit(ok); 24 | _ -> pang 25 | end. 26 | -------------------------------------------------------------------------------- /tests/test_pyerl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | import pyerl 5 | 6 | class PyErlTest(unittest.TestCase): 7 | def setUp(self): 8 | pass 9 | 10 | def tearDown(self): 11 | pyerl.eterm_release() 12 | allocated, freed = pyerl.eterm_statistics() 13 | self.assertEqual(allocated, 0) 14 | self.assertEqual(freed, 0) 15 | 16 | def test_mk_atom(self): 17 | eterm = pyerl.mk_atom("atom") 18 | self.assertEqual(eterm.type, pyerl.ATOM); 19 | self.assertEqual(eterm.is_atom(), True); 20 | self.assertEqual(str(eterm), "atom"); 21 | 22 | def test_mk_binary(self): 23 | eterm = pyerl.mk_binary("\x00\x01\x02\x03\x04") 24 | self.assertEqual(eterm.type, pyerl.BINARY); 25 | self.assertEqual(eterm.is_binary(), True); 26 | self.assertEqual(str(eterm), "#Bin<0,1,2,3,4>"); 27 | 28 | def test_mk_empty_list(self): 29 | eterm = pyerl.mk_empty_list() 30 | self.assertEqual(eterm.type, pyerl.EMPTY_LIST); 31 | self.assertEqual(eterm.is_empty_list(), True); 32 | self.assertEqual(eterm.is_list(), True); 33 | self.assertEqual(eterm.is_nil(), True); 34 | self.assertEqual(str(eterm), "[]"); 35 | 36 | def test_mk_estring(self): 37 | eterm = pyerl.mk_estring("e\x00string") 38 | self.assertEqual(eterm.type, pyerl.LIST); 39 | self.assertEqual(eterm.type, pyerl.CONS); 40 | self.assertEqual(eterm.is_list(), True); 41 | self.assertEqual(eterm.is_cons(), True); 42 | self.assertEqual(str(eterm), "\"e\\x0string\""); 43 | 44 | def test_mk_float(self): 45 | eterm = pyerl.mk_float(0.000001) 46 | self.assertEqual(eterm.type, pyerl.FLOAT); 47 | self.assertEqual(eterm.is_float(), True); 48 | self.assertEqual(str(eterm), "0.000001"); 49 | 50 | def test_mk_int(self): 51 | eterm = pyerl.mk_int(-1) 52 | self.assertEqual(eterm.type, pyerl.INTEGER); 53 | self.assertEqual(eterm.is_integer(), True); 54 | self.assertEqual(str(eterm), "-1"); 55 | 56 | def test_mk_list(self): 57 | atom = eterm = pyerl.mk_atom("atom") 58 | integer = eterm = pyerl.mk_int(-1) 59 | string = eterm = pyerl.mk_string("string") 60 | eterm = pyerl.mk_list([atom, integer, string]) 61 | self.assertEqual(eterm.is_list(), True); 62 | self.assertEqual(eterm.is_cons(), True); 63 | self.assertEqual(eterm.type, pyerl.LIST); 64 | self.assertEqual(str(eterm), "[atom, -1, \"string\"]"); 65 | 66 | def test_mk_pid(self): 67 | eterm = pyerl.mk_pid("node", 1, 2, 3) 68 | self.assertEqual(eterm.type, pyerl.PID); 69 | self.assertEqual(eterm.is_pid(), True); 70 | self.assertEqual(str(eterm), ""); 71 | 72 | def test_mk_port(self): 73 | eterm = pyerl.mk_port("node", 1, 2) 74 | self.assertEqual(eterm.type, pyerl.PORT); 75 | self.assertEqual(eterm.is_port(), True); 76 | self.assertEqual(str(eterm), "#Port<1.2>"); 77 | 78 | def test_mk_ref(self): 79 | eterm = pyerl.mk_ref("node", 1, 2) 80 | self.assertEqual(eterm.type, pyerl.REF); 81 | self.assertEqual(eterm.is_ref(), True); 82 | self.assertEqual(str(eterm), "#Ref<1>"); 83 | 84 | def test_mk_long_ref(self): 85 | eterm = pyerl.mk_long_ref("node", 1, 2, 3, 4) 86 | self.assertEqual(eterm.type, pyerl.REF); 87 | self.assertEqual(eterm.is_ref(), True); 88 | self.assertEqual(str(eterm), "#Ref<3.2.1>"); 89 | 90 | def test_mk_string(self): 91 | eterm = pyerl.mk_string("string") 92 | self.assertEqual(eterm.type, pyerl.LIST); 93 | self.assertEqual(eterm.type, pyerl.CONS); 94 | self.assertEqual(eterm.is_list(), True); 95 | self.assertEqual(eterm.is_cons(), True); 96 | self.assertEqual(str(eterm), "\"string\""); 97 | 98 | def test_mk_list(self): 99 | atom = eterm = pyerl.mk_atom("atom") 100 | integer = eterm = pyerl.mk_int(-1) 101 | string = eterm = pyerl.mk_string("string") 102 | eterm = pyerl.mk_tuple((atom, integer, string)) 103 | self.assertEqual(eterm.is_tuple(), True); 104 | self.assertEqual(eterm.type, pyerl.TUPLE); 105 | self.assertEqual(str(eterm), "{atom, -1, \"string\"}"); 106 | 107 | def test_mk_uint(self): 108 | eterm = pyerl.mk_uint(1) 109 | self.assertEqual(eterm.type, pyerl.U_INTEGER); 110 | self.assertEqual(eterm.is_unsigned_integer(), True); 111 | self.assertEqual(str(eterm), "1"); 112 | 113 | def test_mk_var(self): 114 | eterm = pyerl.mk_var("var") 115 | self.assertEqual(eterm.type, pyerl.VARIABLE); 116 | # Cannot convert string, I don't know why. 117 | # self.assertEqual(str(eterm), "var"); 118 | 119 | def test_mk_longlong(self): 120 | if not 'mk_longlong' in dir(pyerl): 121 | return 122 | eterm = pyerl.mk_longlong(-1) 123 | self.assertEqual(eterm.type, pyerl.LONGLONG); 124 | self.assertEqual(eterm.is_longlong(), True); 125 | self.assertEqual(str(eterm), "-1"); 126 | 127 | def test_mk_ulonglong(self): 128 | if not 'mk_ulonglong' in dir(pyerl): 129 | return 130 | eterm = pyerl.mk_ulonglong(1) 131 | self.assertEqual(eterm.type, pyerl.U_LONGLONG); 132 | self.assertEqual(eterm.is_unsigned_longlong(), True); 133 | self.assertEqual(str(eterm), "1"); 134 | 135 | def test_copy_term(self): 136 | atom = pyerl.mk_atom("atom") 137 | eterm = pyerl.copy_term(atom) 138 | self.assertEqual(eterm.type, pyerl.ATOM); 139 | self.assertEqual(eterm.is_atom(), True); 140 | self.assertEqual(str(eterm), "atom"); 141 | 142 | def test_cons(self): 143 | atom1 = pyerl.mk_atom("atom1") 144 | atom2 = pyerl.mk_atom("atom2") 145 | list = pyerl.mk_list([atom1]) 146 | eterm = pyerl.cons(atom2, list) 147 | self.assertEqual(eterm.type, pyerl.CONS); 148 | self.assertEqual(eterm.is_cons(), True); 149 | self.assertEqual(eterm.is_list(), True); 150 | self.assertEqual(str(eterm), "[atom2, atom1]"); 151 | 152 | if __name__ == '__main__': 153 | unittest.main() 154 | -------------------------------------------------------------------------------- /tests/test_rpc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | import subprocess 5 | import time 6 | import pyerl 7 | 8 | class RPCTest(unittest.TestCase): 9 | def setUp(self): 10 | ret = subprocess.call(["erlc", "tests/pingpong.erl"]) 11 | self.assertEqual(ret, 0) 12 | cmd = 'erl -noshell -setcookie "TESTCOOKIE" -sname node1@localhost -s pingpong start' 13 | self.proc = subprocess.Popen(cmd, shell=True) 14 | 15 | def tearDown(self): 16 | ret = subprocess.call(["kill", str(self.proc.pid)]) 17 | pyerl.eterm_release() 18 | allocated, freed = pyerl.eterm_statistics() 19 | self.assertEqual(allocated, 0) 20 | self.assertEqual(freed, 0) 21 | self.proc.wait() 22 | 23 | def test_rpc(self): 24 | host = "localhost" 25 | name = "test" 26 | node = name + "@" + host 27 | cookie = "TESTCOOKIE" 28 | ret = pyerl.connect_xinit(host, name, node, "127.0.0.1", cookie, 1) 29 | self.assertEqual(ret, 1); 30 | retry = 0 31 | while True: 32 | time.sleep(1) 33 | sock = pyerl.xconnect("127.0.0.1", "node1") 34 | if sock > 0: break 35 | if retry > 3: self.fail() 36 | retry += 1 37 | self.assertEqual(sock > 0, True) 38 | atom = pyerl.mk_atom("ping") 39 | args = pyerl.mk_list([atom]); 40 | eterm = pyerl.rpc(sock, "pingpong", "ping", args); 41 | ret = pyerl.close_connection(sock); 42 | self.assertEqual(ret, 0); 43 | self.assertEqual(eterm.type, pyerl.ATOM); 44 | self.assertEqual(eterm.is_atom(), True); 45 | self.assertEqual(str(eterm), "pong"); 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | --------------------------------------------------------------------------------