|
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): |
|
|
|
|
|
|
|
|
|
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): |
|
|
|
|
|
ignored = ["tests", "locale", "conftest", "_version_meson"] |
|
|
|
|
|
public_lib = [ |
|
"api", |
|
"arrays", |
|
"options", |
|
"test", |
|
"testing", |
|
"errors", |
|
"plotting", |
|
"io", |
|
"tseries", |
|
] |
|
private_lib = ["compat", "core", "pandas", "util", "_built_with_meson"] |
|
|
|
|
|
misc = ["IndexSlice", "NaT", "NA"] |
|
|
|
|
|
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", |
|
] |
|
|
|
|
|
deprecated_classes: list[str] = [] |
|
|
|
|
|
modules: list[str] = [] |
|
|
|
|
|
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", |
|
] |
|
|
|
|
|
funcs_option = [ |
|
"reset_option", |
|
"describe_option", |
|
"get_option", |
|
"option_context", |
|
"set_option", |
|
"set_eng_float_format", |
|
] |
|
|
|
|
|
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", |
|
] |
|
|
|
|
|
funcs_json = ["json_normalize"] |
|
|
|
|
|
funcs_to = ["to_datetime", "to_numeric", "to_pickle", "to_timedelta"] |
|
|
|
|
|
deprecated_funcs_in_future: list[str] = [] |
|
|
|
|
|
deprecated_funcs: list[str] = [] |
|
|
|
|
|
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 |
|
|