diff --git a/pandas-stubs/_libs/lib.pyi b/pandas-stubs/_libs/lib.pyi index c4a51b50..bb392d24 100644 --- a/pandas-stubs/_libs/lib.pyi +++ b/pandas-stubs/_libs/lib.pyi @@ -1,3 +1,9 @@ -no_default = None - def infer_dtype(value: object, skipna: bool = ...) -> str: ... +def is_iterator(obj: object) -> bool: ... +def is_scalar(val: object) -> bool: ... +def is_list_like(obj: object, allow_sets: bool = ...) -> bool: ... +def is_interval(val: object) -> bool: ... +def is_complex(val: object) -> bool: ... +def is_bool(val: object) -> bool: ... +def is_integer(val: object) -> bool: ... +def is_float(val: object) -> bool: ... diff --git a/pandas-stubs/api/extensions/__init__.pyi b/pandas-stubs/api/extensions/__init__.pyi index 41378eb7..dedb5c98 100644 --- a/pandas-stubs/api/extensions/__init__.pyi +++ b/pandas-stubs/api/extensions/__init__.pyi @@ -8,8 +8,6 @@ from pandas.core.arrays import ( ExtensionScalarOpsMixin as ExtensionScalarOpsMixin, ) -from pandas._libs.lib import no_default as no_default - from pandas.core.dtypes.dtypes import ( ExtensionDtype as ExtensionDtype, register_extension_dtype as register_extension_dtype, diff --git a/pandas-stubs/api/types/__init__.pyi b/pandas-stubs/api/types/__init__.pyi index 109274ca..3a5292a1 100644 --- a/pandas-stubs/api/types/__init__.pyi +++ b/pandas-stubs/api/types/__init__.pyi @@ -4,7 +4,6 @@ from pandas.core.dtypes.api import ( is_array_like as is_array_like, is_bool as is_bool, is_bool_dtype as is_bool_dtype, - is_categorical as is_categorical, is_categorical_dtype as is_categorical_dtype, is_complex as is_complex, is_complex_dtype as is_complex_dtype, @@ -15,7 +14,6 @@ from pandas.core.dtypes.api import ( is_dict_like as is_dict_like, is_dtype_equal as is_dtype_equal, is_extension_array_dtype as is_extension_array_dtype, - is_extension_type as is_extension_type, is_file_like as is_file_like, is_float as is_float, is_float_dtype as is_float_dtype, diff --git a/pandas-stubs/core/arrays/sparse/__init__.pyi b/pandas-stubs/core/arrays/sparse/__init__.pyi index 7c057831..6a3a05a6 100644 --- a/pandas-stubs/core/arrays/sparse/__init__.pyi +++ b/pandas-stubs/core/arrays/sparse/__init__.pyi @@ -2,9 +2,5 @@ from .accessor import ( SparseAccessor as SparseAccessor, SparseFrameAccessor as SparseFrameAccessor, ) -from .array import ( - BlockIndex as BlockIndex, - IntIndex as IntIndex, - SparseArray as SparseArray, -) +from .array import SparseArray as SparseArray from .dtype import SparseDtype as SparseDtype diff --git a/pandas-stubs/core/arrays/sparse/accessor.pyi b/pandas-stubs/core/arrays/sparse/accessor.pyi index a0c30e2c..4c091d1d 100644 --- a/pandas-stubs/core/arrays/sparse/accessor.pyi +++ b/pandas-stubs/core/arrays/sparse/accessor.pyi @@ -1,11 +1,4 @@ -from pandas.core.accessor import ( - PandasDelegate as PandasDelegate, - delegate_names as delegate_names, -) -from pandas.core.arrays.sparse.array import SparseArray as SparseArray -from pandas.core.arrays.sparse.dtype import SparseDtype as SparseDtype - -from pandas.core.dtypes.cast import find_common_type as find_common_type +from pandas.core.accessor import PandasDelegate class BaseAccessor: def __init__(self, data=...) -> None: ... diff --git a/pandas-stubs/core/arrays/sparse/array.pyi b/pandas-stubs/core/arrays/sparse/array.pyi index f33db4da..c81bd3d7 100644 --- a/pandas-stubs/core/arrays/sparse/array.pyi +++ b/pandas-stubs/core/arrays/sparse/array.pyi @@ -1,44 +1,9 @@ import numpy as np from pandas.core.arrays import ( - ExtensionArray as ExtensionArray, + ExtensionArray, ExtensionOpsMixin, ) -from pandas.core.arrays.sparse.dtype import SparseDtype as SparseDtype from pandas.core.base import PandasObject as PandasObject -from pandas.core.construction import sanitize_array as sanitize_array -from pandas.core.indexers import check_array_indexer as check_array_indexer -from pandas.core.missing import interpolate_2d as interpolate_2d - -from pandas._libs.sparse import ( - BlockIndex as BlockIndex, - IntIndex as IntIndex, - SparseIndex as SparseIndex, -) -from pandas._libs.tslibs import NaT as NaT -from pandas.errors import PerformanceWarning as PerformanceWarning - -from pandas.core.dtypes.cast import ( - astype_nansafe as astype_nansafe, - construct_1d_arraylike_from_scalar as construct_1d_arraylike_from_scalar, - find_common_type as find_common_type, -) -from pandas.core.dtypes.common import ( - is_array_like as is_array_like, - is_bool_dtype as is_bool_dtype, - is_datetime64_any_dtype as is_datetime64_any_dtype, - is_dtype_equal as is_dtype_equal, - is_integer as is_integer, - is_object_dtype as is_object_dtype, - is_scalar as is_scalar, - is_string_dtype as is_string_dtype, - pandas_dtype as pandas_dtype, -) -from pandas.core.dtypes.generic import ABCSeries as ABCSeries -from pandas.core.dtypes.missing import ( - isna as isna, - na_value_for_dtype as na_value_for_dtype, - notna as notna, -) class SparseArray(PandasObject, ExtensionArray, ExtensionOpsMixin): def __init__( diff --git a/pandas-stubs/core/arrays/sparse/dtype.pyi b/pandas-stubs/core/arrays/sparse/dtype.pyi index be2c1885..630b5be0 100644 --- a/pandas-stubs/core/arrays/sparse/dtype.pyi +++ b/pandas-stubs/core/arrays/sparse/dtype.pyi @@ -3,22 +3,10 @@ from pandas._typing import ( Scalar, ) -from pandas.core.dtypes.base import ExtensionDtype as ExtensionDtype -from pandas.core.dtypes.cast import astype_nansafe as astype_nansafe -from pandas.core.dtypes.common import ( - is_bool_dtype as is_bool_dtype, - is_object_dtype as is_object_dtype, - is_scalar as is_scalar, - is_string_dtype as is_string_dtype, - pandas_dtype as pandas_dtype, -) +from pandas.core.dtypes.base import ExtensionDtype from pandas.core.dtypes.dtypes import ( register_extension_dtype as register_extension_dtype, ) -from pandas.core.dtypes.missing import ( - isna as isna, - na_value_for_dtype as na_value_for_dtype, -) # merged types from pylance diff --git a/pandas-stubs/core/dtypes/api.pyi b/pandas-stubs/core/dtypes/api.pyi index 470210db..89fc968d 100644 --- a/pandas-stubs/core/dtypes/api.pyi +++ b/pandas-stubs/core/dtypes/api.pyi @@ -2,7 +2,6 @@ from pandas.core.dtypes.common import ( is_array_like as is_array_like, is_bool as is_bool, is_bool_dtype as is_bool_dtype, - is_categorical as is_categorical, is_categorical_dtype as is_categorical_dtype, is_complex as is_complex, is_complex_dtype as is_complex_dtype, @@ -13,7 +12,6 @@ from pandas.core.dtypes.common import ( is_dict_like as is_dict_like, is_dtype_equal as is_dtype_equal, is_extension_array_dtype as is_extension_array_dtype, - is_extension_type as is_extension_type, is_file_like as is_file_like, is_float as is_float, is_float_dtype as is_float_dtype, diff --git a/pandas-stubs/core/dtypes/cast.pyi b/pandas-stubs/core/dtypes/cast.pyi index 184e774e..e69de29b 100644 --- a/pandas-stubs/core/dtypes/cast.pyi +++ b/pandas-stubs/core/dtypes/cast.pyi @@ -1,28 +0,0 @@ -import numpy as np - -from pandas._typing import Dtype - -def is_nested_object(obj) -> bool: ... -def infer_dtype_from(val, pandas_dtype: bool = ...): ... -def infer_dtype_from_scalar(val, pandas_dtype: bool = ...): ... -def infer_dtype_from_array(arr, pandas_dtype: bool = ...): ... -def invalidate_string_dtypes(dtype_set) -> None: ... -def coerce_indexer_dtype(indexer, categories): ... -def astype_nansafe(arr, dtype, copy: bool = ..., skipna: bool = ...): ... -def soft_convert_objects( - values: np.ndarray, - datetime: bool = ..., - numeric: bool = ..., - timedelta: bool = ..., - coerce: bool = ..., - copy: bool = ..., -): ... -def convert_dtypes( - input_array, - convert_string: bool = ..., - convert_integer: bool = ..., - convert_boolean: bool = ..., -) -> Dtype: ... -def find_common_type(types): ... -def construct_1d_arraylike_from_scalar(value, length: int, dtype): ... -def construct_1d_object_array_from_listlike(values): ... diff --git a/pandas-stubs/core/dtypes/common.pyi b/pandas-stubs/core/dtypes/common.pyi index 93ec5b43..cdaa9f9b 100644 --- a/pandas-stubs/core/dtypes/common.pyi +++ b/pandas-stubs/core/dtypes/common.pyi @@ -1,6 +1,13 @@ -from typing import Callable +from typing import Union import numpy as np +import pandas as pd + +from pandas._typing import ( + ArrayLike, + DtypeObj, + npt, +) from pandas.core.dtypes.inference import ( is_array_like as is_array_like, @@ -21,37 +28,28 @@ from pandas.core.dtypes.inference import ( is_scalar as is_scalar, ) -def classes(*klasses) -> Callable: ... -def classes_and_not_datetimelike(*klasses) -> Callable: ... -def is_object_dtype(arr_or_dtype) -> bool: ... -def is_sparse(arr) -> bool: ... -def is_scipy_sparse(arr) -> bool: ... -def is_categorical(arr) -> bool: ... -def is_datetime64_dtype(arr_or_dtype) -> bool: ... -def is_datetime64tz_dtype(arr_or_dtype) -> bool: ... -def is_timedelta64_dtype(arr_or_dtype) -> bool: ... -def is_period_dtype(arr_or_dtype) -> bool: ... -def is_interval_dtype(arr_or_dtype) -> bool: ... -def is_categorical_dtype(arr_or_dtype) -> bool: ... -def is_string_dtype(arr_or_dtype) -> bool: ... +_ArrayOrDtype = Union[ArrayLike, npt.DTypeLike, pd.Series, pd.DataFrame] + +def is_object_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_sparse(arr: ArrayLike | pd.Series | pd.DataFrame) -> bool: ... +def is_datetime64_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_datetime64tz_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_timedelta64_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_period_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... def is_dtype_equal(source, target) -> bool: ... -def is_any_int_dtype(arr_or_dtype) -> bool: ... -def is_integer_dtype(arr_or_dtype) -> bool: ... -def is_signed_integer_dtype(arr_or_dtype) -> bool: ... -def is_unsigned_integer_dtype(arr_or_dtype) -> bool: ... -def is_int64_dtype(arr_or_dtype) -> bool: ... -def is_datetime64_any_dtype(arr_or_dtype) -> bool: ... -def is_datetime64_ns_dtype(arr_or_dtype) -> bool: ... -def is_timedelta64_ns_dtype(arr_or_dtype) -> bool: ... -def is_datetime_or_timedelta_dtype(arr_or_dtype) -> bool: ... -def is_numeric_v_string_like(a, b): ... -def is_datetimelike_v_numeric(a, b): ... -def needs_i8_conversion(arr_or_dtype) -> bool: ... -def is_numeric_dtype(arr_or_dtype) -> bool: ... -def is_float_dtype(arr_or_dtype) -> bool: ... -def is_bool_dtype(arr_or_dtype) -> bool: ... -def is_extension_type(arr) -> bool: ... -def is_extension_array_dtype(arr_or_dtype) -> bool: ... -def is_complex_dtype(arr_or_dtype) -> bool: ... -def infer_dtype_from_object(dtype): ... -def pandas_dtype(dtype): ... +def is_interval_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_categorical_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_string_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_integer_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_signed_integer_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_unsigned_integer_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_int64_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_datetime64_any_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_datetime64_ns_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_timedelta64_ns_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_numeric_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_float_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_bool_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_extension_array_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def is_complex_dtype(arr_or_dtype: _ArrayOrDtype) -> bool: ... +def pandas_dtype(dtype: object) -> DtypeObj: ... diff --git a/pandas-stubs/core/dtypes/concat.pyi b/pandas-stubs/core/dtypes/concat.pyi index 7664a425..66256e30 100644 --- a/pandas-stubs/core/dtypes/concat.pyi +++ b/pandas-stubs/core/dtypes/concat.pyi @@ -1,4 +1,16 @@ -def concat_compat(to_concat, axis: int = ...): ... +from typing import ( + TypeVar, + Union, +) + +from pandas import ( + Categorical, + CategoricalIndex, + Series, +) + +_CatT = TypeVar("_CatT", bound=Union[Categorical, CategoricalIndex, Series]) + def union_categoricals( - to_union, sort_categories: bool = ..., ignore_order: bool = ... -): ... + to_union: list[_CatT], sort_categories: bool = ..., ignore_order: bool = ... +) -> Categorical: ... diff --git a/pandas-stubs/core/dtypes/dtypes.pyi b/pandas-stubs/core/dtypes/dtypes.pyi index c935109c..5be1010a 100644 --- a/pandas-stubs/core/dtypes/dtypes.pyi +++ b/pandas-stubs/core/dtypes/dtypes.pyi @@ -6,7 +6,6 @@ from typing import ( from pandas.core.indexes.base import Index from pandas._libs.tslibs import ( # , timezones as timezones - NaT as NaT, Period as Period, Timestamp, ) diff --git a/pandas-stubs/core/dtypes/generic.pyi b/pandas-stubs/core/dtypes/generic.pyi index 380d600f..b21be637 100644 --- a/pandas-stubs/core/dtypes/generic.pyi +++ b/pandas-stubs/core/dtypes/generic.pyi @@ -1,15 +1,5 @@ -from pandas import ( - DataFrame, - Index, - Series, -) +from pandas import Series from pandas.core.arrays import ExtensionArray -from pandas.core.generic import NDFrame -ABCIndex = type[Index] - -ABCNDFrame = type[NDFrame] ABCSeries = type[Series] -ABCDataFrame = type[DataFrame] - ABCExtensionArray = type[ExtensionArray] diff --git a/pandas-stubs/core/dtypes/inference.pyi b/pandas-stubs/core/dtypes/inference.pyi index c20e63af..6346b3e2 100644 --- a/pandas-stubs/core/dtypes/inference.pyi +++ b/pandas-stubs/core/dtypes/inference.pyi @@ -1,19 +1,19 @@ -def is_bool(obj) -> bool: ... -def is_integer(obj) -> bool: ... -def is_float(obj) -> bool: ... -def is_complex(obj) -> bool: ... -def is_scalar(obj) -> bool: ... -def is_decimal(obj) -> bool: ... -def is_interval(obj) -> bool: ... -def is_list_like(obj) -> bool: ... -def is_number(obj) -> bool: ... -def is_iterator(obj) -> bool: ... -def is_file_like(obj) -> bool: ... -def is_re(obj) -> bool: ... -def is_re_compilable(obj) -> bool: ... -def is_array_like(obj) -> bool: ... -def is_nested_list_like(obj) -> bool: ... -def is_dict_like(obj) -> bool: ... -def is_named_tuple(obj) -> bool: ... -def is_hashable(obj) -> bool: ... -def is_sequence(obj) -> bool: ... +from pandas._libs import lib + +is_bool = lib.is_bool +is_integer = lib.is_integer +is_float = lib.is_float +is_complex = lib.is_complex +is_scalar = lib.is_scalar +is_interval = lib.is_interval +is_list_like = lib.is_list_like +is_iterator = lib.is_iterator + +def is_number(obj: object) -> bool: ... +def is_file_like(obj: object) -> bool: ... +def is_re(obj: object) -> bool: ... +def is_array_like(obj: object) -> bool: ... +def is_re_compilable(obj: object) -> bool: ... +def is_dict_like(obj: object) -> bool: ... +def is_named_tuple(obj: object) -> bool: ... +def is_hashable(obj: object) -> bool: ... diff --git a/pandas-stubs/core/dtypes/missing.pyi b/pandas-stubs/core/dtypes/missing.pyi index ed61b497..533193c6 100644 --- a/pandas-stubs/core/dtypes/missing.pyi +++ b/pandas-stubs/core/dtypes/missing.pyi @@ -36,7 +36,3 @@ def notna(obj: Index | list | ArrayLike) -> np.ndarray: ... def notna(obj: Scalar) -> bool: ... notnull = notna - -def array_equivalent(left, right, strict_nan: bool = ...) -> bool: ... -def na_value_for_dtype(dtype, compat: bool = ...): ... -def remove_na_arraylike(arr): ... diff --git a/pandas-stubs/core/ops/dispatch.pyi b/pandas-stubs/core/ops/dispatch.pyi index 47bc3a60..0a69d985 100644 --- a/pandas-stubs/core/ops/dispatch.pyi +++ b/pandas-stubs/core/ops/dispatch.pyi @@ -1,8 +1,5 @@ import numpy as np -from pandas.core.dtypes.generic import ( - ABCExtensionArray as ABCExtensionArray, - ABCSeries, -) +from pandas.core.dtypes.generic import ABCSeries def should_extension_dispatch(left: ABCSeries, right) -> bool: ... diff --git a/tests/__init__.py b/tests/__init__.py index 322da8cd..a5e627a6 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -11,7 +11,6 @@ def check(actual: T, klass: type, dtype: type | None = None, attr: str = "left") -> T: - if not isinstance(actual, klass): raise RuntimeError(f"Expected type '{klass}' but got '{type(actual)}'") if dtype is None: diff --git a/tests/test_api_types.py b/tests/test_api_types.py new file mode 100644 index 00000000..0638aaab --- /dev/null +++ b/tests/test_api_types.py @@ -0,0 +1,178 @@ +import numpy as np +import pandas as pd +import pandas.api.types as api +from typing_extensions import assert_type + +from pandas._typing import DtypeObj + +from tests import check + +nparr = np.array([1, 2, 3]) +arr = pd.Series([1, 2, 3]) +obj = "True" +mapping = {"a": "a"} + + +def test_is_array_like() -> None: + check(assert_type(api.is_array_like(arr), bool), bool) + + +def test_is_bool() -> None: + check(assert_type(api.is_bool(obj), bool), bool) + + +def test_is_bool_dtype() -> None: + check(assert_type(api.is_bool_dtype(arr), bool), bool) + + +def test_is_categorical_dtype() -> None: + check(assert_type(api.is_categorical_dtype(arr), bool), bool) + + +def test_is_complex() -> None: + check(assert_type(api.is_complex(obj), bool), bool) + + +def test_is_complex_dtype() -> None: + check(assert_type(api.is_complex_dtype(arr), bool), bool) + + +def test_is_datetime64_any_dtype() -> None: + check(assert_type(api.is_datetime64_any_dtype(arr), bool), bool) + + +def test_is_datetime64_dtype() -> None: + check(assert_type(api.is_datetime64_dtype(arr), bool), bool) + + +def test_is_datetime64_ns_dtype() -> None: + check(assert_type(api.is_datetime64_ns_dtype(arr), bool), bool) + + +def test_is_datetime64tz_dtype() -> None: + check(assert_type(api.is_datetime64tz_dtype(arr), bool), bool) + + +def test_is_dict_like() -> None: + check(assert_type(api.is_dict_like(mapping), bool), bool) + + +def test_is_dtype_equal() -> None: + check(assert_type(api.is_dtype_equal("i4", np.int8), bool), bool) + + +def test_is_extension_array_dtype() -> None: + check(assert_type(api.is_extension_array_dtype(arr), bool), bool) + + +def test_is_file_like() -> None: + check(assert_type(api.is_file_like(obj), bool), bool) + + +def test_is_float() -> None: + check(assert_type(api.is_float(obj), bool), bool) + + +def test_is_float_dtype() -> None: + check(assert_type(api.is_float_dtype(arr), bool), bool) + + +def test_is_hashable() -> None: + check(assert_type(api.is_hashable(obj), bool), bool) + + +def test_is_int64_dtype() -> None: + check(assert_type(api.is_int64_dtype(arr), bool), bool) + + +def test_is_integer() -> None: + check(assert_type(api.is_integer(obj), bool), bool) + + +def test_is_integer_dtype() -> None: + check(assert_type(api.is_integer_dtype(arr), bool), bool) + + +def test_is_interval() -> None: + check(assert_type(api.is_interval(obj), bool), bool) + + +def test_is_interval_dtype() -> None: + check(assert_type(api.is_interval_dtype(obj), bool), bool) + + +def test_is_iterator() -> None: + check(assert_type(api.is_iterator(obj), bool), bool) + + +def test_is_list_like() -> None: + check(assert_type(api.is_list_like(obj), bool), bool) + + +def test_is_named_tuple() -> None: + check(assert_type(api.is_named_tuple(obj), bool), bool) + + +def test_is_number() -> None: + check(assert_type(api.is_number(obj), bool), bool) + + +def test_is_numeric_dtype() -> None: + check(assert_type(api.is_numeric_dtype(arr), bool), bool) + + +def test_is_object_dtype() -> None: + check(assert_type(api.is_object_dtype(arr), bool), bool) + + +def test_is_period_dtype() -> None: + check(assert_type(api.is_period_dtype(arr), bool), bool) + + +def test_is_re() -> None: + check(assert_type(api.is_re(obj), bool), bool) + + +def test_is_re_compilable() -> None: + check(assert_type(api.is_re_compilable(obj), bool), bool) + + +def test_is_scalar() -> None: + check(assert_type(api.is_scalar(obj), bool), bool) + + +def test_is_signed_integer_dtype() -> None: + check(assert_type(api.is_signed_integer_dtype(arr), bool), bool) + + +def test_is_sparse() -> None: + check(assert_type(api.is_sparse(arr), bool), bool) + + +def test_is_string_dtype() -> None: + check(assert_type(api.is_string_dtype(arr), bool), bool) + + +def test_is_timedelta64_dtype() -> None: + check(assert_type(api.is_timedelta64_dtype(arr), bool), bool) + + +def test_is_timedelta64_ns_dtype() -> None: + check(assert_type(api.is_timedelta64_ns_dtype(arr), bool), bool) + + +def test_is_unsigned_integer_dtype() -> None: + check(assert_type(api.is_unsigned_integer_dtype(arr), bool), bool) + + +def test_pandas_dtype() -> None: + check(assert_type(api.pandas_dtype(arr), DtypeObj), type(np.dtype("i8"))) + + +def test_infer_dtype() -> None: + check(assert_type(api.infer_dtype([1, 2, 3]), str), str) + + +def test_union_categoricals() -> None: + to_union = [pd.Categorical([1, 2, 3]), pd.Categorical([3, 4, 5])] + check(assert_type(api.union_categoricals(to_union), pd.Categorical), pd.Categorical)