[Python-checkins] python/nondist/sandbox/datetime datetime.c,1.32,1.33 obj_date.c,1.13,1.14 obj_datetime.c,1.7,1.8 test_both.py,1.17,1.18

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Mon, 02 Dec 2002 11:40:45 -0800


Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv15411

Modified Files:
	datetime.c obj_date.c obj_datetime.c test_both.py 
Log Message:
Pickling works now, but doesn't meet its primary design goal for
date and datetime:  since those types require 3 arguments, __reduce__
has to supply a 3-tuple of args for the constructor to chew on, which
__setstate__ then immediately overwrites.  So instead of having a
pickle that's just a short string in these cases, we also get a
pointless 3-tuple buried in the pickle.  Perhaps doing this right
requires defining Yet Another constructor function?  I confess I'm
not a pickling professional <wink>.


Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -C2 -d -r1.32 -r1.33
*** datetime.c	2 Dec 2002 18:10:32 -0000	1.32
--- datetime.c	2 Dec 2002 19:40:41 -0000	1.33
***************
*** 536,539 ****
--- 536,541 ----
  }
  
+ static PyObject* three_ones = NULL;	/* an argument tuple for __reduce__ */
+ 
  #include "obj_delta.c"
  #include "obj_date.c"
***************
*** 564,568 ****
  	/* date values */
  	d = PyDateTime_DateType.tp_dict;
- 	Py_INCREF(Py_True);
  	if (PyDict_SetItem(d, safepickle, Py_True) < 0)
  		return;
--- 566,569 ----
***************
*** 652,654 ****
--- 653,673 ----
  	us_per_week = PyLong_FromDouble(604800000000.0);
  
+ 	{
+ 		/* Build (1, 1, 1) so __reduce__ for date-like objects
+ 		 * has something to pass to the type.
+ 		 */
+ 		int i;
+ 		PyObject *one = PyInt_FromLong(1);
+ 
+ 		if (one == NULL)
+ 			return;
+ 		three_ones = PyTuple_New(3);
+ 		if (three_ones == NULL)
+ 			return;
+ 		for (i = 0; i < 3; ++i) {
+ 			Py_INCREF(one);
+ 			PyTuple_SetItem(three_ones, i, one);
+ 		}
+ 		Py_DECREF(one);
+ 	}
  }

Index: obj_date.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_date.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** obj_date.c	2 Dec 2002 06:42:28 -0000	1.13
--- obj_date.c	2 Dec 2002 19:40:42 -0000	1.14
***************
*** 372,382 ****
  }
  
! /* XXX Broken attempt to get pickles working.  An attempt to pickle
!  * XXX craps out in
!  * XXX
!  * XXX     if base is self.__class__:
!  * XXX         raise TypeError, "can't pickle %s objects" % base.__name__
!  * XXX
!  * XXX in Python's copy_reg.py.  How to fix?
   */
  static PyObject *
--- 372,378 ----
  }
  
! /* Pickle support.  Quite a maze!  While __getstate__/__setstate__ sufficed
!  * in the Python implementation, the C implementation also requires
!  * __reduce__, and a __safe_for_unpickling__ attr in the type object.
   */
  static PyObject *
***************
*** 402,405 ****
--- 398,419 ----
  }
  
+ /* XXX This is a ridiculously inefficient way to pickle a short string. */
+ static PyObject *
+ date_reduce(PyDateTime_Date* self)
+ {
+ 	PyObject* result = NULL;
+ 	PyObject* state;
+ 
+ 	state = date_getstate(self);
+ 	if (state != NULL) {
+ 		result = Py_BuildValue("OOO",
+ 				       self->ob_type,
+ 				       three_ones,
+ 				       state);
+ 		Py_DECREF(state);
+ 	}
+ 	return result;
+ }
+ 
  static PyMethodDef date_methods[] = {
  	/* Class methods: */
***************
*** 428,435 ****
  	 "Return the day of the week represented by the date.\n"
  	 "Monday == 0 ... Sunday == 6"},
