Skip to content

Commit a7c5773

Browse files
FIX: PeriodIndex json roundtrip (#47747)
* FIX: PeriodIndex json roundtrip * update changelog * Update doc/source/whatsnew/v1.5.0.rst Co-authored-by: Matthew Roeschke <[email protected]> * simplify change and add specialized tests * pep8 change Co-authored-by: Matthew Roeschke <[email protected]>
1 parent 1b1dd36 commit a7c5773

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,7 @@ I/O
956956
- Bug in :func:`read_sas` that scrambled column names (:issue:`31243`)
957957
- Bug in :func:`read_sas` with RLE-compressed SAS7BDAT files that contain 0x00 control bytes (:issue:`47099`)
958958
- Bug in :func:`read_parquet` with ``use_nullable_dtypes=True`` where ``float64`` dtype was returned instead of nullable ``Float64`` dtype (:issue:`45694`)
959+
- Bug in :meth:`DataFrame.to_json` where ``PeriodDtype`` would not make the serialization roundtrip when read back with :meth:`read_json` (:issue:`44720`)
959960

960961
Period
961962
^^^^^^

pandas/io/json/_table_schema.py

+3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ def convert_json_field_to_pandas_type(field) -> str | CategoricalDtype:
197197
elif typ == "datetime":
198198
if field.get("tz"):
199199
return f"datetime64[ns, {field['tz']}]"
200+
elif field.get("freq"):
201+
# GH#47747 using datetime over period to minimize the change surface
202+
return f"period[{field['freq']}]"
200203
else:
201204
return "datetime64[ns]"
202205
elif typ == "any":

pandas/tests/io/json/test_json_table_schema.py

+38
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,44 @@ def test_read_json_table_orient_raises(self, index_nm, vals, recwarn):
708708
with pytest.raises(NotImplementedError, match="can not yet read "):
709709
pd.read_json(out, orient="table")
710710

711+
@pytest.mark.parametrize(
712+
"index_nm",
713+
[None, "idx", pytest.param("index", marks=pytest.mark.xfail), "level_0"],
714+
)
715+
@pytest.mark.parametrize(
716+
"vals",
717+
[
718+
{"ints": [1, 2, 3, 4]},
719+
{"objects": ["a", "b", "c", "d"]},
720+
{"objects": ["1", "2", "3", "4"]},
721+
{"date_ranges": pd.date_range("2016-01-01", freq="d", periods=4)},
722+
{"categoricals": pd.Series(pd.Categorical(["a", "b", "c", "c"]))},
723+
{
724+
"ordered_cats": pd.Series(
725+
pd.Categorical(["a", "b", "c", "c"], ordered=True)
726+
)
727+
},
728+
{"floats": [1.0, 2.0, 3.0, 4.0]},
729+
{"floats": [1.1, 2.2, 3.3, 4.4]},
730+
{"bools": [True, False, False, True]},
731+
{
732+
"timezones": pd.date_range(
733+
"2016-01-01", freq="d", periods=4, tz="US/Central"
734+
) # added in # GH 35973
735+
},
736+
],
737+
)
738+
def test_read_json_table_period_orient(self, index_nm, vals, recwarn):
739+
df = DataFrame(
740+
vals,
741+
index=pd.Index(
742+
(pd.Period(f"2022Q{q}") for q in range(1, 5)), name=index_nm
743+
),
744+
)
745+
out = df.to_json(orient="table")
746+
result = pd.read_json(out, orient="table")
747+
tm.assert_frame_equal(df, result)
748+
711749
@pytest.mark.parametrize(
712750
"idx",
713751
[

0 commit comments

Comments
 (0)