Author: Amaury Forgeot d'Arc <[email protected]>
Branch:
Changeset: r84668:b5096e623454
Date: 2016-05-24 23:01 +0200
http://bitbucket.org/pypy/pypy/changeset/b5096e623454/
Log: Improve the datetime C API: the struct contains function pointers
that are more precise than the extern functions.
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -1,4 +1,5 @@
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.annlowlevel import llhelper
from pypy.module.cpyext.pyobject import PyObject, make_ref
from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct,
PyObjectFields)
@@ -16,6 +17,23 @@
('TimeType', PyTypeObjectPtr),
('DeltaType', PyTypeObjectPtr),
('TZInfoType', PyTypeObjectPtr),
+
+ ('Date_FromDate', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real, PyTypeObjectPtr],
+ PyObject))),
+ ('Time_FromTime', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr],
+ PyObject))),
+ ('DateTime_FromDateAndTime', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr],
+ PyObject))),
+ ('Delta_FromDelta', lltype.Ptr(lltype.FuncType(
+ [rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyTypeObjectPtr],
+ PyObject))),
))
@cpython_api([], lltype.Ptr(PyDateTime_CAPI))
@@ -45,6 +63,19 @@
datetimeAPI.c_TZInfoType = rffi.cast(
PyTypeObjectPtr, make_ref(space, w_type))
+ datetimeAPI.c_Date_FromDate = llhelper(
+ _PyDate_FromDate.api_func.functype,
+ _PyDate_FromDate.api_func.get_wrapper(space))
+ datetimeAPI.c_Time_FromTime = llhelper(
+ _PyTime_FromTime.api_func.functype,
+ _PyTime_FromTime.api_func.get_wrapper(space))
+ datetimeAPI.c_DateTime_FromDateAndTime = llhelper(
+ _PyDateTime_FromDateAndTime.api_func.functype,
+ _PyDateTime_FromDateAndTime.api_func.get_wrapper(space))
+ datetimeAPI.c_Delta_FromDelta = llhelper(
+ _PyDelta_FromDelta.api_func.functype,
+ _PyDelta_FromDelta.api_func.get_wrapper(space))
+
return datetimeAPI
PyDateTime_DateStruct = lltype.ForwardReference()
@@ -94,36 +125,40 @@
make_check_function("PyDelta_Check", "timedelta")
make_check_function("PyTZInfo_Check", "tzinfo")
-# Constructors
+# Constructors. They are better used as macros.
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDate_FromDate(space, year, month, day):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, PyTypeObjectPtr],
+ PyObject)
+def _PyDate_FromDate(space, year, month, day, w_type):
"""Return a datetime.date object with the specified year, month and day.
"""
year = rffi.cast(lltype.Signed, year)
month = rffi.cast(lltype.Signed, month)
day = rffi.cast(lltype.Signed, day)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "date",
+ return space.call_function(
+ w_type,
space.wrap(year), space.wrap(month), space.wrap(day))
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real],
PyObject)
-def PyTime_FromTime(space, hour, minute, second, usecond):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr], PyObject)
+def _PyTime_FromTime(space, hour, minute, second, usecond, w_tzinfo, w_type):
"""Return a ``datetime.time`` object with the specified hour, minute,
second and
microsecond."""
hour = rffi.cast(lltype.Signed, hour)
minute = rffi.cast(lltype.Signed, minute)
second = rffi.cast(lltype.Signed, second)
usecond = rffi.cast(lltype.Signed, usecond)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "time",
+ return space.call_function(
+ w_type,
space.wrap(hour), space.wrap(minute), space.wrap(second),
- space.wrap(usecond))
+ space.wrap(usecond), w_tzinfo)
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDateTime_FromDateAndTime(space, year, month, day, hour, minute, second,
usecond):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyTypeObjectPtr], PyObject)
+def _PyDateTime_FromDateAndTime(space, year, month, day,
+ hour, minute, second, usecond,
+ w_tzinfo, w_type):
"""Return a datetime.datetime object with the specified year, month, day,
hour,
minute, second and microsecond.
"""
@@ -134,12 +169,11 @@
minute = rffi.cast(lltype.Signed, minute)
second = rffi.cast(lltype.Signed, second)
usecond = rffi.cast(lltype.Signed, usecond)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "datetime",
+ return space.call_function(
+ w_type,
space.wrap(year), space.wrap(month), space.wrap(day),
space.wrap(hour), space.wrap(minute), space.wrap(second),
- space.wrap(usecond))
+ space.wrap(usecond), w_tzinfo)
@cpython_api([PyObject], PyObject)
def PyDateTime_FromTimestamp(space, w_args):
@@ -161,8 +195,10 @@
w_method = space.getattr(w_type, space.wrap("fromtimestamp"))
return space.call(w_method, w_args)
-@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDelta_FromDSU(space, days, seconds, useconds):
+@cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyTypeObjectPtr],
+ PyObject)
+def _PyDelta_FromDelta(space, days, seconds, useconds, normalize, w_type):
"""Return a datetime.timedelta object representing the given number of
days,
seconds and microseconds. Normalization is performed so that the resulting
number of microseconds and seconds lie in the ranges documented for
@@ -171,9 +207,8 @@
days = rffi.cast(lltype.Signed, days)
seconds = rffi.cast(lltype.Signed, seconds)
useconds = rffi.cast(lltype.Signed, useconds)
- w_datetime = PyImport_Import(space, space.wrap("datetime"))
- return space.call_method(
- w_datetime, "timedelta",
+ return space.call_function(
+ w_type,
space.wrap(days), space.wrap(seconds), space.wrap(useconds))
# Accessors
diff --git a/pypy/module/cpyext/include/datetime.h
b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -12,6 +12,13 @@
PyTypeObject *TimeType;
PyTypeObject *DeltaType;
PyTypeObject *TZInfoType;
+
+ /* constructors */
+ PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*);
+ PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int,
+ PyObject*, PyTypeObject*);
+ PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*);
+ PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*);
} PyDateTime_CAPI;
PyAPI_DATA(PyDateTime_CAPI*) PyDateTimeAPI;
@@ -41,6 +48,22 @@
PyObject_HEAD
} PyDateTime_TZInfo;
+/* Macros for accessing constructors in a simplified fashion. */
+#define PyDate_FromDate(year, month, day) \
+ PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType)
+
+#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \
+ PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \
+ min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType)
+
+#define PyTime_FromTime(hour, minute, second, usecond) \
+ PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \
+ Py_None, PyDateTimeAPI->TimeType)
+
+#define PyDelta_FromDSU(days, seconds, useconds) \
+ PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \
+ PyDateTimeAPI->DeltaType)
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/test/test_datetime.py
b/pypy/module/cpyext/test/test_datetime.py
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -4,7 +4,8 @@
class TestDatetime(BaseApiTest):
def test_date(self, space, api):
- w_date = api.PyDate_FromDate(2010, 06, 03)
+ date_api = api._PyDateTime_Import()
+ w_date = api._PyDate_FromDate(2010, 06, 03, date_api.c_DateType)
assert space.unwrap(space.str(w_date)) == '2010-06-03'
assert api.PyDate_Check(w_date)
@@ -15,7 +16,9 @@
assert api.PyDateTime_GET_DAY(w_date) == 3
def test_time(self, space, api):
- w_time = api.PyTime_FromTime(23, 15, 40, 123456)
+ date_api = api._PyDateTime_Import()
+ w_time = api._PyTime_FromTime(23, 15, 40, 123456,
+ space.w_None, date_api.c_TimeType)
assert space.unwrap(space.str(w_time)) == '23:15:40.123456'
assert api.PyTime_Check(w_time)
@@ -27,8 +30,10 @@
assert api.PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
def test_datetime(self, space, api):
- w_date = api.PyDateTime_FromDateAndTime(
- 2010, 06, 03, 23, 15, 40, 123456)
+ date_api = api._PyDateTime_Import()
+ w_date = api._PyDateTime_FromDateAndTime(
+ 2010, 06, 03, 23, 15, 40, 123456,
+ space.w_None, date_api.c_DateTimeType)
assert space.unwrap(space.str(w_date)) == '2010-06-03 23:15:40.123456'
assert api.PyDateTime_Check(w_date)
@@ -45,6 +50,7 @@
assert api.PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
def test_delta(self, space, api):
+ date_api = api._PyDateTime_Import()
w_delta = space.appexec(
[space.wrap(3), space.wrap(15)], """(days, seconds):
from datetime import timedelta
@@ -53,7 +59,7 @@
assert api.PyDelta_Check(w_delta)
assert api.PyDelta_CheckExact(w_delta)
- w_delta = api.PyDelta_FromDSU(10, 20, 30)
+ w_delta = api._PyDelta_FromDelta(10, 20, 30, True,
date_api.c_DeltaType)
assert api.PyDelta_Check(w_delta)
assert api.PyDelta_CheckExact(w_delta)
@@ -118,6 +124,31 @@
datetime.tzinfo)
module.clear_types()
+ def test_constructors(self):
+ module = self.import_extension('foo', [
+ ("new_date", "METH_NOARGS",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->Date_FromDate(
+ 2000, 6, 6, PyDateTimeAPI->DateType);
+ """),
+ ("new_time", "METH_NOARGS",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->Time_FromTime(
+ 6, 6, 6, 6, Py_None, PyDateTimeAPI->TimeType);
+ """),
+ ("new_datetime", "METH_NOARGS",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->DateTime_FromDateAndTime(
+ 2000, 6, 6, 6, 6, 6, 6, Py_None,
+ PyDateTimeAPI->DateTimeType);
+ """),
+ ])
+ import datetime
+ assert module.new_date() == datetime.date(2000, 6, 6)
+ assert module.new_time() == datetime.time(6, 6, 6, 6)
+ assert module.new_datetime() == datetime.datetime(
+ 2000, 6, 6, 6, 6, 6, 6)
+
def test_macros(self):
module = self.import_extension('foo', [
("test_date_macros", "METH_NOARGS",
@@ -222,3 +253,9 @@
return obj;
"""),
])
+ import datetime
+ assert module.test_date_macros() == datetime.date(2000, 6, 6)
+ assert module.test_datetime_macros() == datetime.datetime(
+ 2000, 6, 6, 6, 6, 6, 6)
+ assert module.test_time_macros() == datetime.time(6, 6, 6, 6)
+ assert module.test_delta_macros() == datetime.timedelta(6, 6, 6)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit