Skip to content

Commit 546ce65

Browse files
Issue #28752: Restored the __reduce__() methods of datetime objects.
1 parent f89854f commit 546ce65

4 files changed

Lines changed: 44 additions & 11 deletions

File tree

Lib/datetime.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,16 +932,16 @@ def isocalendar(self):
932932

933933
# Pickle support.
934934

935-
def _getstate(self, protocol=3):
935+
def _getstate(self):
936936
yhi, ylo = divmod(self._year, 256)
937937
return bytes([yhi, ylo, self._month, self._day]),
938938

939939
def __setstate(self, string):
940940
yhi, ylo, self._month, self._day = string
941941
self._year = yhi * 256 + ylo
942942

943-
def __reduce_ex__(self, protocol):
944-
return (self.__class__, self._getstate(protocol))
943+
def __reduce__(self):
944+
return (self.__class__, self._getstate())
945945

946946
_date_class = date # so functions w/ args named "date" can get at the class
947947

@@ -1348,6 +1348,9 @@ def __setstate(self, string, tzinfo):
13481348
def __reduce_ex__(self, protocol):
13491349
return (time, self._getstate(protocol))
13501350

1351+
def __reduce__(self):
1352+
return self.__reduce_ex__(2)
1353+
13511354
_time_class = time # so functions w/ args named "time" can get at the class
13521355

13531356
time.min = time(0, 0, 0)
@@ -1923,6 +1926,9 @@ def __setstate(self, string, tzinfo):
19231926
def __reduce_ex__(self, protocol):
19241927
return (self.__class__, self._getstate(protocol))
19251928

1929+
def __reduce__(self):
1930+
return self.__reduce_ex__(2)
1931+
19261932

19271933
datetime.min = datetime(1, 1, 1)
19281934
datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999)

Lib/test/datetimetester.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,7 @@ def test_pickling(self):
13291329
green = pickler.dumps(orig, proto)
13301330
derived = unpickler.loads(green)
13311331
self.assertEqual(orig, derived)
1332+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
13321333

13331334
def test_compare(self):
13341335
t1 = self.theclass(2, 3, 4)
@@ -1830,6 +1831,7 @@ def test_pickling(self):
18301831
green = pickler.dumps(orig, proto)
18311832
derived = unpickler.loads(green)
18321833
self.assertEqual(orig, derived)
1834+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
18331835

18341836
def test_more_pickling(self):
18351837
a = self.theclass(2003, 2, 7, 16, 48, 37, 444116)
@@ -2469,6 +2471,7 @@ def test_pickling(self):
24692471
green = pickler.dumps(orig, proto)
24702472
derived = unpickler.loads(green)
24712473
self.assertEqual(orig, derived)
2474+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
24722475

24732476
def test_pickling_subclass_time(self):
24742477
args = 20, 59, 16, 64**2
@@ -2829,6 +2832,7 @@ def test_pickling(self):
28292832
green = pickler.dumps(orig, proto)
28302833
derived = unpickler.loads(green)
28312834
self.assertEqual(orig, derived)
2835+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
28322836

28332837
# Try one with a tzinfo.
28342838
tinfo = PicklableFixedOffset(-300, 'cookie')
@@ -2840,6 +2844,7 @@ def test_pickling(self):
28402844
self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
28412845
self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
28422846
self.assertEqual(derived.tzname(), 'cookie')
2847+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
28432848

28442849
def test_more_bool(self):
28452850
# time is always True.
@@ -3043,6 +3048,7 @@ def test_pickling(self):
30433048
green = pickler.dumps(orig, proto)
30443049
derived = unpickler.loads(green)
30453050
self.assertEqual(orig, derived)
3051+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
30463052

30473053
# Try one with a tzinfo.
30483054
tinfo = PicklableFixedOffset(-300, 'cookie')
@@ -3055,6 +3061,7 @@ def test_pickling(self):
30553061
self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
30563062
self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
30573063
self.assertEqual(derived.tzname(), 'cookie')
3064+
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
30583065

