From 51e7ee4e6166c7fd30bf8649ff7203603d18ea25 Mon Sep 17 00:00:00 2001 From: adam Date: Tue, 12 Feb 2013 00:30:31 +0700 Subject: [PATCH] #47 --- .idea/codeStyleSettings.xml | 9 +++++++++ pyejdb/pyejdb/__init__.py | 13 +++++++++---- pyejdb/pyejdb/bson.py | 4 ++-- pyejdb/src/EJDB.c | 41 +++++++++++++++++++---------------------- pyejdb/src/pyejdb.c | 4 ++-- pyejdb/src/pyejdb.h | 32 +++++++++++++++++++++++++++++++- pyejdb/test/__init__.py | 2 +- pyejdb/test/test_one.py | 30 ++++++++++++++++++++++++++++++ pyejdb/test/test_openclose.py | 21 --------------------- 9 files changed, 103 insertions(+), 53 deletions(-) create mode 100644 .idea/codeStyleSettings.xml create mode 100644 pyejdb/test/test_one.py delete mode 100644 pyejdb/test/test_openclose.py diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 0000000..1129f00 --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/pyejdb/pyejdb/__init__.py b/pyejdb/pyejdb/__init__.py index e69195b..ee96840 100644 --- a/pyejdb/pyejdb/__init__.py +++ b/pyejdb/pyejdb/__init__.py @@ -1,5 +1,6 @@ import _pyejdb from pprint import pprint +from pyejdb import bson __all__ = [ "EJDB" @@ -14,7 +15,7 @@ class EJDB(object): def __init__(self, fpath): #pprint (vars(_pyejdb)) self.__ejdb = _pyejdb.EJDB() - self.__ejdb.open(fpath, _pyejdb.JBOWRITER | _pyejdb.JBOCREAT) + self.__ejdb.open(fpath, _pyejdb.JBOWRITER | _pyejdb.JBOCREAT | _pyejdb.JBOTSYNC) def close(self): if self.__ejdb: @@ -23,9 +24,13 @@ class EJDB(object): def save(self, cname, *jsarr, **kwargs): _check_collname(cname) - _objs = [] - for o in jsarr: - _objs.append(o) + for doc in jsarr: + _oid = self.__ejdb.save(cname, bson.serialize_to_bytes(doc), **kwargs) + if "_id" not in doc: + doc["_id"] = _oid + print("ID=%s" % _oid) + + diff --git a/pyejdb/pyejdb/bson.py b/pyejdb/pyejdb/bson.py index 44e3b1c..868bd12 100644 --- a/pyejdb/pyejdb/bson.py +++ b/pyejdb/pyejdb/bson.py @@ -109,12 +109,12 @@ import calendar; from calendar import timegm import collections; from collections import OrderedDict as odict import binascii; from binascii import b2a_hex try: - import typecheck + import pyejdb.typecheck except ImportError: print("warning: module typecheck.py cannot be imported, type checking is skipped") typecheck = lambda x: x; optional = callable = with_attr = lambda *args: True else: - from typecheck import typecheck, optional, callable, with_attr + from pyejdb.typecheck import typecheck, optional, callable, with_attr ############################################################################### diff --git a/pyejdb/src/EJDB.c b/pyejdb/src/EJDB.c index 6cb05f3..c76cdb8 100644 --- a/pyejdb/src/EJDB.c +++ b/pyejdb/src/EJDB.c @@ -52,49 +52,46 @@ static PyObject* EJDB_close(PEJDB *self) { static PyObject* EJDB_save(PEJDB *self, PyObject *args, PyObject *kwargs) { const char *cname; PyObject *merge = Py_False; - Py_buffer *bsonbuff; + void *bsonbuf = NULL; + int bsonbufz; + PyObject *bsonbufpy; EJCOLL *ejcoll; bson_oid_t oid; bson bsonval; - bool ret = false; + bool bret = false; static char *kwlist[] = {"cname", "bson", "merge", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss*|O:EJDB_save", kwlist, - &cname, &bsonbuff, &merge)) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O:EJDB_save", kwlist, + &cname, &bsonbufpy, &merge)) { + return NULL; + } + if (bytes_to_void(bsonbufpy, &bsonbuf, &bsonbufz)) { return NULL; } if (!PyBool_Check(merge)) { - PyBuffer_Release(bsonbuff); return set_error(PyExc_TypeError, "'merge' must be an instance of boolean type"); } Py_BEGIN_ALLOW_THREADS ejcoll = ejdbcreatecoll(self->ejdb, cname, NULL); Py_END_ALLOW_THREADS if (!ejcoll) { - PyBuffer_Release(bsonbuff); return set_ejdb_error(self->ejdb); } - bson_init_finished_data(&bsonval, bsonbuff->buf); + bson_init_finished_data(&bsonval, bsonbuf); + //bson_print_raw(stderr, bsonbuf, 0); + Py_BEGIN_ALLOW_THREADS - ret = ejdbsavebson2(ejcoll, &bsonval, &oid, (merge == Py_True)); + bret = ejdbsavebson2(ejcoll, &bsonval, &oid, (merge == Py_True)); Py_END_ALLOW_THREADS - if (!ret) { - PyBuffer_Release(bsonbuff); - return set_ejdb_error(self->ejdb); - } - PyBuffer_Release(bsonbuff); bsonval.data = NULL; bson_destroy(&bsonval); - - //todo return OID - //PyString_FromString() - Py_RETURN_NONE; + if (!bret) { + return set_ejdb_error(self->ejdb); + } + char xoid[25]; + bson_oid_to_string(&oid, xoid); + return PyUnicode_FromString(xoid); } - -//EJDB_EXPORT EJCOLL* ejdbcreatecoll(EJDB *jb, const char *colname, EJCOLLOPTS *opts); -//EJDB_EXPORT bool ejdbsavebson2(EJCOLL *jcoll, bson *bs, bson_oid_t *oid, bool merge); - - /* EJDBType.tp_methods */ static PyMethodDef EJDB_tp_methods[] = { {"open", (PyCFunction) EJDB_open, METH_VARARGS, NULL}, diff --git a/pyejdb/src/pyejdb.c b/pyejdb/src/pyejdb.c index 48596d3..4034ef4 100644 --- a/pyejdb/src/pyejdb.c +++ b/pyejdb/src/pyejdb.c @@ -4,7 +4,7 @@ typedef struct { PyObject_HEAD EJDB *ejdb; -} PEJDB; +} PEJDB; #include "EJDB.c" @@ -12,7 +12,7 @@ PyDoc_STRVAR(ejdb_m_doc, "EJDB http://ejdb.org"); PyDoc_STRVAR(ejdb_version_doc, "version() -> str\n\nReturns the version string of the underlying EJDB library."); static PyObject* ejdb_version(PyObject *module) { - return PyString_FromString(tcversion); + return PyUnicode_FromString(tcversion); } /* cabinet_module.m_methods */ diff --git a/pyejdb/src/pyejdb.h b/pyejdb/src/pyejdb.h index 4a77284..e3617a5 100644 --- a/pyejdb/src/pyejdb.h +++ b/pyejdb/src/pyejdb.h @@ -11,6 +11,11 @@ #include #include +#if SIZEOF_SIZE_T > SIZEOF_INT +#define TK_PY_SIZE_T_BIGGER_THAN_INT +#define TK_PY_MAX_LEN ((Py_ssize_t)INT_MAX) +#endif + /* Error */ static PyObject *Error; @@ -41,7 +46,6 @@ char* PyUnicode_Object_AsString(PyObject *obj) { #if PY_MAJOR_VERSION >= 3 #define PyString_AsString PyUnicode_Object_AsString -#define PyString_FromString PyUnicode_FromString #define PyInt_FromLong PyLong_FromLong #endif @@ -54,6 +58,32 @@ int PyModule_AddType(PyObject *module, const char *name, PyTypeObject *type) { return 0; } +int check_py_ssize_t_len(Py_ssize_t len, PyObject *obj) { +#ifdef TK_PY_SIZE_T_BIGGER_THAN_INT + if (len > TK_PY_MAX_LEN) { + PyErr_Format(PyExc_OverflowError, "%s is too large", + Py_TYPE(obj)->tp_name); + return -1; + } +#endif + return 0; +} + +/* convert a bytes object to a void ptr */ +int bytes_to_void(PyObject *pyvalue, void **value, int *value_len) { + char *tmp; + Py_ssize_t tmp_len; + if (PyBytes_AsStringAndSize(pyvalue, &tmp, &tmp_len)) { + return -1; + } + if (check_py_ssize_t_len(tmp_len, pyvalue)) { + return -1; + } + *value = (void *) tmp; + *value_len = (int) tmp_len; + return 0; +} + /* error handling utils */ PyObject* set_error(PyObject *type, const char *message) { PyErr_SetString(type, message); diff --git a/pyejdb/test/__init__.py b/pyejdb/test/__init__.py index 0bb7873..1c5f176 100644 --- a/pyejdb/test/__init__.py +++ b/pyejdb/test/__init__.py @@ -4,7 +4,7 @@ import sys import unittest -names = ['openclose'] +names = ['one'] def test_suite(): import pyejdb diff --git a/pyejdb/test/test_one.py b/pyejdb/test/test_one.py new file mode 100644 index 0000000..3fb7073 --- /dev/null +++ b/pyejdb/test/test_one.py @@ -0,0 +1,30 @@ +import unittest +import pyejdb + +class TestOne(unittest.TestCase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + _ejdb = None + + @classmethod + def setUpClass(cls): + cls._ejdb = pyejdb.EJDB("testdb") + + def test_save1(self): + ejdb = TestOne._ejdb + doc1 = {"foo" : "bar", "foo2" : 2} + ejdb.save("foocoll", doc1) + + @classmethod + def tearDownClass(cls): + if cls._ejdb: + cls._ejdb.close() + cls._ejdb = None + +if __name__ == '__main__': + unittest.main() + + + + diff --git a/pyejdb/test/test_openclose.py b/pyejdb/test/test_openclose.py deleted file mode 100644 index a5a8323..0000000 --- a/pyejdb/test/test_openclose.py +++ /dev/null @@ -1,21 +0,0 @@ -import unittest -import pyejdb - -class TestOpenClose(unittest.TestCase): - def setUp(self): - pass - - def test_open(self): - self.ejdb = pyejdb.EJDB("testdb") - - def tearDown(self): - if self.ejdb: - self.ejdb.close() - self.ejdb = None - -if __name__ == '__main__': - unittest.main() - - - - -- 2.7.4