[Python-checkins] python/nondist/sandbox/datetime datetime.c,1.60,1.61 datetime.py,1.96,1.97 obj_date.c,1.46,1.47 obj_datetime.c,1.44,1.45 obj_time.c,1.7,1.8 obj_timetz.c,1.16,1.17 test_both.py,1.66,1.67
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
2002年12月12日 09:58:31 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv30947
Modified Files:
datetime.c datetime.py obj_date.c obj_datetime.c obj_time.c
obj_timetz.c test_both.py
Log Message:
Tried to implement timetz pickling. This doesn't work in the C
implementation if timetz.tzinfo is non-None; don't know why; it works
in the Python implementation; the C part of the test is disabled
for now.
Fixed a subtle bug in time.__hash__, only triggered if a subclass had
its own __getstate__ and ended up invoking time.__hash__.
Added some more error checks.
There's a new leak when running the tests on the C implementation;
don't know why; it's *not* in the timetz tests, so that makes it a
bit of a mystery.
Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.60
retrieving revision 1.61
diff -C2 -d -r1.60 -r1.61
*** datetime.c 12 Dec 2002 03:15:02 -0000 1.60
--- datetime.c 12 Dec 2002 17:58:28 -0000 1.61
***************
*** 1043,1047 ****
timetz_unpickler_object = PyObject_GetAttrString(m,
"_timetz_unpickler");
! assert(time_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TimeTZType,
--- 1043,1047 ----
timetz_unpickler_object = PyObject_GetAttrString(m,
"_timetz_unpickler");
! assert(timetz_unpickler_object);
temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
&PyDateTime_TimeTZType,
Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.96
retrieving revision 1.97
diff -C2 -d -r1.96 -r1.97
*** datetime.py 12 Dec 2002 04:03:47 -0000 1.96
--- datetime.py 12 Dec 2002 17:58:28 -0000 1.97
***************
*** 814,818 ****
def __hash__(self):
"""Hash."""
! return hash(self.__getstate__())
# Conversions to string
--- 814,821 ----
def __hash__(self):
"""Hash."""
! # Force use of time.__getstate__(). If self is of a subclass
! # type, we want the hash of its projection onto time, not the
! # hash of all the extra stuff it may contain.
! return hash(time.__getstate__(self))
# Conversions to string
***************
*** 971,978 ****
def __hash__(self):
"""Hash."""
! tz = self.__tzinfo
! if tz is None:
! return super(timetz, self).__hash__()
! tzoff = tz.utcoffset(self)
if not tzoff: # zero or None!
return super(timetz, self).__hash__()
--- 974,978 ----
def __hash__(self):
"""Hash."""
! tzoff = self.utcoffset()
if not tzoff: # zero or None!
return super(timetz, self).__hash__()
***************
*** 1083,1086 ****
--- 1083,1106 ----
return tz.dst(self)
+ # Pickle support.
+
+ def __getstate__(self):
+ basestate = time.__getstate__(self)
+ if self.__tzinfo is None:
+ return (basestate,)
+ else:
+ return (basestate, self.__tzinfo)
+
+ def __setstate__(self, state):
+ if not isinstance(state, tuple):
+ raise TypeError("timetz.__setstate__() requires a tuple arg")
+ if not 1 <= len(state) <= 2:
+ raise TypeError("timetz.__setstate__() requires a 1-tuple or "
+ "2-tuple argument")
+ time.__setstate__(self, state[0])
+ if len(state) == 1:
+ self.__tzinfo = None
+ else:
+ self.__tzinfo = state[1]
timetz.min = timetz(0, 0, 0)
Index: obj_date.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_date.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -C2 -d -r1.46 -r1.47
*** obj_date.c 10 Dec 2002 00:13:35 -0000 1.46
--- obj_date.c 12 Dec 2002 17:58:28 -0000 1.47
***************
*** 468,472 ****
if (self != NULL) {
PyObject *res = date_setstate(self, arg);
! Py_XDECREF(res);
}
return (PyObject *)self;
--- 468,475 ----
if (self != NULL) {
PyObject *res = date_setstate(self, arg);
! if (res == NULL) {
! Py_DECREF(self);
! return NULL;
! }
}
return (PyObject *)self;
Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -C2 -d -r1.44 -r1.45
*** obj_datetime.c 9 Dec 2002 23:16:39 -0000 1.44
--- obj_datetime.c 12 Dec 2002 17:58:28 -0000 1.45
***************
*** 585,589 ****
if (self != NULL) {
PyObject *res = datetime_setstate(self, arg);
! Py_XDECREF(res);
}
return (PyObject *)self;
--- 585,592 ----
if (self != NULL) {
PyObject *res = datetime_setstate(self, arg);
! if (res == NULL) {
! Py_DECREF(self);
! return NULL;
! }
}
return (PyObject *)self;
Index: obj_time.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_time.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** obj_time.c 11 Dec 2002 18:54:10 -0000 1.7
--- obj_time.c 12 Dec 2002 17:58:28 -0000 1.8
***************
*** 266,270 ****
if (self != NULL) {
PyObject *res = time_setstate(self, arg);
! Py_XDECREF(res);
}
return (PyObject *)self;
--- 266,274 ----
if (self != NULL) {
PyObject *res = time_setstate(self, arg);
! if (res == NULL) {
! Py_DECREF(self);
! return NULL;
! }
! Py_DECREF(res);
}
return (PyObject *)self;
Index: obj_timetz.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_timetz.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -d -r1.16 -r1.17
*** obj_timetz.c 12 Dec 2002 02:55:16 -0000 1.16
--- obj_timetz.c 12 Dec 2002 17:58:28 -0000 1.17
***************
*** 307,315 ****
/* Pickle support. Quite a maze! */
static PyObject *
timetz_getstate(PyDateTime_TimeTZ *self)
{
! return PyString_FromStringAndSize(self->data,
! _PyDateTime_TIME_DATASIZE);
}
--- 307,329 ----
/* Pickle support. Quite a maze! */
+ /* Let basestate be the state string returned by time_getstate.
+ * If tzinfo is None, this returns (basestate,) * else (basestate, tzinfo).
+ * So it's a tuple in any (non-error) case.
+ */
static PyObject *
timetz_getstate(PyDateTime_TimeTZ *self)
{
! PyObject *basestate;
! PyObject *result = NULL;
!
! basestate = time_getstate((PyDateTime_Time *)self);
! if (basestate != NULL) {
! if (self->tzinfo == Py_None)
! result = Py_BuildValue("(O)", basestate);
! else
! result = Py_BuildValue("OO", basestate, self->tzinfo);
! Py_DECREF(basestate);
! }
! return result;
}
***************
*** 317,331 ****
timetz_setstate(PyDateTime_TimeTZ *self, PyObject *state)
{
! const int len = PyString_Size(state);
! unsigned char *pdata = (unsigned char*)PyString_AsString(state);
! if (! PyString_Check(state) ||
! len != _PyDateTime_TIME_DATASIZE) {
! PyErr_SetString(PyExc_TypeError,
! "bad argument to time.__setstate__");
return NULL;
! }
! memcpy(self->data, pdata, _PyDateTime_TIME_DATASIZE);
! self->hashcode = -1;
Py_INCREF(Py_None);
--- 331,350 ----
timetz_setstate(PyDateTime_TimeTZ *self, PyObject *state)
{
! PyObject *temp;
! PyObject *basestate;
! PyObject *tzinfo = Py_None;
! if (! PyArg_ParseTuple(state, "O!|O:__setstate__",
! &PyString_Type, &basestate,
! &tzinfo))
return NULL;
! temp = time_setstate((PyDateTime_Time *)self, basestate);
! if (temp == NULL)
! return NULL;
! Py_DECREF(temp);
!
! Py_INCREF(tzinfo);
! Py_XDECREF(self->tzinfo);
! self->tzinfo = tzinfo;
Py_INCREF(Py_None);
***************
*** 333,353 ****
}
- /* XXX This seems a ridiculously inefficient way to pickle a short string. */
static PyObject *
! timetz_pickler(PyObject *module, PyDateTime_TimeTZ *time)
{
PyObject *state;
PyObject *result = NULL;
! if (time->ob_type != &PyDateTime_TimeTZType) {
PyErr_Format(PyExc_TypeError,
! "bad type passed to time pickler: %s",
! time->ob_type->tp_name);
return NULL;
}
! state = timetz_getstate(time);
if (state) {
result = Py_BuildValue("O(O)",
! time_unpickler_object,
state);
Py_DECREF(state);
--- 352,371 ----
}
static PyObject *
! timetz_pickler(PyObject *module, PyDateTime_TimeTZ *timetz)
{
PyObject *state;
PyObject *result = NULL;
! if (timetz->ob_type != &PyDateTime_TimeTZType) {
PyErr_Format(PyExc_TypeError,
! "bad type passed to timetz pickler: %s",
! timetz->ob_type->tp_name);
return NULL;
}
! state = timetz_getstate(timetz);
if (state) {
result = Py_BuildValue("O(O)",
! timetz_unpickler_object,
state);
Py_DECREF(state);
***************
*** 361,374 ****
PyDateTime_TimeTZ *self;
- if (! PyString_CheckExact(arg)) {
- PyErr_Format(PyExc_TypeError,
- "bad type passed to time unpickler: %s",
- arg->ob_type->tp_name);
- return NULL;
- }
self = PyObject_New(PyDateTime_TimeTZ, &PyDateTime_TimeTZType);
if (self != NULL) {
! PyObject *res = timetz_setstate(self, arg);
! Py_XDECREF(res);
}
return (PyObject *)self;
--- 379,393 ----
PyDateTime_TimeTZ *self;
self = PyObject_New(PyDateTime_TimeTZ, &PyDateTime_TimeTZType);
if (self != NULL) {
! PyObject *res;
!
! self->tzinfo = NULL;
! res = timetz_setstate(self, arg);
! if (res == NULL) {
! Py_DECREF(self);
! return NULL;
! }
! Py_DECREF(res);
}
return (PyObject *)self;
Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.66
retrieving revision 1.67
diff -C2 -d -r1.66 -r1.67
*** test_both.py 12 Dec 2002 03:24:55 -0000 1.66
--- test_both.py 12 Dec 2002 17:58:28 -0000 1.67
***************
*** 1418,1428 ****
def test_pickling(self):
- # XXX The C implementation of timetz passes this by accident right
- # XXX now, and the Python implementation of timetz fails this by
- # XXX accident. That's because neither of them yet know how to
- # XXX pickle a timetz.
- if self.theclass is timetz and not TESTING_C:
- return
-
import pickle, cPickle
args = 20, 59, 16, 64**2
--- 1418,1421 ----
***************
*** 1568,1571 ****
--- 1561,1604 ----
else:
self.assertRaises(ValueError, str, t)
+
+ def test_pickling(self):
+ import pickle, cPickle
+ args = 20, 59, 16, 64**2
+ orig = self.theclass(*args)
+ state = orig.__getstate__()
+ self.assertEqual(state, ('\x14\x3b\x10\x00\x10\x00',))
+ derived = self.theclass()
+ derived.__setstate__(state)
+ self.assertEqual(orig, derived)
+ for pickler in pickle, cPickle:
+ for binary in 0, 1:
+ green = pickler.dumps(orig, binary)
+ derived = pickler.loads(green)
+ self.assertEqual(orig, derived)
+
+ tinfo = FixedOffset(-300, 'cookie')
+ orig = self.theclass(5, 6, 7, tzinfo=tinfo)
+ state = orig.__getstate__()
+ derived = self.theclass()
+ derived.__setstate__(state)
+ self.assertEqual(orig, derived)
+ self.failUnless(isinstance(derived.tzinfo, FixedOffset))
+ self.assertEqual(derived.utcoffset(), -300)
+ self.assertEqual(derived.tzname(), 'cookie')
+
+ # XXX Picking a timetz with a non-None tzinfo doesn't work in the
+ # XXX C implementation yet; don't know why.
+ if TESTING_C:
+ return
+
+ for pickler in pickle, cPickle:
+ for binary in 0, 1:
+ green = pickler.dumps(orig, binary)
+ derived = pickler.loads(green)
+ self.assertEqual(orig, derived)
+ self.failUnless(isinstance(derived.tzinfo, FixedOffset))
+ self.assertEqual(derived.utcoffset(), -300)
+ self.assertEqual(derived.tzname(), 'cookie')
+
def test_suite():