30593066
def test_extreme_hashes(self):
30603067
# If an attempt is made to hash these via subtracting the offset

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Core and Builtins
4242
Library
4343
-------
4444

45+
- Issue #28752: Restored the __reduce__() methods of datetime objects.
46+
4547
- Issue #28727: Regular expression patterns, _sre.SRE_Pattern objects created
4648
by re.compile(), become comparable (only x==y and x!=y operators). This
4749
change should fix the issue #18383: don't duplicate warning filters when the

Modules/_datetimemodule.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3955,15 +3955,21 @@ time_getstate(PyDateTime_Time *self, int proto)
39553955
}
39563956

39573957
static PyObject *
3958-
time_reduce(PyDateTime_Time *self, PyObject *args)
3958+
time_reduce_ex(PyDateTime_Time *self, PyObject *args)
39593959
{
3960-
int proto = 0;
3961-
if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto))
3960+
int proto;
3961+
if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
39623962
return NULL;
39633963

39643964
return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto));
39653965
}
39663966

3967+
static PyObject *
3968+
time_reduce(PyDateTime_Time *self, PyObject *arg)
3969+
{
3970+
return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2));
3971+
}
3972+
39673973
static PyMethodDef time_methods[] = {
39683974

39693975
{"isoformat", (PyCFunction)time_isoformat, METH_VARARGS | METH_KEYWORDS,
@@ -3989,9 +3995,12 @@ static PyMethodDef time_methods[] = {
39893995
{"replace", (PyCFunction)time_replace, METH_VARARGS | METH_KEYWORDS,
39903996
PyDoc_STR("Return time with new specified fields.")},
39913997

3992-
{"__reduce_ex__", (PyCFunction)time_reduce, METH_VARARGS,
3998+
{"__reduce_ex__", (PyCFunction)time_reduce_ex, METH_VARARGS,
39933999
PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
39944000

4001+
{"__reduce__", (PyCFunction)time_reduce, METH_NOARGS,
4002+
PyDoc_STR("__reduce__() -> (cls, state)")},
4003+
39954004
{NULL, NULL}
39964005
};
39974006

@@ -5420,15 +5429,21 @@ datetime_getstate(PyDateTime_DateTime *self, int proto)
54205429
}
54215430

54225431
static PyObject *
5423-
datetime_reduce(PyDateTime_DateTime *self, PyObject *args)
5432+
datetime_reduce_ex(PyDateTime_DateTime *self, PyObject *args)
54245433
{
5425-
int proto = 0;
5426-
if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto))
5434+
int proto;
5435+
if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto))
54275436
return NULL;
54285437

54295438
return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto));
54305439
}
54315440

5441+
static PyObject *
5442+
datetime_reduce(PyDateTime_DateTime *self, PyObject *arg)
5443+
{
5444+
return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2));
5445+
}
5446+
54325447
static PyMethodDef datetime_methods[] = {
54335448

54345449
/* Class methods: */
@@ -5503,9 +5518,12 @@ static PyMethodDef datetime_methods[] = {
55035518
{"astimezone", (PyCFunction)datetime_astimezone, METH_VARARGS | METH_KEYWORDS,
55045519
PyDoc_STR("tz -> convert to local time in new timezone tz\n")},
55055520

5506-
{"__reduce_ex__", (PyCFunction)datetime_reduce, METH_VARARGS,
5521+
{"__reduce_ex__", (PyCFunction)datetime_reduce_ex, METH_VARARGS,
55075522
PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")},
55085523

5524+
{"__reduce__", (PyCFunction)datetime_reduce, METH_NOARGS,
5525+
PyDoc_STR("__reduce__() -> (cls, state)")},
5526+
55095527
{NULL, NULL}
55105528
};
55115529

0 commit comments

Comments
 (0)