- 	{"__getstate__", (PyCFunction)date_getstate,	METH_NOARGS,
- 	 	PyDoc_STR("__getstate__() -> state")},
  	{"__setstate__", (PyCFunction)date_setstate,	METH_O,
  	 	PyDoc_STR("__setstate__(state)")},
  	{NULL,	NULL}
  };
--- 442,451 ----
  	 "Return the day of the week represented by the date.\n"
  	 "Monday == 0 ... Sunday == 6"},
  	{"__setstate__", (PyCFunction)date_setstate,	METH_O,
  	 	PyDoc_STR("__setstate__(state)")},
+ 	{"__reduce__", (PyCFunction)date_reduce, 	METH_NOARGS,
+ 		NULL},
+ 	{"__getstate__", (PyCFunction)date_getstate,	METH_NOARGS,
+ 	 	PyDoc_STR("__getstate__() -> state")},
  	{NULL,	NULL}
  };
***************
*** 455,459 ****
  	PyObject_HEAD_INIT(NULL)
  	0,						/* ob_size */
! 	"date",						/* tp_name */
  	sizeof(PyDateTime_Date),			/* tp_basicsize */
  	0,						/* tp_itemsize */
--- 471,476 ----
  	PyObject_HEAD_INIT(NULL)
  	0,						/* ob_size */
! 	/* XXX When this module is renamed to datetime, change tp_name. */
! 	"_datetime.date",				/* tp_name */
  	sizeof(PyDateTime_Date),			/* tp_basicsize */
  	0,						/* tp_itemsize */

Index: obj_datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_datetime.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** obj_datetime.c	2 Dec 2002 06:42:28 -0000	1.7
--- obj_datetime.c	2 Dec 2002 19:40:42 -0000	1.8
***************
*** 372,382 ****
  }
  
! /* XXX Broken attempt to get pickles working.  An attempt to pickle
!  * XXX craps out in
!  * XXX
!  * XXX     if base is self.__class__:
!  * XXX         raise TypeError, "can't pickle %s objects" % base.__name__
!  * XXX
!  * XXX in Python's copy_reg.py.  How to fix?
   */
  static PyObject *
--- 372,378 ----
  }
  
! /* Pickle support.  Quite a maze!  While __getstate__/__setstate__ sufficed
!  * in the Python implementation, the C implementation also requires
!  * __reduce__, and a __safe_for_unpickling__ attr in the type object.
   */
  static PyObject *
***************
*** 402,422 ****
  }
  
  static PyMethodDef datetime_methods[] = {
  	/* Class methods: */
! 	{"now",         (PyCFunction)datetime_now,	 METH_O | METH_CLASS,
  	 "Return a new datetime that represents the current time."},
! 	{"today",         (PyCFunction)datetime_today,	 METH_O | METH_CLASS,
  	 "Return a new datetime that represents the current date."},
  
  	/* Instance methods: */
! 	{"ctime",       (PyCFunction)datetime_ctime,	 METH_NOARGS,
  	 "Return ctime() style string."},
  	{"isoformat",   (PyCFunction)datetime_isoformat, METH_KEYWORDS,
  	 "Return the day of the week represented by the datetime.\n"
  	 "Monday == 1 ... Sunday == 7"},
- 	{"__getstate__", (PyCFunction)datetime_getstate, METH_NOARGS,
- 	 	PyDoc_STR("__getstate__() -> state")},
  	{"__setstate__", (PyCFunction)datetime_setstate, METH_O,
  	 	PyDoc_STR("__setstate__(state)")},
  	{NULL,	NULL}
  };
--- 398,438 ----
  }
  
