[Python-checkins] python/dist/src/Modules datetimemodule.c,1.48,1.49

gvanrossum@users.sourceforge.net gvanrossum@users.sourceforge.net
Thu, 30 Jan 2003 14:06:58 -0800


Update of /cvsroot/python/python/dist/src/Modules
In directory sc8-pr-cvs1:/tmp/cvs-serv16937/Modules

Modified Files:
	datetimemodule.c 
Log Message:
Change the approach to pickling to use __reduce__ everywhere.  Most
classes have a __reduce__ that returns (self.__class__,
self.__getstate__()).  tzinfo.__reduce__() is a bit smarter, calling
__getinitargs__ and __getstate__ if they exist, and falling back to
__dict__ if it exists and isn't empty.


Index: datetimemodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/datetimemodule.c,v
retrieving revision 1.48
retrieving revision 1.49
diff -C2 -d -r1.48 -r1.49
*** datetimemodule.c	24 Jan 2003 22:36:34 -0000	1.48
--- datetimemodule.c	30 Jan 2003 22:06:21 -0000	1.49
***************
*** 1351,1360 ****
  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 *tzinfo_unpickler_object = NULL;
- static PyObject *time_unpickler_object = NULL;
- 
  /* ---------------------------------------------------------------------------
   * Class implementations.
--- 1351,1354 ----
***************
*** 2004,2007 ****
--- 1998,2002 ----
  
  static PyMemberDef delta_members[] = {
+ 
  	{"days",         T_INT, OFFSET(days),         READONLY,
  	 PyDoc_STR("Number of days.")},
***************
*** 2016,2027 ****
  
  static PyMethodDef delta_methods[] = {
- 	{"__setstate__", (PyCFunction)delta_setstate, METH_O,
- 	 PyDoc_STR("__setstate__(state)")},
  
! 	{"__reduce__", (PyCFunction)delta_reduce,     METH_NOARGS,
  	 PyDoc_STR("__setstate__(state)")},
  
  	{"__getstate__", (PyCFunction)delta_getstate, METH_NOARGS,
  	 PyDoc_STR("__getstate__() -> state")},
  	{NULL,	NULL},
  };
--- 2011,2024 ----
  
  static PyMethodDef delta_methods[] = {
  
! 	{"__setstate__", (PyCFunction)delta_setstate, METH_O,
  	 PyDoc_STR("__setstate__(state)")},
  
  	{"__getstate__", (PyCFunction)delta_getstate, METH_NOARGS,
  	 PyDoc_STR("__getstate__() -> state")},
+ 
+ 	{"__reduce__", (PyCFunction)delta_reduce,     METH_NOARGS,
+ 	 PyDoc_STR("__reduce__() -> (cls, state)")},
+ 
  	{NULL,	NULL},
  };
***************
*** 2149,2152 ****
--- 2146,2151 ----
  static char *date_kws[] = {"year", "month", "day", NULL};
  
+ static PyObject *date_setstate(PyDateTime_Date *self, PyObject *arg);
+ 
  static PyObject *
  date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
***************
*** 2157,2160 ****
--- 2156,2177 ----
  	int day;
  
+ 	/* Check for invocation from pickle with __getstate__ state */
+ 	if (PyTuple_GET_SIZE(args) == 1 &&
+ 	    PyString_Check(PyTuple_GET_ITEM(args, 0)))
+ 	{
+ 		self = new_date(1, 1, 1);
+ 		if (self != NULL) {
+ 			PyObject *res = date_setstate(
+ 				(PyDateTime_Date *)self, args);
+ 			if (res == Py_None)
+ 				Py_DECREF(res);
+ 			else {
+ 				Py_DECREF(self);
+ 				self = NULL;
+ 			}
+ 		}
+ 		return self;
+ 	}
+ 
  	if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws,
  					&year, &month, &day)) {
***************
*** 2519,2538 ****
  date_getstate(PyDateTime_Date *self)
  {
! 	return PyString_FromStringAndSize((char *)self->data,
! 					  _PyDateTime_DATE_DATASIZE);
  }
  
  static PyObject *
! date_setstate(PyDateTime_Date *self, PyObject *state)
  {
! 	const int len = PyString_Size(state);
! 	unsigned char *pdata = (unsigned char*)PyString_AsString(state);
  
! 	if (! PyString_Check(state) ||
! 	    len != _PyDateTime_DATE_DATASIZE) {
  		PyErr_SetString(PyExc_TypeError,
  				"bad argument to date.__setstate__");
  		return NULL;
  	}
  	memcpy(self->data, pdata, _PyDateTime_DATE_DATASIZE);
  	self->hashcode = -1;
--- 2536,2567 ----
  date_getstate(PyDateTime_Date *self)
  {
! 	return Py_BuildValue(
! 		"(N)",
! 		PyString_FromStringAndSize((char *)self->data,
! 					   _PyDateTime_DATE_DATASIZE));
  }
  
  static PyObject *
! date_setstate(PyDateTime_Date *self, PyObject *arg)
  {
! 	PyObject *state;
! 	int len;
! 	unsigned char *pdata;
  
! 	if (!PyTuple_Check(arg) || PyTuple_GET_SIZE(arg) != 1) {
!   error:
  		PyErr_SetString(PyExc_TypeError,
  				"bad argument to date.__setstate__");
  		return NULL;
  	}
+ 	state = PyTuple_GET_ITEM(arg, 0);
+ 	if (!PyString_Check(state))
+ 		goto error;
+ 
+ 	len = PyString_Size(state);
+ 	if (len != _PyDateTime_DATE_DATASIZE)
+ 		goto error;
+ 
+ 	pdata = (unsigned char*)PyString_AsString(state);
  	memcpy(self->data, pdata, _PyDateTime_DATE_DATASIZE);
  	self->hashcode = -1;
***************
*** 2542,2591 ****
  }
  
- /* XXX This seems a ridiculously inefficient way to pickle a short string. */
  static PyObject *
! date_pickler(PyObject *module, PyDateTime_Date *date)
! {
! 	PyObject *state;
! 	PyObject *result = NULL;
! 
! 	if (! PyDate_CheckExact(date)) {
! 		PyErr_Format(PyExc_TypeError,
! 			     "bad type passed to date pickler: %s",
! 			     date->ob_type->tp_name);
! 		return NULL;
! 	}
! 	state = date_getstate(date);
! 	if (state) {
! 		result = Py_BuildValue("O(O)", date_unpickler_object, state);
! 		Py_DECREF(state);
! 	}
! 	return result;
! }
! 
! static PyObject *
! date_unpickler(PyObject *module, PyObject *arg)
  {
! 	PyDateTime_Date *self;
! 
! 	if (! PyString_CheckExact(arg)) {
! 		PyErr_Format(PyExc_TypeError,
! 			     "bad type passed to date unpickler: %s",
! 			     arg->ob_type->tp_name);
! 		return NULL;
! 	}
! 	self = PyObject_New(PyDateTime_Date, &PyDateTime_DateType);
! 	if (self != NULL) {
! 		PyObject *res = date_setstate(self, arg);
! 		if (res == NULL) {
! 			Py_DECREF(self);
! 			return NULL;
! 		}
! 		Py_DECREF(res);
! 	}
! 	return (PyObject *)self;
  }
  
  static PyMethodDef date_methods[] = {
  	/* Class methods: */
  	{"fromtimestamp", (PyCFunction)date_fromtimestamp, METH_VARARGS |
  							   METH_CLASS,
--- 2571,2584 ----
  }
  
  static PyObject *
! date_reduce(PyDateTime_Date *self, PyObject *arg)
  {
! 	return Py_BuildValue("(ON)", self->ob_type, date_getstate(self));
  }
  
  static PyMethodDef date_methods[] = {
+ 
  	/* Class methods: */
+ 
  	{"fromtimestamp", (PyCFunction)date_fromtimestamp, METH_VARARGS |
  							   METH_CLASS,
***************
*** 2641,2644 ****
--- 2634,2640 ----
  	 PyDoc_STR("__getstate__() -> state")},
  
+ 	{"__reduce__", (PyCFunction)date_reduce,        METH_NOARGS,
+ 	 PyDoc_STR("__reduce__() -> (cls, state)")},
+ 
  	{NULL,	NULL}
  };
***************
*** 2835,2855 ****
  /*
   * 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,
  	 PyDoc_STR("datetime -> string name of time zone.")},
--- 2831,2894 ----
  /*
   * Pickle support.  This is solely so that tzinfo subclasses can use
!  * pickling -- tzinfo itself is supposed to be uninstantiable.
   */
  
! static PyObject *
! tzinfo_reduce(PyObject *self)
! {
! 	PyObject *args, *state, *tmp;
! 	PyObject *getinitargs, *getstate;
  
! 	tmp = PyTuple_New(0);
! 	if (tmp == NULL)
! 		return NULL;
! 
! 	getinitargs = PyObject_GetAttrString(self, "__getinitargs__");
! 	if (getinitargs != NULL) {
! 		args = PyObject_CallObject(getinitargs, tmp);
! 		Py_DECREF(getinitargs);
! 		if (args == NULL) {
! 			Py_DECREF(tmp);
! 			return NULL;
! 		}
! 	}
! 	else {
! 		PyErr_Clear();
! 		args = tmp;
! 		Py_INCREF(args);
! 	}
  
+ 	getstate = PyObject_GetAttrString(self, "__getstate__");
+ 	if (getstate != NULL) {
+ 		state = PyObject_CallObject(getstate, tmp);
+ 		Py_DECREF(getstate);
+ 		if (state == NULL) {
+ 			Py_DECREF(args);
+ 			Py_DECREF(tmp);
+ 			return NULL;
+ 		}
+ 	}
+ 	else {
+ 		PyObject **dictptr;
+ 		PyErr_Clear();
+ 		state = Py_None;
+ 		dictptr = _PyObject_GetDictPtr(self);
+ 		if (dictptr && *dictptr && PyDict_Size(*dictptr))
+ 			state = *dictptr;
+ 		Py_INCREF(state);
+ 	}
+ 
+ 	Py_DECREF(tmp);
+ 
+ 	if (state == Py_None) {
+ 		Py_DECREF(state);
+ 		return Py_BuildValue("(ON)", self->ob_type, args);
+ 	}
+ 	else
+ 		return Py_BuildValue("(ONN)", self->ob_type, args, state);
+ }
  
  static PyMethodDef tzinfo_methods[] = {
+ 
  	{"tzname",	(PyCFunction)tzinfo_tzname,		METH_O,
  	 PyDoc_STR("datetime -> string name of time zone.")},
***************
*** 2865,2868 ****
--- 2904,2910 ----
  	 PyDoc_STR("datetime in UTC -> datetime in local time.")},
  
+ 	{"__reduce__",  (PyCFunction)tzinfo_reduce,             METH_NOARGS,
+ 	 PyDoc_STR("-> (cls, state)")},
+ 
  	{NULL, NULL}
  };
***************
*** 2971,2974 ****
--- 3013,3018 ----
  			   "tzinfo", NULL};
  
+ static PyObject *time_setstate(PyDateTime_Time *self, PyObject *state);
+ 
  static PyObject *
  time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
***************
*** 2981,2984 ****
--- 3025,3049 ----
  	PyObject *tzinfo = Py_None;
  
+ 	/* Check for invocation from pickle with __getstate__ state */
+ 	if (PyTuple_GET_SIZE(args) >= 1 &&
+ 	    PyTuple_GET_SIZE(args) <= 2 &&
+ 	    PyString_Check(PyTuple_GET_ITEM(args, 0)))
+ 	{
+ 		if (PyTuple_GET_SIZE(args) == 2)
+ 			tzinfo = PyTuple_GET_ITEM(args, 1);
+ 		self = new_time(0, 0, 0, 0, tzinfo);
+ 		if (self != NULL) {
+ 			PyObject *res = time_setstate(
+ 				(PyDateTime_Time *)self, args);
+ 			if (res == Py_None)
+ 				Py_DECREF(res);
+ 			else {
+ 				Py_DECREF(self);
+ 				self = NULL;
+ 			}
+ 		}
+ 		return self;
+ 	}
+ 
  	if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO", time_kws,
  					&hour, &minute, &second, &usecond,
***************
*** 3338,3397 ****
  
  static PyObject *
! time_pickler(PyObject *module, PyDateTime_Time *time)
! {
! 	PyObject *state;
! 	PyObject *result = NULL;
! 
! 	if (! PyTime_CheckExact(time)) {
! 		PyErr_Format(PyExc_TypeError,
! 			     "bad type passed to time pickler: %s",
! 			     time->ob_type->tp_name);
! 		return NULL;
! 	}
! 	state = time_getstate(time);
! 	if (state) {
! 		result = Py_BuildValue("O(O)",
! 				       time_unpickler_object,
! 				       state);
! 		Py_DECREF(state);
! 	}
! 	return result;
! }
! 
! static PyObject *
! time_unpickler(PyObject *module, PyObject *arg)
  {
! 	PyDateTime_Time *self;
! 
! 	/* We don't want to allocate space for tzinfo if it's not needed.
! 	 * Figuring that out in advance is irritating, so for now we
! 	 * realloc later.
! 	 */
! 	self = PyObject_New(PyDateTime_Time, &PyDateTime_TimeType);
! 	if (self != NULL) {
! 		PyObject *res;
! 
! 		self->tzinfo = Py_None;
! 		Py_INCREF(self->tzinfo);
! 		self->hastzinfo = (char)1;	/* true */
! 		res = time_setstate(self, arg);
! 		if (res == NULL) {
! 			Py_DECREF(self);
! 			return NULL;
! 		}
! 		Py_DECREF(res);
! 		if (self->tzinfo == Py_None) {
! 			/* shrinking; can't fail */
! 			Py_DECREF(self->tzinfo);
! 			self = (PyDateTime_Time *)PyObject_Realloc(self,
! 						sizeof(_PyDateTime_BaseTime));
! 			assert(self != NULL);
! 			self->hastzinfo = (char)0;
!  		}
! 	}
! 	return (PyObject *)self;
  }
  
  static PyMethodDef time_methods[] = {
  	{"isoformat",   (PyCFunction)time_isoformat,	METH_KEYWORDS,
  	 PyDoc_STR("Return string in ISO 8601 format, HH:MM:SS[.mmmmmm]"
--- 3403,3413 ----
  
  static PyObject *
! time_reduce(PyDateTime_Time *self, PyObject *arg)
  {
! 	return Py_BuildValue("(ON)", self->ob_type, time_getstate(self));
  }
  
  static PyMethodDef time_methods[] = {
+ 
  	{"isoformat",   (PyCFunction)time_isoformat,	METH_KEYWORDS,
  	 PyDoc_STR("Return string in ISO 8601 format, HH:MM:SS[.mmmmmm]"
***************
*** 3418,3421 ****
--- 3434,3441 ----
  	{"__getstate__", (PyCFunction)time_getstate,	METH_NOARGS,
  	 PyDoc_STR("__getstate__() -> state")},
+ 
+ 	{"__reduce__", (PyCFunction)time_reduce,        METH_NOARGS,
+ 	 PyDoc_STR("__reduce__() -> (cls, state)")},
+ 
  	{NULL,	NULL}
  };
***************
*** 3540,3543 ****
--- 3560,3565 ----
  };
  
+ static PyObject *datetime_setstate(PyDateTime_DateTime *self, PyObject *state);
+ 
  static PyObject *
  datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
***************
*** 3553,3556 ****
--- 3575,3599 ----
  	PyObject *tzinfo = Py_None;
  
+ 	/* Check for invocation from pickle with __getstate__ state */
+ 	if (PyTuple_GET_SIZE(args) >= 1 &&
+ 	    PyTuple_GET_SIZE(args) <= 2 &&
+ 	    PyString_Check(PyTuple_GET_ITEM(args, 0)))
+ 	{
+ 		if (PyTuple_GET_SIZE(args) == 2)
+ 			tzinfo = PyTuple_GET_ITEM(args, 1);
+ 		self = new_datetime(1, 1, 1, 0, 0, 0, 0, tzinfo);
+ 		if (self != NULL) {
+ 			PyObject *res = datetime_setstate(
+ 				(PyDateTime_DateTime *)self, args);
+ 			if (res == Py_None)
+ 				Py_DECREF(res);
+ 			else {
+ 				Py_DECREF(self);
+ 				self = NULL;
+ 			}
+ 		}
+ 		return self;
+ 	}
+ 
  	if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO", datetime_kws,
  					&year, &month, &day, &hour, &minute,
***************
*** 4364,4424 ****
  
  static PyObject *
! datetime_pickler(PyObject *module, PyDateTime_DateTime *datetime)
! {
! 	PyObject *state;
! 	PyObject *result = NULL;
! 
! 	if (! PyDateTime_CheckExact(datetime)) {
! 		PyErr_Format(PyExc_TypeError,
! 			     "bad type passed to datetime pickler: %s",
! 			     datetime->ob_type->tp_name);
! 		return NULL;
! 	}
! 	state = datetime_getstate(datetime);
! 	if (state) {
! 		result = Py_BuildValue("O(O)",
! 				       datetime_unpickler_object,
! 				       state);
! 		Py_DECREF(state);
! 	}
! 	return result;
! }
! 
! static PyObject *
! datetime_unpickler(PyObject *module, PyObject *arg)
  {
! 	PyDateTime_DateTime *self;
! 
! 	/* We don't want to allocate space for tzinfo if it's not needed.
! 	 * Figuring that out in advance is irritating, so for now we
! 	 * realloc later.
! 	 */
! 	self = PyObject_New(PyDateTime_DateTime, &PyDateTime_DateTimeType);
! 	if (self != NULL) {
! 		PyObject *res;
! 
! 		self->tzinfo = Py_None;
! 		Py_INCREF(self->tzinfo);
! 		self->hastzinfo = (char)1;	/* true */
! 		res = datetime_setstate(self, arg);
! 		if (res == NULL) {
! 			Py_DECREF(self);
! 			return NULL;
! 		}
! 		Py_DECREF(res);
! 		if (self->tzinfo == Py_None) {
! 			/* shrinking; can't fail */
! 			Py_DECREF(self->tzinfo);
! 			self = (PyDateTime_DateTime *)PyObject_Realloc(self,
! 					 sizeof(_PyDateTime_BaseDateTime));
! 			assert(self != NULL);
! 			self->hastzinfo = (char)0;
!  		}
! 	}
! 	return (PyObject *)self;
  }
  
- 
  static PyMethodDef datetime_methods[] = {
  	/* Class methods: */
  
--- 4407,4417 ----
  
  static PyObject *
! datetime_reduce(PyDateTime_DateTime *self, PyObject *arg)
  {
! 	return Py_BuildValue("(ON)", self->ob_type, datetime_getstate(self));
  }
  
  static PyMethodDef datetime_methods[] = {
+ 
  	/* Class methods: */
  
***************
*** 4445,4448 ****
--- 4438,4442 ----
  
  	/* Instance methods: */
+ 
  	{"date",   (PyCFunction)datetime_getdate, METH_NOARGS,
           PyDoc_STR("Return date object with same year, month and day.")},
***************
*** 4489,4492 ****
--- 4483,4490 ----
  	{"__getstate__", (PyCFunction)datetime_getstate, METH_NOARGS,
  	 PyDoc_STR("__getstate__() -> state")},
+ 
+ 	{"__reduce__", (PyCFunction)datetime_reduce,     METH_NOARGS,
+ 	 PyDoc_STR("__reduce__() -> (cls, state)")},
+ 
  	{NULL,	NULL}
  };
***************
*** 4558,4573 ****
  
  static PyMethodDef module_methods[] = {
- 	/* Private functions for pickling support, registered with the
- 	 * copy_reg module by the module init function.
- 	 */
- 	{"_date_pickler",	(PyCFunction)date_pickler,	METH_O, NULL},
- 	{"_date_unpickler",	(PyCFunction)date_unpickler, 	METH_O, NULL},
- 	{"_datetime_pickler",	(PyCFunction)datetime_pickler,	METH_O, NULL},
- 	{"_datetime_unpickler",	(PyCFunction)datetime_unpickler,METH_O, NULL},
- 	{"_time_pickler",	(PyCFunction)time_pickler,	METH_O, NULL},
- 	{"_time_unpickler",	(PyCFunction)time_unpickler,	METH_O, NULL},
- 	{"_tzinfo_pickler",	(PyCFunction)tzinfo_pickler,	METH_O, NULL},
- 	{"_tzinfo_unpickler",	(PyCFunction)tzinfo_unpickler,	METH_NOARGS,
- 	 NULL},
  	{NULL, NULL}
  };
--- 4556,4559 ----
***************
*** 4601,4666 ****
  		return;
  
! 	/* Pickling support, via registering functions with copy_reg. */
  	{
! 		PyObject *pickler;
! 		PyObject *copyreg = PyImport_ImportModule("copy_reg");
! 
! 		if (copyreg == NULL) return;
  
! 		pickler = PyObject_GetAttrString(m, "_date_pickler");
! 		if (pickler == NULL) return;
! 		date_unpickler_object = PyObject_GetAttrString(m,
! 						"_date_unpickler");
! 		if (date_unpickler_object == NULL) return;
! 	    	x = PyObject_CallMethod(copyreg, "pickle", "OOO",
! 	    				&PyDateTime_DateType,
! 	    				pickler,
! 		                    	date_unpickler_object);
! 		if (x == NULL) return;
! 		Py_DECREF(x);
! 		Py_DECREF(pickler);
  
! 		pickler = PyObject_GetAttrString(m, "_time_pickler");
! 		if (pickler == NULL) return;
! 		time_unpickler_object = PyObject_GetAttrString(m,
! 						"_time_unpickler");
! 		if (time_unpickler_object == NULL) return;
! 	    	x = PyObject_CallMethod(copyreg, "pickle", "OOO",
! 	    				&PyDateTime_TimeType,
! 	    				pickler,
! 		                	time_unpickler_object);
! 		if (x == NULL) return;
! 		Py_DECREF(x);
! 		Py_DECREF(pickler);
  
! 		pickler = PyObject_GetAttrString(m, "_tzinfo_pickler");
! 		if (pickler == NULL) return;
! 		tzinfo_unpickler_object = PyObject_GetAttrString(m,
! 							"_tzinfo_unpickler");
! 		if (tzinfo_unpickler_object == NULL) return;
! 	    	x = PyObject_CallMethod(copyreg, "pickle", "OOO",
! 	    				&PyDateTime_TZInfoType,
! 	    				pickler,
! 		        		tzinfo_unpickler_object);
! 		if (x== NULL) return;
! 		Py_DECREF(x);
! 		Py_DECREF(pickler);
  
! 		pickler = PyObject_GetAttrString(m, "_datetime_pickler");
! 		if (pickler == NULL) return;
! 		datetime_unpickler_object = PyObject_GetAttrString(m,
! 						 "_datetime_unpickler");
! 		if (datetime_unpickler_object == NULL) return;
! 	    	x = PyObject_CallMethod(copyreg, "pickle", "OOO",
! 	    				&PyDateTime_DateTimeType,
! 	    				pickler,
! 		                	datetime_unpickler_object);
! 		if (x== NULL) return;
! 		Py_DECREF(x);
! 		Py_DECREF(pickler);
  
! 		Py_DECREF(copyreg);
  	}
  
  	/* timedelta values */
  	d = PyDateTime_DeltaType.tp_dict;
--- 4587,4636 ----
  		return;
  
! 	/* Make __getnewargs__ a true alias for __getstate__ */
  	{
! 		PyObject *d, *f;
  
! 		d = PyDateTime_DateType.tp_dict;
! 		f = PyDict_GetItemString(d, "__getstate__");
! 		if (f != NULL) {
! 			if (PyDict_SetItemString(d, "__getnewargs__", f) < 0)
! 				return;
! 		}
  
! 		d = PyDateTime_DateTimeType.tp_dict;
! 		f = PyDict_GetItemString(d, "__getstate__");
! 		if (f != NULL) {
! 			if (PyDict_SetItemString(d, "__getnewargs__", f) < 0)
! 				return;
! 		}
  
! 		d = PyDateTime_DeltaType.tp_dict;
! 		f = PyDict_GetItemString(d, "__getstate__");
! 		if (f != NULL) {
! 			if (PyDict_SetItemString(d, "__getnewargs__", f) < 0)
! 				return;
! 		}
  
! 		d = PyDateTime_TimeType.tp_dict;
! 		f = PyDict_GetItemString(d, "__getstate__");
! 		if (f != NULL) {
! 			if (PyDict_SetItemString(d, "__getnewargs__", f) < 0)
! 				return;
! 		}
  
! 		d = PyDateTime_TZInfoType.tp_dict;
! 		f = PyDict_GetItemString(d, "__getstate__");
! 		if (f != NULL) {
! 			if (PyDict_SetItemString(d, "__getnewargs__", f) < 0)
! 				return;
! 		}
  	}
  
+ 	/* tzinfo values */
+ 	d = PyDateTime_TZInfoType.tp_dict;
+ 
+ 	if (PyDict_SetItem(d, safepickle, Py_True) < 0)
+ 		return;
+ 
  	/* timedelta values */
  	d = PyDateTime_DeltaType.tp_dict;
***************
*** 4687,4690 ****
--- 4657,4663 ----
  	d = PyDateTime_DateType.tp_dict;
  
+ 	if (PyDict_SetItem(d, safepickle, Py_True) < 0)
+ 		return;
+ 
  	x = new_date(1, 1, 1);
  	if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
***************
*** 4705,4708 ****
--- 4678,4684 ----
  	d = PyDateTime_TimeType.tp_dict;
  
+ 	if (PyDict_SetItem(d, safepickle, Py_True) < 0)
+ 		return;
+ 
  	x = new_time(0, 0, 0, 0, Py_None);
  	if (x == NULL || PyDict_SetItemString(d, "min", x) < 0)
***************
*** 4722,4725 ****
--- 4698,4704 ----
  	/* datetime values */
  	d = PyDateTime_DateTimeType.tp_dict;
+ 
+ 	if (PyDict_SetItem(d, safepickle, Py_True) < 0)
+ 		return;
  
  	x = new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None);