diff -r 593ec9658f4b Lib/datetime.py --- a/Lib/datetime.py Sun Nov 20 17:43:09 2016 +0200 +++ b/Lib/datetime.py Sun Nov 20 19:07:42 2016 +0200 @@ -932,7 +932,7 @@ class date: # Pickle support. - def _getstate(self, protocol=3): + def _getstate(self): yhi, ylo = divmod(self._year, 256) return bytes([yhi, ylo, self._month, self._day]), @@ -940,8 +940,8 @@ class date: yhi, ylo, self._month, self._day = string self._year = yhi * 256 + ylo - def __reduce_ex__(self, protocol): - return (self.__class__, self._getstate(protocol)) + def __reduce__(self): + return (self.__class__, self._getstate()) _date_class = date # so functions w/ args named "date" can get at the class @@ -1348,6 +1348,9 @@ class time: def __reduce_ex__(self, protocol): return (time, self._getstate(protocol)) + def __reduce__(self): + return self.__reduce_ex__(2) + _time_class = time # so functions w/ args named "time" can get at the class time.min = time(0, 0, 0) @@ -1923,6 +1926,9 @@ class datetime(date): def __reduce_ex__(self, protocol): return (self.__class__, self._getstate(protocol)) + def __reduce__(self): + return self.__reduce_ex__(2) + datetime.min = datetime(1, 1, 1) datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) diff -r 593ec9658f4b Lib/test/datetimetester.py --- a/Lib/test/datetimetester.py Sun Nov 20 17:43:09 2016 +0200 +++ b/Lib/test/datetimetester.py Sun Nov 20 19:07:42 2016 +0200 @@ -1329,6 +1329,7 @@ class TestDate(HarmlessMixedComparison, green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) def test_compare(self): t1 = self.theclass(2, 3, 4) @@ -1830,6 +1831,7 @@ class TestDateTime(TestDate): green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) def test_more_pickling(self): a = self.theclass(2003, 2, 7, 16, 48, 37, 444116) @@ -2469,6 +2471,7 @@ class TestTime(HarmlessMixedComparison, green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) def test_pickling_subclass_time(self): args = 20, 59, 16, 64**2 @@ -2829,6 +2832,7 @@ class TestTimeTZ(TestTime, TZInfoBase, u green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) # Try one with a tzinfo. tinfo = PicklableFixedOffset(-300, 'cookie') @@ -2840,6 +2844,7 @@ class TestTimeTZ(TestTime, TZInfoBase, u self.assertIsInstance(derived.tzinfo, PicklableFixedOffset) self.assertEqual(derived.utcoffset(), timedelta(minutes=-300)) self.assertEqual(derived.tzname(), 'cookie') + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) def test_more_bool(self): # time is always True. @@ -3043,6 +3048,7 @@ class TestDateTimeTZ(TestDateTime, TZInf green = pickler.dumps(orig, proto) derived = unpickler.loads(green) self.assertEqual(orig, derived) + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) # Try one with a tzinfo. tinfo = PicklableFixedOffset(-300, 'cookie') @@ -3055,6 +3061,7 @@ class TestDateTimeTZ(TestDateTime, TZInf self.assertIsInstance(derived.tzinfo, PicklableFixedOffset) self.assertEqual(derived.utcoffset(), timedelta(minutes=-300)) self.assertEqual(derived.tzname(), 'cookie') + self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2)) def test_extreme_hashes(self): # If an attempt is made to hash these via subtracting the offset diff -r 593ec9658f4b Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c Sun Nov 20 17:43:09 2016 +0200 +++ b/Modules/_datetimemodule.c Sun Nov 20 19:07:42 2016 +0200 @@ -3954,15 +3954,21 @@ time_getstate(PyDateTime_Time *self, int } static PyObject * -time_reduce(PyDateTime_Time *self, PyObject *args) -{ - int proto = 0; - if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) +time_reduce_ex(PyDateTime_Time *self, PyObject *args) +{ + int proto; + if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto)) return NULL; return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto)); } +static PyObject * +time_reduce(PyDateTime_Time *self, PyObject *arg) +{ + return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2)); +} + static PyMethodDef time_methods[] = { {"isoformat", (PyCFunction)time_isoformat, METH_VARARGS | METH_KEYWORDS, @@ -3988,9 +3994,12 @@ static PyMethodDef time_methods[] = { {"replace", (PyCFunction)time_replace, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Return time with new specified fields.")}, - {"__reduce_ex__", (PyCFunction)time_reduce, METH_VARARGS, + {"__reduce_ex__", (PyCFunction)time_reduce_ex, METH_VARARGS, PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, + {"__reduce__", (PyCFunction)time_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + {NULL, NULL} }; @@ -5419,15 +5428,21 @@ datetime_getstate(PyDateTime_DateTime *s } static PyObject * -datetime_reduce(PyDateTime_DateTime *self, PyObject *args) -{ - int proto = 0; - if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) +datetime_reduce_ex(PyDateTime_DateTime *self, PyObject *args) +{ + int proto; + if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto)) return NULL; return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto)); } +static PyObject * +datetime_reduce(PyDateTime_DateTime *self, PyObject *arg) +{ + return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2)); +} + static PyMethodDef datetime_methods[] = { /* Class methods: */ @@ -5502,9 +5517,12 @@ static PyMethodDef datetime_methods[] = {"astimezone", (PyCFunction)datetime_astimezone, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("tz -> convert to local time in new timezone tz\n")}, - {"__reduce_ex__", (PyCFunction)datetime_reduce, METH_VARARGS, + {"__reduce_ex__", (PyCFunction)datetime_reduce_ex, METH_VARARGS, PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, + {"__reduce__", (PyCFunction)datetime_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + {NULL, NULL} };