384 lines
9.2 KiB
Python
384 lines
9.2 KiB
Python
|
from __future__ import annotations
|
||
|
|
||
|
import pytest
|
||
|
|
||
|
import pandas as pd
|
||
|
from pandas import api
|
||
|
import pandas._testing as tm
|
||
|
from pandas.api import (
|
||
|
extensions as api_extensions,
|
||
|
indexers as api_indexers,
|
||
|
interchange as api_interchange,
|
||
|
types as api_types,
|
||
|
typing as api_typing,
|
||
|
)
|
||
|
|
||
|
|
||
|
class Base:
|
||
|
def check(self, namespace, expected, ignored=None):
|
||
|
# see which names are in the namespace, minus optional
|
||
|
# ignored ones
|
||
|
# compare vs the expected
|
||
|
|
||
|
result = sorted(
|
||
|
f for f in dir(namespace) if not f.startswith("__") and f != "annotations"
|
||
|
)
|
||
|
if ignored is not None:
|
||
|
result = sorted(set(result) - set(ignored))
|
||
|
|
||
|
expected = sorted(expected)
|
||
|
tm.assert_almost_equal(result, expected)
|
||
|
|
||
|
|
||
|
class TestPDApi(Base):
|
||
|
# these are optionally imported based on testing
|
||
|
# & need to be ignored
|
||
|
ignored = ["tests", "locale", "conftest", "_version_meson"]
|
||
|
|
||
|
# top-level sub-packages
|
||
|
public_lib = [
|
||
|
"api",
|
||
|
"arrays",
|
||
|
"options",
|
||
|
"test",
|
||
|
"testing",
|
||
|
"errors",
|
||
|
"plotting",
|
||
|
"io",
|
||
|
"tseries",
|
||
|
]
|
||
|
private_lib = ["compat", "core", "pandas", "util", "_built_with_meson"]
|
||
|
|
||
|
# misc
|
||
|
misc = ["IndexSlice", "NaT", "NA"]
|
||
|
|
||
|
# top-level classes
|
||
|
classes = [
|
||
|
"ArrowDtype",
|
||
|
"Categorical",
|
||
|
"CategoricalIndex",
|
||
|
"DataFrame",
|
||
|
"DateOffset",
|
||
|
"DatetimeIndex",
|
||
|
"ExcelFile",
|
||
|
"ExcelWriter",
|
||
|
"Flags",
|
||
|
"Grouper",
|
||
|
"HDFStore",
|
||
|
"Index",
|
||
|
"MultiIndex",
|
||
|
"Period",
|
||
|
"PeriodIndex",
|
||
|
"RangeIndex",
|
||
|
"Series",
|
||
|
"SparseDtype",
|
||
|
"StringDtype",
|
||
|
"Timedelta",
|
||
|
"TimedeltaIndex",
|
||
|
"Timestamp",
|
||
|
"Interval",
|
||
|
"IntervalIndex",
|
||
|
"CategoricalDtype",
|
||
|
"PeriodDtype",
|
||
|
"IntervalDtype",
|
||
|
"DatetimeTZDtype",
|
||
|
"BooleanDtype",
|
||
|
"Int8Dtype",
|
||
|
"Int16Dtype",
|
||
|
"Int32Dtype",
|
||
|
"Int64Dtype",
|
||
|
"UInt8Dtype",
|
||
|
"UInt16Dtype",
|
||
|
"UInt32Dtype",
|
||
|
"UInt64Dtype",
|
||
|
"Float32Dtype",
|
||
|
"Float64Dtype",
|
||
|
"NamedAgg",
|
||
|
]
|
||
|
|
||
|
# these are already deprecated; awaiting removal
|
||
|
deprecated_classes: list[str] = []
|
||
|
|
||
|
# external modules exposed in pandas namespace
|
||
|
modules: list[str] = []
|
||
|
|
||
|
# top-level functions
|
||
|
funcs = [
|
||
|
"array",
|
||
|
"bdate_range",
|
||
|
"concat",
|
||
|
"crosstab",
|
||
|
"cut",
|
||
|
"date_range",
|
||
|
"interval_range",
|
||
|
"eval",
|
||
|
"factorize",
|
||
|
"get_dummies",
|
||
|
"from_dummies",
|
||
|
"infer_freq",
|
||
|
"isna",
|
||
|
"isnull",
|
||
|
"lreshape",
|
||
|
"melt",
|
||
|
"notna",
|
||
|
"notnull",
|
||
|
"offsets",
|
||
|
"merge",
|
||
|
"merge_ordered",
|
||
|
"merge_asof",
|
||
|
"period_range",
|
||
|
"pivot",
|
||
|
"pivot_table",
|
||
|
"qcut",
|
||
|
"show_versions",
|
||
|
"timedelta_range",
|
||
|
"unique",
|
||
|
"value_counts",
|
||
|
"wide_to_long",
|
||
|
]
|
||
|
|
||
|
# top-level option funcs
|
||
|
funcs_option = [
|
||
|
"reset_option",
|
||
|
"describe_option",
|
||
|
"get_option",
|
||
|
"option_context",
|
||
|
"set_option",
|
||
|
"set_eng_float_format",
|
||
|
]
|
||
|
|
||
|
# top-level read_* funcs
|
||
|
funcs_read = [
|
||
|
"read_clipboard",
|
||
|
"read_csv",
|
||
|
"read_excel",
|
||
|
"read_fwf",
|
||
|
"read_gbq",
|
||
|
"read_hdf",
|
||
|
"read_html",
|
||
|
"read_xml",
|
||
|
"read_json",
|
||
|
"read_pickle",
|
||
|
"read_sas",
|
||
|
"read_sql",
|
||
|
"read_sql_query",
|
||
|
"read_sql_table",
|
||
|
"read_stata",
|
||
|
"read_table",
|
||
|
"read_feather",
|
||
|
"read_parquet",
|
||
|
"read_orc",
|
||
|
"read_spss",
|
||
|
]
|
||
|
|
||
|
# top-level json funcs
|
||
|
funcs_json = ["json_normalize"]
|
||
|
|
||
|
# top-level to_* funcs
|
||
|
funcs_to = ["to_datetime", "to_numeric", "to_pickle", "to_timedelta"]
|
||
|
|
||
|
# top-level to deprecate in the future
|
||
|
deprecated_funcs_in_future: list[str] = []
|
||
|
|
||
|
# these are already deprecated; awaiting removal
|
||
|
deprecated_funcs: list[str] = []
|
||
|
|
||
|
# private modules in pandas namespace
|
||
|
private_modules = [
|
||
|
"_config",
|
||
|
"_libs",
|
||
|
"_is_numpy_dev",
|
||
|
"_pandas_datetime_CAPI",
|
||
|
"_pandas_parser_CAPI",
|
||
|
"_testing",
|
||
|
"_typing",
|
||
|
]
|
||
|
if not pd._built_with_meson:
|
||
|
private_modules.append("_version")
|
||
|
|
||
|
def test_api(self):
|
||
|
checkthese = (
|
||
|
self.public_lib
|
||
|
+ self.private_lib
|
||
|
+ self.misc
|
||
|
+ self.modules
|
||
|
+ self.classes
|
||
|
+ self.funcs
|
||
|
+ self.funcs_option
|
||
|
+ self.funcs_read
|
||
|
+ self.funcs_json
|
||
|
+ self.funcs_to
|
||
|
+ self.private_modules
|
||
|
)
|
||
|
self.check(namespace=pd, expected=checkthese, ignored=self.ignored)
|
||
|
|
||
|
def test_api_all(self):
|
||
|
expected = set(
|
||
|
self.public_lib
|
||
|
+ self.misc
|
||
|
+ self.modules
|
||
|
+ self.classes
|
||
|
+ self.funcs
|
||
|
+ self.funcs_option
|
||
|
+ self.funcs_read
|
||
|
+ self.funcs_json
|
||
|
+ self.funcs_to
|
||
|
) - set(self.deprecated_classes)
|
||
|
actual = set(pd.__all__)
|
||
|
|
||
|
extraneous = actual - expected
|
||
|
assert not extraneous
|
||
|
|
||
|
missing = expected - actual
|
||
|
assert not missing
|
||
|
|
||
|
def test_depr(self):
|
||
|
deprecated_list = (
|
||
|
self.deprecated_classes
|
||
|
+ self.deprecated_funcs
|
||
|
+ self.deprecated_funcs_in_future
|
||
|
)
|
||
|
for depr in deprecated_list:
|
||
|
with tm.assert_produces_warning(FutureWarning):
|
||
|
_ = getattr(pd, depr)
|
||
|
|
||
|
|
||
|
class TestApi(Base):
|
||
|
allowed_api_dirs = [
|
||
|
"types",
|
||
|
"extensions",
|
||
|
"indexers",
|
||
|
"interchange",
|
||
|
"typing",
|
||
|
]
|
||
|
allowed_typing = [
|
||
|
"DataFrameGroupBy",
|
||
|
"DatetimeIndexResamplerGroupby",
|
||
|
"Expanding",
|
||
|
"ExpandingGroupby",
|
||
|
"ExponentialMovingWindow",
|
||
|
"ExponentialMovingWindowGroupby",
|
||
|
"JsonReader",
|
||
|
"NaTType",
|
||
|
"NAType",
|
||
|
"PeriodIndexResamplerGroupby",
|
||
|
"Resampler",
|
||
|
"Rolling",
|
||
|
"RollingGroupby",
|
||
|
"SeriesGroupBy",
|
||
|
"StataReader",
|
||
|
"TimedeltaIndexResamplerGroupby",
|
||
|
"TimeGrouper",
|
||
|
"Window",
|
||
|
]
|
||
|
allowed_api_types = [
|
||
|
"is_any_real_numeric_dtype",
|
||
|
"is_array_like",
|
||
|
"is_bool",
|
||
|
"is_bool_dtype",
|
||
|
"is_categorical_dtype",
|
||
|
"is_complex",
|
||
|
"is_complex_dtype",
|
||
|
"is_datetime64_any_dtype",
|
||
|
"is_datetime64_dtype",
|
||
|
"is_datetime64_ns_dtype",
|
||
|
"is_datetime64tz_dtype",
|
||
|
"is_dict_like",
|
||
|
"is_dtype_equal",
|
||
|
"is_extension_array_dtype",
|
||
|
"is_file_like",
|
||
|
"is_float",
|
||
|
"is_float_dtype",
|
||
|
"is_hashable",
|
||
|
"is_int64_dtype",
|
||
|
"is_integer",
|
||
|
"is_integer_dtype",
|
||
|
"is_interval",
|
||
|
"is_interval_dtype",
|
||
|
"is_iterator",
|
||
|
"is_list_like",
|
||
|
"is_named_tuple",
|
||
|
"is_number",
|
||
|
"is_numeric_dtype",
|
||
|
"is_object_dtype",
|
||
|
"is_period_dtype",
|
||
|
"is_re",
|
||
|
"is_re_compilable",
|
||
|
"is_scalar",
|
||
|
"is_signed_integer_dtype",
|
||
|
"is_sparse",
|
||
|
"is_string_dtype",
|
||
|
"is_timedelta64_dtype",
|
||
|
"is_timedelta64_ns_dtype",
|
||
|
"is_unsigned_integer_dtype",
|
||
|
"pandas_dtype",
|
||
|
"infer_dtype",
|
||
|
"union_categoricals",
|
||
|
"CategoricalDtype",
|
||
|
"DatetimeTZDtype",
|
||
|
"IntervalDtype",
|
||
|
"PeriodDtype",
|
||
|
]
|
||
|
allowed_api_interchange = ["from_dataframe", "DataFrame"]
|
||
|
allowed_api_indexers = [
|
||
|
"check_array_indexer",
|
||
|
"BaseIndexer",
|
||
|
"FixedForwardWindowIndexer",
|
||
|
"VariableOffsetWindowIndexer",
|
||
|
]
|
||
|
allowed_api_extensions = [
|
||
|
"no_default",
|
||
|
"ExtensionDtype",
|
||
|
"register_extension_dtype",
|
||
|
"register_dataframe_accessor",
|
||
|
"register_index_accessor",
|
||
|
"register_series_accessor",
|
||
|
"take",
|
||
|
"ExtensionArray",
|
||
|
"ExtensionScalarOpsMixin",
|
||
|
]
|
||
|
|
||
|
def test_api(self):
|
||
|
self.check(api, self.allowed_api_dirs)
|
||
|
|
||
|
def test_api_typing(self):
|
||
|
self.check(api_typing, self.allowed_typing)
|
||
|
|
||
|
def test_api_types(self):
|
||
|
self.check(api_types, self.allowed_api_types)
|
||
|
|
||
|
def test_api_interchange(self):
|
||
|
self.check(api_interchange, self.allowed_api_interchange)
|
||
|
|
||
|
def test_api_indexers(self):
|
||
|
self.check(api_indexers, self.allowed_api_indexers)
|
||
|
|
||
|
def test_api_extensions(self):
|
||
|
self.check(api_extensions, self.allowed_api_extensions)
|
||
|
|
||
|
|
||
|
class TestTesting(Base):
|
||
|
funcs = [
|
||
|
"assert_frame_equal",
|
||
|
"assert_series_equal",
|
||
|
"assert_index_equal",
|
||
|
"assert_extension_array_equal",
|
||
|
]
|
||
|
|
||
|
def test_testing(self):
|
||
|
from pandas import testing
|
||
|
|
||
|
self.check(testing, self.funcs)
|
||
|
|
||
|
def test_util_in_top_level(self):
|
||
|
with pytest.raises(AttributeError, match="foo"):
|
||
|
pd.util.foo
|
||
|
|
||
|
|
||
|
def test_pandas_array_alias():
|
||
|
msg = "PandasArray has been renamed NumpyExtensionArray"
|
||
|
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||
|
res = pd.arrays.PandasArray
|
||
|
|
||
|
assert res is pd.arrays.NumpyExtensionArray
|