[pypy-commit] pypy datetime_api_27: Add _FromTimestamp methods to CAPI capsule

pganssle pypy.commits at gmail.com
Sun Apr 14 10:00:15 EDT 2019


Author: Paul Ganssle <paul at ganssle.io>
Branch: datetime_api_27
Changeset: r96483:d5b44bb7b84d
Date: 2019-04-12 12:44 -0400
http://bitbucket.org/pypy/pypy/changeset/d5b44bb7b84d/

Log:	Add _FromTimestamp methods to CAPI capsule

	The CPython CAPI capsule includes fromtimestamp constructors, but
	the current cpyext implementation does not, which causes some
	problems for people writing C extensions that use the capsule
	directly rather than the C macros.

	Closes bitbucket issue #2986:
	https://bitbucket.org/pypy/pypy/issues/2986

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
@@ -67,6 +67,14 @@
         _PyDelta_FromDelta.api_func.functype,
         _PyDelta_FromDelta.api_func.get_wrapper(space))
 
+    datetimeAPI.c_DateTime_FromTimestamp = llhelper(
+        _PyDateTime_FromTimestamp.api_func.functype,
+        _PyDateTime_FromTimestamp.api_func.get_wrapper(space))
+
+    datetimeAPI.c_Date_FromTimestamp = llhelper(
+        _PyDate_FromTimestamp.api_func.functype,
+        _PyDate_FromTimestamp.api_func.get_wrapper(space))
+
     state.datetimeAPI.append(datetimeAPI)
     return state.datetimeAPI[0]
 
@@ -243,8 +251,16 @@
     """
     w_datetime = PyImport_Import(space, space.newtext("datetime"))
     w_type = space.getattr(w_datetime, space.newtext("datetime"))
+    return _PyDateTime_FromTimestamp(space, w_type, w_args, None)
+
+ at cpython_api([PyObject, PyObject, PyObject], PyObject)
+def _PyDateTime_FromTimestamp(space, w_type, w_args, w_kwds):
+    """Implementation of datetime.fromtimestamp that matches the signature for
+    PyDatetimeCAPI.DateTime_FromTimestamp
+    """
     w_method = space.getattr(w_type, space.newtext("fromtimestamp"))
-    return space.call(w_method, w_args)
+
+    return space.call(w_method, w_args, w_kwds=w_kwds)
 
 @cpython_api([PyObject], PyObject)
 def PyDate_FromTimestamp(space, w_args):
@@ -253,6 +269,12 @@
     """
     w_datetime = PyImport_Import(space, space.newtext("datetime"))
     w_type = space.getattr(w_datetime, space.newtext("date"))
+    return _PyDate_FromTimestamp(space, w_type, w_args)
+
+ at cpython_api([PyObject, PyObject], PyObject)
+def _PyDate_FromTimestamp(space, w_type, w_args):
+    """Implementation of date.fromtimestamp that matches the signature for
+    PyDatetimeCAPI.Date_FromTimestamp"""
     w_method = space.getattr(w_type, space.newtext("fromtimestamp"))
     return space.call(w_method, w_args)
 
diff --git a/pypy/module/cpyext/parse/cpyext_datetime.h b/pypy/module/cpyext/parse/cpyext_datetime.h
--- a/pypy/module/cpyext/parse/cpyext_datetime.h
+++ b/pypy/module/cpyext/parse/cpyext_datetime.h
@@ -13,6 +13,10 @@
         PyObject*, PyTypeObject*);
     PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*);
     PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*);
+
+    /* constructors for the DB API */
+    PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*);
+    PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*);
 } PyDateTime_CAPI;
 
 typedef struct
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
@@ -146,6 +146,41 @@
                     2000, 6, 6, 6, 6, 6, 6, Py_None,
                     PyDateTimeAPI->DateTimeType);
              """),
+            ("new_datetime_fromtimestamp", "METH_NOARGS",
+             """ PyDateTime_IMPORT;
+                 PyObject *ts = PyFloat_FromDouble(200000.0);
+                 Py_INCREF(Py_None);
+                 PyObject *tsargs = PyTuple_Pack(2, ts, Py_None);
+                 PyObject *rv = PyDateTimeAPI->DateTime_FromTimestamp(
+                    (PyObject *)PyDateTimeAPI->DateTimeType, tsargs, NULL);
+                 Py_DECREF(tsargs);
+                 return rv;
+             """),
+            ("new_dt_fromts_tzinfo", "METH_O",
+             """ PyDateTime_IMPORT;
+                 PyObject *ts = PyFloat_FromDouble(200000.0);
+                 PyObject *tsargs = PyTuple_Pack(1, ts);
+                 PyObject *tskwargs = PyDict_New();
+
+                 Py_INCREF(args);
+                 PyDict_SetItemString(tskwargs, "tz", args);
+                 PyObject *rv = PyDateTimeAPI->DateTime_FromTimestamp(
+                    (PyObject *)PyDateTimeAPI->DateTimeType, tsargs, tskwargs);
+                 Py_DECREF(tsargs);
+                 Py_DECREF(tskwargs);
+                 return rv;
+             """),
+            ("new_date_fromtimestamp", "METH_NOARGS",
+             """ PyDateTime_IMPORT;
+                 PyObject *ts = PyFloat_FromDouble(1430366400.0);
+                 Py_INCREF(Py_None);
+                 PyObject *tsargs = PyTuple_Pack(1, ts);
+                 PyObject *rv = PyDateTimeAPI->Date_FromTimestamp(
+                    (PyObject *)PyDateTimeAPI->DateType, tsargs);
+                 Py_DECREF(tsargs);
+                 return rv;
+             """),
+
         ], prologue='#include "datetime.h"\n')
         import datetime
         assert module.new_date() == datetime.date(2000, 6, 6)
@@ -153,6 +188,28 @@
         assert module.new_datetime() == datetime.datetime(
             2000, 6, 6, 6, 6, 6, 6)
 
+        class UTC(datetime.tzinfo):
+            def utcoffset(self, dt):
+                return datetime.timedelta(hours=0)
+
+            def dst(self, dt):
+                return datetime.timedelta(0)
+
+            def tzname(self, dt):
+                return "UTC"
+
+        utc = UTC()
+
+        # .fromtimestamp tests
+        assert (module.new_datetime_fromtimestamp() ==
+                datetime.datetime.fromtimestamp(200000.0))
+
+        assert (module.new_dt_fromts_tzinfo(utc) ==
+                datetime.datetime.fromtimestamp(200000.0, tz=utc))
+
+        assert (module.new_date_fromtimestamp() ==
+                datetime.date.fromtimestamp(1430366400.0))
+
     def test_macros(self):
         module = self.import_extension('foo', [
             ("test_date_macros", "METH_NOARGS",
@@ -305,16 +362,18 @@
              """),
         ], prologue='#include "datetime.h"\n')
         from datetime import tzinfo, datetime, timedelta, time
+
         # copied from datetime documentation
         class GMT1(tzinfo):
             def __del__(self):
-                print 'deleting GMT1'
+                print('deleting GMT1')
             def utcoffset(self, dt):
                 return timedelta(hours=1) + self.dst(dt)
             def dst(self, dt):
                 return timedelta(0)
             def tzname(self,dt):
                 return "GMT +1"
+
         gmt1 = GMT1()
         dt1 = module.time_with_tzinfo(gmt1)
         assert dt1 == time(6, 6, 6, 6, gmt1)


More information about the pypy-commit mailing list