Permalink
Browse files

First steps towards python support for serial

So far it's just the decoder, and only the simpler deserializations:

- Single values (int, string etc...)
- List/hash
- Regexp
- Snappy support

Basic tests were performed in the python shell, so the code should be
ok. Caveat emptor.
  • Loading branch information...
1 parent 4912c3d commit df86186354d3cd9b75a9084279eddcdf5301747e @seveas seveas committed Nov 14, 2012
Showing with 810 additions and 15 deletions.
  1. +3 −0 .gitignore
  2. +17 −15 Perl/shared/author_tools/update_from_header.pl
  3. +91 −0 Python/_serealmodule.c
  4. +1 −0 Python/sereal.py
  5. +25 −0 Python/setup.py
  6. +452 −0 Python/srl_decoder.c
  7. +221 −0 Python/srl_decoder.h
View
@@ -3,3 +3,6 @@
*~
*.bak
Java/bin/
+Python/build
+*.o
+*.so
@@ -75,22 +75,24 @@ sub replace_block {
close $in;
}
sub update_srl_decoder_h {
- replace_block("Perl/Decoder/srl_decoder.h",
- join("\n",
- "* NOTE this section is autoupdated by $0",
- "*/",
- "static const char * const tag_name[] = {",
- ( map {
- my $str= Data::Dumper::qquote(chr($_));
- if ($str=~/^"\\[0-9]+"\z/) { $str="";}
- sprintf qq(\t%-*s /* %-4s %3d 0x%02x 0b%08b */),
- $max_name_length+3, qq("$value_to_name_expanded{$_}") . ($_==127 ? " " : ","), $str, $_, $_, $_
- } 0 .. 127 ),
- "};",
- "/*",
- "* NOTE the above section is auto-updated by $0",
+ for my $file ("Perl/Decoder/srl_decoder.h", "Python/srl_decoder.h") {
+ replace_block($file,
+ join("\n",
+ "* NOTE this section is autoupdated by $0",
+ "*/",
+ "static const char * const tag_name[] = {",
+ ( map {
+ my $str= Data::Dumper::qquote(chr($_));
+ if ($str=~/^"\\[0-9]+"\z/) { $str="";}
+ sprintf qq(\t%-*s /* %-4s %3d 0x%02x 0b%08b */),
+ $max_name_length+3, qq("$value_to_name_expanded{$_}") . ($_==127 ? " " : ","), $str, $_, $_, $_
+ } 0 .. 127 ),
+ "};",
+ "/*",
+ "* NOTE the above section is auto-updated by $0",
+ )
)
- )
+ }
}
sub update_JavaSerealHeader {
View
@@ -0,0 +1,91 @@
+/*
+ * pysereal - An implemetation of the Sereal serialization protocol
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#if PY_MAJOR_VERSION >= 3
+#define PyInt_FromLong PyLong_FromLong
+#define PyInt_Check PyLong_Check
+#define PyInt_AsLong PyLong_AsLong
+#endif
+
+#include "srl_decoder.h"
+#include <stdbool.h>
+
+static PyObject * sereal_encode(PyObject *self, PyObject *args, PyObject *kw) {
+ PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
+ return NULL;
+}
+
+static PyObject * sereal_decode(PyObject *self, PyObject *args, PyObject *kw) {
+ srl_decoder_t *dec = srl_decoder_new();
+ PyObject *ret;
+ char *keywords[] = {
+ "buffer",
+ "refuse_snappy",
+ "refuse_objects",
+ "validate_utf8",
+ NULL,
+ };
+ bool refuse_snappy=0, refuse_objects=0, validate_utf8 = 0;
+ if(!PyArg_ParseTupleAndKeywords(args, kw, "s#|bbb", keywords,
+ &(dec->buf_start), &(dec->buf_len),
+ &refuse_snappy, &refuse_objects, &validate_utf8
+ )) {
+ return NULL;
+ }
+ if(refuse_snappy)
+ dec->flags |= SRL_F_DECODER_REFUSE_SNAPPY;
+ if(refuse_objects)
+ dec->flags |= SRL_F_DECODER_REFUSE_OBJECTS;
+ if(validate_utf8)
+ dec->flags |= SRL_F_DECODER_VALIDATE_UTF8;
+
+ ret = srl_decode(dec);
+ srl_decoder_free(dec);
+ return ret;
+}
+
+static PyMethodDef SerealMethods[] = {
+ {"encode", (PyCFunction)sereal_encode, METH_VARARGS|METH_KEYWORDS, "Encode objects using sereal"},
+ {"decode", (PyCFunction)sereal_decode, METH_VARARGS|METH_KEYWORDS, "Decode a sereal-encoded bytestring"},
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef serealmodule = {
+ PyModuleDef_HEAD_INIT,
+ "_sereal",
+ NULL,
+ -1,
+ SerealMethods
+};
+#endif
+
+PyMODINIT_FUNC
+#if PY_MAJOR_VERSION < 3
+init_sereal(void)
+#else
+PyInit__sereal(void)
+#endif
+{
+#if PY_MAJOR_VERSION < 3
+ /* PyObject *_sereal = */ Py_InitModule("_sereal", SerealMethods);
+#else
+ PyObject *_sereal = PyModule_Create(&serealmodule);
+#endif
+ PyObject *re = PyImport_ImportModule("re");
+ srl_re_compile = PyObject_GetAttrString(re, "compile");
+ /* All below use borrowed references */
+ PyObject *re_dict = PyModule_GetDict(re);
+ RE_IGNORECASE = PyInt_AS_LONG(PyDict_GetItemString(re_dict, "IGNORECASE"));
+ RE_DOTALL = PyInt_AS_LONG(PyDict_GetItemString(re_dict, "DOTALL"));
+ RE_VERBOSE = PyInt_AS_LONG(PyDict_GetItemString(re_dict, "VERBOSE"));
+ RE_MULTILINE = PyInt_AS_LONG(PyDict_GetItemString(re_dict, "MULTILINE"));
+ RE_UNICODE = PyInt_AS_LONG(PyDict_GetItemString(re_dict, "UNICODE"));
+ RE_LOCALE = PyInt_AS_LONG(PyDict_GetItemString(re_dict, "LOCALE"));
+#if PY_MAJOR_VERSION >= 3
+ return _sereal;
+#endif
+}
View
@@ -0,0 +1 @@
+from _sereal import *
View
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+from distutils.core import setup, Extension
+import os
+srl_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+_sereal = Extension("_sereal",
+ sources = ['_serealmodule.c', 'srl_decoder.c'],
+ depends = ['srl_common.h', 'srl_protocol.h', 'srl_inline.h', 'srl_decoder.h', 'snappy/snappy_decompress.c'],
+ include_dirs = [os.path.join(srl_root, 'Perl', 'shared')],
+)
+
+setup(name = "sereal",
+ version = "0.1",
+ author = "Dennis Kaarsemaker",
+ author_email = "dennis@kaarsemaker.net",
+ url = "http://github.com/Sereal/Sereal",
+ description = "Python implemetation of the Sereal protocol",
+ py_modules = ["sereal"],
+ ext_modules = [_sereal],
+ classifiers = [
+ 'Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ ]
+)
Oops, something went wrong.

0 comments on commit df86186

Please sign in to comment.