test_api.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. from __future__ import annotations
  2. import pytest
  3. import pandas as pd
  4. from pandas import api
  5. import pandas._testing as tm
  6. from pandas.api import (
  7. extensions as api_extensions,
  8. indexers as api_indexers,
  9. interchange as api_interchange,
  10. types as api_types,
  11. typing as api_typing,
  12. )
  13. class Base:
  14. def check(self, namespace, expected, ignored=None):
  15. # see which names are in the namespace, minus optional
  16. # ignored ones
  17. # compare vs the expected
  18. result = sorted(
  19. f for f in dir(namespace) if not f.startswith("__") and f != "annotations"
  20. )
  21. if ignored is not None:
  22. result = sorted(set(result) - set(ignored))
  23. expected = sorted(expected)
  24. tm.assert_almost_equal(result, expected)
  25. class TestPDApi(Base):
  26. # these are optionally imported based on testing
  27. # & need to be ignored
  28. ignored = ["tests", "locale", "conftest", "_version_meson"]
  29. # top-level sub-packages
  30. public_lib = [
  31. "api",
  32. "arrays",
  33. "options",
  34. "test",
  35. "testing",
  36. "errors",
  37. "plotting",
  38. "io",
  39. "tseries",
  40. ]
  41. private_lib = ["compat", "core", "pandas", "util", "_built_with_meson"]
  42. # misc
  43. misc = ["IndexSlice", "NaT", "NA"]
  44. # top-level classes
  45. classes = [
  46. "ArrowDtype",
  47. "Categorical",
  48. "CategoricalIndex",
  49. "DataFrame",
  50. "DateOffset",
  51. "DatetimeIndex",
  52. "ExcelFile",
  53. "ExcelWriter",
  54. "Flags",
  55. "Grouper",
  56. "HDFStore",
  57. "Index",
  58. "MultiIndex",
  59. "Period",
  60. "PeriodIndex",
  61. "RangeIndex",
  62. "Series",
  63. "SparseDtype",
  64. "StringDtype",
  65. "Timedelta",
  66. "TimedeltaIndex",
  67. "Timestamp",
  68. "Interval",
  69. "IntervalIndex",
  70. "CategoricalDtype",
  71. "PeriodDtype",
  72. "IntervalDtype",
  73. "DatetimeTZDtype",
  74. "BooleanDtype",
  75. "Int8Dtype",
  76. "Int16Dtype",
  77. "Int32Dtype",
  78. "Int64Dtype",
  79. "UInt8Dtype",
  80. "UInt16Dtype",
  81. "UInt32Dtype",
  82. "UInt64Dtype",
  83. "Float32Dtype",
  84. "Float64Dtype",
  85. "NamedAgg",
  86. ]
  87. # these are already deprecated; awaiting removal
  88. deprecated_classes: list[str] = []
  89. # external modules exposed in pandas namespace
  90. modules: list[str] = []
  91. # top-level functions
  92. funcs = [
  93. "array",
  94. "bdate_range",
  95. "concat",
  96. "crosstab",
  97. "cut",
  98. "date_range",
  99. "interval_range",
  100. "eval",
  101. "factorize",
  102. "get_dummies",
  103. "from_dummies",
  104. "infer_freq",
  105. "isna",
  106. "isnull",
  107. "lreshape",
  108. "melt",
  109. "notna",
  110. "notnull",
  111. "offsets",
  112. "merge",
  113. "merge_ordered",
  114. "merge_asof",
  115. "period_range",
  116. "pivot",
  117. "pivot_table",
  118. "qcut",
  119. "show_versions",
  120. "timedelta_range",
  121. "unique",
  122. "value_counts",
  123. "wide_to_long",
  124. ]
  125. # top-level option funcs
  126. funcs_option = [
  127. "reset_option",
  128. "describe_option",
  129. "get_option",
  130. "option_context",
  131. "set_option",
  132. "set_eng_float_format",
  133. ]
  134. # top-level read_* funcs
  135. funcs_read = [
  136. "read_clipboard",
  137. "read_csv",
  138. "read_excel",
  139. "read_fwf",
  140. "read_gbq",
  141. "read_hdf",
  142. "read_html",
  143. "read_xml",
  144. "read_json",
  145. "read_pickle",
  146. "read_sas",
  147. "read_sql",
  148. "read_sql_query",
  149. "read_sql_table",
  150. "read_stata",
  151. "read_table",
  152. "read_feather",
  153. "read_parquet",
  154. "read_orc",
  155. "read_spss",
  156. ]
  157. # top-level json funcs
  158. funcs_json = ["json_normalize"]
  159. # top-level to_* funcs
  160. funcs_to = ["to_datetime", "to_numeric", "to_pickle", "to_timedelta"]
  161. # top-level to deprecate in the future
  162. deprecated_funcs_in_future: list[str] = []
  163. # these are already deprecated; awaiting removal
  164. deprecated_funcs: list[str] = []
  165. # private modules in pandas namespace
  166. private_modules = [
  167. "_config",
  168. "_libs",
  169. "_is_numpy_dev",
  170. "_pandas_datetime_CAPI",
  171. "_pandas_parser_CAPI",
  172. "_testing",
  173. "_typing",
  174. ]
  175. if not pd._built_with_meson:
  176. private_modules.append("_version")
  177. def test_api(self):
  178. checkthese = (
  179. self.public_lib
  180. + self.private_lib
  181. + self.misc
  182. + self.modules
  183. + self.classes
  184. + self.funcs
  185. + self.funcs_option
  186. + self.funcs_read
  187. + self.funcs_json
  188. + self.funcs_to
  189. + self.private_modules
  190. )
  191. self.check(namespace=pd, expected=checkthese, ignored=self.ignored)
  192. def test_api_all(self):
  193. expected = set(
  194. self.public_lib
  195. + self.misc
  196. + self.modules
  197. + self.classes
  198. + self.funcs
  199. + self.funcs_option
  200. + self.funcs_read
  201. + self.funcs_json
  202. + self.funcs_to
  203. ) - set(self.deprecated_classes)
  204. actual = set(pd.__all__)
  205. extraneous = actual - expected
  206. assert not extraneous
  207. missing = expected - actual
  208. assert not missing
  209. def test_depr(self):
  210. deprecated_list = (
  211. self.deprecated_classes
  212. + self.deprecated_funcs
  213. + self.deprecated_funcs_in_future
  214. )
  215. for depr in deprecated_list:
  216. with tm.assert_produces_warning(FutureWarning):
  217. _ = getattr(pd, depr)
  218. class TestApi(Base):
  219. allowed_api_dirs = [
  220. "types",
  221. "extensions",
  222. "indexers",
  223. "interchange",
  224. "typing",
  225. ]
  226. allowed_typing = [
  227. "DataFrameGroupBy",
  228. "DatetimeIndexResamplerGroupby",
  229. "Expanding",
  230. "ExpandingGroupby",
  231. "ExponentialMovingWindow",
  232. "ExponentialMovingWindowGroupby",
  233. "JsonReader",
  234. "NaTType",
  235. "NAType",
  236. "PeriodIndexResamplerGroupby",
  237. "Resampler",
  238. "Rolling",
  239. "RollingGroupby",
  240. "SeriesGroupBy",
  241. "StataReader",
  242. "TimedeltaIndexResamplerGroupby",
  243. "TimeGrouper",
  244. "Window",
  245. ]
  246. allowed_api_types = [
  247. "is_any_real_numeric_dtype",
  248. "is_array_like",
  249. "is_bool",
  250. "is_bool_dtype",
  251. "is_categorical_dtype",
  252. "is_complex",
  253. "is_complex_dtype",
  254. "is_datetime64_any_dtype",
  255. "is_datetime64_dtype",
  256. "is_datetime64_ns_dtype",
  257. "is_datetime64tz_dtype",
  258. "is_dict_like",
  259. "is_dtype_equal",
  260. "is_extension_array_dtype",
  261. "is_file_like",
  262. "is_float",
  263. "is_float_dtype",
  264. "is_hashable",
  265. "is_int64_dtype",
  266. "is_integer",
  267. "is_integer_dtype",
  268. "is_interval",
  269. "is_interval_dtype",
  270. "is_iterator",
  271. "is_list_like",
  272. "is_named_tuple",
  273. "is_number",
  274. "is_numeric_dtype",
  275. "is_object_dtype",
  276. "is_period_dtype",
  277. "is_re",
  278. "is_re_compilable",
  279. "is_scalar",
  280. "is_signed_integer_dtype",
  281. "is_sparse",
  282. "is_string_dtype",
  283. "is_timedelta64_dtype",
  284. "is_timedelta64_ns_dtype",
  285. "is_unsigned_integer_dtype",
  286. "pandas_dtype",
  287. "infer_dtype",
  288. "union_categoricals",
  289. "CategoricalDtype",
  290. "DatetimeTZDtype",
  291. "IntervalDtype",
  292. "PeriodDtype",
  293. ]
  294. allowed_api_interchange = ["from_dataframe", "DataFrame"]
  295. allowed_api_indexers = [
  296. "check_array_indexer",
  297. "BaseIndexer",
  298. "FixedForwardWindowIndexer",
  299. "VariableOffsetWindowIndexer",
  300. ]
  301. allowed_api_extensions = [
  302. "no_default",
  303. "ExtensionDtype",
  304. "register_extension_dtype",
  305. "register_dataframe_accessor",
  306. "register_index_accessor",
  307. "register_series_accessor",
  308. "take",
  309. "ExtensionArray",
  310. "ExtensionScalarOpsMixin",
  311. ]
  312. def test_api(self):
  313. self.check(api, self.allowed_api_dirs)
  314. def test_api_typing(self):
  315. self.check(api_typing, self.allowed_typing)
  316. def test_api_types(self):
  317. self.check(api_types, self.allowed_api_types)
  318. def test_api_interchange(self):
  319. self.check(api_interchange, self.allowed_api_interchange)
  320. def test_api_indexers(self):
  321. self.check(api_indexers, self.allowed_api_indexers)
  322. def test_api_extensions(self):
  323. self.check(api_extensions, self.allowed_api_extensions)
  324. class TestTesting(Base):
  325. funcs = [
  326. "assert_frame_equal",
  327. "assert_series_equal",
  328. "assert_index_equal",
  329. "assert_extension_array_equal",
  330. ]
  331. def test_testing(self):
  332. from pandas import testing
  333. self.check(testing, self.funcs)
  334. def test_util_in_top_level(self):
  335. with pytest.raises(AttributeError, match="foo"):
  336. pd.util.foo
  337. def test_pandas_array_alias():
  338. msg = "PandasArray has been renamed NumpyExtensionArray"
  339. with tm.assert_produces_warning(FutureWarning, match=msg):
  340. res = pd.arrays.PandasArray
  341. assert res is pd.arrays.NumpyExtensionArray