1"""define generic base classes for pandas objects"""
2
3from __future__ import annotations
4
5from typing import (
6 TYPE_CHECKING,
7 Type,
8 cast,
9)
10
11if TYPE_CHECKING:
12 from pandas import (
13 Categorical,
14 CategoricalIndex,
15 DataFrame,
16 DatetimeIndex,
17 Index,
18 IntervalIndex,
19 MultiIndex,
20 PeriodIndex,
21 RangeIndex,
22 Series,
23 TimedeltaIndex,
24 )
25 from pandas.core.arrays import (
26 DatetimeArray,
27 ExtensionArray,
28 NumpyExtensionArray,
29 PeriodArray,
30 TimedeltaArray,
31 )
32 from pandas.core.generic import NDFrame
33
34
35# define abstract base classes to enable isinstance type checking on our
36# objects
37def create_pandas_abc_type(name, attr, comp) -> type:
38 def _check(inst) -> bool:
39 return getattr(inst, attr, "_typ") in comp
40
41 # https://github.com/python/mypy/issues/1006
42 # error: 'classmethod' used with a non-method
43 @classmethod # type: ignore[misc]
44 def _instancecheck(cls, inst) -> bool:
45 return _check(inst) and not isinstance(inst, type)
46
47 @classmethod # type: ignore[misc]
48 def _subclasscheck(cls, inst) -> bool:
49 # Raise instead of returning False
50 # This is consistent with default __subclasscheck__ behavior
51 if not isinstance(inst, type):
52 raise TypeError("issubclass() arg 1 must be a class")
53
54 return _check(inst)
55
56 dct = {"__instancecheck__": _instancecheck, "__subclasscheck__": _subclasscheck}
57 meta = type("ABCBase", (type,), dct)
58 return meta(name, (), dct)
59
60
61ABCRangeIndex = cast(
62 "Type[RangeIndex]",
63 create_pandas_abc_type("ABCRangeIndex", "_typ", ("rangeindex",)),
64)
65ABCMultiIndex = cast(
66 "Type[MultiIndex]",
67 create_pandas_abc_type("ABCMultiIndex", "_typ", ("multiindex",)),
68)
69ABCDatetimeIndex = cast(
70 "Type[DatetimeIndex]",
71 create_pandas_abc_type("ABCDatetimeIndex", "_typ", ("datetimeindex",)),
72)
73ABCTimedeltaIndex = cast(
74 "Type[TimedeltaIndex]",
75 create_pandas_abc_type("ABCTimedeltaIndex", "_typ", ("timedeltaindex",)),
76)
77ABCPeriodIndex = cast(
78 "Type[PeriodIndex]",
79 create_pandas_abc_type("ABCPeriodIndex", "_typ", ("periodindex",)),
80)
81ABCCategoricalIndex = cast(
82 "Type[CategoricalIndex]",
83 create_pandas_abc_type("ABCCategoricalIndex", "_typ", ("categoricalindex",)),
84)
85ABCIntervalIndex = cast(
86 "Type[IntervalIndex]",
87 create_pandas_abc_type("ABCIntervalIndex", "_typ", ("intervalindex",)),
88)
89ABCIndex = cast(
90 "Type[Index]",
91 create_pandas_abc_type(
92 "ABCIndex",
93 "_typ",
94 {
95 "index",
96 "rangeindex",
97 "multiindex",
98 "datetimeindex",
99 "timedeltaindex",
100 "periodindex",
101 "categoricalindex",
102 "intervalindex",
103 },
104 ),
105)
106
107
108ABCNDFrame = cast(
109 "Type[NDFrame]",
110 create_pandas_abc_type("ABCNDFrame", "_typ", ("series", "dataframe")),
111)
112ABCSeries = cast(
113 "Type[Series]",
114 create_pandas_abc_type("ABCSeries", "_typ", ("series",)),
115)
116ABCDataFrame = cast(
117 "Type[DataFrame]", create_pandas_abc_type("ABCDataFrame", "_typ", ("dataframe",))
118)
119
120ABCCategorical = cast(
121 "Type[Categorical]",
122 create_pandas_abc_type("ABCCategorical", "_typ", ("categorical")),
123)
124ABCDatetimeArray = cast(
125 "Type[DatetimeArray]",
126 create_pandas_abc_type("ABCDatetimeArray", "_typ", ("datetimearray")),
127)
128ABCTimedeltaArray = cast(
129 "Type[TimedeltaArray]",
130 create_pandas_abc_type("ABCTimedeltaArray", "_typ", ("timedeltaarray")),
131)
132ABCPeriodArray = cast(
133 "Type[PeriodArray]",
134 create_pandas_abc_type("ABCPeriodArray", "_typ", ("periodarray",)),
135)
136ABCExtensionArray = cast(
137 "Type[ExtensionArray]",
138 create_pandas_abc_type(
139 "ABCExtensionArray",
140 "_typ",
141 # Note: IntervalArray and SparseArray are included bc they have _typ="extension"
142 {"extension", "categorical", "periodarray", "datetimearray", "timedeltaarray"},
143 ),
144)
145ABCNumpyExtensionArray = cast(
146 "Type[NumpyExtensionArray]",
147 create_pandas_abc_type("ABCNumpyExtensionArray", "_typ", ("npy_extension",)),
148)