From 223c20f9912401244079ef189f0235fa9605b251 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Tue, 4 Nov 2014 19:20:39 -0500 Subject: [PATCH 01/37] fixing python->js and js->python for dictionaries and arrays. bug was converting array values ->ToObject() which was obscuring their type, causing them to blow up on conversion coming back out of python --- .gitignore | 1 + index.js | 12 +- src/py_object_wrapper.cc | 271 +++++++++++++++++++++------------------ src/py_object_wrapper.h | 2 + test/index.js | 12 +- 5 files changed, 162 insertions(+), 136 deletions(-) diff --git a/.gitignore b/.gitignore index 5990836..fd29272 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules .cproject .project .settings +npm-debug.log diff --git a/index.js b/index.js index 2c6d5fc..e9b8f91 100644 --- a/index.js +++ b/index.js @@ -30,7 +30,7 @@ function pythonFinalized () { module.exports.eval = function (string) { if (pythonFinalized()) throw new PythonError('node-python\'s python interpreter has already been finalized. python code cannot be executed.'); return binding.eval(string); -} +}; module.exports.finalize = function () { if ( ! pythonFinalized()) { @@ -39,7 +39,7 @@ module.exports.finalize = function () { return finalized; } return false; -} +}; var _import = module.exports.import = function (string) { if (pythonFinalized()) throw new PythonError('node-python\'s python interpreter has already been finalized. python code cannot be executed.'); @@ -49,13 +49,13 @@ var _import = module.exports.import = function (string) { try { result = binding.import(string); } catch (e) { - e = new PythonError(e); - debug(e); - throw e; + var err = new PythonError(e); + debug(err); + throw err; } return result; -} +}; var os = _import('os'); diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index a8f472f..66e478b 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -33,74 +33,23 @@ void PyObjectWrapper::Initialize() { Handle PyObjectWrapper::New(PyObject* obj) { HandleScope scope; - Local jsVal; + Local jsObj; - // undefined - if(obj == Py_None) { - jsVal = Local::New(Undefined()); - } - else if(PyDict_Check(obj)) { - Local dict = v8::Object::New(); - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(obj, &pos, &key, &value)) { - Handle jsKey = PyObjectWrapper::New(key); - Handle jsValue = PyObjectWrapper::New(value); - dict->Set(jsKey, jsValue); - } - jsVal = dict; - } - else if(PyList_CheckExact(obj)) { - int size = PyList_Size(obj); - Local array = v8::Array::New(size); - PyObject* value; - for(int i = 0; i < size; i++ ){ - value = PyList_GetItem(obj, i); - Handle jsValue = PyObjectWrapper::New(value); - array->Set(i, jsValue); - } - jsVal = array; - } - // double - else if(PyFloat_CheckExact(obj)) { - double d = PyFloat_AsDouble(obj); - jsVal = Local::New(Number::New(d)); - } - // integer (can be 64b) - else if(PyInt_CheckExact(obj)) { - long i = PyInt_AsLong(obj); - jsVal = Local::New(Number::New((double) i)); - } - // string - else if(PyString_CheckExact(obj)) { - // ref to internal representation: no need to dealloc - char *str = PyString_AsString(obj); - if(str) { - jsVal = Local::New(String::New(str)); - } - } - else if(PyBool_Check(obj)) { - int b = PyObject_IsTrue(obj); - if(b != -1) { - jsVal = Local::New(Boolean::New(b)); - } + try { + jsObj = PyObjectWrapper::ConvertToJavaScript(obj); + } catch (int e) { + if (PyErr_Occurred()) { + Py_XDECREF(obj); + return ThrowPythonException(); + } } - if(PyErr_Occurred()) { + if (PyErr_Occurred()) { Py_XDECREF(obj); return ThrowPythonException(); - } - - if(jsVal.IsEmpty()) { - Local jsObj = py_function_template->GetFunction()->NewInstance(); - PyObjectWrapper* wrapper = new PyObjectWrapper(obj); - wrapper->Wrap(jsObj); - jsVal = Local::New(jsObj); - } - else { - Py_XDECREF(obj); - } - return scope.Close(jsVal); + } + + return scope.Close(jsObj); } Handle PyObjectWrapper::Get(Local key, const AccessorInfo& info) { @@ -199,78 +148,152 @@ Handle PyObjectWrapper::ValueOf(const Arguments& args) { return Undefined(); } +Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { + Local jsVal; + // undefined + if(obj == Py_None) { + jsVal = Local::New(Undefined()); + } + // double + else if(PyFloat_CheckExact(obj)) { + printf("float\n"); + double d = PyFloat_AsDouble(obj); + jsVal = Local::New(Number::New(d)); + } + // integer (can be 64b) + else if(PyInt_CheckExact(obj)) { + printf("int\n"); + long i = PyInt_AsLong(obj); + jsVal = Local::New(Number::New((double) i)); + } + // string + else if(PyString_CheckExact(obj)) { + // ref to internal representation: no need to dealloc + char *str = PyString_AsString(obj); + if (str) { + jsVal = Local::New(String::New(str)); + } else { + } + } + else if(PyBool_Check(obj)) { + int b = PyObject_IsTrue(obj); + if(b != -1) { + jsVal = Local::New(Boolean::New(b)); + } + } + // dict + else if(PyDict_CheckExact(obj)) { + Local dict = v8::Object::New(); + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(obj, &pos, &key, &value)) { + Handle jsKey = ConvertToJavaScript(key); + Handle jsValue = ConvertToJavaScript(value); + dict->Set(jsKey, jsValue); + } + jsVal = dict; + Py_XDECREF(key); + Py_XDECREF(value); + } + // list + else if(PyList_CheckExact(obj)) { + int size = PyList_Size(obj); + Local array = v8::Array::New(size); + PyObject* value; + for(int i = 0; i < size; i++ ){ + value = PyList_GetItem(obj, i); + char *format; + if(PyDict_CheckExact(value)) { + printf("damn! dict!\n"); + } + // PyArg_ParseTuple(value, format); + Handle jsValue = ConvertToJavaScript(value); + array->Set(i, jsValue); + } + jsVal = array; + Py_XDECREF(value); + } + + if(jsVal.IsEmpty()) { + Local jsObj = py_function_template->GetFunction()->NewInstance(); + PyObjectWrapper* wrapper = new PyObjectWrapper(obj); + wrapper->Wrap(jsObj); + jsVal = Local::New(jsObj); + } + else { + Py_XDECREF(obj); + } + + return jsVal; +} + PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { int len; - HandleScope scope; - - if(value->IsString()) { - return PyString_FromString(*String::Utf8Value(value->ToString())); + if (value->IsString()) { + PyObject* str = PyString_FromString(*String::Utf8Value(value->ToString())); + return str; } else if (value->IsBoolean()) { - if (value->ToBoolean()->IsTrue()) { - return Py_True; - } else { - return Py_False; - } + if (value->ToBoolean()->IsTrue()) { + return Py_True; + } else { + return Py_False; + } } else if (value->IsNull() || value->IsUndefined()) { - return Py_None; - } else if(value->IsNumber()) { + return Py_None; + } else if (value->IsNumber()) { return PyFloat_FromDouble(value->NumberValue()); - } else if(value->IsDate()) { - Handle date = Handle::Cast(value); + } else if (value->IsDate()) { + Handle date = Handle::Cast(value); PyObject* floatObj = PyFloat_FromDouble(date->NumberValue() / 1000.0 ); // javascript returns milliseconds since epoch. python wants seconds since epoch - PyObject* timeTuple = Py_BuildValue("(O)", floatObj); + PyObject* timeTuple = Py_BuildValue("(O)", floatObj); Py_DECREF(floatObj); PyObject* dateTime = PyDateTime_FromTimestamp(timeTuple); Py_DECREF(timeTuple); return dateTime; - } else if(value->IsObject()) { - if(value->IsArray()) { - Local array = Array::Cast(*value); - len = array->Length(); - PyObject* py_list = PyList_New(len); - for(int i = 0; i < len; ++i) { - Local obj = array->Get(i)->ToObject(); - if (!obj->FindInstanceInPrototypeChain(PyObjectWrapper::py_function_template).IsEmpty()) { - PyObjectWrapper* python_object = ObjectWrap::Unwrap(obj); - PyObject* pyobj = python_object->InstanceGetPyObject(); - PyList_SET_ITEM(py_list, i, pyobj); - } else { - Local js_val = array->Get(i); - PyList_SET_ITEM(py_list, i, ConvertToPython(js_val)); - } - } - return py_list; - } else { - Local obj = value->ToObject(); - if(!obj->FindInstanceInPrototypeChain(PyObjectWrapper::py_function_template).IsEmpty()) { - PyObjectWrapper* python_object = ObjectWrap::Unwrap(value->ToObject()); - PyObject* pyobj = python_object->InstanceGetPyObject(); - return pyobj; - } else { - Local property_names = obj->GetPropertyNames(); - len = property_names->Length(); - PyObject* py_dict = PyDict_New(); - for(int i = 0; i < len; ++i) { - Local str = property_names->Get(i)->ToString(); - Local js_val = obj->Get(str); - PyDict_SetItemString(py_dict, *String::Utf8Value(str), ConvertToPython(js_val)); - } - return py_dict; - } - } + } else if (value->IsObject()) { + if (value->IsArray()) { + Local array = Array::Cast(*value); + len = array->Length(); + PyObject* py_list = PyList_New(len); + for (int i = 0; i < len; ++i) { + Local js_val = array->Get(i); + PyObject* pyobj = ConvertToPython(js_val); + PyList_SET_ITEM(py_list, i, pyobj); + } + return py_list; + } else { + Local obj = value->ToObject(); + if(!obj->FindInstanceInPrototypeChain(PyObjectWrapper::py_function_template).IsEmpty()) { + PyObjectWrapper* python_object = ObjectWrap::Unwrap(value->ToObject()); + PyObject* pyobj = python_object->InstanceGetPyObject(); + return pyobj; + } else { + Local property_names = obj->GetPropertyNames(); + len = property_names->Length(); + PyObject* py_dict = PyDict_New(); + + for (int i = 0; i < len; ++i) { + Local str = property_names->Get(i)->ToString(); + Local js_val = obj->Get(str); + PyDict_SetItemString(py_dict, *String::Utf8Value(str), ConvertToPython(js_val)); + } + return py_dict; + } + } return NULL; - } else if(value->IsArray()) { - Local array = Array::Cast(*value); - len = array->Length(); - PyObject* py_list = PyList_New(len); - for(int i = 0; i < len; ++i) { - Local js_val = array->Get(i); - PyList_SET_ITEM(py_list, i, ConvertToPython(js_val)); - } - return py_list; - } else if(value->IsUndefined()) { + } else if (value->IsArray()) { + Local array = Array::Cast(*value); + len = array->Length(); + PyObject* py_list = PyList_New(len); + for (int i = 0; i < len; ++i) { + Local js_val = array->Get(i); + PyList_SET_ITEM(py_list, i, ConvertToPython(js_val)); + } + return py_list; + } else if (value->IsUndefined()) { Py_RETURN_NONE; } + return NULL; } @@ -280,7 +303,7 @@ Handle PyObjectWrapper::InstanceCall(const Arguments& args) { int len = args.Length(); PyObject* args_tuple = PyTuple_New(len); - for(int i = 0; i < len; ++i) { + for (int i = 0; i < len; ++i) { PyObject* py_arg = ConvertToPython(args[i]); if (PyErr_Occurred()) { return ThrowPythonException(); @@ -294,7 +317,7 @@ Handle PyObjectWrapper::InstanceCall(const Arguments& args) { Py_XDECREF(args_tuple); - if(result) { + if (result) { return scope.Close(PyObjectWrapper::New(result)); } else { return ThrowPythonException(); diff --git a/src/py_object_wrapper.h b/src/py_object_wrapper.h index 9020fa0..5824495 100644 --- a/src/py_object_wrapper.h +++ b/src/py_object_wrapper.h @@ -43,6 +43,8 @@ class PyObjectWrapper : public node::ObjectWrap { static Handle ValueOf(const Arguments& args); static PyObject* ConvertToPython(const Handle& value); + + static Local ConvertToJavaScript(PyObject* obj); PyObject* InstanceGetPyObject() { return mPyObject; diff --git a/test/index.js b/test/index.js index 5d878d8..a48f3b2 100644 --- a/test/index.js +++ b/test/index.js @@ -25,9 +25,9 @@ describe('node-python', function () { }).throw(/No module named jibberish/); }); it('should throw an Error when importing a module that includes bad syntax', function () { - should(function () { - python.import('test'); - }).throw(/Python Error: SyntaxError/) + should(function () { + python.import('test'); + }).throw(/Python Error: SyntaxError/); }); }); it('should convert javascript null to python NoneType', function () { @@ -52,7 +52,7 @@ describe('node-python', function () { }); it('should convert javascript numbers to python floats', function () { test = python.import('test2'); - var type = test.getPythonTypeName(1); + var type = test.getPythonTypeName(1.1); type.should.equal('float'); }); it('should convert javascript arrays to python list', function () { @@ -89,7 +89,7 @@ describe('node-python', function () { type.should.equal('list'); var i = 0, arr = []; while (i < 10000) { - arr.push(Math.random().toString()) + arr.push(Math.random().toString()); i++; } var type = test.getPythonTypeName(arr); @@ -104,7 +104,7 @@ describe('node-python', function () { }); it('should convert python lists to javascript arrays', function () { test = python.import('test2'); - var value = test.getPythonValue([ 1, 2, 3]); + var value = test.getPythonValue([ '1', '2', '3']); value.should.containEql(1); value.should.containEql(2); value.should.containEql(3); From 6e3891abc15c845dc0d2d25cc48ac84d4f9bd495 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Tue, 4 Nov 2014 19:21:05 -0500 Subject: [PATCH 02/37] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46b4829..a462096 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc4", + "version": "v0.0.5-rc5", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From eb27de22083f113a73b2df2b73d709fb3860d8fb Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 5 Nov 2014 11:10:41 -0500 Subject: [PATCH 03/37] fixing problems decrementing references to items in lists and dicts --- src/py_object_wrapper.cc | 22 +++++++++------------- test/index.js | 14 ++++++++++++++ test/support/test3.py | 7 +++++++ test/support/test3.pyc | Bin 0 -> 688 bytes 4 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 test/support/test3.py create mode 100644 test/support/test3.pyc diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 66e478b..33d8203 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -154,17 +154,20 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { if(obj == Py_None) { jsVal = Local::New(Undefined()); } + // integer (can be 64b) + else if(PyInt_CheckExact(obj)) { + long i = PyInt_AsLong(obj); + jsVal = Local::New(Number::New((double) i)); + } // double else if(PyFloat_CheckExact(obj)) { - printf("float\n"); double d = PyFloat_AsDouble(obj); jsVal = Local::New(Number::New(d)); } - // integer (can be 64b) - else if(PyInt_CheckExact(obj)) { - printf("int\n"); - long i = PyInt_AsLong(obj); - jsVal = Local::New(Number::New((double) i)); + // double + else if(PyLong_CheckExact(obj)) { + double d = PyFloat_AsDouble(obj); + jsVal = Local::New(Number::New(d)); } // string else if(PyString_CheckExact(obj)) { @@ -192,8 +195,6 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { dict->Set(jsKey, jsValue); } jsVal = dict; - Py_XDECREF(key); - Py_XDECREF(value); } // list else if(PyList_CheckExact(obj)) { @@ -203,15 +204,10 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { for(int i = 0; i < size; i++ ){ value = PyList_GetItem(obj, i); char *format; - if(PyDict_CheckExact(value)) { - printf("damn! dict!\n"); - } - // PyArg_ParseTuple(value, format); Handle jsValue = ConvertToJavaScript(value); array->Set(i, jsValue); } jsVal = array; - Py_XDECREF(value); } if(jsVal.IsEmpty()) { diff --git a/test/index.js b/test/index.js index a48f3b2..c41e1fb 100644 --- a/test/index.js +++ b/test/index.js @@ -109,4 +109,18 @@ describe('node-python', function () { value.should.containEql(2); value.should.containEql(3); }); + it('should convert basic python dict to javascript object', function () { + test = python.import('test3'); + var obj = test.getPythonDict(); + obj.should.have.property('one', 1); + obj.should.have.property('two', '2'); + obj.should.have.property('three', 3); + }); + it('should convert basic python list to javascript array', function () { + test = python.import('test3'); + var obj = test.getPythonList(); + obj.should.have.containEql(1); + obj.should.have.containEql('2'); + obj.should.have.containEql('three'); + }); }); \ No newline at end of file diff --git a/test/support/test3.py b/test/support/test3.py new file mode 100644 index 0000000..23a6125 --- /dev/null +++ b/test/support/test3.py @@ -0,0 +1,7 @@ +from decimal import * + +def getPythonDict(): + return dict(one=1, two=str(Decimal(2)), three=3) + +def getPythonList(): + return [1, str(Decimal(2)), 'three'] \ No newline at end of file diff --git a/test/support/test3.pyc b/test/support/test3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8efb4387d16f588fae91359f37b458f0accdaf1e GIT binary patch literal 688 zcmcIiO-sW-5S=8gABFw^Z(f8T=pMX^2rXWeB5A$!A|*Sv3rRL)r;6wLkNpAqW?THY z>ymky$`ciuW}l90M$#gesz$P3etjo{-IAl9KJwH1DIyePHDY zGEq4FqS{9_LWC3Di&UTi0s15oY!bp_`(*cML)kRfBNNGhzF`+RwU8I@bTHBTWYsY{ z{hY_W9y04niN}I;q9kK3UA?Gsr1TBp2Bmoj+yzrFM2zKUu6$c_BZez3rSpw@a%>uJ z`K*1Fm2Zr25EIsI>pO|X#W{9{pjxur$DT3n*I|NANlB@wOJ^G)!Vv&g!Uc$j3p?c* zEi>4tZIdWB$}E&BSE@n<7kgSFe!#yexpP7EzMYcE)?>BQZY?b|FAjc96NmfDk(B Date: Wed, 5 Nov 2014 11:11:04 -0500 Subject: [PATCH 04/37] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a462096..2cdfed1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc5", + "version": "v0.0.5-rc6", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 19e6088ee006cba97abe40d40e196afcc4320d84 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 5 Nov 2014 11:53:48 -0500 Subject: [PATCH 05/37] only Py_XDECREFing objects after individual conversions, escapes bug where components of a dictionary get DECREFed before their final use, in the case of keys --- src/py_object_wrapper.cc | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 33d8203..ca2d182 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -36,16 +36,14 @@ Handle PyObjectWrapper::New(PyObject* obj) { Local jsObj; try { - jsObj = PyObjectWrapper::ConvertToJavaScript(obj); + jsObj = ConvertToJavaScript(obj); } catch (int e) { if (PyErr_Occurred()) { - Py_XDECREF(obj); return ThrowPythonException(); } } if (PyErr_Occurred()) { - Py_XDECREF(obj); return ThrowPythonException(); } @@ -130,9 +128,9 @@ Handle PyObjectWrapper::ValueOf(const Arguments& args) { PyObject* keys = PyMapping_Keys(py_obj); PyObject* values = PyMapping_Values(py_obj); for(int i = 0; i < len; ++i) { - PyObject *key = PySequence_GetItem(keys, i), - *value = PySequence_GetItem(values, i), - *key_as_string = PyObject_Str(key); + PyObject *key = PySequence_GetItem(keys, i); + PyObject *value = PySequence_GetItem(values, i); + PyObject *key_as_string = PyObject_Str(key); char* cstr = PyString_AsString(key_as_string); Local jsobj = PyObjectWrapper::py_function_template->GetFunction()->NewInstance(); @@ -153,21 +151,31 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { // undefined if(obj == Py_None) { jsVal = Local::New(Undefined()); + Py_XDECREF(obj); } // integer (can be 64b) else if(PyInt_CheckExact(obj)) { long i = PyInt_AsLong(obj); jsVal = Local::New(Number::New((double) i)); + Py_XDECREF(obj); } // double else if(PyFloat_CheckExact(obj)) { double d = PyFloat_AsDouble(obj); jsVal = Local::New(Number::New(d)); + Py_XDECREF(obj); } - // double + // long else if(PyLong_CheckExact(obj)) { - double d = PyFloat_AsDouble(obj); + double d; + try{ + d = PyLong_AsDouble(obj); + } + catch (OverflowError error) { + + } jsVal = Local::New(Number::New(d)); + Py_XDECREF(obj); } // string else if(PyString_CheckExact(obj)) { @@ -177,12 +185,14 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { jsVal = Local::New(String::New(str)); } else { } + Py_XDECREF(obj); } else if(PyBool_Check(obj)) { int b = PyObject_IsTrue(obj); if(b != -1) { jsVal = Local::New(Boolean::New(b)); } + Py_XDECREF(obj); } // dict else if(PyDict_CheckExact(obj)) { @@ -216,9 +226,6 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { wrapper->Wrap(jsObj); jsVal = Local::New(jsObj); } - else { - Py_XDECREF(obj); - } return jsVal; } From b4d8d0d7733951222b91b6d17922fdc819434db6 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 5 Nov 2014 12:02:29 -0500 Subject: [PATCH 06/37] removing decrefing on dicts --- package.json | 2 +- src/py_object_wrapper.cc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 2cdfed1..a06912f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc6", + "version": "v0.0.5-rc7", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index ca2d182..930a1d6 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -205,6 +205,10 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { dict->Set(jsKey, jsValue); } jsVal = dict; + // TODO: figure out correct way to DECREF a dict + // Py_XDECREF(key); + // Py_XDECREF(value); + // Py_XDECREF(obj); } // list else if(PyList_CheckExact(obj)) { @@ -218,6 +222,7 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { array->Set(i, jsValue); } jsVal = array; + Py_XDECREF(obj); } if(jsVal.IsEmpty()) { From 6732ac96cdd396460041a75185942c060fac2583 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:03:21 -0500 Subject: [PATCH 07/37] getting python dates to convert to js dates correctly --- src/py_object_wrapper.cc | 31 +++++++++++++++++++++++++++++++ test/index.js | 21 +++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 930a1d6..e238258 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -1,7 +1,9 @@ #include +#include #include "py_object_wrapper.h" #include "utils.h" #include "datetime.h" +#include "time.h" Persistent PyObjectWrapper::py_function_template; @@ -187,6 +189,7 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { } Py_XDECREF(obj); } + // bool else if(PyBool_Check(obj)) { int b = PyObject_IsTrue(obj); if(b != -1) { @@ -194,6 +197,34 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { } Py_XDECREF(obj); } + // date + else if (PyDateTime_Check(obj)) { + + struct tm tmp; + + int year = PyDateTime_GET_YEAR(obj); + int month = PyDateTime_GET_MONTH(obj); + int day = PyDateTime_GET_DAY(obj); + + tmp.tm_year = year - 1900; + tmp.tm_mon = month - 1; + + if ((day == 28) && (month == 2) && (year % 4 == 0) && (year % 100 == 0 && year % 400 != 0)) { + tmp.tm_mday = 29; + } else { + tmp.tm_mday = day; + } + + tmp.tm_hour = PyDateTime_DATE_GET_HOUR(obj) + 1; + tmp.tm_min = PyDateTime_DATE_GET_MINUTE(obj); + tmp.tm_sec = PyDateTime_DATE_GET_SECOND(obj); + + int milliseconds = PyDateTime_DATE_GET_MICROSECOND(obj) / 1000; + + time_t result = mktime(&tmp) * 1000 + milliseconds; + + jsVal = v8::Date::New(result); + } // dict else if(PyDict_CheckExact(obj)) { Local dict = v8::Object::New(); diff --git a/test/index.js b/test/index.js index c41e1fb..7dc2a80 100644 --- a/test/index.js +++ b/test/index.js @@ -109,6 +109,27 @@ describe('node-python', function () { value.should.containEql(2); value.should.containEql(3); }); + it('should convert python strings to javascript strings', function () { + test = python.import('test2'); + var value = test.getPythonValue('str'); + value.should.equal('str'); + }); + it('should convert python boolean to javascript booleans', function () { + test = python.import('test2'); + var value = test.getPythonValue(true); + value.should.equal(true); + }); + it('should convert python numbers to javascript numbers', function () { + test = python.import('test2'); + var value = test.getPythonValue(1); + value.should.equal(1); + }); + it('should convert python dates to javascript dates', function () { + test = python.import('test2'); + var date = new Date(); + var value = test.getPythonValue(date); + value.should.eql(date); + }); it('should convert basic python dict to javascript object', function () { test = python.import('test3'); var obj = test.getPythonDict(); From 577845ab0877d7762e7837d5aeb142caff3036e5 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:03:39 -0500 Subject: [PATCH 08/37] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a06912f..4f32041 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc7", + "version": "v0.0.5-rc8", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 6a75ead5d74844ad94b945ba67552cd1cdc9e19e Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:10:08 -0500 Subject: [PATCH 09/37] updating readme --- README.md | 67 ++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 887f4a7..74d9e36 100644 --- a/README.md +++ b/README.md @@ -29,38 +29,35 @@ You should now go have fun with that and make it brokes :) ## Current status -What should work: - -* Conversion between None and Undefined -* Conversion between Python's and Node's Boolean -* Conversion between Python's and Node's String -* Calling python functions from node -* Conversion from Python's Array to Node's Array - -What may be broken: - -* Losing precision from Python's 64 bits Integer to Node's Number -* If you're using node v0.6.x (please upgrade) you'll have to manually compile with node-gyp - -What's to be done: - -* Conversion from Node's Array to Python's Array -* Pass javascript object to python -* Call javascript function from python - -What would be realy awesome: - -* Proper object introspection - - -## History - -* **v0.0.4** : 2013-10-09 - - use the bindings module to load the native extension -* **v0.0.3** : 2013-07-06 - - Refactor - - Better type conversion & error handling - - Compilation now properly working on both OSX and Linux. Windows compilation _may_ work too -* **v0.0.2** : 2012-12-21 - - Forked from [chrisdickinson/node-python](https://github.com/chrisdickinson/node-python) - - Compilation with node-gyp +What works: + +(per unit tests) + + node-python + ✓ should convert javascript null to python NoneType + ✓ should convert javascript undefined to python NoneType + ✓ should convert javascript booleans to python booleans + ✓ should convert javascript date to python date + ✓ should convert javascript numbers to python floats + ✓ should convert javascript arrays to python list + ✓ should convert javascript objects to python dictionaries + ✓ should convert javascript nested objects correctly + ✓ should convert python dicts to javascript objects + ✓ should convert python lists to javascript arrays + ✓ should convert python strings to javascript strings + ✓ should convert python boolean to javascript booleans + ✓ should convert python numbers to javascript numbers + ✓ should convert python dates to javascript dates + ✓ should convert basic python dict to javascript object + ✓ should convert basic python list to javascript array + eval + ✓ should return resulting value from python statement executed + ✓ should return resulting value from python statement executed, converting to string with complex types + import + ✓ should return object representing module imported, containing functions from imported module + ✓ should throw a PythonError when importing a module that does not exist + ✓ should throw an Error when importing a module that includes bad syntax + +What to watch out for: + +* Losing precision from Python's 64 bits Integer to Node's Number (we hande this by converting decimals to string and using bignumber.js to consume them. better solutions to come) \ No newline at end of file From 3ab61ef0cbbbe9ce91f1087385fd169eb68d11ee Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:11:21 -0500 Subject: [PATCH 10/37] updating readme --- README.md | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 74d9e36..d3c6252 100644 --- a/README.md +++ b/README.md @@ -31,32 +31,32 @@ You should now go have fun with that and make it brokes :) What works: -(per unit tests) - - node-python - ✓ should convert javascript null to python NoneType - ✓ should convert javascript undefined to python NoneType - ✓ should convert javascript booleans to python booleans - ✓ should convert javascript date to python date - ✓ should convert javascript numbers to python floats - ✓ should convert javascript arrays to python list - ✓ should convert javascript objects to python dictionaries - ✓ should convert javascript nested objects correctly - ✓ should convert python dicts to javascript objects - ✓ should convert python lists to javascript arrays - ✓ should convert python strings to javascript strings - ✓ should convert python boolean to javascript booleans - ✓ should convert python numbers to javascript numbers - ✓ should convert python dates to javascript dates - ✓ should convert basic python dict to javascript object - ✓ should convert basic python list to javascript array - eval - ✓ should return resulting value from python statement executed - ✓ should return resulting value from python statement executed, converting to string with complex types - import - ✓ should return object representing module imported, containing functions from imported module - ✓ should throw a PythonError when importing a module that does not exist - ✓ should throw an Error when importing a module that includes bad syntax + - (per unit tests) + + * node-python + * ✓ should convert javascript null to python NoneType + * ✓ should convert javascript undefined to python NoneType + * ✓ should convert javascript booleans to python booleans + * ✓ should convert javascript date to python date + * ✓ should convert javascript numbers to python floats + * ✓ should convert javascript arrays to python list + * ✓ should convert javascript objects to python dictionaries + * ✓ should convert javascript nested objects correctly + * ✓ should convert python dicts to javascript objects + * ✓ should convert python lists to javascript arrays + * ✓ should convert python strings to javascript strings + * ✓ should convert python boolean to javascript booleans + * ✓ should convert python numbers to javascript numbers + * ✓ should convert python dates to javascript dates + * ✓ should convert basic python dict to javascript object + * ✓ should convert basic python list to javascript array + * eval + * ✓ should return resulting value from python statement executed + * ✓ should return resulting value from python statement executed, converting to string with complex types + * import + * ✓ should return object representing module imported, containing functions from imported module + * ✓ should throw a PythonError when importing a module that does not exist + * ✓ should throw an Error when importing a module that includes bad syntax What to watch out for: From d6b3eabbacb69dd84cbeec1e399ada135808453c Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:12:28 -0500 Subject: [PATCH 11/37] updating readme --- README.md | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index d3c6252..af07124 100644 --- a/README.md +++ b/README.md @@ -31,32 +31,27 @@ You should now go have fun with that and make it brokes :) What works: - - (per unit tests) - - * node-python - * ✓ should convert javascript null to python NoneType - * ✓ should convert javascript undefined to python NoneType - * ✓ should convert javascript booleans to python booleans - * ✓ should convert javascript date to python date - * ✓ should convert javascript numbers to python floats - * ✓ should convert javascript arrays to python list - * ✓ should convert javascript objects to python dictionaries - * ✓ should convert javascript nested objects correctly - * ✓ should convert python dicts to javascript objects - * ✓ should convert python lists to javascript arrays - * ✓ should convert python strings to javascript strings - * ✓ should convert python boolean to javascript booleans - * ✓ should convert python numbers to javascript numbers - * ✓ should convert python dates to javascript dates - * ✓ should convert basic python dict to javascript object - * ✓ should convert basic python list to javascript array - * eval - * ✓ should return resulting value from python statement executed - * ✓ should return resulting value from python statement executed, converting to string with complex types - * import - * ✓ should return object representing module imported, containing functions from imported module - * ✓ should throw a PythonError when importing a module that does not exist - * ✓ should throw an Error when importing a module that includes bad syntax + * ✓ should convert javascript null to python NoneType + * ✓ should convert javascript undefined to python NoneType + * ✓ should convert javascript booleans to python booleans + * ✓ should convert javascript date to python date + * ✓ should convert javascript numbers to python floats + * ✓ should convert javascript arrays to python list + * ✓ should convert javascript objects to python dictionaries + * ✓ should convert javascript nested objects correctly + * ✓ should convert python dicts to javascript objects + * ✓ should convert python lists to javascript arrays + * ✓ should convert python strings to javascript strings + * ✓ should convert python boolean to javascript booleans + * ✓ should convert python numbers to javascript numbers + * ✓ should convert python dates to javascript dates + * ✓ should convert basic python dict to javascript object + * ✓ should convert basic python list to javascript array + * ✓ should return resulting value from python statement executed + * ✓ should return resulting value from python statement executed, converting to string with complex types + * ✓ should return object representing module imported, containing functions from imported module + * ✓ should throw a PythonError when importing a module that does not exist + * ✓ should throw an Error when importing a module that includes bad syntax What to watch out for: From 6f9ab74492c41daac9a2852a056372c1f6515b37 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:17:50 -0500 Subject: [PATCH 12/37] readme --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index af07124..1dd71e4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # node-python binding -python bridge for nodejs! - -Hyper-beta, don't hesitate to try and report bugs! +Python bridge for nodejs! Call you python code from node! [![Build Status](https://travis-ci.org/JeanSebTr/node-python.png)](https://travis-ci.org/JeanSebTr/node-python) From fbd401226e210e3956df5d9b28b00e73ae9008a8 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Wed, 12 Nov 2014 00:18:18 -0500 Subject: [PATCH 13/37] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1dd71e4..1b58c62 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # node-python binding -Python bridge for nodejs! Call you python code from node! +Python bridge for nodejs! Call your python code from node! [![Build Status](https://travis-ci.org/JeanSebTr/node-python.png)](https://travis-ci.org/JeanSebTr/node-python) From 3bb8c46627e94c1c64ddb57e083b91c5fde306b7 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Thu, 20 Nov 2014 15:37:59 -0500 Subject: [PATCH 14/37] fixing compile issue on centos --- binding.gyp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/binding.gyp b/binding.gyp index ebeaa63..4e00396 100644 --- a/binding.gyp +++ b/binding.gyp @@ -21,6 +21,10 @@ "cflags": [ " Date: Thu, 20 Nov 2014 15:38:45 -0500 Subject: [PATCH 15/37] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f32041..1f9f142 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc8", + "version": "v0.0.5-rc9", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 384b2c8c34fe6fe390577dc654ca1b6fe2d35f14 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Thu, 20 Nov 2014 16:26:01 -0500 Subject: [PATCH 16/37] second shot at centos compile fix --- binding.gyp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/binding.gyp b/binding.gyp index 4e00396..ce01af9 100644 --- a/binding.gyp +++ b/binding.gyp @@ -19,12 +19,13 @@ } }, { # not OSX "cflags": [ - " Date: Thu, 20 Nov 2014 16:26:19 -0500 Subject: [PATCH 17/37] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1f9f142..4409586 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc9", + "version": "v0.0.5-rc10", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 57db6e361b4381072713ab9a185133334dc29aef Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Fri, 21 Nov 2014 16:57:04 -0500 Subject: [PATCH 18/37] current place --- Makefile | 6 +++++- binding.gyp | 28 ++++++++++++++-------------- src/.py_object_wrapper.cc.swo | Bin 0 -> 16384 bytes src/.py_object_wrapper.cc.swp | Bin 0 -> 24576 bytes src/binding.cc | 2 +- src/py_object_wrapper.cc | 6 +++++- test/support/test2.pyc | Bin 782 -> 710 bytes test/support/test3.pyc | Bin 688 -> 634 bytes test/test.js | 15 +++++++++++++++ 9 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 src/.py_object_wrapper.cc.swo create mode 100644 src/.py_object_wrapper.cc.swp create mode 100644 test/test.js diff --git a/Makefile b/Makefile index fe41d5b..c2e990d 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +LD_PRELOAD=/usr/lib64/libpython2.7.so DEBUG=node-python* PYTHONPATH=./test/support @@ -5,6 +6,9 @@ test: $(MAKE) DEBUG= test-debug test-debug: - DEBUG=$(DEBUG) PYTHONPATH=$(PYTHONPATH) ./node_modules/.bin/mocha -R spec + DEBUG=$(DEBUG) \ + LD_PRELOAD=$(LD_PRELOAD) \ + PYTHONPATH=$(PYTHONPATH) \ + ./node_modules/.bin/mocha -R spec .PHONY: test test-debug diff --git a/binding.gyp b/binding.gyp index ce01af9..f745476 100644 --- a/binding.gyp +++ b/binding.gyp @@ -8,27 +8,27 @@ "src/py_object_wrapper.cc" ], "conditions": [ - ['OS=="mac"', { - "xcode_settings": { - "OTHER_CFLAGS": [ - "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 literal 0 HcmV?d00001 diff --git a/src/.py_object_wrapper.cc.swp b/src/.py_object_wrapper.cc.swp new file mode 100644 index 0000000000000000000000000000000000000000..6a609ce7c7b462cb3dfdff8a8cc78bc6fde92b4c GIT binary patch literal 24576 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 Z6f~X;AF exports) { } -NODE_MODULE(binding, init) \ No newline at end of file +NODE_MODULE(binding, init) diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index e238258..1610988 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -173,7 +173,7 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { try{ d = PyLong_AsDouble(obj); } - catch (OverflowError error) { + catch (int e) { } jsVal = Local::New(Number::New(d)); @@ -216,6 +216,9 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { } tmp.tm_hour = PyDateTime_DATE_GET_HOUR(obj) + 1; + + printf(" c:%d \n", tmp.tm_hour); + tmp.tm_min = PyDateTime_DATE_GET_MINUTE(obj); tmp.tm_sec = PyDateTime_DATE_GET_SECOND(obj); @@ -283,6 +286,7 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { return PyFloat_FromDouble(value->NumberValue()); } else if (value->IsDate()) { Handle date = Handle::Cast(value); + printf(" v8:timestamp: %f \n", date->NumberValue()); PyObject* floatObj = PyFloat_FromDouble(date->NumberValue() / 1000.0 ); // javascript returns milliseconds since epoch. python wants seconds since epoch PyObject* timeTuple = Py_BuildValue("(O)", floatObj); Py_DECREF(floatObj); diff --git a/test/support/test2.pyc b/test/support/test2.pyc index 6c6520c21e380b2efa86935d112a9d0950067bc6..5720fbf197ab141624fada725e93657c3f9946a0 100644 GIT binary patch delta 82 zcmeBUJI2b+{F#?aBtCB<`%F#~1_lQGjQrfx$rBh2Ccf@M5$HwX8BES#azYdN$|MN@ DzrGi5 delta 154 zcmX@c+Q-Ju{F#?)!*$+?>@%g^7#JAzLyJ?3iuH37OG@-pQp-|v@(XfP^GYVyG8s&~ V*+odn`O*G)Mpd diff --git a/test/support/test3.pyc b/test/support/test3.pyc index 8efb4387d16f588fae91359f37b458f0accdaf1e..475a6222dab7d571ed8ebd28a5d3cb37e4fc9ab7 100644 GIT binary patch delta 65 zcmdnM`iq5~`7D9Qi; diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..260f682 --- /dev/null +++ b/test/test.js @@ -0,0 +1,15 @@ +var python = require('../'); +var PythonError = python.PythonError; +var should = require('should'); + +function run () { + test = python.import('test2'); + var date = new Date(); + console.log(' js timestamp before:', date.getTime()); + var value = test.getPythonValue(date); + console.log(date, date.getHours(), value); + console.log(' js timestamp after:', value.getTime()); + value.should.eql(date); +} + +setInterval(run, 100); From 9c2efc0fc68974c49b33b50230f27fabcfb489a3 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Fri, 21 Nov 2014 17:01:13 -0500 Subject: [PATCH 19/37] fixing compile issues on centos. fixing typos in test --- Makefile | 6 +++++- binding.gyp | 30 +++++++++++++++--------------- src/py_object_wrapper.cc | 11 ++++++++--- test/index.js | 7 ++++--- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index fe41d5b..3656b54 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,14 @@ DEBUG=node-python* +LD_PRELOAD=/usr/lib64/libpython2.7.so PYTHONPATH=./test/support test: $(MAKE) DEBUG= test-debug test-debug: - DEBUG=$(DEBUG) PYTHONPATH=$(PYTHONPATH) ./node_modules/.bin/mocha -R spec + DEBUG=$(DEBUG) \ + LD_PRELOAD=$(LD_PRELOAD) \ + PYTHONPATH=$(PYTHONPATH) \ + ./node_modules/.bin/mocha -R spec .PHONY: test test-debug diff --git a/binding.gyp b/binding.gyp index ce01af9..51d95e4 100644 --- a/binding.gyp +++ b/binding.gyp @@ -8,29 +8,29 @@ "src/py_object_wrapper.cc" ], "conditions": [ - ['OS=="mac"', { - "xcode_settings": { - "OTHER_CFLAGS": [ - " PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { try{ d = PyLong_AsDouble(obj); } - catch (OverflowError error) { + catch (int e) { } jsVal = Local::New(Number::New(d)); @@ -283,10 +283,15 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { return PyFloat_FromDouble(value->NumberValue()); } else if (value->IsDate()) { Handle date = Handle::Cast(value); - PyObject* floatObj = PyFloat_FromDouble(date->NumberValue() / 1000.0 ); // javascript returns milliseconds since epoch. python wants seconds since epoch + Local getTime = Local::Cast(date->Get(String::New("getTime"))); + Local result = getTime->Call(date, 0, NULL); + printf(" getTime: %f \n ", result->NumberValue()); + printf(" date->NumberValue: %f \n ", (double) date->NumberValue()); + printf(" date->NumberValue: %s \n ", *String::Utf8Value(date->ToString())); + PyObject* floatObj = PyFloat_FromDouble(date->NumberValue() / 1000 ); // javascript returns milliseconds since epoch. python wants seconds since epoch PyObject* timeTuple = Py_BuildValue("(O)", floatObj); - Py_DECREF(floatObj); PyObject* dateTime = PyDateTime_FromTimestamp(timeTuple); + Py_DECREF(floatObj); Py_DECREF(timeTuple); return dateTime; } else if (value->IsObject()) { diff --git a/test/index.js b/test/index.js index 7dc2a80..1f7cf9d 100644 --- a/test/index.js +++ b/test/index.js @@ -104,10 +104,10 @@ describe('node-python', function () { }); it('should convert python lists to javascript arrays', function () { test = python.import('test2'); - var value = test.getPythonValue([ '1', '2', '3']); + var value = test.getPythonValue([ 1, 2, '3']); value.should.containEql(1); value.should.containEql(2); - value.should.containEql(3); + value.should.containEql('3'); }); it('should convert python strings to javascript strings', function () { test = python.import('test2'); @@ -127,6 +127,7 @@ describe('node-python', function () { it('should convert python dates to javascript dates', function () { test = python.import('test2'); var date = new Date(); + console.log('js: ', date.getTime()); var value = test.getPythonValue(date); value.should.eql(date); }); @@ -144,4 +145,4 @@ describe('node-python', function () { obj.should.have.containEql('2'); obj.should.have.containEql('three'); }); -}); \ No newline at end of file +}); From 1f75a0ceda45d7a0d22f3fb93beda6b43bed9fec Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Fri, 21 Nov 2014 17:01:28 -0500 Subject: [PATCH 20/37] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4409586..585f547 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc10", + "version": "v0.0.5-rc11", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From c2fb4843c83067142e449fded8ed3053e289492e Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Mon, 24 Nov 2014 14:44:21 -0500 Subject: [PATCH 21/37] fixing date conversions on centos --- src/py_object_wrapper.cc | 22 ++++++++++------------ test/test.js | 15 --------------- 2 files changed, 10 insertions(+), 27 deletions(-) delete mode 100644 test/test.js diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 1610988..f0f3b8d 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -217,14 +217,10 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { tmp.tm_hour = PyDateTime_DATE_GET_HOUR(obj) + 1; - printf(" c:%d \n", tmp.tm_hour); - tmp.tm_min = PyDateTime_DATE_GET_MINUTE(obj); tmp.tm_sec = PyDateTime_DATE_GET_SECOND(obj); - int milliseconds = PyDateTime_DATE_GET_MICROSECOND(obj) / 1000; - - time_t result = mktime(&tmp) * 1000 + milliseconds; + time_t result = mktime(&tmp) * 1000 + PyDateTime_DATE_GET_MICROSECOND(obj); jsVal = v8::Date::New(result); } @@ -285,13 +281,15 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { } else if (value->IsNumber()) { return PyFloat_FromDouble(value->NumberValue()); } else if (value->IsDate()) { - Handle date = Handle::Cast(value); - printf(" v8:timestamp: %f \n", date->NumberValue()); - PyObject* floatObj = PyFloat_FromDouble(date->NumberValue() / 1000.0 ); // javascript returns milliseconds since epoch. python wants seconds since epoch - PyObject* timeTuple = Py_BuildValue("(O)", floatObj); - Py_DECREF(floatObj); - PyObject* dateTime = PyDateTime_FromTimestamp(timeTuple); - Py_DECREF(timeTuple); + + Handle dt = Handle::Cast(value); + long sinceEpoch = dt->NumberValue(); + long time = sinceEpoch / 1000; + time_t timestamp = static_cast(time); + struct tm* tmp = localtime(×tamp); + + PyObject* dateTime = PyDateTime_FromDateAndTime(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, sinceEpoch % 1000); + return dateTime; } else if (value->IsObject()) { if (value->IsArray()) { diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 260f682..0000000 --- a/test/test.js +++ /dev/null @@ -1,15 +0,0 @@ -var python = require('../'); -var PythonError = python.PythonError; -var should = require('should'); - -function run () { - test = python.import('test2'); - var date = new Date(); - console.log(' js timestamp before:', date.getTime()); - var value = test.getPythonValue(date); - console.log(date, date.getHours(), value); - console.log(' js timestamp after:', value.getTime()); - value.should.eql(date); -} - -setInterval(run, 100); From 09e34d5a27c021215e80fcdb23bde84e9619fbc0 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Mon, 24 Nov 2014 14:46:13 -0500 Subject: [PATCH 22/37] fixing incorrect test --- test/index.js | 6 +++--- test/support/test2.pyc | Bin 710 -> 782 bytes test/support/test3.pyc | Bin 634 -> 688 bytes 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/index.js b/test/index.js index 7dc2a80..f764793 100644 --- a/test/index.js +++ b/test/index.js @@ -104,10 +104,10 @@ describe('node-python', function () { }); it('should convert python lists to javascript arrays', function () { test = python.import('test2'); - var value = test.getPythonValue([ '1', '2', '3']); - value.should.containEql(1); + var value = test.getPythonValue([ '1', 2, '3']); + value.should.containEql('1'); value.should.containEql(2); - value.should.containEql(3); + value.should.containEql('3'); }); it('should convert python strings to javascript strings', function () { test = python.import('test2'); diff --git a/test/support/test2.pyc b/test/support/test2.pyc index 5720fbf197ab141624fada725e93657c3f9946a0..6c6520c21e380b2efa86935d112a9d0950067bc6 100644 GIT binary patch delta 154 zcmX@c+Q-Ju{F#?)!*$+?>@%g^7#JAzLyJ?3iuH37OG@-pQp-|v@(XfP^GYVyG8s&~ V*+odn`O*G)Mpd delta 82 zcmeBUJI2b+{F#?aBtCB<`%F#~1_lQGjQrfx$rBh2Ccf@M5$HwX8BES#azYdN$|MN@ DzrGi5 diff --git a/test/support/test3.pyc b/test/support/test3.pyc index 475a6222dab7d571ed8ebd28a5d3cb37e4fc9ab7..8efb4387d16f588fae91359f37b458f0accdaf1e 100644 GIT binary patch delta 123 zcmeyxvVoPI`7D9Qi; delta 65 zcmdnM`iq5~`7 Date: Mon, 8 Dec 2014 20:31:16 -0500 Subject: [PATCH 23/37] fixing reference counting (i think) --- src/binding.cc | 1 + src/py_object_wrapper.cc | 42 ++++++++++----------------------------- test/index.js | 23 +++++++++++++++++++++ test/support/test2.pyc | Bin 782 -> 794 bytes test/support/test3.py | 8 +++++++- test/support/test3.pyc | Bin 688 -> 1240 bytes 6 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/binding.cc b/src/binding.cc index 6c881f2..b83d18d 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -3,6 +3,7 @@ #include #include "py_object_wrapper.h" #include "utils.h" +#include using namespace v8; using namespace node; diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 80bd200..9542647 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -39,6 +39,7 @@ Handle PyObjectWrapper::New(PyObject* obj) { try { jsObj = ConvertToJavaScript(obj); + Py_XDECREF(obj); } catch (int e) { if (PyErr_Occurred()) { return ThrowPythonException(); @@ -153,53 +154,33 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { // undefined if(obj == Py_None) { jsVal = Local::New(Undefined()); - Py_XDECREF(obj); } // integer (can be 64b) else if(PyInt_CheckExact(obj)) { long i = PyInt_AsLong(obj); jsVal = Local::New(Number::New((double) i)); - Py_XDECREF(obj); } // double else if(PyFloat_CheckExact(obj)) { double d = PyFloat_AsDouble(obj); jsVal = Local::New(Number::New(d)); - Py_XDECREF(obj); } // long else if(PyLong_CheckExact(obj)) { - double d; - try{ - d = PyLong_AsDouble(obj); - } - catch (int e) { - - } + double d = PyLong_AsDouble(obj); jsVal = Local::New(Number::New(d)); - Py_XDECREF(obj); } // string else if(PyString_CheckExact(obj)) { - // ref to internal representation: no need to dealloc - char *str = PyString_AsString(obj); - if (str) { - jsVal = Local::New(String::New(str)); - } else { - } - Py_XDECREF(obj); + jsVal = Local::New(String::New(PyString_AsString(obj))); } // bool else if(PyBool_Check(obj)) { int b = PyObject_IsTrue(obj); - if(b != -1) { - jsVal = Local::New(Boolean::New(b)); - } - Py_XDECREF(obj); + jsVal = Local::New(Boolean::New(b)); } // date else if (PyDateTime_Check(obj)) { - struct tm tmp; int year = PyDateTime_GET_YEAR(obj); @@ -216,7 +197,6 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { } tmp.tm_hour = PyDateTime_DATE_GET_HOUR(obj) + 1; - tmp.tm_min = PyDateTime_DATE_GET_MINUTE(obj); tmp.tm_sec = PyDateTime_DATE_GET_SECOND(obj); @@ -229,16 +209,14 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { Local dict = v8::Object::New(); PyObject *key, *value; Py_ssize_t pos = 0; + while (PyDict_Next(obj, &pos, &key, &value)) { - Handle jsKey = ConvertToJavaScript(key); + Handle jsKey = Local::New(String::New(PyString_AsString(key))); Handle jsValue = ConvertToJavaScript(value); - dict->Set(jsKey, jsValue); + + dict->Set(jsKey, jsValue); } jsVal = dict; - // TODO: figure out correct way to DECREF a dict - // Py_XDECREF(key); - // Py_XDECREF(value); - // Py_XDECREF(obj); } // list else if(PyList_CheckExact(obj)) { @@ -252,10 +230,10 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { array->Set(i, jsValue); } jsVal = array; - Py_XDECREF(obj); } - + if(jsVal.IsEmpty()) { + Py_XINCREF(obj); Local jsObj = py_function_template->GetFunction()->NewInstance(); PyObjectWrapper* wrapper = new PyObjectWrapper(obj); wrapper->Wrap(jsObj); diff --git a/test/index.js b/test/index.js index 7a36bd0..bb14d48 100644 --- a/test/index.js +++ b/test/index.js @@ -137,6 +137,22 @@ describe('node-python', function () { obj.should.have.property('two', '2'); obj.should.have.property('three', 3); }); + it('should convert nested python dict to javascript object', function () { + + test = python.import('test3'); + + for(var i = 0; i < 10000; i++) { + + var obj = test.getPythonNestedDict(); + obj.should.have.property('one'); + obj.one.should.have.property('four', 4); + obj.one.should.have.property('five', 5); + obj.should.have.property('two', '2'); + obj.should.have.property('three', 3); + + } + + }); it('should convert basic python list to javascript array', function () { test = python.import('test3'); var obj = test.getPythonList(); @@ -144,4 +160,11 @@ describe('node-python', function () { obj.should.have.containEql('2'); obj.should.have.containEql('three'); }); + it('should convert nested python list to javascript array', function () { + test = python.import('test3'); + var obj = test.getPythonNestedList(); + obj.should.have.containEql([4, 5, 6]); + obj.should.have.containEql('2'); + obj.should.have.containEql('three'); + }); }); diff --git a/test/support/test2.pyc b/test/support/test2.pyc index 6c6520c21e380b2efa86935d112a9d0950067bc6..691dbfd5cc6a940ed9e089312350dbc2078ffd50 100644 GIT binary patch delta 218 zcmeBUo5jY?{F#?4uBd(@`%G<51_lQG(BjmhV*TQh)U?FB?9!6#eErm%)Z~(){JhMx m%vAm2#JrTG{EEqQ8I>o#?jli31BvRDCucA@k*wz{lOzBbLQcW} delta 202 zcmbQm*2l)q{F#?)!*$+?>@zjo7#JAzLyJ?3iuH37OG@-pQp-|v@(XfP^Gftnb5fH_ iit_U^(=t;h`!Oj`eAh*i`pL%_V@c7FO1$EGOf~@WXGjSE diff --git a/test/support/test3.py b/test/support/test3.py index 23a6125..0e4d6e2 100644 --- a/test/support/test3.py +++ b/test/support/test3.py @@ -3,5 +3,11 @@ def getPythonDict(): return dict(one=1, two=str(Decimal(2)), three=3) +def getPythonNestedDict(): + return dict(one=dict(four=4, five=5), two=str(Decimal(2)), three=3) + def getPythonList(): - return [1, str(Decimal(2)), 'three'] \ No newline at end of file + return [1, str(Decimal(2)), 'three'] + +def getPythonNestedList(): + return [[4, 5, 6], str(Decimal(2)), 'three'] \ No newline at end of file diff --git a/test/support/test3.pyc b/test/support/test3.pyc index 8efb4387d16f588fae91359f37b458f0accdaf1e..2cdea807cb1b86b8768ab1372b376a38e915b760 100644 GIT binary patch literal 1240 zcmc&zO>fgc5FOh|+XQ;z#1#q2LZX&{BSJ{+1qoTmlnb}u-L$Kw-pD)QfGKsdaatVGUTE;l0YGjW9}xwwfb zg}A9H6LAOfwmihP@ExPfpeepSMa+?WWgha5d6hpjP3;4&* z2a8EVKgGaQbxLvBdmlJm+S&w~3$5C=q`mUoGv9{m#j1oVqe!n{R_~JUQTfE}vIPgK(Z6$z=WidMWp`#<6P xP05Jz?ufE3?cTAI-EglO>J1ySxkEwczuQ@T*t;8Ix!8$Q$y@nf5KtHrNwWwG>H?gEd zKP9y+H7CCyH#M(BKQ$*cxuhsRFEcGOb+SE^@??KT)ycg~QKV|()$qwIE@1;%4RQkm rqn`#dkSbvZ5-F+4nYoEMK_GSz$7Dt(VbV Date: Tue, 9 Dec 2014 11:17:39 -0500 Subject: [PATCH 24/37] debug logging --- src/py_object_wrapper.cc | 4 ++++ test/index.js | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 9542647..21f18c0 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -61,6 +61,7 @@ Handle PyObjectWrapper::Get(Local key, const AccessorInfo& info) String::Utf8Value utf8_key(key); string value(*utf8_key); PyObject* result = wrapper->InstanceGet(value); + if(result) { return PyObjectWrapper::New(result); } @@ -230,6 +231,8 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { array->Set(i, jsValue); } jsVal = array; + } else { + //printf("%s\n", PyString_AsString(PyObject_Repr(obj))); } if(jsVal.IsEmpty()) { @@ -352,5 +355,6 @@ PyObject* PyObjectWrapper::InstanceGet(const string& key) { PyObject* attribute = PyObject_GetAttrString(mPyObject, key.c_str()); return attribute; } + return (PyObject*)NULL; } diff --git a/test/index.js b/test/index.js index bb14d48..8a80511 100644 --- a/test/index.js +++ b/test/index.js @@ -141,15 +141,15 @@ describe('node-python', function () { test = python.import('test3'); - for(var i = 0; i < 10000; i++) { - - var obj = test.getPythonNestedDict(); + var dict = test.getPythonNestedDict; + + for(var i = 0; i < 100000; i++) { + var obj = dict(); obj.should.have.property('one'); obj.one.should.have.property('four', 4); obj.one.should.have.property('five', 5); obj.should.have.property('two', '2'); obj.should.have.property('three', 3); - } }); From e8159cb0b7ec87af11ccad21b317200eec90bc10 Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 9 Dec 2014 11:18:58 -0500 Subject: [PATCH 25/37] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 585f547..46b218e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc11", + "version": "v0.0.5-rc12", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 6ee4ca6cda707f9a386fd4273368289e52b1c5c4 Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 9 Dec 2014 11:21:48 -0500 Subject: [PATCH 26/37] release candidate version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46b218e..69325c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc12", + "version": "v0.0.5-rc13", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From e0eed1d9aacba12d7d273874361484ec0efdc326 Mon Sep 17 00:00:00 2001 From: Matt Walters Date: Tue, 9 Dec 2014 16:41:37 -0500 Subject: [PATCH 27/37] bumping to rc14 to fix tag the easy way --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 69325c4..90e8040 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc13", + "version": "v0.0.5-rc14", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 3711eb0a09405f6eb8f1ba594879367141aa9ad3 Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 9 Dec 2014 19:36:41 -0500 Subject: [PATCH 28/37] updating test --- test/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/index.js b/test/index.js index 8a80511..2231940 100644 --- a/test/index.js +++ b/test/index.js @@ -143,7 +143,7 @@ describe('node-python', function () { var dict = test.getPythonNestedDict; - for(var i = 0; i < 100000; i++) { + for(var i = 0; i < 10000; i++) { var obj = dict(); obj.should.have.property('one'); obj.one.should.have.property('four', 4); From 8f97e166f13c8879a7e4ab2e7a71e05ea84560b0 Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Fri, 12 Dec 2014 19:10:21 -0500 Subject: [PATCH 29/37] fixed refence counting segfaults --- package.json | 2 +- src/py_object_wrapper.cc | 58 +++++++++++++--------------------------- src/utils.cc | 4 ++- 3 files changed, 22 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 90e8040..8b030e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc14", + "version": "v0.0.5-rc15", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 21f18c0..0ef2f30 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -39,7 +39,6 @@ Handle PyObjectWrapper::New(PyObject* obj) { try { jsObj = ConvertToJavaScript(obj); - Py_XDECREF(obj); } catch (int e) { if (PyErr_Occurred()) { return ThrowPythonException(); @@ -54,16 +53,13 @@ Handle PyObjectWrapper::New(PyObject* obj) { } Handle PyObjectWrapper::Get(Local key, const AccessorInfo& info) { - // returning an empty Handle object signals V8 that we didn't - // find the property here, and we should check the "NamedAccessor" functions HandleScope scope; PyObjectWrapper* wrapper = ObjectWrap::Unwrap(info.Holder()); String::Utf8Value utf8_key(key); string value(*utf8_key); PyObject* result = wrapper->InstanceGet(value); - if(result) { - return PyObjectWrapper::New(result); + return scope.Close(PyObjectWrapper::New(result)); } return Handle(); } @@ -134,14 +130,9 @@ Handle PyObjectWrapper::ValueOf(const Arguments& args) { for(int i = 0; i < len; ++i) { PyObject *key = PySequence_GetItem(keys, i); PyObject *value = PySequence_GetItem(values, i); - PyObject *key_as_string = PyObject_Str(key); - char* cstr = PyString_AsString(key_as_string); - Local jsobj = PyObjectWrapper::py_function_template->GetFunction()->NewInstance(); PyObjectWrapper* obj_out = new PyObjectWrapper(value); obj_out->Wrap(jsobj); - Py_XDECREF(key); - Py_XDECREF(key_as_string); } Py_XDECREF(keys); Py_XDECREF(values); @@ -212,7 +203,7 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { Py_ssize_t pos = 0; while (PyDict_Next(obj, &pos, &key, &value)) { - Handle jsKey = Local::New(String::New(PyString_AsString(key))); + Handle jsKey = ConvertToJavaScript(key); Handle jsValue = ConvertToJavaScript(value); dict->Set(jsKey, jsValue); @@ -226,16 +217,10 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { PyObject* value; for(int i = 0; i < size; i++ ){ value = PyList_GetItem(obj, i); - char *format; - Handle jsValue = ConvertToJavaScript(value); - array->Set(i, jsValue); + array->Set(i, ConvertToJavaScript(value)); } jsVal = array; } else { - //printf("%s\n", PyString_AsString(PyObject_Repr(obj))); - } - - if(jsVal.IsEmpty()) { Py_XINCREF(obj); Local jsObj = py_function_template->GetFunction()->NewInstance(); PyObjectWrapper* wrapper = new PyObjectWrapper(obj); @@ -249,8 +234,7 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { int len; if (value->IsString()) { - PyObject* str = PyString_FromString(*String::Utf8Value(value->ToString())); - return str; + return PyString_FromString(*String::Utf8Value(value->ToString())); } else if (value->IsBoolean()) { if (value->ToBoolean()->IsTrue()) { return Py_True; @@ -267,8 +251,7 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { long time = sinceEpoch / 1000; time_t timestamp = static_cast(time); struct tm* tmp = localtime(×tamp); - PyObject* dateTime = PyDateTime_FromDateAndTime(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, sinceEpoch % 1000); - return dateTime; + return PyDateTime_FromDateAndTime(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, sinceEpoch % 1000);; } else if (value->IsObject()) { if (value->IsArray()) { Local array = Array::Cast(*value); @@ -276,12 +259,12 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { PyObject* py_list = PyList_New(len); for (int i = 0; i < len; ++i) { Local js_val = array->Get(i); - PyObject* pyobj = ConvertToPython(js_val); - PyList_SET_ITEM(py_list, i, pyobj); + PyList_SET_ITEM(py_list, i, ConvertToPython(js_val)); } return py_list; } else { Local obj = value->ToObject(); + if(!obj->FindInstanceInPrototypeChain(PyObjectWrapper::py_function_template).IsEmpty()) { PyObjectWrapper* python_object = ObjectWrap::Unwrap(value->ToObject()); PyObject* pyobj = python_object->InstanceGetPyObject(); @@ -319,25 +302,24 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { Handle PyObjectWrapper::InstanceCall(const Arguments& args) { // for now, we don't do anything. HandleScope scope; + int len = args.Length(); PyObject* args_tuple = PyTuple_New(len); - for (int i = 0; i < len; ++i) { - PyObject* py_arg = ConvertToPython(args[i]); - if (PyErr_Occurred()) { - return ThrowPythonException(); - } - PyTuple_SET_ITEM(args_tuple, i, py_arg); + PyTuple_SET_ITEM(args_tuple, i, ConvertToPython(args[i])); } + PyObject* result = PyObject_CallObject(mPyObject, args_tuple); + //Py_XDECREF(args_tuple); + if (PyErr_Occurred()) { return ThrowPythonException(); } - Py_XDECREF(args_tuple); - if (result) { - return scope.Close(PyObjectWrapper::New(result)); + Handle val = PyObjectWrapper::New(result); + Py_XDECREF(result); + return scope.Close(val); } else { return ThrowPythonException(); } @@ -345,16 +327,12 @@ Handle PyObjectWrapper::InstanceCall(const Arguments& args) { string PyObjectWrapper::InstanceToString(const Arguments& args) { PyObject* as_string = PyObject_Str(mPyObject); - string native_string(PyString_AsString(as_string)); - Py_XDECREF(as_string); - return native_string; + return PyString_AsString(as_string); } PyObject* PyObjectWrapper::InstanceGet(const string& key) { if(PyObject_HasAttrString(mPyObject, key.c_str())) { - PyObject* attribute = PyObject_GetAttrString(mPyObject, key.c_str()); - return attribute; - } - + return PyObject_GetAttrString(mPyObject, key.c_str()); + } return (PyObject*)NULL; } diff --git a/src/utils.cc b/src/utils.cc index dd395e1..b1d49a6 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -8,12 +8,14 @@ Handle ThrowPythonException() { PyObject *ptype, *pvalue, *ptraceback; PyErr_Fetch(&ptype, &pvalue, &ptraceback); PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); + // maybe useless to protect against bad use of ThrowPythonException ? if(pvalue == NULL) { return ThrowException( Exception::Error(String::New("No exception found")) ); } + // handle exception message Local msg = String::New("Python Error: "); @@ -33,8 +35,8 @@ Handle ThrowPythonException() { PyObject *module_name, *pyth_module, *pyth_func; module_name = PyString_FromString("traceback"); pyth_module = PyImport_Import(module_name); - Py_DECREF(module_name); + pyth_func = PyObject_GetAttrString(pyth_module, "format_exception"); Py_DECREF(pyth_module); From cf42b15a331a1ee9942200f9bb0437a112f95d6a Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 16 Dec 2014 11:01:07 -0500 Subject: [PATCH 30/37] fixing date conversion logic --- src/py_object_wrapper.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 0ef2f30..3ebeb26 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -251,7 +251,7 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { long time = sinceEpoch / 1000; time_t timestamp = static_cast(time); struct tm* tmp = localtime(×tamp); - return PyDateTime_FromDateAndTime(tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, sinceEpoch % 1000);; + return PyDateTime_FromDateAndTime(tmp->tm_year + 1900, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, sinceEpoch % 1000);; } else if (value->IsObject()) { if (value->IsArray()) { Local array = Array::Cast(*value); From 2654ab6c64338d285954dc755f91d3be00bd8623 Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 16 Dec 2014 11:01:27 -0500 Subject: [PATCH 31/37] fixing date conversion logic --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b030e3..3c36907 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc15", + "version": "v0.0.5-rc16", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 191b1b6f9806dba33a9b33f528f4af5b1b7cc84a Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 16 Dec 2014 12:19:31 -0500 Subject: [PATCH 32/37] fixing date --- src/py_object_wrapper.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index 3ebeb26..ac8ed5d 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -180,7 +180,7 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { int day = PyDateTime_GET_DAY(obj); tmp.tm_year = year - 1900; - tmp.tm_mon = month - 1; + tmp.tm_mon = month; if ((day == 28) && (month == 2) && (year % 4 == 0) && (year % 100 == 0 && year % 400 != 0)) { tmp.tm_mday = 29; From e6ef0213ed625955d3960eece0b095b5544e955a Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Tue, 16 Dec 2014 12:19:55 -0500 Subject: [PATCH 33/37] fixing dates --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c36907..8c4c7db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc16", + "version": "v0.0.5-rc17", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { From 647e9b048d80b0553aa154b51f42b1ab73cbd054 Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Thu, 18 Dec 2014 20:24:14 -0500 Subject: [PATCH 34/37] dates working --- package.json | 2 +- src/py_object_wrapper.cc | 58 +++++++++++++++++++++++++++++----------- test/index.js | 6 +++++ 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 8c4c7db..6ad0db6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc17", + "version": "v0.0.5-rc18", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index ac8ed5d..fef7bf1 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -172,27 +172,45 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { jsVal = Local::New(Boolean::New(b)); } // date - else if (PyDateTime_Check(obj)) { - struct tm tmp; + else if (PyDate_Check(obj)) { + time_t rawtime; + struct tm * timeinfo; + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); int year = PyDateTime_GET_YEAR(obj); int month = PyDateTime_GET_MONTH(obj); int day = PyDateTime_GET_DAY(obj); - tmp.tm_year = year - 1900; - tmp.tm_mon = month; - if ((day == 28) && (month == 2) && (year % 4 == 0) && (year % 100 == 0 && year % 400 != 0)) { - tmp.tm_mday = 29; + timeinfo->tm_mday = 29; + } + + timeinfo->tm_year = year - 1900; + timeinfo->tm_mon = month - 1; + timeinfo->tm_mday = day; + + int microseconds = 0; + if ( PyDateTime_Check(obj) ) { + timeinfo->tm_hour = PyDateTime_DATE_GET_HOUR(obj); + timeinfo->tm_min = PyDateTime_DATE_GET_MINUTE(obj); + timeinfo->tm_sec = PyDateTime_DATE_GET_SECOND(obj); + timeinfo->tm_isdst = -1; + microseconds = PyDateTime_DATE_GET_MICROSECOND(obj); + } else if (PyTime_Check(obj) ) { + timeinfo->tm_hour = PyDateTime_TIME_GET_HOUR(obj); + timeinfo->tm_min = PyDateTime_TIME_GET_MINUTE(obj); + timeinfo->tm_sec = PyDateTime_TIME_GET_SECOND(obj); + timeinfo->tm_isdst = -1; + microseconds = PyDateTime_TIME_GET_MICROSECOND(obj); } else { - tmp.tm_mday = day; + timeinfo->tm_hour = 0; + timeinfo->tm_min = 0; + timeinfo->tm_sec = 0; + timeinfo->tm_isdst = -1; } - - tmp.tm_hour = PyDateTime_DATE_GET_HOUR(obj) + 1; - tmp.tm_min = PyDateTime_DATE_GET_MINUTE(obj); - tmp.tm_sec = PyDateTime_DATE_GET_SECOND(obj); - time_t result = mktime(&tmp) * 1000 + PyDateTime_DATE_GET_MICROSECOND(obj); + time_t result = mktime(timeinfo) * 1000 + microseconds; jsVal = v8::Date::New(result); } @@ -248,10 +266,20 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle& value) { } else if (value->IsDate()) { Handle dt = Handle::Cast(value); long sinceEpoch = dt->NumberValue(); - long time = sinceEpoch / 1000; - time_t timestamp = static_cast(time); + long milliseconds = (sinceEpoch / 1000); + time_t timestamp = (time_t)(milliseconds); + struct tm* tmp = localtime(×tamp); - return PyDateTime_FromDateAndTime(tmp->tm_year + 1900, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec, sinceEpoch % 1000);; + + return PyDateTime_FromDateAndTime( + tmp->tm_year + 1900, + tmp->tm_mon + 1, + tmp->tm_mday, + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + sinceEpoch % 1000 + ); } else if (value->IsObject()) { if (value->IsArray()) { Local array = Array::Cast(*value); diff --git a/test/index.js b/test/index.js index 2231940..70860f8 100644 --- a/test/index.js +++ b/test/index.js @@ -130,6 +130,12 @@ describe('node-python', function () { var value = test.getPythonValue(date); value.should.eql(date); }); + it('should convert summer dates from python to javascript', function () { + test = python.import('test2'); + var date = new Date('06-01-2014'); + var value = test.getPythonValue(date); + value.should.eql(date); + }); it('should convert basic python dict to javascript object', function () { test = python.import('test3'); var obj = test.getPythonDict(); From aca1e05bb38d7a3cde532205fea10b7df080a8dc Mon Sep 17 00:00:00 2001 From: Stefan Kutko Date: Mon, 22 Dec 2014 14:19:11 -0500 Subject: [PATCH 35/37] time conversions --- package.json | 2 +- src/py_object_wrapper.cc | 13 +++++++++---- test/index.js | 8 +++++--- test/support/test2.pyc | Bin 794 -> 801 bytes 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 6ad0db6..167f9f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-python", - "version": "v0.0.5-rc18", + "version": "v0.0.5-rc19", "description": "Call python stuff from nodejs", "main": "index.js", "repository": { diff --git a/src/py_object_wrapper.cc b/src/py_object_wrapper.cc index fef7bf1..d7f1d7a 100644 --- a/src/py_object_wrapper.cc +++ b/src/py_object_wrapper.cc @@ -173,11 +173,11 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { } // date else if (PyDate_Check(obj)) { - time_t rawtime; - struct tm * timeinfo; + time_t rawtime = 0; + + struct tm * timeinfo = { 0 }; + timeinfo = gmtime ( &rawtime ); - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); int year = PyDateTime_GET_YEAR(obj); int month = PyDateTime_GET_MONTH(obj); int day = PyDateTime_GET_DAY(obj); @@ -192,6 +192,11 @@ Local PyObjectWrapper::ConvertToJavaScript(PyObject* obj) { int microseconds = 0; if ( PyDateTime_Check(obj) ) { + PyObject *utcoffset = PyObject_CallMethod(obj, "utcoffset", NULL); + if(utcoffset != Py_None){ + obj = PyNumber_Subtract(obj, utcoffset); + } + timeinfo->tm_hour = PyDateTime_DATE_GET_HOUR(obj); timeinfo->tm_min = PyDateTime_DATE_GET_MINUTE(obj); timeinfo->tm_sec = PyDateTime_DATE_GET_SECOND(obj); diff --git a/test/index.js b/test/index.js index 70860f8..7c82d12 100644 --- a/test/index.js +++ b/test/index.js @@ -126,13 +126,15 @@ describe('node-python', function () { }); it('should convert python dates to javascript dates', function () { test = python.import('test2'); - var date = new Date(); + var date = new Date('2014-12-01'); + console.log(date); var value = test.getPythonValue(date); value.should.eql(date); }); - it('should convert summer dates from python to javascript', function () { + it('should convert daylight savings dates from python to javascript', function () { test = python.import('test2'); - var date = new Date('06-01-2014'); + var date = new Date('2014-06-01'); + console.log(date); var value = test.getPythonValue(date); value.should.eql(date); }); diff --git a/test/support/test2.pyc b/test/support/test2.pyc index 691dbfd5cc6a940ed9e089312350dbc2078ffd50..81895875d778acaa4817e2106d50cc2e96d277c5 100644 GIT binary patch delta 42 xcmbQmwvdgT`7|Yo;IT;ujY8V*YJtqHW>||#F@)#IdC-*Y-0s!ej3L*di delta 35 pcmZ3;Hj9m&`7 Date: Tue, 27 Oct 2015 12:04:22 -0400 Subject: [PATCH 36/37] Add jenkins test reporter. --- .gitignore | 1 + Makefile | 8 ++++++-- package.json | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d6b1210..023e130 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ node_modules npm-debug.log *.swp */**.swp +test-report.xml diff --git a/Makefile b/Makefile index 3ed3854..11819d4 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,18 @@ LD_PRELOAD=/usr/lib64/libpython2.7.so DEBUG=node-python* LD_PRELOAD=/usr/lib64/libpython2.7.so PYTHONPATH=./test/support +REPORTER=spec test: $(MAKE) DEBUG= test-debug - + test-debug: DEBUG=$(DEBUG) \ LD_PRELOAD=$(LD_PRELOAD) \ PYTHONPATH=$(PYTHONPATH) \ - ./node_modules/.bin/mocha -R spec + ./node_modules/.bin/mocha -R $(REPORTER) + +test-jenkins: + $(MAKE) JUNIT_REPORT_PATH=test-report.xml JUNIT_REPORT_STACK=1 REPORTER=mocha-jenkins-reporter test .PHONY: test test-debug diff --git a/package.json b/package.json index 167f9f4..1c3117d 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ }, "devDependencies": { "mocha": "^1.21.3", + "mocha-jenkins-reporter": "^0.1.9", "should": "^4.0.4", "sinon": "^1.10.3" } From 7caa7d0753e907485a4b52c42978e5e78f33d08f Mon Sep 17 00:00:00 2001 From: Andrew McKenzie Date: Mon, 30 Nov 2015 17:04:42 -0500 Subject: [PATCH 37/37] Upgrade debug to 2.2.0 (for nsp compliance). --- package.json | 2 +- test/support/test2.pyc | Bin 801 -> 822 bytes test/support/test3.pyc | Bin 1240 -> 1275 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c3117d..3ed129c 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "readmeFilename": "README.md", "dependencies": { "bindings": "~1.1.1", - "debug": "^1.0.4" + "debug": "^2.2.0" }, "devDependencies": { "mocha": "^1.21.3", diff --git a/test/support/test2.pyc b/test/support/test2.pyc index 81895875d778acaa4817e2106d50cc2e96d277c5..fd789603ea0dd2c7b3657df495b91cf559bc9f6c 100644 GIT binary patch delta 263 zcmZ3;wvCO0`7ZQnUp8{Gae;R>k9I;fo$ZR?8Mwko_4dz8Z55lX;q%Q Hn?)7?JEL#c delta 276 zcmey(d4rRK`7H*m`i9|isB&t`Qe2+yI0IvgJ AcK`qY