From 7b09a22010a36f6cfd0518b2e8dc21bb5aeef102 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 6 Jan 2020 10:47:06 -0600 Subject: [PATCH 1/4] DEPR/REGR: Fix pandas.util.testing deprecation Closes https://github.com/pandas-dev/pandas/issues/30735 This avoids using _DeprecatedModule, which doesn't work for direct imports from a module. --- pandas/tests/api/test_api.py | 21 +++-- pandas/util/__init__.py | 62 +++++++++++++- pandas/util/testing/__init__.py | 144 -------------------------------- 3 files changed, 73 insertions(+), 154 deletions(-) delete mode 100644 pandas/util/testing/__init__.py diff --git a/pandas/tests/api/test_api.py b/pandas/tests/api/test_api.py index bdb4e813023b6..72e2413ce87d9 100644 --- a/pandas/tests/api/test_api.py +++ b/pandas/tests/api/test_api.py @@ -1,3 +1,4 @@ +import sys from typing import List import pandas as pd @@ -288,14 +289,20 @@ def test_testing(self): self.check(testing, self.funcs) def test_util_testing_deprecated(self): - s = pd.Series([], dtype="object") - with tm.assert_produces_warning(FutureWarning) as m: - import pandas.util.testing as tm2 + # avoid cache state affecting the test + sys.modules.pop("pandas.util.testing", None) - tm2.assert_series_equal(s, s) + with tm.assert_produces_warning(FutureWarning) as m: + import pandas.util.testing # noqa: F401 - assert "pandas.testing.assert_series_equal" in str(m[0].message) + assert "pandas.util.testing is deprecated" in str(m[0].message) + assert "pandas.testing instead" in str(m[0].message) + def test_util_testing_deprecated_direct(self): + # avoid cache state affecting the test + sys.modules.pop("pandas.util.testing", None) with tm.assert_produces_warning(FutureWarning) as m: - tm2.DataFrame - assert "removed" in str(m[0].message) + from pandas.util.testing import assert_series_equal # noqa: F401 + + assert "pandas.util.testing is deprecated" in str(m[0].message) + assert "pandas.testing instead" in str(m[0].message) diff --git a/pandas/util/__init__.py b/pandas/util/__init__.py index 231a23e247650..7a88f5c92bafa 100644 --- a/pandas/util/__init__.py +++ b/pandas/util/__init__.py @@ -1,4 +1,60 @@ -from pandas.util._decorators import Appender, Substitution, cache_readonly # noqa +import importlib as _importlib +from importlib.abc import Loader as _Loader, MetaPathFinder +from importlib.machinery import ModuleSpec as _ModuleSpec +import sys as _sys +import warnings as _warnings -from pandas.core.util.hashing import hash_array, hash_pandas_object # noqa -from pandas.util.testing import testing # noqa: F401 +from pandas.util._decorators import Appender, Substitution, cache_readonly + +from pandas.core.util.hashing import hash_array, hash_pandas_object + +# Custom import hook for the deprecated pandas.util.testing module. +# The custom Finder only runs when python's standard import fail, +# since we're adding to the end of sys.meta_path. In TestingLoader.create_module +# we simply warn and then return the real testing module, pandas._testing. +# This differs from _DeprecatedModule by using the import system, which +# allows it to work with both `import foo; foo.bar` and `from foo import bar`. +# But because Python caches imports, the warning appears only once. + + +class _TestingFinder(MetaPathFinder): + @classmethod + def find_spec(cls, fullname, path=None, target=None): + + name_parts = fullname.split(".") + if name_parts[:3] != ["pandas", "util", "testing"] or len(name_parts) > 3: + return None + else: + # return ModuleSpec(fullname, DataPackageImporter()) + return _ModuleSpec(fullname, _TestingLoader()) + + +class _TestingLoader(_Loader): + @classmethod + def create_module(cls, spec): + module = _importlib.import_module("pandas._testing") + _warnings.warn( + ( + "pandas.util.testing is deprecated. Use the " + "public methods from pandas.testing instead." + ), + FutureWarning, + stacklevel=2, + ) + return module + + @classmethod + def exec_module(cls, module): + pass + + +_sys.meta_path.append(_TestingFinder()) + + +__all__ = [ + "Appender", + "Substitution", + "cache_readonly", + "hash_array", + "hash_pandas_object", +] diff --git a/pandas/util/testing/__init__.py b/pandas/util/testing/__init__.py deleted file mode 100644 index 02cbd19a9a888..0000000000000 --- a/pandas/util/testing/__init__.py +++ /dev/null @@ -1,144 +0,0 @@ -from pandas.util._depr_module import _DeprecatedModule - -_removals = [ - "Categorical", - "CategoricalIndex", - "Counter", - "DataFrame", - "DatetimeArray", - "DatetimeIndex", - "ExtensionArray", - "FrameOrSeries", - "Index", - "IntervalArray", - "IntervalIndex", - "K", - "List", - "MultiIndex", - "N", - "Optional", - "PeriodArray", - "RANDS_CHARS", - "RANDU_CHARS", - "RNGContext", - "RangeIndex", - "Series", - "SubclassedCategorical", - "SubclassedDataFrame", - "SubclassedSeries", - "TimedeltaArray", - "Union", - "all_index_generator", - "all_timeseries_index_generator", - "array_equivalent", - "assert_attr_equal", - "assert_class_equal", - "assert_contains_all", - "assert_copy", - "assert_dict_equal", - "assert_is_sorted", - "assert_is_valid_plot_return_object", - "assert_produces_warning", - "bdate_range", - "box_expected", - "bz2", - "can_connect", - "can_set_locale", - "cast", - "close", - "contextmanager", - "convert_rows_list_to_csv_str", - "datetime", - "decompress_file", - "ensure_clean", - "ensure_clean_dir", - "ensure_safe_environment_variables", - "equalContents", - "getCols", - "getMixedTypeDict", - "getPeriodData", - "getSeriesData", - "getTimeSeriesData", - "get_locales", - "gzip", - "index_subclass_makers_generator", - "is_bool", - "is_categorical_dtype", - "is_datetime64_dtype", - "is_datetime64tz_dtype", - "is_extension_array_dtype", - "is_interval_dtype", - "is_list_like", - "is_number", - "is_period_dtype", - "is_sequence", - "is_timedelta64_dtype", - "isiterable", - "lzma", - "makeBoolIndex", - "makeCategoricalIndex", - "makeCustomDataframe", - "makeCustomIndex", - "makeDataFrame", - "makeDateIndex", - "makeFloatIndex", - "makeFloatSeries", - "makeIntIndex", - "makeIntervalIndex", - "makeMissingCustomDataframe", - "makeMissingDataframe", - "makeMixedDataFrame", - "makeMultiIndex", - "makeObjectSeries", - "makePeriodFrame", - "makePeriodIndex", - "makePeriodSeries", - "makeRangeIndex", - "makeStringIndex", - "makeStringSeries", - "makeTimeDataFrame", - "makeTimeSeries", - "makeTimedeltaIndex", - "makeUIntIndex", - "makeUnicodeIndex", - "needs_i8_conversion", - "network", - "np", - "optional_args", - "os", - "pd", - "period_array", - "pprint_thing", - "raise_assert_detail", - "rand", - "randbool", - "randn", - "rands", - "rands_array", - "randu", - "randu_array", - "reset_display_options", - "reset_testing_mode", - "rmtree", - "round_trip_localpath", - "round_trip_pathlib", - "round_trip_pickle", - "set_locale", - "set_testing_mode", - "set_timezone", - "string", - "take_1d", - "tempfile", - "test_parallel", - "to_array", - "urlopen", - "use_numexpr", - "warnings", - "with_connectivity_check", - "with_csv_dialect", - "wraps", - "write_to_compressed", - "zipfile", -] - -testing = _DeprecatedModule("pandas._testing", "pandas.testing", _removals) From a04603d1866660e545842580c6a96e9755970cca Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 6 Jan 2020 13:24:20 -0600 Subject: [PATCH 2/4] simplify --- pandas/util/__init__.py | 49 ----------------------------------------- pandas/util/testing.py | 5 +++++ 2 files changed, 5 insertions(+), 49 deletions(-) create mode 100644 pandas/util/testing.py diff --git a/pandas/util/__init__.py b/pandas/util/__init__.py index 7a88f5c92bafa..b0db5dc4fa025 100644 --- a/pandas/util/__init__.py +++ b/pandas/util/__init__.py @@ -1,56 +1,7 @@ -import importlib as _importlib -from importlib.abc import Loader as _Loader, MetaPathFinder -from importlib.machinery import ModuleSpec as _ModuleSpec -import sys as _sys -import warnings as _warnings - from pandas.util._decorators import Appender, Substitution, cache_readonly from pandas.core.util.hashing import hash_array, hash_pandas_object -# Custom import hook for the deprecated pandas.util.testing module. -# The custom Finder only runs when python's standard import fail, -# since we're adding to the end of sys.meta_path. In TestingLoader.create_module -# we simply warn and then return the real testing module, pandas._testing. -# This differs from _DeprecatedModule by using the import system, which -# allows it to work with both `import foo; foo.bar` and `from foo import bar`. -# But because Python caches imports, the warning appears only once. - - -class _TestingFinder(MetaPathFinder): - @classmethod - def find_spec(cls, fullname, path=None, target=None): - - name_parts = fullname.split(".") - if name_parts[:3] != ["pandas", "util", "testing"] or len(name_parts) > 3: - return None - else: - # return ModuleSpec(fullname, DataPackageImporter()) - return _ModuleSpec(fullname, _TestingLoader()) - - -class _TestingLoader(_Loader): - @classmethod - def create_module(cls, spec): - module = _importlib.import_module("pandas._testing") - _warnings.warn( - ( - "pandas.util.testing is deprecated. Use the " - "public methods from pandas.testing instead." - ), - FutureWarning, - stacklevel=2, - ) - return module - - @classmethod - def exec_module(cls, module): - pass - - -_sys.meta_path.append(_TestingFinder()) - - __all__ = [ "Appender", "Substitution", diff --git a/pandas/util/testing.py b/pandas/util/testing.py new file mode 100644 index 0000000000000..309db621da020 --- /dev/null +++ b/pandas/util/testing.py @@ -0,0 +1,5 @@ +import warnings + +from pandas._testing import * # noqa + +warnings.warn("pandas.util.testing is deprecated", FutureWarning) From bbcd6e28323d59fea80a95f06b0681bb07fdb743 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 6 Jan 2020 13:26:19 -0600 Subject: [PATCH 3/4] simplify --- pandas/util/testing.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pandas/util/testing.py b/pandas/util/testing.py index 309db621da020..af9fe4846b27d 100644 --- a/pandas/util/testing.py +++ b/pandas/util/testing.py @@ -2,4 +2,11 @@ from pandas._testing import * # noqa -warnings.warn("pandas.util.testing is deprecated", FutureWarning) +warnings.warn( + ( + "pandas.util.testing is deprecated. Use the functions in the " + "public API at pandas.testing instead." + ), + FutureWarning, + stacklevel=2, +) From cc9e18df220349e8bd296e5102b098e92794c40b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 6 Jan 2020 13:27:16 -0600 Subject: [PATCH 4/4] revert --- pandas/util/__init__.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pandas/util/__init__.py b/pandas/util/__init__.py index b0db5dc4fa025..d906c0371d207 100644 --- a/pandas/util/__init__.py +++ b/pandas/util/__init__.py @@ -1,11 +1,3 @@ -from pandas.util._decorators import Appender, Substitution, cache_readonly +from pandas.util._decorators import Appender, Substitution, cache_readonly # noqa -from pandas.core.util.hashing import hash_array, hash_pandas_object - -__all__ = [ - "Appender", - "Substitution", - "cache_readonly", - "hash_array", - "hash_pandas_object", -] +from pandas.core.util.hashing import hash_array, hash_pandas_object # noqa