[pypy-commit] pypy default: test, fix for tzinfo. datetime inherits from date, but date has no tzinfo, monkeypatch alloc appropriately
mattip
pypy.commits at gmail.com
Sat Feb 17 15:20:26 EST 2018
Author: Matti Picus <matti.picus at gmail.com>
Branch:
Changeset: r93827:c7ea666563e3
Date: 2018-02-17 22:19 +0200
http://bitbucket.org/pypy/pypy/changeset/c7ea666563e3/
Log: test, fix for tzinfo. datetime inherits from date, but date has no
tzinfo, monkeypatch alloc appropriately
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
@@ -2,9 +2,10 @@
from rpython.rtyper.annlowlevel import llhelper
from rpython.rlib.rarithmetic import widen
from pypy.module.cpyext.pyobject import (PyObject, make_ref, make_typedescr,
- decref)
+ decref, as_pyobj, incref)
from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct,
- PyObjectFields, cts, parse_dir, bootstrap_function, slot_function)
+ PyObjectFields, cts, parse_dir, bootstrap_function, slot_function,
+ Py_TPFLAGS_HEAPTYPE)
from pypy.module.cpyext.import_ import PyImport_Import
from pypy.module.cpyext.typeobject import PyTypeObjectPtr
from pypy.interpreter.error import OperationError
@@ -128,6 +129,8 @@
# W_DateTime_Date->tp_dealloc
make_typedescr(W_DateTime_Date.typedef,
basestruct=PyDateTime_DateTime.TO,
+ alloc=date_or_datetime_allocate,
+ attach=type_attach,
dealloc=date_dealloc,
)
@@ -136,10 +139,33 @@
attach=timedeltatype_attach,
)
+def date_or_datetime_allocate(self, space, w_type, itemcount=0, immortal=False):
+ # allocates a date or datetime object. datetime has a tzinfo field, date does not
+ pytype = as_pyobj(space, w_type)
+ pytype = rffi.cast(PyTypeObjectPtr, pytype)
+ if w_type.name == 'date':
+ # XXX we should do this where the 'date' and 'datetime' type is instantiated
+ pytype.c_tp_basicsize = rffi.sizeof(PyObject.TO)
+ size = pytype.c_tp_basicsize
+ incref(space, pytype)
+ assert size >= rffi.sizeof(PyObject.TO)
+ buf = lltype.malloc(rffi.VOIDP.TO, size,
+ flavor='raw', zero=True,
+ add_memory_pressure=True, immortal=immortal)
+ pyobj = rffi.cast(PyObject, buf)
+ pyobj.c_ob_refcnt = 1
+ #pyobj.c_ob_pypy_link should get assigned very quickly
+ pyobj.c_ob_type = pytype
+ return pyobj
+
def type_attach(space, py_obj, w_obj, w_userdata=None):
'''Fills a newly allocated py_obj from the w_obj
- Can be called with a datetime, or a time
'''
+ if space.type(w_obj).name == 'date':
+ # No tzinfo
+ return
+ # just make sure, should be removed
+ assert py_obj.c_ob_type.c_tp_basicsize > rffi.sizeof(PyObject.TO)
py_datetime = rffi.cast(PyDateTime_Time, py_obj)
w_tzinfo = space.getattr(w_obj, space.newtext('tzinfo'))
if space.is_none(w_tzinfo):
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
@@ -82,16 +82,6 @@
date = datetime.datetime.fromtimestamp(0)
assert space.unwrap(space.str(w_date)) == str(date)
- def test_tzinfo(self, space):
- w_tzinfo = space.appexec(
- [], """():
- from datetime import tzinfo
- return tzinfo()
- """)
- assert PyTZInfo_Check(space, w_tzinfo)
- assert PyTZInfo_CheckExact(space, w_tzinfo)
- assert not PyTZInfo_Check(space, space.w_None)
-
class AppTestDatetime(AppTestCpythonExtensionBase):
def test_CAPI(self):
module = self.import_extension('foo', [
@@ -272,3 +262,81 @@
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)
+
+ def test_tzinfo(self):
+ module = self.import_extension('foo', [
+ ("time_with_tzinfo", "METH_O",
+ """ PyDateTime_IMPORT;
+ return PyDateTimeAPI->Time_FromTime(
+ 6, 6, 6, 6, args, PyDateTimeAPI->TimeType);
+ """),
+ ("datetime_with_tzinfo", "METH_O",
+ """
+ PyObject * obj;
+ int tzrefcnt = args->ob_refcnt;
+ PyDateTime_IMPORT;
+ obj = PyDateTimeAPI->DateTime_FromDateAndTime(
+ 2000, 6, 6, 6, 6, 6, 6, args,
+ PyDateTimeAPI->DateTimeType);
+ if (!((PyDateTime_DateTime*)obj)->hastzinfo)
+ {
+ Py_DECREF(obj);
+ PyErr_SetString(PyExc_ValueError, "missing tzinfo");
+ return NULL;
+ }
+ if (((PyDateTime_DateTime*)obj)->tzinfo->ob_refcnt <= tzrefcnt)
+ {
+ Py_DECREF(obj);
+ PyErr_SetString(PyExc_ValueError, "tzinfo refcnt not incremented");
+ return NULL;
+ }
+ return obj;
+
+ """),
+ ], prologue='#include "datetime.h"\n')
+ from datetime import tzinfo, datetime, timedelta, time
+ # copied from datetime documentation
+ class GMT1(tzinfo):
+ 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)
+ assert '+01' in str(dt1)
+ assert module.datetime_with_tzinfo(gmt1) == datetime(
+ 2000, 6, 6, 6, 6, 6, 6, gmt1)
+
+ def test_checks(self):
+ module = self.import_extension('foo', [
+ ("checks", "METH_O",
+ """ PyDateTime_IMPORT;
+ return PyTuple_Pack(10,
+ PyBool_FromLong(PyDateTime_Check(args)),
+ PyBool_FromLong(PyDateTime_CheckExact(args)),
+ PyBool_FromLong(PyDate_Check(args)),
+ PyBool_FromLong(PyDate_CheckExact(args)),
+ PyBool_FromLong(PyTime_Check(args)),
+ PyBool_FromLong(PyTime_CheckExact(args)),
+ PyBool_FromLong(PyDelta_Check(args)),
+ PyBool_FromLong(PyDelta_CheckExact(args)),
+ PyBool_FromLong(PyTZInfo_Check(args)),
+ PyBool_FromLong(PyTZInfo_CheckExact(args))
+ );
+ """),
+ ], prologue='#include "datetime.h"\n')
+ from datetime import tzinfo, datetime, timedelta, time, date
+ o = date(1, 1, 1)
+ assert module.checks(o) == (False,) * 2 + (True,) * 2 + (False,) * 6
+ o = time(1, 1, 1)
+ assert module.checks(o) == (False,) * 4 + (True,) * 2 + (False,) * 4
+ o = timedelta(1, 1, 1)
+ assert module.checks(o) == (False,) * 6 + (True,) * 2 + (False,) * 2
+ o = datetime(1, 1, 1)
+ assert module.checks(o) == (True,) * 3 + (False,) * 7 # isinstance(datetime, date)
+ o = tzinfo()
+ assert module.checks(o) == (False,) * 8 + (True,) * 2
+
More information about the pypy-commit
mailing list