[Python-checkins] python/nondist/sandbox/datetime datetime.c,1.61,1.62 datetime.py,1.97,1.98 doc.txt,1.47,1.48 obj_tzinfo.c,1.2,1.3 test_both.py,1.68,1.69
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
2002年12月12日 14:08:28 -0800
- Previous message: [Python-checkins] python/dist/src/Lib/test test_macpath.py,NONE,1.1 test_ntpath.py,1.16,1.17 test_posixpath.py,1.4,1.5
- Next message: [Python-checkins] python/nondist/sandbox/datetime datetime.py,1.98,1.99 doc.txt,1.48,1.49 obj_timetz.c,1.17,1.18 test_both.py,1.69,1.70
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv29781
Modified Files:
datetime.c datetime.py doc.txt obj_tzinfo.c test_both.py
Log Message:
There appears to be no way that a timetz object with a non-None tzinfo
member can be pickled by the C implemenation so long as the base
tzinfo class __init__ raises NotImplementedError. This wasn't an issue
in the Python implementation, but a brick wall in the C implementation.
So, tzinfo.__init__() can be called now, and the abstractness of
tzinfo is merely advisory (although you could construct a tzinfo
before too via using __new__ ).
Pickling of timetz objects with non-None tzinfo members appears to
work now.
Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.61
retrieving revision 1.62
diff -C2 -d -r1.61 -r1.62
*** datetime.c 12 Dec 2002 17:58:28 -0000 1.61
--- datetime.c 12 Dec 2002 22:08:22 -0000 1.62
***************
*** 538,551 ****
}
- static PyObject *us_per_us = NULL; /* 1 */
- static PyObject *us_per_ms = NULL; /* 1000 */
- static PyObject *us_per_second = NULL; /* 1000000 */
- static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */
- static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python long */
- static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python long */
- static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python long */
-
- static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */
-
/* Ensure that p is None or of a tzinfo subclass. Return 0 if OK; if not
* raise TypeError and return -1.
--- 538,541 ----
***************
*** 784,791 ****
--- 774,797 ----
}
+ /*
+ * Cached Python objects; these are set by the module init function.
+ */
+
+ /* Conversion factors. */
+ static PyObject *us_per_us = NULL; /* 1 */
+ static PyObject *us_per_ms = NULL; /* 1000 */
+ static PyObject *us_per_second = NULL; /* 1000000 */
+ static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */
+ static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python long */
+ static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python long */
+ static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python long */
+ static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */
+
+ /* Callables to support unpickling. */
static PyObject *date_unpickler_object = NULL;
static PyObject *datetime_unpickler_object = NULL;
static PyObject *time_unpickler_object = NULL;
static PyObject *timetz_unpickler_object = NULL;
+ static PyObject *tzinfo_unpickler_object = NULL;
#include "obj_delta.c"
***************
*** 809,812 ****
--- 815,821 ----
{"_timetz_pickler", (PyCFunction)timetz_pickler, METH_O, NULL},
{"_timetz_unpickler", (PyCFunction)timetz_unpickler, METH_O, NULL},
+ {"_tzinfo_pickler", (PyCFunction)tzinfo_pickler, METH_O, NULL},
+ {"_tzinfo_unpickler", (PyCFunction)tzinfo_unpickler, METH_NOARGS,
+ NULL},
{NULL, NULL}
};
***************
*** 823,830 ****
*/
PyObject *safepickle = PyString_FromString("__safe_for_unpickling__");
-
if (safepickle == NULL)
return;
if (PyType_Ready(&PyDateTime_DateType) < 0)
return;
--- 832,841 ----
*/
PyObject *safepickle = PyString_FromString("__safe_for_unpickling__");
if (safepickle == NULL)
return;
+ m = Py_InitModule3("_datetime", module_methods,
+ "Fast implementation of the datetime type.");
+
if (PyType_Ready(&PyDateTime_DateType) < 0)
return;
***************
*** 840,843 ****
--- 851,930 ----
return;
+ /* Pickling support, via registering functions with copy_reg. */
+ {
+ PyObject *temp;
+ PyObject *pickler;
+ PyObject *copyreg = PyImport_ImportModule("copy_reg");
+
+ assert(copyreg);
+
+ pickler = PyObject_GetAttrString(m, "_date_pickler");
+ assert(pickler);
+ date_unpickler_object = PyObject_GetAttrString(m,
+ "_date_unpickler");
+ assert(date_unpickler_object);
+ temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
+ &PyDateTime_DateType,
+ pickler,
+ date_unpickler_object);
+ assert(temp);
+ Py_DECREF(temp);
+ Py_DECREF(pickler);
+
+ pickler = PyObject_GetAttrString(m, "_datetime_pickler");
+ assert(pickler);
+ datetime_unpickler_object = PyObject_GetAttrString(m,
+ "_datetime_unpickler");
+ assert(datetime_unpickler_object);
+ temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
+ &PyDateTime_DateTimeType,
+ pickler,
+ datetime_unpickler_object);
+ assert(temp);
+ Py_DECREF(temp);
+ Py_DECREF(pickler);
+
+ pickler = PyObject_GetAttrString(m, "_time_pickler");
+ assert(pickler);
+ time_unpickler_object = PyObject_GetAttrString(m,
+ "_time_unpickler");
+ assert(time_unpickler_object);
+ temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
+ &PyDateTime_TimeType,
+ pickler,
+ time_unpickler_object);
+ assert(temp);
+ Py_DECREF(temp);
+ Py_DECREF(pickler);
+
+ pickler = PyObject_GetAttrString(m, "_timetz_pickler");
+ assert(pickler);
+ timetz_unpickler_object = PyObject_GetAttrString(m,
+ "_timetz_unpickler");
+ assert(timetz_unpickler_object);
+ temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
+ &PyDateTime_TimeTZType,
+ pickler,
+ timetz_unpickler_object);
+ assert(temp);
+ Py_DECREF(temp);
+ Py_DECREF(pickler);
+
+ pickler = PyObject_GetAttrString(m, "_tzinfo_pickler");
+ assert(pickler);
+ tzinfo_unpickler_object = PyObject_GetAttrString(m,
+ "_tzinfo_unpickler");
+ assert(tzinfo_unpickler_object);
+ temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
+ &PyDateTime_TZInfoType,
+ pickler,
+ tzinfo_unpickler_object);
+ assert(temp);
+ Py_DECREF(temp);
+ Py_DECREF(pickler);
+
+ Py_DECREF(copyreg);
+ }
+
/* timedelta values */
d = PyDateTime_DeltaType.tp_dict;
***************
*** 936,941 ****
/* module initialization */
- m = Py_InitModule3("_datetime", module_methods,
- "Fast implementation of the datetime type.");
PyModule_AddIntConstant(m, "MINYEAR", MINYEAR);
PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR);
--- 1023,1026 ----
***************
*** 984,987 ****
--- 1069,1075 ----
us_per_minute = PyInt_FromLong(60000000);
seconds_per_day = PyInt_FromLong(24 * 3600);
+ if (us_per_us == NULL || us_per_ms == NULL || us_per_second == NULL ||
+ us_per_minute == NULL || seconds_per_day == NULL)
+ return;
/* The rest are too big for 32-bit ints, but even
***************
*** 991,1055 ****
us_per_day = PyLong_FromDouble(86400000000.0);
us_per_week = PyLong_FromDouble(604800000000.0);
!
! /* Pickling support, via registering functions with copy_reg. */
! {
! PyObject *temp;
! PyObject *pickler;
! PyObject *copyreg = PyImport_ImportModule("copy_reg");
!
! assert(copyreg);
!
! pickler = PyObject_GetAttrString(m, "_date_pickler");
! assert(pickler);
! date_unpickler_object = PyObject_GetAttrString(m,
! "_date_unpickler");
! assert(date_unpickler_object);
! temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
! &PyDateTime_DateType,
! pickler,
! date_unpickler_object);
! assert(temp);
! Py_DECREF(temp);
! Py_DECREF(pickler);
!
! pickler = PyObject_GetAttrString(m, "_datetime_pickler");
! assert(pickler);
! datetime_unpickler_object = PyObject_GetAttrString(m,
! "_datetime_unpickler");
! assert(datetime_unpickler_object);
! temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
! &PyDateTime_DateTimeType,
! pickler,
! datetime_unpickler_object);
! assert(temp);
! Py_DECREF(temp);
! Py_DECREF(pickler);
!
! pickler = PyObject_GetAttrString(m, "_time_pickler");
! assert(pickler);
! time_unpickler_object = PyObject_GetAttrString(m,
! "_time_unpickler");
! assert(time_unpickler_object);
! temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
! &PyDateTime_TimeType,
! pickler,
! time_unpickler_object);
! assert(temp);
! Py_DECREF(temp);
! Py_DECREF(pickler);
!
! pickler = PyObject_GetAttrString(m, "_timetz_pickler");
! assert(pickler);
! timetz_unpickler_object = PyObject_GetAttrString(m,
! "_timetz_unpickler");
! assert(timetz_unpickler_object);
! temp = PyObject_CallMethod(copyreg, "pickle", "OOO",
! &PyDateTime_TimeTZType,
! pickler,
! timetz_unpickler_object);
! assert(temp);
! Py_DECREF(temp);
! Py_DECREF(pickler);
! Py_DECREF(copyreg);
! }
}
--- 1079,1083 ----
us_per_day = PyLong_FromDouble(86400000000.0);
us_per_week = PyLong_FromDouble(604800000000.0);
! if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL)
! return;
}
Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.97
retrieving revision 1.98
diff -C2 -d -r1.97 -r1.98
*** datetime.py 12 Dec 2002 17:58:28 -0000 1.97
--- datetime.py 12 Dec 2002 22:08:24 -0000 1.98
***************
*** 880,886 ****
"""
- def __init__(self, *args, **kw):
- raise NotImplementedError("tzinfo must be subclassed")
-
def tzname(self, dt):
"datetime -> string name of time zone."
--- 880,883 ----
Index: doc.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/doc.txt,v
retrieving revision 1.47
retrieving revision 1.48
diff -C2 -d -r1.47 -r1.48
*** doc.txt 12 Dec 2002 02:55:16 -0000 1.47
--- doc.txt 12 Dec 2002 22:08:24 -0000 1.48
***************
*** 684,697 ****
class tzinfo
============
! tzinfo is an abstract base clase, meaning that objects of this class
! cannot be instantiated. You need to derive a concrete subclass, and
! supply implementations of (at least) the standard tzinfo methods.
! The datetime module does not supply any concrete subclasses of tzinfo.
An instance of (a concrete subclass of) tzinfo can be passed to the
constructors for datetimetz and timetz objects. The latter objects
view their fields as being in local time, and the tzinfo object supports
! methods revealing offset of local time from UTC, and the name of the
! time zone.
A concrete subclass of tzinfo must implement the following methods.
--- 684,697 ----
class tzinfo
============
! tzinfo is an abstract base clase, meaning that objects directly of this
! class should not be instantiated. You need to derive a concrete subclass,
! and supply implementations of (at least) the standard tzinfo methods. The
! datetime module does not supply any concrete subclasses of tzinfo.
An instance of (a concrete subclass of) tzinfo can be passed to the
constructors for datetimetz and timetz objects. The latter objects
view their fields as being in local time, and the tzinfo object supports
! methods revealing offset of local time from UTC, the name of the time zone,
! and DST offset, all relative to a date or time object passed to them.
A concrete subclass of tzinfo must implement the following methods.
***************
*** 699,709 ****
- __init__()
There are no special requirements on the constructor.
! tzinfo.__init__() must not be called, since tzinfo is an abstract
! class.
! The remaining methods are normally called by a datetimetz object, in
! response to the datetimetz method of the same name, passing itself as
! the argument. If dt.tzinfo is not None and not equal to self, an
! exception should be raised:
- utcoffset(dt)
--- 699,709 ----
- __init__()
There are no special requirements on the constructor.
! tzinfo.__init__() should not be called, since tzinfo is an
! abstract class.
! The remaining methods are normally called by a datetimetz or timetz object,
! in response to their methods of the same names, passing itself as the
! argument. If dt.tzinfo is not None and not equal to self, an exception
! should be raised:
- utcoffset(dt)
Index: obj_tzinfo.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_tzinfo.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** obj_tzinfo.c 11 Dec 2002 02:06:52 -0000 1.2
--- obj_tzinfo.c 12 Dec 2002 22:08:24 -0000 1.3
***************
*** 8,11 ****
--- 8,17 ----
* datetimetz and timetz constructors (their tzinfo arguments need to
* be subclasses of this tzinfo class, which is easy and quick to check).
+ *
+ * Note: For reasons having to do with pickling of subclasses, we have
+ * to allow tzinfo objects to be instantiated. This wasn't an issue
+ * in the Python implementation (__init__() could raise NotImplementedError
+ * there without ill effect), but doing so in the C implementation hit a
+ * brick wall.
*/
***************
*** 19,33 ****
}
- /* Constructors -- you can't actually construct one of these! Well,
- * you can, via fooling __new__, but you can't do much with it.
- */
-
- static int
- tzinfo_init(PyDateTime_TZInfo *self, PyObject *args, PyObject *kw)
- {
- (void)tzinfo_nogo("__init__");
- return -1;
- }
-
/* Methods. A subclass must implement these. */
--- 25,28 ----
***************
*** 50,53 ****
--- 45,66 ----
}
+ /*
+ * Pickle support. This is solely so that tzinfo subclasses can use
+ * pickling -- tzinfo itself is supposed to be uninstantiable. The
+ * pickler and unpickler functions are given module-level private
+ * names, and registered with copy_reg, by the module init function.
+ */
+
+ static PyObject*
+ tzinfo_pickler(PyDateTime_TZInfo *self) {
+ return Py_BuildValue("O()", tzinfo_unpickler_object);
+ }
+
+ static PyObject*
+ tzinfo_unpickler(PyObject * unused) {
+ return PyType_GenericNew(&PyDateTime_TZInfoType, NULL, NULL);
+ }
+
+
static PyMethodDef tzinfo_methods[] = {
{"tzname", (PyCFunction)tzinfo_tzname, METH_O,
***************
*** 106,110 ****
0, /* tp_descr_set */
0, /* tp_dictoffset */
! (initproc)tzinfo_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
--- 119,123 ----
0, /* tp_descr_set */
0, /* tp_dictoffset */
! 0, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.68
retrieving revision 1.69
diff -C2 -d -r1.68 -r1.69
*** test_both.py 12 Dec 2002 19:14:31 -0000 1.68
--- test_both.py 12 Dec 2002 22:08:25 -0000 1.69
***************
*** 80,83 ****
--- 80,87 ----
def test_abstractness(self):
+ return
+ # In order to allow subclasses to get pickled, the C implementation
+ # wasn't able to get away with having __init__ raise
+ # NotImplementedError, so we no longer test this.
self.assertRaises(NotImplementedError, tzinfo)
***************
*** 100,103 ****
--- 104,139 ----
self.assertEqual(fo.dst(dt), 42)
+ def test_pickling_base(self):
+ import pickle, cPickle
+
+ # There's no point to pickling tzinfo objects on their own (they
+ # carry no data), but they need to be picklable anyway else
+ # concrete subclasses can't be pickled.
+ orig = tzinfo.__new__(tzinfo)
+ self.failUnless(type(orig) is tzinfo)
+ for pickler in pickle, cPickle:
+ for binary in 0, 1:
+ green = pickler.dumps(orig, binary)
+ derived = pickler.loads(green)
+ self.failUnless(type(derived) is tzinfo)
+
+ def test_pickling_subclass(self):
+ import pickle, cPickle
+
+ # Make sure we can pickle/unpickle an instance of a subclass.
+ orig = FixedOffset(-300, 'cookie')
+ self.failUnless(isinstance(orig, tzinfo))
+ self.failUnless(type(orig) is FixedOffset)
+ self.assertEqual(orig.utcoffset(None), -300)
+ self.assertEqual(orig.tzname(None), 'cookie')
+ for pickler in pickle, cPickle:
+ for binary in 0, 1:
+ green = pickler.dumps(orig, binary)
+ derived = pickler.loads(green)
+ self.failUnless(isinstance(derived, tzinfo))
+ self.failUnless(type(derived) is FixedOffset)
+ self.assertEqual(derived.utcoffset(None), -300)
+ self.assertEqual(derived.tzname(None), 'cookie')
+
#############################################################################
# timedelta tests
***************
*** 1564,1567 ****
--- 1600,1605 ----
def test_pickling(self):
import pickle, cPickle
+
+ # Try one without a tzinfo.
args = 20, 59, 16, 64**2
orig = self.theclass(*args)
***************
*** 1577,1597 ****
self.assertEqual(orig, derived)
tinfo = FixedOffset(-300, 'cookie')
- # Make sure we can pickle/unpickle the tzinfo object on its own.
- orig = tinfo
- # XXX This doesn't work in the C implementation yet; don't
- # XXX 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.failUnless(isinstance(derived, tzinfo))
- self.assertEqual(derived.utcoffset(None), -300)
- self.assertEqual(derived.tzname(None), 'cookie')
-
- # Now add the tzinfo object to a date, and try pickle/unpickle on
- # that.
orig = self.theclass(5, 6, 7, tzinfo=tinfo)
state = orig.__getstate__()
--- 1615,1620 ----
self.assertEqual(orig, derived)
+ # Try one with a tzinfo.
tinfo = FixedOffset(-300, 'cookie')
orig = self.theclass(5, 6, 7, tzinfo=tinfo)
state = orig.__getstate__()
- Previous message: [Python-checkins] python/dist/src/Lib/test test_macpath.py,NONE,1.1 test_ntpath.py,1.16,1.17 test_posixpath.py,1.4,1.5
- Next message: [Python-checkins] python/nondist/sandbox/datetime datetime.py,1.98,1.99 doc.txt,1.48,1.49 obj_timetz.c,1.17,1.18 test_both.py,1.69,1.70
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]