Skip to content

Commit

Permalink
Merge pull request #252 from spencerkclark/pickle-subclasses
Browse files Browse the repository at this point in the history
Ensure subclass type is properly roundtripped during pickling
  • Loading branch information
jswhit authored Aug 9, 2021
2 parents 081c19e + 940ac9b commit 4f28eb6
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ version 1.5.1 (not yet released)
======================================
* added support for "common_year" and "common_years" units for "noleap"
and "365_day" calendars (issue #5, PR #246)
* fixed a bug that led to subclasses losing their type identity upon
pickling (issue #251, PR #252).

version 1.5.0 (release tag v1.5.0.rel)
======================================
Expand Down
5 changes: 3 additions & 2 deletions src/cftime/_cftime.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@ cdef _year_zero_defaults(calendar):
return False

# factory function without optional kwargs that can be used in datetime.__reduce__
def _create_datetime(args, kwargs): return datetime(*args, **kwargs)
def _create_datetime(date_type, args, kwargs): return date_type(*args, **kwargs)
# custorm warning for invalid CF dates.
class CFWarning(UserWarning):
pass
Expand Down Expand Up @@ -1255,7 +1255,8 @@ The default format of the string produced by strftime is controlled by self.form
def __reduce__(self):
"""special method that allows instance to be pickled"""
args, kwargs = self._getstate()
return (_create_datetime, (args, kwargs))
date_type = type(self)
return (_create_datetime, (date_type, args, kwargs))

cdef _add_timedelta(self, other):
return NotImplemented
Expand Down
11 changes: 9 additions & 2 deletions test/test_cftime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1305,8 +1305,15 @@ def test_pickling(self):
import pickle

date = Datetime360Day(year=1, month=2, day=3, hour=4, minute=5, second=6, microsecond=7)
self.assertEqual(date, pickle.loads(pickle.dumps(date)))

deserialized = pickle.loads(pickle.dumps(date))
self.assertEqual(date, deserialized)
self.assertEqual(type(date), type(deserialized))

date = datetimex(1, 2, 3, 4, 5, 6, 7, calendar="360_day")
deserialized = pickle.loads(pickle.dumps(date))
self.assertEqual(date, deserialized)
self.assertEqual(type(date), type(deserialized))

def test_misc(self):
"Miscellaneous tests."
# make sure repr succeeds
Expand Down

0 comments on commit 4f28eb6

Please sign in to comment.