From 339b2e053cca2f528efabd749998746c26376d16 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Mon, 25 Mar 2024 02:08:27 +0300 Subject: [PATCH 01/12] deprecate epoch date format in to_json --- doc/source/whatsnew/v2.2.2.rst | 2 +- pandas/core/generic.py | 12 ++++++++++++ .../tests/io/json/test_json_table_schema.py | 11 ++++++++--- pandas/tests/io/json/test_pandas.py | 19 +++++++++++++++++-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/doc/source/whatsnew/v2.2.2.rst b/doc/source/whatsnew/v2.2.2.rst index 54084abab7817..5484b25f00377 100644 --- a/doc/source/whatsnew/v2.2.2.rst +++ b/doc/source/whatsnew/v2.2.2.rst @@ -30,7 +30,7 @@ Bug fixes Other ~~~~~ -- +- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. .. --------------------------------------------------------------------------- .. _whatsnew_222.contributors: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index c0eda7f022d8f..e8587352d7243 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2365,6 +2365,10 @@ def to_json( Accepted args are 'w' (writing) and 'a' (append) only. mode='a' is only supported when lines is True and orient is 'records'. + .. deprecated:: 2.2.2 + 'epoch' date format is deprecated and will be removed in a future version, + please use 'iso' instead. + Returns ------- None or str @@ -2530,6 +2534,14 @@ def to_json( date_format = "iso" elif date_format is None: date_format = "epoch" + elif date_format == "epoch": + # GH#57063 + warnings.warn( + "'Epoch' date format is deprecated and will be removed in a future " + "version, please use 'iso' date format instead.", + FutureWarning, + stacklevel=find_stack_level(), + ) config.is_nonnegative_int(indent) indent = indent or 0 diff --git a/pandas/tests/io/json/test_json_table_schema.py b/pandas/tests/io/json/test_json_table_schema.py index afc9974c75e6a..e9ff96d7f182a 100644 --- a/pandas/tests/io/json/test_json_table_schema.py +++ b/pandas/tests/io/json/test_json_table_schema.py @@ -451,12 +451,17 @@ def test_to_json_categorical_index(self): assert result == expected def test_date_format_raises(self, df_table): - msg = ( + error_msg = ( "Trying to write with `orient='table'` and `date_format='epoch'`. Table " "Schema requires dates to be formatted with `date_format='iso'`" ) - with pytest.raises(ValueError, match=msg): - df_table.to_json(orient="table", date_format="epoch") + warning_msg = ( + "'Epoch' date format is deprecated and will be removed in a future " + "version, please use 'iso' date format instead." + ) + with pytest.raises(ValueError, match=error_msg): + with tm.assert_produces_warning(FutureWarning, match=warning_msg): + df_table.to_json(orient="table", date_format="epoch") # others work df_table.to_json(orient="table", date_format="iso") diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index db120588b234c..bc29797cde817 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -940,7 +940,12 @@ def test_date_unit(self, unit, datetime_frame): df.iloc[2, dl] = Timestamp("21460101 20:43:42") df.iloc[4, dl] = pd.NaT - json = df.to_json(date_format="epoch", date_unit=unit) + msg = ( + "'Epoch' date format is deprecated and will be removed in a future " + "version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + json = df.to_json(date_format="epoch", date_unit=unit) # force date unit result = read_json(StringIO(json), date_unit=unit) @@ -1669,7 +1674,17 @@ def test_read_json_with_very_long_file_path(self, compression): def test_timedelta_as_label(self, date_format, key): df = DataFrame([[1]], columns=[pd.Timedelta("1D")]) expected = f'{{"{key}":{{"0":1}}}}' - result = df.to_json(date_format=date_format) + + expected_warning = None + if date_format == "epoch": + expected_warning = FutureWarning + + msg = ( + "'Epoch' date format is deprecated and will be removed in a future " + "version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(expected_warning, match=msg): + result = df.to_json(date_format=date_format) assert result == expected From 41156fdc7d895c9277a53bc2618e3009b8490425 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Mon, 25 Mar 2024 05:43:22 +0300 Subject: [PATCH 02/12] Fix tests --- pandas/core/generic.py | 9 +++++---- pandas/tests/io/json/test_pandas.py | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index e8587352d7243..a06e96498b134 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2328,6 +2328,11 @@ def to_json( 'iso' = ISO8601. The default depends on the `orient`. For ``orient='table'``, the default is 'iso'. For all other orients, the default is 'epoch'. + + .. deprecated:: 2.2.2 + 'epoch' date format is deprecated and will be removed in a future + version, please use 'iso' instead. + double_precision : int, default 10 The number of decimal places to use when encoding floating point values. The possible maximal value is 15. @@ -2365,10 +2370,6 @@ def to_json( Accepted args are 'w' (writing) and 'a' (append) only. mode='a' is only supported when lines is True and orient is 'records'. - .. deprecated:: 2.2.2 - 'epoch' date format is deprecated and will be removed in a future version, - please use 'iso' instead. - Returns ------- None or str diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index bc29797cde817..070b569cef7a5 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -835,15 +835,23 @@ def test_date_index_and_values(self, date_format, as_object, date_typ): data.append("a") ser = Series(data, index=data) - result = ser.to_json(date_format=date_format) + expected_warning = None if date_format == "epoch": expected = '{"1577836800000":1577836800000,"null":null}' + expected_warning = FutureWarning else: expected = ( '{"2020-01-01T00:00:00.000":"2020-01-01T00:00:00.000","null":null}' ) + msg = ( + "'Epoch' date format is deprecated and will be removed in a future " + "version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(expected_warning, match=msg): + result = ser.to_json(date_format=date_format) + if as_object: expected = expected.replace("}", ',"a":"a"}') @@ -1111,17 +1119,24 @@ def test_timedelta_to_json(self, as_object, date_format, timedelta_typ): data.append("a") ser = Series(data, index=data) + expected_warning = None if date_format == "iso": expected = ( '{"P1DT0H0M0S":"P1DT0H0M0S","P2DT0H0M0S":"P2DT0H0M0S","null":null}' ) else: + expected_warning = FutureWarning expected = '{"86400000":86400000,"172800000":172800000,"null":null}' if as_object: expected = expected.replace("}", ',"a":"a"}') - result = ser.to_json(date_format=date_format) + msg = ( + "'Epoch' date format is deprecated and will be removed in a future " + "version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(expected_warning, match=msg): + result = ser.to_json(date_format=date_format) assert result == expected @pytest.mark.parametrize("as_object", [True, False]) From 8fee0ea892692ce002da37c80911fa11e4cf70be Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Mon, 25 Mar 2024 05:55:15 +0300 Subject: [PATCH 03/12] Remove examples using epoch --- doc/source/user_guide/io.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index db2326d5b9754..183283e37435c 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1949,13 +1949,6 @@ Writing in ISO date format, with microseconds: json = dfd.to_json(date_format="iso", date_unit="us") json -Epoch timestamps, in seconds: - -.. ipython:: python - - json = dfd.to_json(date_format="epoch", date_unit="s") - json - Writing to a file, with a date index and a date column: .. ipython:: python From 80cd7fefcdfe7f0d8e08d3f538adf6339e62a97d Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Mon, 25 Mar 2024 21:10:53 +0300 Subject: [PATCH 04/12] Deprecate in v3.0.0 --- doc/source/whatsnew/v2.2.2.rst | 2 +- doc/source/whatsnew/v3.0.0.rst | 1 + pandas/core/generic.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v2.2.2.rst b/doc/source/whatsnew/v2.2.2.rst index 5484b25f00377..54084abab7817 100644 --- a/doc/source/whatsnew/v2.2.2.rst +++ b/doc/source/whatsnew/v2.2.2.rst @@ -30,7 +30,7 @@ Bug fixes Other ~~~~~ -- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. +- .. --------------------------------------------------------------------------- .. _whatsnew_222.contributors: diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index f748f6e23e003..74b95479d347e 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -182,6 +182,7 @@ Other Deprecations - Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`) - Deprecated allowing non-keyword arguments in :meth:`Series.to_markdown` except ``buf``. (:issue:`57280`) - Deprecated allowing non-keyword arguments in :meth:`Series.to_string` except ``buf``. (:issue:`57280`) +- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. - .. --------------------------------------------------------------------------- diff --git a/pandas/core/generic.py b/pandas/core/generic.py index a06e96498b134..2ef54bfc8cb99 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2329,7 +2329,7 @@ def to_json( ``orient='table'``, the default is 'iso'. For all other orients, the default is 'epoch'. - .. deprecated:: 2.2.2 + .. deprecated:: 3.0.0 'epoch' date format is deprecated and will be removed in a future version, please use 'iso' instead. From 5300d7e4124e60437b60f59ddac6d20fac998818 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Sun, 7 Apr 2024 01:16:04 +0300 Subject: [PATCH 05/12] Warn for using default format --- pandas/core/generic.py | 7 ++++++ pandas/tests/io/json/test_pandas.py | 39 ++++++++++++++++------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2ef54bfc8cb99..06914a462ac9b 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2535,6 +2535,13 @@ def to_json( date_format = "iso" elif date_format is None: date_format = "epoch" + if "m8[ns]" in self.dtypes.values or "M8[ns]" in self.dtypes.values: + warnings.warn( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead.", + FutureWarning, + stacklevel=find_stack_level(), + ) elif date_format == "epoch": # GH#57063 warnings.warn( diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index 070b569cef7a5..7cd1019de2b1f 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -137,16 +137,19 @@ def test_frame_non_unique_columns(self, orient, data): df = DataFrame(data, index=[1, 2], columns=["x", "x"]) result = read_json( - StringIO(df.to_json(orient=orient)), orient=orient, convert_dates=["x"] + StringIO(df.to_json(orient=orient, date_format="iso")), + orient=orient, + convert_dates=["x"], ) if orient == "values": expected = DataFrame(data) if expected.iloc[:, 0].dtype == "datetime64[ns]": - # orient == "values" by default will write Timestamp objects out - # in milliseconds; these are internally stored in nanosecond, - # so divide to get where we need - # TODO: a to_epoch method would also solve; see GH 14772 - expected.isetitem(0, expected.iloc[:, 0].astype(np.int64) // 1000000) + expected.isetitem( + 0, + expected.iloc[:, 0].apply( + lambda x: x.isoformat(timespec="milliseconds") + ), + ) elif orient == "split": expected = df expected.columns = ["x", "x.1"] @@ -807,22 +810,24 @@ def test_convert_dates(self, datetime_series, datetime_frame): df = datetime_frame df["date"] = Timestamp("20130101").as_unit("ns") - json = StringIO(df.to_json()) + json = StringIO(df.to_json(date_format="iso")) result = read_json(json) tm.assert_frame_equal(result, df) df["foo"] = 1.0 - json = StringIO(df.to_json(date_unit="ns")) + json = StringIO(df.to_json(date_unit="ns", date_format="iso")) result = read_json(json, convert_dates=False) expected = df.copy() - expected["date"] = expected["date"].values.view("i8") + expected["date"] = expected["date"].apply( + lambda x: x.isoformat(timespec="nanoseconds") + ) expected["foo"] = expected["foo"].astype("int64") tm.assert_frame_equal(result, expected) # series ts = Series(Timestamp("20130101").as_unit("ns"), index=datetime_series.index) - json = StringIO(ts.to_json()) + json = StringIO(ts.to_json(date_format="iso")) result = read_json(json, typ="series") tm.assert_series_equal(result, ts) @@ -1091,9 +1096,9 @@ def test_timedelta2(self): "c": date_range(start="20130101", periods=2), } ) - data = StringIO(frame.to_json(date_unit="ns")) + data = StringIO(frame.to_json(date_unit="ns", date_format="iso")) result = read_json(data) - result["a"] = pd.to_timedelta(result.a, unit="ns") + result["a"] = pd.to_timedelta(result.a) result["c"] = pd.to_datetime(result.c) tm.assert_frame_equal(frame, result) @@ -1229,12 +1234,12 @@ def test_datetime_tz(self): df_naive = df.copy() df_naive["A"] = tz_naive - expected = df_naive.to_json() - assert expected == df.to_json() + expected = df_naive.to_json(date_format="iso") + assert expected == df.to_json(date_format="iso").replace("000Z", "000") stz = Series(tz_range) s_naive = Series(tz_naive) - assert stz.to_json() == s_naive.to_json() + assert stz.to_json(date_format="iso") == s_naive.to_json(date_format="iso") def test_sparse(self): # GH4377 df.to_json segfaults with non-ndarray blocks @@ -1499,7 +1504,7 @@ def test_to_json_from_json_columns_dtypes(self, orient): ), } ) - dfjson = expected.to_json(orient=orient) + dfjson = expected.to_json(orient=orient, date_format="iso") result = read_json( StringIO(dfjson), @@ -1931,7 +1936,7 @@ def test_json_pandas_nulls(self, nulls_fixture, request): mark = pytest.mark.xfail(reason="not implemented") request.applymarker(mark) - result = DataFrame([[nulls_fixture]]).to_json() + result = DataFrame([[nulls_fixture]]).to_json(date_format="iso") assert result == '{"0":{"0":null}}' def test_readjson_bool_series(self): From f59aa8087249d0bf1e8aed90ded9b26f47a41436 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Sun, 7 Apr 2024 02:29:33 +0300 Subject: [PATCH 06/12] Fix detection logic --- pandas/core/generic.py | 3 ++- pandas/tests/io/json/test_pandas.py | 21 +++++++++++++-------- pandas/tests/io/test_gcs.py | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 06914a462ac9b..5c60c951ea114 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2535,7 +2535,8 @@ def to_json( date_format = "iso" elif date_format is None: date_format = "epoch" - if "m8[ns]" in self.dtypes.values or "M8[ns]" in self.dtypes.values: + dtypes = getattr(self.dtypes, "values", [self.dtypes]) + if "m8[ns]" in dtypes or "M8[ns]" in dtypes: warnings.warn( "The default 'Epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead.", diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index 7cd1019de2b1f..d116d6f4c06cd 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -759,12 +759,12 @@ def test_series_with_dtype(self): "dtype,expected", [ (True, Series(["2000-01-01"], dtype="datetime64[ns]")), - (False, Series([946684800000])), + (False, Series(["2000-01-01T00:00:00.000"])), ], ) def test_series_with_dtype_datetime(self, dtype, expected): s = Series(["2000-01-01"], dtype="datetime64[ns]") - data = StringIO(s.to_json()) + data = StringIO(s.to_json(date_format="iso")) result = read_json(data, typ="series", dtype=dtype) tm.assert_series_equal(result, expected) @@ -1069,23 +1069,28 @@ def test_url(self, field, dtype, httpserver): assert result[field].dtype == dtype def test_timedelta(self): - converter = lambda x: pd.to_timedelta(x, unit="ms") + converter = lambda x: pd.to_timedelta(x) ser = Series([timedelta(23), timedelta(seconds=5)]) assert ser.dtype == "timedelta64[ns]" - result = read_json(StringIO(ser.to_json()), typ="series").apply(converter) + result = read_json( + StringIO(ser.to_json(date_format="iso")), typ="series" + ).apply(converter) tm.assert_series_equal(result, ser) ser = Series([timedelta(23), timedelta(seconds=5)], index=Index([0, 1])) assert ser.dtype == "timedelta64[ns]" - result = read_json(StringIO(ser.to_json()), typ="series").apply(converter) + result = read_json( + StringIO(ser.to_json(date_format="iso")), typ="series" + ).apply(converter) tm.assert_series_equal(result, ser) frame = DataFrame([timedelta(23), timedelta(seconds=5)]) assert frame[0].dtype == "timedelta64[ns]" tm.assert_frame_equal( - frame, read_json(StringIO(frame.to_json())).apply(converter) + frame, + read_json(StringIO(frame.to_json(date_format="iso"))).apply(converter), ) def test_timedelta2(self): @@ -1152,8 +1157,8 @@ def test_timedelta_to_json_fractional_precision(self, as_object, timedelta_typ): if as_object: ser = ser.astype(object) - result = ser.to_json() - expected = '{"42":42}' + result = ser.to_json(date_format="iso") + expected = '{"P0DT0H0M0.042S":"P0DT0H0M0.042S"}' assert result == expected def test_default_handler(self): diff --git a/pandas/tests/io/test_gcs.py b/pandas/tests/io/test_gcs.py index a4cf257296b09..e07bf7d545bde 100644 --- a/pandas/tests/io/test_gcs.py +++ b/pandas/tests/io/test_gcs.py @@ -78,7 +78,7 @@ def test_to_read_gcs(gcs_buffer, format, monkeypatch, capsys): df1.to_excel(path) df2 = read_excel(path, parse_dates=["dt"], index_col=0) elif format == "json": - df1.to_json(path) + df1.to_json(path, date_format="iso") df2 = read_json(path, convert_dates=["dt"]) elif format == "parquet": pytest.importorskip("pyarrow") From 9938eb50a41ef8d5d920a750b5fee95e11ee0104 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:30:25 +0300 Subject: [PATCH 07/12] Keep default and expect warning --- pandas/core/generic.py | 8 +- pandas/tests/io/json/test_pandas.py | 109 +++++++++++++++++++--------- pandas/tests/io/test_gcs.py | 7 +- 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 5c60c951ea114..3999d94873e74 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2535,8 +2535,12 @@ def to_json( date_format = "iso" elif date_format is None: date_format = "epoch" - dtypes = getattr(self.dtypes, "values", [self.dtypes]) - if "m8[ns]" in dtypes or "M8[ns]" in dtypes: + dtypes = ( + self.dtypes.values + if self.ndim == 2 + else np.array([self.dtype], dtype=object) + ) + if any(lib.is_np_dtype(dtype, "mM") for dtype in dtypes): warnings.warn( "The default 'Epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead.", diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index d116d6f4c06cd..c6971e1f302aa 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -123,6 +123,7 @@ def test_frame_non_unique_index_raises(self, orient): with pytest.raises(ValueError, match=msg): df.to_json(orient=orient) + @pytest.mark.filterwarnings("ignore::FutureWarning") @pytest.mark.parametrize("orient", ["split", "values"]) @pytest.mark.parametrize( "data", @@ -137,19 +138,14 @@ def test_frame_non_unique_columns(self, orient, data): df = DataFrame(data, index=[1, 2], columns=["x", "x"]) result = read_json( - StringIO(df.to_json(orient=orient, date_format="iso")), + StringIO(df.to_json(orient=orient)), orient=orient, convert_dates=["x"], ) if orient == "values": expected = DataFrame(data) if expected.iloc[:, 0].dtype == "datetime64[ns]": - expected.isetitem( - 0, - expected.iloc[:, 0].apply( - lambda x: x.isoformat(timespec="milliseconds") - ), - ) + expected.isetitem(0, expected.iloc[:, 0].astype(np.int64) // 1000000) elif orient == "split": expected = df expected.columns = ["x", "x.1"] @@ -759,12 +755,17 @@ def test_series_with_dtype(self): "dtype,expected", [ (True, Series(["2000-01-01"], dtype="datetime64[ns]")), - (False, Series(["2000-01-01T00:00:00.000"])), + (False, Series([946684800000])), ], ) def test_series_with_dtype_datetime(self, dtype, expected): s = Series(["2000-01-01"], dtype="datetime64[ns]") - data = StringIO(s.to_json(date_format="iso")) + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + data = StringIO(s.to_json()) result = read_json(data, typ="series", dtype=dtype) tm.assert_series_equal(result, expected) @@ -810,24 +811,29 @@ def test_convert_dates(self, datetime_series, datetime_frame): df = datetime_frame df["date"] = Timestamp("20130101").as_unit("ns") - json = StringIO(df.to_json(date_format="iso")) + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + json = StringIO(df.to_json()) result = read_json(json) tm.assert_frame_equal(result, df) df["foo"] = 1.0 - json = StringIO(df.to_json(date_unit="ns", date_format="iso")) + with tm.assert_produces_warning(FutureWarning, match=msg): + json = StringIO(df.to_json(date_unit="ns")) result = read_json(json, convert_dates=False) expected = df.copy() - expected["date"] = expected["date"].apply( - lambda x: x.isoformat(timespec="nanoseconds") - ) + expected["date"] = expected["date"].values.view("i8") expected["foo"] = expected["foo"].astype("int64") tm.assert_frame_equal(result, expected) # series ts = Series(Timestamp("20130101").as_unit("ns"), index=datetime_series.index) - json = StringIO(ts.to_json(date_format="iso")) + with tm.assert_produces_warning(FutureWarning, match=msg): + json = StringIO(ts.to_json()) result = read_json(json, typ="series") tm.assert_series_equal(result, ts) @@ -1037,7 +1043,12 @@ def test_doc_example(self): dfj2["bools"] = True dfj2.index = date_range("20130101", periods=5) - json = StringIO(dfj2.to_json()) + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + json = StringIO(dfj2.to_json()) result = read_json(json, dtype={"ints": np.int64, "bools": np.bool_}) tm.assert_frame_equal(result, result) @@ -1069,29 +1080,31 @@ def test_url(self, field, dtype, httpserver): assert result[field].dtype == dtype def test_timedelta(self): - converter = lambda x: pd.to_timedelta(x) + converter = lambda x: pd.to_timedelta(x, unit="ms") ser = Series([timedelta(23), timedelta(seconds=5)]) assert ser.dtype == "timedelta64[ns]" - result = read_json( - StringIO(ser.to_json(date_format="iso")), typ="series" - ).apply(converter) + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = read_json(StringIO(ser.to_json()), typ="series").apply(converter) tm.assert_series_equal(result, ser) ser = Series([timedelta(23), timedelta(seconds=5)], index=Index([0, 1])) assert ser.dtype == "timedelta64[ns]" - result = read_json( - StringIO(ser.to_json(date_format="iso")), typ="series" - ).apply(converter) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = read_json(StringIO(ser.to_json()), typ="series").apply(converter) tm.assert_series_equal(result, ser) frame = DataFrame([timedelta(23), timedelta(seconds=5)]) assert frame[0].dtype == "timedelta64[ns]" - tm.assert_frame_equal( - frame, - read_json(StringIO(frame.to_json(date_format="iso"))).apply(converter), - ) + + with tm.assert_produces_warning(FutureWarning, match=msg): + json = frame.to_json() + tm.assert_frame_equal(frame, read_json(StringIO(json)).apply(converter)) def test_timedelta2(self): frame = DataFrame( @@ -1101,9 +1114,14 @@ def test_timedelta2(self): "c": date_range(start="20130101", periods=2), } ) - data = StringIO(frame.to_json(date_unit="ns", date_format="iso")) + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + data = StringIO(frame.to_json(date_unit="ns")) result = read_json(data) - result["a"] = pd.to_timedelta(result.a) + result["a"] = pd.to_timedelta(result.a, unit="ns") result["c"] = pd.to_datetime(result.c) tm.assert_frame_equal(frame, result) @@ -1154,11 +1172,18 @@ def test_timedelta_to_json(self, as_object, date_format, timedelta_typ): def test_timedelta_to_json_fractional_precision(self, as_object, timedelta_typ): data = [timedelta_typ(milliseconds=42)] ser = Series(data, index=data) + warn = FutureWarning if as_object: ser = ser.astype(object) + warn = None - result = ser.to_json(date_format="iso") - expected = '{"P0DT0H0M0.042S":"P0DT0H0M0.042S"}' + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(warn, match=msg): + result = ser.to_json() + expected = '{"42":42}' assert result == expected def test_default_handler(self): @@ -1239,12 +1264,18 @@ def test_datetime_tz(self): df_naive = df.copy() df_naive["A"] = tz_naive - expected = df_naive.to_json(date_format="iso") - assert expected == df.to_json(date_format="iso").replace("000Z", "000") + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + expected = df_naive.to_json() + assert expected == df.to_json() stz = Series(tz_range) s_naive = Series(tz_naive) - assert stz.to_json(date_format="iso") == s_naive.to_json(date_format="iso") + with tm.assert_produces_warning(FutureWarning, match=msg): + assert stz.to_json() == s_naive.to_json() def test_sparse(self): # GH4377 df.to_json segfaults with non-ndarray blocks @@ -1509,7 +1540,12 @@ def test_to_json_from_json_columns_dtypes(self, orient): ), } ) - dfjson = expected.to_json(orient=orient, date_format="iso") + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + dfjson = expected.to_json(orient=orient) result = read_json( StringIO(dfjson), @@ -1935,13 +1971,14 @@ def test_to_s3(self, s3_public_bucket, s3so): timeout -= 0.1 assert timeout > 0, "Timed out waiting for file to appear on moto" + @pytest.mark.filterwarnings("ignore::FutureWarning") def test_json_pandas_nulls(self, nulls_fixture, request): # GH 31615 if isinstance(nulls_fixture, Decimal): mark = pytest.mark.xfail(reason="not implemented") request.applymarker(mark) - result = DataFrame([[nulls_fixture]]).to_json(date_format="iso") + result = DataFrame([[nulls_fixture]]).to_json() assert result == '{"0":{"0":null}}' def test_readjson_bool_series(self): diff --git a/pandas/tests/io/test_gcs.py b/pandas/tests/io/test_gcs.py index e07bf7d545bde..c4617d4eaed5c 100644 --- a/pandas/tests/io/test_gcs.py +++ b/pandas/tests/io/test_gcs.py @@ -78,7 +78,12 @@ def test_to_read_gcs(gcs_buffer, format, monkeypatch, capsys): df1.to_excel(path) df2 = read_excel(path, parse_dates=["dt"], index_col=0) elif format == "json": - df1.to_json(path, date_format="iso") + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + df1.to_json(path) df2 = read_json(path, convert_dates=["dt"]) elif format == "parquet": pytest.importorskip("pyarrow") From 75df145cb6e16238b750284894bdc7295f17b3dd Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Tue, 9 Apr 2024 22:10:27 +0300 Subject: [PATCH 08/12] Add deprecation test --- pandas/tests/io/json/test_pandas.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index c6971e1f302aa..32aea7de03c7d 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -974,6 +974,33 @@ def test_date_unit(self, unit, datetime_frame): result = read_json(StringIO(json), date_unit=None) tm.assert_frame_equal(result, df) + @pytest.mark.parametrize( + "df, warn", + [ + (DataFrame({"A": ["a", "b", "c"], "B": np.arange(3)}), None), + (DataFrame({"A": [True, False, False]}), None), + ( + DataFrame( + {"A": ["a", "b", "c"], "B": pd.to_timedelta(np.arange(3), unit="D")} + ), + FutureWarning, + ), + ( + DataFrame( + {"A": pd.to_datetime(["2020-01-01", "2020-02-01", "2020-03-01"])} + ), + FutureWarning, + ), + ], + ) + def test_default_epoch_date_format_deprecated(self, df, warn): + msg = ( + "The default 'Epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + with tm.assert_produces_warning(warn, match=msg): + df.to_json() + @pytest.mark.parametrize("unit", ["s", "ms", "us"]) def test_iso_non_nano_datetimes(self, unit): # Test that numpy datetimes From f9c39b4bee60c5f75e2ab4b331c245fbe097919b Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Sat, 13 Apr 2024 21:41:21 +0300 Subject: [PATCH 09/12] Final changes --- doc/source/user_guide/io.rst | 4 ++++ pandas/tests/io/json/test_pandas.py | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index 183283e37435c..cf8e71fc582c6 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1952,6 +1952,7 @@ Writing in ISO date format, with microseconds: Writing to a file, with a date index and a date column: .. ipython:: python + :okwarning: dfj2 = dfj.copy() dfj2["date"] = pd.Timestamp("20130101") @@ -2131,6 +2132,7 @@ Preserve string indices: Dates written in nanoseconds need to be read back in nanoseconds: .. ipython:: python + :okwarning: from io import StringIO json = dfj2.to_json(date_unit="ns") @@ -2268,6 +2270,7 @@ other attributes. You can use the orient ``table`` to build a JSON string with two fields, ``schema`` and ``data``. .. ipython:: python + :okwarning: df = pd.DataFrame( { @@ -2377,6 +2380,7 @@ the preservation of metadata such as dtypes and index names in a round-trippable manner. .. ipython:: python + :okwarning: df = pd.DataFrame( { diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index 32aea7de03c7d..0bce482de5a79 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -138,13 +138,15 @@ def test_frame_non_unique_columns(self, orient, data): df = DataFrame(data, index=[1, 2], columns=["x", "x"]) result = read_json( - StringIO(df.to_json(orient=orient)), - orient=orient, - convert_dates=["x"], + StringIO(df.to_json(orient=orient)), orient=orient, convert_dates=["x"] ) if orient == "values": expected = DataFrame(data) if expected.iloc[:, 0].dtype == "datetime64[ns]": + # orient == "values" by default will write Timestamp objects out + # in milliseconds; these are internally stored in nanosecond, + # so divide to get where we need + # TODO: a to_epoch method would also solve; see GH 14772 expected.isetitem(0, expected.iloc[:, 0].astype(np.int64) // 1000000) elif orient == "split": expected = df @@ -994,6 +996,7 @@ def test_date_unit(self, unit, datetime_frame): ], ) def test_default_epoch_date_format_deprecated(self, df, warn): + # GH 57063 msg = ( "The default 'Epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." From 36d3cf4ec1670cab53fa8744a1a7877c59458c73 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:15:44 +0300 Subject: [PATCH 10/12] Code review suggestions --- doc/source/user_guide/io.rst | 8 ++---- pandas/core/generic.py | 4 +-- .../tests/io/json/test_json_table_schema.py | 2 +- pandas/tests/io/json/test_pandas.py | 26 +++++++++---------- pandas/tests/io/test_gcs.py | 2 +- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/doc/source/user_guide/io.rst b/doc/source/user_guide/io.rst index cf8e71fc582c6..49609a80d7e15 100644 --- a/doc/source/user_guide/io.rst +++ b/doc/source/user_guide/io.rst @@ -1952,14 +1952,13 @@ Writing in ISO date format, with microseconds: Writing to a file, with a date index and a date column: .. ipython:: python - :okwarning: dfj2 = dfj.copy() dfj2["date"] = pd.Timestamp("20130101") dfj2["ints"] = list(range(5)) dfj2["bools"] = True dfj2.index = pd.date_range("20130101", periods=5) - dfj2.to_json("test.json") + dfj2.to_json("test.json", date_format="iso") with open("test.json") as fh: print(fh.read()) @@ -2132,10 +2131,9 @@ Preserve string indices: Dates written in nanoseconds need to be read back in nanoseconds: .. ipython:: python - :okwarning: from io import StringIO - json = dfj2.to_json(date_unit="ns") + json = dfj2.to_json(date_format="iso", date_unit="ns") # Try to parse timestamps as milliseconds -> Won't Work dfju = pd.read_json(StringIO(json), date_unit="ms") @@ -2270,7 +2268,6 @@ other attributes. You can use the orient ``table`` to build a JSON string with two fields, ``schema`` and ``data``. .. ipython:: python - :okwarning: df = pd.DataFrame( { @@ -2380,7 +2377,6 @@ the preservation of metadata such as dtypes and index names in a round-trippable manner. .. ipython:: python - :okwarning: df = pd.DataFrame( { diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 3999d94873e74..64bc29f13dabf 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2542,7 +2542,7 @@ def to_json( ) if any(lib.is_np_dtype(dtype, "mM") for dtype in dtypes): warnings.warn( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead.", FutureWarning, stacklevel=find_stack_level(), @@ -2550,7 +2550,7 @@ def to_json( elif date_format == "epoch": # GH#57063 warnings.warn( - "'Epoch' date format is deprecated and will be removed in a future " + "'epoch' date format is deprecated and will be removed in a future " "version, please use 'iso' date format instead.", FutureWarning, stacklevel=find_stack_level(), diff --git a/pandas/tests/io/json/test_json_table_schema.py b/pandas/tests/io/json/test_json_table_schema.py index e9ff96d7f182a..4fa5d6e480ed2 100644 --- a/pandas/tests/io/json/test_json_table_schema.py +++ b/pandas/tests/io/json/test_json_table_schema.py @@ -456,7 +456,7 @@ def test_date_format_raises(self, df_table): "Schema requires dates to be formatted with `date_format='iso'`" ) warning_msg = ( - "'Epoch' date format is deprecated and will be removed in a future " + "'epoch' date format is deprecated and will be removed in a future " "version, please use 'iso' date format instead." ) with pytest.raises(ValueError, match=error_msg): diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index 0bce482de5a79..e3ecf5dc5f18a 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -763,7 +763,7 @@ def test_series_with_dtype(self): def test_series_with_dtype_datetime(self, dtype, expected): s = Series(["2000-01-01"], dtype="datetime64[ns]") msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -814,7 +814,7 @@ def test_convert_dates(self, datetime_series, datetime_frame): df["date"] = Timestamp("20130101").as_unit("ns") msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -859,7 +859,7 @@ def test_date_index_and_values(self, date_format, as_object, date_typ): ) msg = ( - "'Epoch' date format is deprecated and will be removed in a future " + "'epoch' date format is deprecated and will be removed in a future " "version, please use 'iso' date format instead." ) with tm.assert_produces_warning(expected_warning, match=msg): @@ -962,7 +962,7 @@ def test_date_unit(self, unit, datetime_frame): df.iloc[4, dl] = pd.NaT msg = ( - "'Epoch' date format is deprecated and will be removed in a future " + "'epoch' date format is deprecated and will be removed in a future " "version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -998,7 +998,7 @@ def test_date_unit(self, unit, datetime_frame): def test_default_epoch_date_format_deprecated(self, df, warn): # GH 57063 msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(warn, match=msg): @@ -1074,7 +1074,7 @@ def test_doc_example(self): dfj2.index = date_range("20130101", periods=5) msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -1116,7 +1116,7 @@ def test_timedelta(self): assert ser.dtype == "timedelta64[ns]" msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -1145,7 +1145,7 @@ def test_timedelta2(self): } ) msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -1190,7 +1190,7 @@ def test_timedelta_to_json(self, as_object, date_format, timedelta_typ): expected = expected.replace("}", ',"a":"a"}') msg = ( - "'Epoch' date format is deprecated and will be removed in a future " + "'epoch' date format is deprecated and will be removed in a future " "version, please use 'iso' date format instead." ) with tm.assert_produces_warning(expected_warning, match=msg): @@ -1208,7 +1208,7 @@ def test_timedelta_to_json_fractional_precision(self, as_object, timedelta_typ): warn = None msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(warn, match=msg): @@ -1295,7 +1295,7 @@ def test_datetime_tz(self): df_naive = df.copy() df_naive["A"] = tz_naive msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -1571,7 +1571,7 @@ def test_to_json_from_json_columns_dtypes(self, orient): } ) msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): @@ -1771,7 +1771,7 @@ def test_timedelta_as_label(self, date_format, key): expected_warning = FutureWarning msg = ( - "'Epoch' date format is deprecated and will be removed in a future " + "'epoch' date format is deprecated and will be removed in a future " "version, please use 'iso' date format instead." ) with tm.assert_produces_warning(expected_warning, match=msg): diff --git a/pandas/tests/io/test_gcs.py b/pandas/tests/io/test_gcs.py index c4617d4eaed5c..4b2be41d0c9f9 100644 --- a/pandas/tests/io/test_gcs.py +++ b/pandas/tests/io/test_gcs.py @@ -79,7 +79,7 @@ def test_to_read_gcs(gcs_buffer, format, monkeypatch, capsys): df2 = read_excel(path, parse_dates=["dt"], index_col=0) elif format == "json": msg = ( - "The default 'Epoch' date format is deprecated and will be removed " + "The default 'epoch' date format is deprecated and will be removed " "in a future version, please use 'iso' date format instead." ) with tm.assert_produces_warning(FutureWarning, match=msg): From 50d6d998dcf69ff5767dca438c4510d5d959009c Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:50:38 +0300 Subject: [PATCH 11/12] Stop use of filterwarnings --- doc/source/whatsnew/v3.0.0.rst | 2 +- pandas/core/generic.py | 4 ++-- pandas/tests/io/json/test_pandas.py | 26 +++++++++++++++++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 74b95479d347e..b3224b52663cc 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -182,7 +182,7 @@ Other Deprecations - Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`) - Deprecated allowing non-keyword arguments in :meth:`Series.to_markdown` except ``buf``. (:issue:`57280`) - Deprecated allowing non-keyword arguments in :meth:`Series.to_string` except ``buf``. (:issue:`57280`) -- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. +- Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. (:issue:`57063`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 64bc29f13dabf..7240fab260abd 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2536,9 +2536,9 @@ def to_json( elif date_format is None: date_format = "epoch" dtypes = ( - self.dtypes.values + self.dtypes if self.ndim == 2 - else np.array([self.dtype], dtype=object) + else [self.dtype] ) if any(lib.is_np_dtype(dtype, "mM") for dtype in dtypes): warnings.warn( diff --git a/pandas/tests/io/json/test_pandas.py b/pandas/tests/io/json/test_pandas.py index e3ecf5dc5f18a..c4065ea01988f 100644 --- a/pandas/tests/io/json/test_pandas.py +++ b/pandas/tests/io/json/test_pandas.py @@ -123,7 +123,6 @@ def test_frame_non_unique_index_raises(self, orient): with pytest.raises(ValueError, match=msg): df.to_json(orient=orient) - @pytest.mark.filterwarnings("ignore::FutureWarning") @pytest.mark.parametrize("orient", ["split", "values"]) @pytest.mark.parametrize( "data", @@ -137,9 +136,18 @@ def test_frame_non_unique_index_raises(self, orient): def test_frame_non_unique_columns(self, orient, data): df = DataFrame(data, index=[1, 2], columns=["x", "x"]) - result = read_json( - StringIO(df.to_json(orient=orient)), orient=orient, convert_dates=["x"] + expected_warning = None + msg = ( + "The default 'epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." ) + if df.iloc[:, 0].dtype == "datetime64[ns]": + expected_warning = FutureWarning + + with tm.assert_produces_warning(expected_warning, match=msg): + result = read_json( + StringIO(df.to_json(orient=orient)), orient=orient, convert_dates=["x"] + ) if orient == "values": expected = DataFrame(data) if expected.iloc[:, 0].dtype == "datetime64[ns]": @@ -2001,14 +2009,22 @@ def test_to_s3(self, s3_public_bucket, s3so): timeout -= 0.1 assert timeout > 0, "Timed out waiting for file to appear on moto" - @pytest.mark.filterwarnings("ignore::FutureWarning") def test_json_pandas_nulls(self, nulls_fixture, request): # GH 31615 if isinstance(nulls_fixture, Decimal): mark = pytest.mark.xfail(reason="not implemented") request.applymarker(mark) - result = DataFrame([[nulls_fixture]]).to_json() + expected_warning = None + msg = ( + "The default 'epoch' date format is deprecated and will be removed " + "in a future version, please use 'iso' date format instead." + ) + if nulls_fixture is pd.NaT: + expected_warning = FutureWarning + + with tm.assert_produces_warning(expected_warning, match=msg): + result = DataFrame([[nulls_fixture]]).to_json() assert result == '{"0":{"0":null}}' def test_readjson_bool_series(self): From 8e4b95c3b374ee7d4ae5a6637e30d0c0dd75e408 Mon Sep 17 00:00:00 2001 From: Abdulaziz Aloqeely <52792999+DAzVise@users.noreply.github.com> Date: Tue, 16 Apr 2024 20:54:31 +0300 Subject: [PATCH 12/12] Make pre-commit happy --- pandas/core/generic.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 7240fab260abd..32c955779763e 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2535,11 +2535,7 @@ def to_json( date_format = "iso" elif date_format is None: date_format = "epoch" - dtypes = ( - self.dtypes - if self.ndim == 2 - else [self.dtype] - ) + dtypes = self.dtypes if self.ndim == 2 else [self.dtype] if any(lib.is_np_dtype(dtype, "mM") for dtype in dtypes): warnings.warn( "The default 'epoch' date format is deprecated and will be removed "