Skip to content

[BUG] fixed DateOffset pickle bug when months >= 12 #35258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 14, 2020
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Datetimelike
^^^^^^^^^^^^
- Bug in :attr:`DatetimeArray.date` where a ``ValueError`` would be raised with a read-only backing array (:issue:`33530`)
- Bug in ``NaT`` comparisons failing to raise ``TypeError`` on invalid inequality comparisons (:issue:`35046`)
- Bug in :class:`DateOffset` where attributes reconstructed from pickle files differ from original objects when input values exceed normal ranges (e.g months=12) (:issue:`34511`)
-

Timedelta
Expand Down
7 changes: 0 additions & 7 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -989,13 +989,6 @@ cdef class RelativeDeltaOffset(BaseOffset):
state["_offset"] = state.pop("offset")
state["kwds"]["offset"] = state["_offset"]

if "_offset" in state and not isinstance(state["_offset"], timedelta):
# relativedelta, we need to populate using its kwds
offset = state["_offset"]
odict = offset.__dict__
kwds = {key: odict[key] for key in odict if odict[key]}
state.update(kwds)

self.n = state.pop("n")
self.normalize = state.pop("normalize")
self._cache = state.pop("_cache", {})
Expand Down
Binary file not shown.
8 changes: 4 additions & 4 deletions pandas/tests/io/generate_legacy_storage_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
in ~/pandas

. activate pandas_0.20.3
cd ~/
cd ~/pandas/pandas

$ python pandas/pandas/tests/io/generate_legacy_storage_files.py \
pandas/pandas/tests/io/data/legacy_pickle/0.20.3/ pickle
$ python -m tests.io.generate_legacy_storage_files \
tests/io/data/legacy_pickle/0.20.3/ pickle

This script generates a storage file for the current arch, system,
and python version
Expand Down Expand Up @@ -328,7 +328,7 @@ def write_legacy_pickles(output_dir):
pth = f"{platform_name()}.pickle"

fh = open(os.path.join(output_dir, pth), "wb")
pickle.dump(create_pickle_data(), fh, pickle.HIGHEST_PROTOCOL)
pickle.dump(create_pickle_data(), fh, pickle.DEFAULT_PROTOCOL)
fh.close()

print(f"created pickle file: {pth}")
Expand Down
183 changes: 0 additions & 183 deletions pandas/tests/tseries/offsets/data/dateoffset_0_15_2.pickle

This file was deleted.

25 changes: 9 additions & 16 deletions pandas/tests/tseries/offsets/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,22 +635,6 @@ def test_add_empty_datetimeindex(self, offset_types, tz_naive_fixture):
result = offset_s + dta
tm.assert_equal(result, dta)

def test_pickle_v0_15_2(self, datapath):
offsets = {
"DateOffset": DateOffset(years=1),
"MonthBegin": MonthBegin(1),
"Day": Day(1),
"YearBegin": YearBegin(1),
"Week": Week(1),
}

pickle_path = datapath("tseries", "offsets", "data", "dateoffset_0_15_2.pickle")
# This code was executed once on v0.15.2 to generate the pickle:
# with open(pickle_path, 'wb') as f: pickle.dump(offsets, f)
#
result = read_pickle(pickle_path)
tm.assert_dict_equal(offsets, result)

def test_pickle_roundtrip(self, offset_types):
off = self._get_offset(offset_types)
res = tm.round_trip_pickle(off)
Expand All @@ -664,6 +648,15 @@ def test_pickle_roundtrip(self, offset_types):
# Make sure nothings got lost from _params (which __eq__) is based on
assert getattr(off, attr) == getattr(res, attr)

def test_pickle_dateoffset_odd_inputs(self):
# GH#34511
off = DateOffset(months=12)
res = tm.round_trip_pickle(off)
assert off == res

base_dt = datetime(2020, 1, 1)
assert base_dt + off == base_dt + res

def test_onOffset_deprecated(self, offset_types):
# GH#30340 use idiomatic naming
off = self._get_offset(offset_types)
Expand Down