+ /* XXX This is a ridiculously inefficient way to pickle a short string. */
+ static PyObject *
+ datetime_reduce(PyDateTime_DateTime* self)
+ {
+ 	PyObject* result = NULL;
+ 	PyObject* state;
+ 
+ 	state = datetime_getstate(self);
+ 	if (state != NULL) {
+ 		result = Py_BuildValue("OOO",
+ 				       self->ob_type,
+ 				       three_ones,
+ 				       state);
+ 		Py_DECREF(state);
+ 	}
+ 	return result;
+ }
+ 
  static PyMethodDef datetime_methods[] = {
  	/* Class methods: */
! 	{"now",         (PyCFunction)datetime_now,	METH_O | METH_CLASS,
  	 "Return a new datetime that represents the current time."},
! 	{"today",         (PyCFunction)datetime_today,	METH_O | METH_CLASS,
  	 "Return a new datetime that represents the current date."},
  
  	/* Instance methods: */
! 	{"ctime",       (PyCFunction)datetime_ctime,	METH_NOARGS,
  	 "Return ctime() style string."},
  	{"isoformat",   (PyCFunction)datetime_isoformat, METH_KEYWORDS,
  	 "Return the day of the week represented by the datetime.\n"
  	 "Monday == 1 ... Sunday == 7"},
  	{"__setstate__", (PyCFunction)datetime_setstate, METH_O,
  	 	PyDoc_STR("__setstate__(state)")},
+ 	{"__reduce__", (PyCFunction)datetime_reduce,	METH_NOARGS,
+ 		NULL},
+ 	{"__getstate__", (PyCFunction)datetime_getstate, METH_NOARGS,
+ 	 	PyDoc_STR("__getstate__() -> state")},
  	{NULL,	NULL}
  };
***************
*** 442,446 ****
  	PyObject_HEAD_INIT(NULL)
  	0,					/* ob_size */
! 	"datetime",				/* tp_name */
  	sizeof(PyDateTime_DateTime),		/* tp_basicsize */
  	0,					/* tp_itemsize */
--- 458,463 ----
  	PyObject_HEAD_INIT(NULL)
  	0,					/* ob_size */
! 	/* XXX When this module is renamed to datetime, change tp_name. */
! 	"_datetime.datetime",			/* tp_name */
  	sizeof(PyDateTime_DateTime),		/* tp_basicsize */
  	0,					/* tp_itemsize */

Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -d -r1.17 -r1.18
*** test_both.py	2 Dec 2002 18:10:34 -0000	1.17
--- test_both.py	2 Dec 2002 19:40:42 -0000	1.18
***************
*** 18,24 ****
  
  # Import the right implementation, under name "datetime".
! if 'c' in sys.argv:
      print "Testing the C implementation."
      import _datetime as datetime
  else:
      print "Testing the Python implementation."
--- 18,26 ----
  
  # Import the right implementation, under name "datetime".
! TESTING_C = 'c' in sys.argv
! if TESTING_C:
      print "Testing the C implementation."
      import _datetime as datetime
+     import _datetime
  else:
      print "Testing the Python implementation."
***************
*** 409,414 ****
          for pickler in pickle, cPickle:
              for binary in 0, 1:
-                 # XXX Pickling fails in the C implementation.
-                 # XXX Needs to be fixed as for timedelta.
                  green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
--- 411,414 ----
***************
*** 448,452 ****
                     self.theclass.now()):
              # Verify dt -> string -> datetime identity.
!             s = 'datetime.' + repr(dt)
              dt2 = eval(s)
              self.assertEqual(dt, dt2)
--- 448,460 ----
                     self.theclass.now()):
              # Verify dt -> string -> datetime identity.
!             s = repr(dt)
!             if not TESTING_C:
!                 # XXX This hack is due to that the Python implementation of
!                 # XXX type datetime calls its name 'datetime', but that's a
!                 # XXX module object here.  The C implementation calls its name
!                 # XXX '_datetime.datetime', so doesn't need a hack.
!                 # XXX This can get simpler when the Python implementation goes
!                 # XXX away.
!                 s = 'datetime.' + s
              dt2 = eval(s)
              self.assertEqual(dt, dt2)
***************
*** 621,626 ****
          for pickler in pickle, cPickle:
              for binary in 0, 1:
-                 # XXX Pickling fails in the C implementation.
-                 # XXX Needs to be fixed as for timedelta.
                  green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
--- 629,632 ----