diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index e524b8d2fbf8c..1e27496be3e12 100755 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -225,6 +225,9 @@ Other enhancements - :meth:`DataFrame.drop_duplicates` has gained ``ignore_index`` keyword to reset index (:issue:`30114`) - Added new writer for exporting Stata dta files in version 118, ``StataWriter118``. This format supports exporting strings containing Unicode characters (:issue:`23573`) - :meth:`Series.map` now accepts ``collections.abc.Mapping`` subclasses as a mapper (:issue:`29733`) +- The ``pandas.datetime`` class is now deprecated. Import from ``datetime`` instead (:issue:`30296`) + + Build Changes ^^^^^^^^^^^^^ diff --git a/pandas/__init__.py b/pandas/__init__.py index 99495d4b7dcb6..f9de17a2e3914 100644 --- a/pandas/__init__.py +++ b/pandas/__init__.py @@ -39,8 +39,6 @@ "the C extensions first." ) -from datetime import datetime - from pandas._config import ( get_option, set_option, @@ -210,6 +208,19 @@ class Panel: return Panel + elif name == "datetime": + warnings.warn( + "The pandas.datetime class is deprecated " + "and will be removed from pandas in a future version. " + "Import from datetime module instead.", + FutureWarning, + stacklevel=2, + ) + + from datetime import datetime as dt + + return dt + elif name == "np": warnings.warn( @@ -264,6 +275,7 @@ def __getattr__(self, item): FutureWarning, stacklevel=2, ) + try: return getattr(self.np, item) except AttributeError: @@ -271,6 +283,31 @@ def __getattr__(self, item): np = __numpy() + class __Datetime: + def __init__(self): + from datetime import datetime as dt + + self.datetime = dt + + def __getattr__(self, item): + import warnings + + warnings.warn( + "The pandas.datetime class is deprecated " + "and will be removed from pandas in a future version. " + "Import from datetime instead.", + FutureWarning, + stacklevel=2, + ) + + try: + return getattr(self.datetime, item) + except AttributeError: + raise AttributeError(f"module datetime has no attribute {item}") + + datetime = __Datetime().datetime + + # module level doc-string __doc__ = """ pandas - a powerful data analysis and manipulation library for Python diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index d586dbbb72831..d865f26983579 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -92,7 +92,7 @@ class TestPDApi(Base): ] if not compat.PY37: classes.extend(["Panel", "SparseSeries", "SparseDataFrame"]) - deprecated_modules.append("np") + deprecated_modules.extend(["np", "datetime"]) # these are already deprecated; awaiting removal deprecated_classes: List[str] = [] @@ -101,7 +101,7 @@ class TestPDApi(Base): deprecated_classes_in_future: List[str] = [] # external modules exposed in pandas namespace - modules = ["datetime"] + modules: List[str] = [] # top-level functions funcs = [ @@ -232,11 +232,23 @@ def test_depr(self): with tm.assert_produces_warning(FutureWarning): if compat.PY37: getattr(pd, depr) + elif depr == "datetime": + deprecated = getattr(pd, "__Datetime") + deprecated().__getattr__(dir(pd.datetime)[-1]) else: deprecated = getattr(pd, depr) deprecated.__getattr__(dir(deprecated)[-1]) +def test_datetime(): + from datetime import datetime + import warnings + + with warnings.catch_warnings(): + warnings.simplefilter("ignore", FutureWarning) + assert datetime(2015, 1, 2, 0, 0) == pd.datetime(2015, 1, 2, 0, 0) + + def test_np(): import numpy as np import warnings diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py index b8f7e585d8a51..7abb43bb25e14 100644 --- a/pandas/tests/dtypes/test_common.py +++ b/pandas/tests/dtypes/test_common.py @@ -1,3 +1,4 @@ +from datetime import datetime from typing import List import numpy as np @@ -490,7 +491,7 @@ def test_is_numeric_v_string_like(): def test_is_datetimelike_v_numeric(): - dt = np.datetime64(pd.datetime(2017, 1, 1)) + dt = np.datetime64(datetime(2017, 1, 1)) assert not com.is_datetimelike_v_numeric(1, 1) assert not com.is_datetimelike_v_numeric(dt, dt) diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index cd384d6fdbfad..9a53caa491970 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1146,18 +1146,18 @@ def test_setitem_mixed_datetime(self): { "a": [0, 0, 0, 0, 13, 14], "b": [ - pd.datetime(2012, 1, 1), + datetime(2012, 1, 1), 1, "x", "y", - pd.datetime(2013, 1, 1), - pd.datetime(2014, 1, 1), + datetime(2013, 1, 1), + datetime(2014, 1, 1), ], } ) df = pd.DataFrame(0, columns=list("ab"), index=range(6)) df["b"] = pd.NaT - df.loc[0, "b"] = pd.datetime(2012, 1, 1) + df.loc[0, "b"] = datetime(2012, 1, 1) df.loc[1, "b"] = 1 df.loc[[2, 3], "b"] = "x", "y" A = np.array( diff --git a/pandas/tests/groupby/test_groupby.py b/pandas/tests/groupby/test_groupby.py index c7e76a4accee6..242434948fc6f 100644 --- a/pandas/tests/groupby/test_groupby.py +++ b/pandas/tests/groupby/test_groupby.py @@ -1729,9 +1729,7 @@ def test_pivot_table_values_key_error(): # This test is designed to replicate the error in issue #14938 df = pd.DataFrame( { - "eventDate": pd.date_range( - pd.datetime.today(), periods=20, freq="M" - ).tolist(), + "eventDate": pd.date_range(datetime.today(), periods=20, freq="M").tolist(), "thename": range(0, 20), } ) diff --git a/pandas/tests/indexes/datetimes/test_constructors.py b/pandas/tests/indexes/datetimes/test_constructors.py index 2f1fa3ce627e6..18f8a9ee60167 100644 --- a/pandas/tests/indexes/datetimes/test_constructors.py +++ b/pandas/tests/indexes/datetimes/test_constructors.py @@ -1,4 +1,4 @@ -from datetime import timedelta +from datetime import datetime, timedelta from functools import partial from operator import attrgetter @@ -10,15 +10,7 @@ from pandas._libs.tslibs import OutOfBoundsDatetime, conversion import pandas as pd -from pandas import ( - DatetimeIndex, - Index, - Timestamp, - date_range, - datetime, - offsets, - to_datetime, -) +from pandas import DatetimeIndex, Index, Timestamp, date_range, offsets, to_datetime from pandas.core.arrays import DatetimeArray, period_array import pandas.util.testing as tm diff --git a/pandas/tests/indexes/datetimes/test_misc.py b/pandas/tests/indexes/datetimes/test_misc.py index c144f2a447ed3..afc3bed85a8d2 100644 --- a/pandas/tests/indexes/datetimes/test_misc.py +++ b/pandas/tests/indexes/datetimes/test_misc.py @@ -1,4 +1,5 @@ import calendar +from datetime import datetime import locale import unicodedata @@ -6,7 +7,7 @@ import pytest import pandas as pd -from pandas import DatetimeIndex, Index, Timestamp, date_range, datetime, offsets +from pandas import DatetimeIndex, Index, Timestamp, date_range, offsets import pandas.util.testing as tm diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 2f27757d6a754..d4731bcdc5b46 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -1,5 +1,6 @@ """ test positional based indexing with iloc """ +from datetime import datetime from warnings import catch_warnings, simplefilter import numpy as np @@ -122,7 +123,7 @@ def check(result, expected): [ ([slice(None), ["A", "D"]]), (["1", "2"], slice(None)), - ([pd.datetime(2019, 1, 1)], slice(None)), + ([datetime(2019, 1, 1)], slice(None)), ], ) def test_iloc_non_integer_raises(self, index, columns, index_vals, column_vals): diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py index e0cb75b0a6c99..c394bc87c99e7 100644 --- a/pandas/tests/io/excel/test_writers.py +++ b/pandas/tests/io/excel/test_writers.py @@ -252,7 +252,7 @@ def test_read_excel_parse_dates(self, ext): res = pd.read_excel(pth, parse_dates=["date_strings"], index_col=0) tm.assert_frame_equal(df, res) - date_parser = lambda x: pd.datetime.strptime(x, "%m/%d/%Y") + date_parser = lambda x: datetime.strptime(x, "%m/%d/%Y") res = pd.read_excel( pth, parse_dates=["date_strings"], date_parser=date_parser, index_col=0 ) diff --git a/pandas/tests/io/sas/test_sas7bdat.py b/pandas/tests/io/sas/test_sas7bdat.py index d3480b246b91f..c89342627f796 100644 --- a/pandas/tests/io/sas/test_sas7bdat.py +++ b/pandas/tests/io/sas/test_sas7bdat.py @@ -1,3 +1,4 @@ +from datetime import datetime import io import os from pathlib import Path @@ -23,7 +24,7 @@ def setup_method(self, datapath): for j in 1, 2: fname = os.path.join(self.dirpath, f"test_sas7bdat_{j}.csv") df = pd.read_csv(fname) - epoch = pd.datetime(1960, 1, 1) + epoch = datetime(1960, 1, 1) t1 = pd.to_timedelta(df["Column4"], unit="d") df["Column4"] = epoch + t1 t2 = pd.to_timedelta(df["Column12"], unit="d")