Skip to content

Commit 71d2871

Browse files
author
Matt Walters
committed
fixed conversion of js dates to python datetimes
1 parent c08c54a commit 71d2871

6 files changed

Lines changed: 80 additions & 7 deletions

File tree

src/binding.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <node.h>
22
#include <Python.h>
3-
3+
#include <datetime.h>
44
#include "py_object_wrapper.h"
55
#include "utils.h"
66

@@ -52,7 +52,6 @@ Handle<Value> import(const Arguments& args) {
5252
module = PyImport_Import(module_name);
5353

5454
if (PyErr_Occurred()) {
55-
5655
return ThrowPythonException();
5756
}
5857

@@ -66,8 +65,8 @@ Handle<Value> import(const Arguments& args) {
6665

6766
void init (Handle<Object> exports) {
6867
HandleScope scope;
69-
Py_Initialize();
7068

69+
Py_Initialize();
7170
PyObjectWrapper::Initialize();
7271

7372
// how to schedule Py_Finalize(); to be called when process exits?
@@ -98,4 +97,4 @@ void init (Handle<Object> exports) {
9897

9998
}
10099

101-
NODE_MODULE(binding, init)
100+
NODE_MODULE(binding, init)

src/py_object_wrapper.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
#include <node.h>
22
#include "py_object_wrapper.h"
33
#include "utils.h"
4+
#include "datetime.h"
45

56
Persistent<FunctionTemplate> PyObjectWrapper::py_function_template;
67

78
void PyObjectWrapper::Initialize() {
89
HandleScope scope;
10+
11+
PyDateTime_IMPORT;
12+
913
Local<FunctionTemplate> fn_tpl = FunctionTemplate::New();
1014
Local<ObjectTemplate> proto = fn_tpl->PrototypeTemplate();
1115
Local<ObjectTemplate> obj_tpl = fn_tpl->InstanceTemplate();
@@ -176,6 +180,7 @@ Handle<Value> PyObjectWrapper::ValueOf(const Arguments& args) {
176180
PyObject* PyObjectWrapper::ConvertToPython(const Handle<Value>& value) {
177181
int len;
178182
HandleScope scope;
183+
179184
if(value->IsString()) {
180185
return PyString_FromString(*String::Utf8Value(value->ToString()));
181186
} else if (value->IsBoolean()) {
@@ -186,6 +191,14 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle<Value>& value) {
186191
}
187192
} else if(value->IsNumber()) {
188193
return PyFloat_FromDouble(value->NumberValue());
194+
} else if(value->IsDate()) {
195+
Handle<Date> date = Handle<Date>::Cast(value);
196+
PyObject* floatObj = PyFloat_FromDouble(date->NumberValue() / 1000.0 ); // javascript returns milliseconds since epoch. python wants seconds since epoch
197+
PyObject* timeTuple = Py_BuildValue("(O)", floatObj);
198+
Py_DECREF(floatObj);
199+
PyObject* dateTime = PyDateTime_FromTimestamp(timeTuple);
200+
Py_DECREF(timeTuple);
201+
return dateTime;
189202
} else if(value->IsObject()) {
190203
if(value->IsArray()) {
191204
Local<Array> array = Array::Cast(*value);
@@ -221,7 +234,6 @@ PyObject* PyObjectWrapper::ConvertToPython(const Handle<Value>& value) {
221234
return py_dict;
222235
}
223236
}
224-
225237
return NULL;
226238
} else if(value->IsArray()) {
227239
Local<Array> array = Array::Cast(*value);

test/index.js

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,59 @@ describe('node-python', function () {
3030
}).throw(/Python Error: SyntaxError/)
3131
});
3232
});
33-
});
33+
it('should convert javascript booleans to python booleans', function () {
34+
test = python.import('test2');
35+
var type = test.getPythonTypeName(true);
36+
type.should.equal('bool');
37+
});
38+
it('should convert javascript date to python date', function () {
39+
test = python.import('test2');
40+
var type = test.getPythonTypeName(new Date());
41+
type.should.equal('datetime');
42+
});
43+
it('should convert javascript numbers to python floats', function () {
44+
test = python.import('test2');
45+
var type = test.getPythonTypeName(1);
46+
type.should.equal('float');
47+
});
48+
it('should convert javascript arrays to python list', function () {
49+
test = python.import('test2');
50+
var type = test.getPythonTypeName([]);
51+
type.should.equal('list');
52+
});
53+
it('should convert javascript objects to python dictionaries', function () {
54+
test = python.import('test2');
55+
var type = test.getPythonTypeName({});
56+
type.should.equal('dict');
57+
});
58+
it('should convert javascript nested objects correctly', function () {
59+
test = python.import('test2');
60+
var type = test.getPythonTypeName2({
61+
value: 1
62+
}, 'value');
63+
type.should.equal('float');
64+
var type = test.getPythonTypeName2({
65+
value: true
66+
}, 'value');
67+
type.should.equal('bool');
68+
var type = test.getPythonTypeName2({
69+
value: new Date()
70+
}, 'value');
71+
type.should.equal('datetime');
72+
var type = test.getPythonTypeName2({
73+
value: {}
74+
}, 'value');
75+
type.should.equal('dict');
76+
var type = test.getPythonTypeName2({
77+
value: ['one', 'two', 'three']
78+
}, 'value');
79+
type.should.equal('list');
80+
var i = 0, arr = [];
81+
while (i < 10000) {
82+
arr.push(Math.random().toString())
83+
i++;
84+
}
85+
var type = test.getPythonTypeName(arr);
86+
type.should.equal('list');
87+
});
88+
});

test/support/test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ def good(self):
44

55
class Bad():
66
def bad(self):
7-
should cause parse error
7+
should cause parse error

test/support/test2.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def getPythonTypeName(value):
2+
return type(value).__name__
3+
def getPythonTypeName2(value, index):
4+
item = value[index]
5+
return type(item).__name__
6+
def getPythonValue(value):
7+
return value

test/support/test2.pyc

782 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)