Skip to content

Commit 5506476

Browse files
authored
TYP: Improve typing interval inclusive (#47646)
* TYP: Make typing of inclusive consistent * Fix comparison * Fix typing issues * Try fixing pyright
1 parent e915b0a commit 5506476

File tree

10 files changed

+52
-42
lines changed

10 files changed

+52
-42
lines changed

pandas/_libs/interval.pyi

+8-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import numpy.typing as npt
1212

1313
from pandas._libs import lib
1414
from pandas._typing import (
15-
IntervalClosedType,
15+
IntervalInclusiveType,
1616
Timedelta,
1717
Timestamp,
1818
)
@@ -56,25 +56,25 @@ class IntervalMixin:
5656

5757
def _warning_interval(
5858
inclusive, closed
59-
) -> tuple[IntervalClosedType, lib.NoDefault]: ...
59+
) -> tuple[IntervalInclusiveType, lib.NoDefault]: ...
6060

6161
class Interval(IntervalMixin, Generic[_OrderableT]):
6262
@property
6363
def left(self: Interval[_OrderableT]) -> _OrderableT: ...
6464
@property
6565
def right(self: Interval[_OrderableT]) -> _OrderableT: ...
6666
@property
67-
def inclusive(self) -> IntervalClosedType: ...
67+
def inclusive(self) -> IntervalInclusiveType: ...
6868
@property
69-
def closed(self) -> IntervalClosedType: ...
69+
def closed(self) -> IntervalInclusiveType: ...
7070
mid: _MidDescriptor
7171
length: _LengthDescriptor
7272
def __init__(
7373
self,
7474
left: _OrderableT,
7575
right: _OrderableT,
76-
inclusive: IntervalClosedType = ...,
77-
closed: IntervalClosedType = ...,
76+
inclusive: IntervalInclusiveType = ...,
77+
closed: IntervalInclusiveType = ...,
7878
) -> None: ...
7979
def __hash__(self) -> int: ...
8080
@overload
@@ -151,14 +151,14 @@ class Interval(IntervalMixin, Generic[_OrderableT]):
151151

152152
def intervals_to_interval_bounds(
153153
intervals: np.ndarray, validate_closed: bool = ...
154-
) -> tuple[np.ndarray, np.ndarray, str]: ...
154+
) -> tuple[np.ndarray, np.ndarray, IntervalInclusiveType]: ...
155155

156156
class IntervalTree(IntervalMixin):
157157
def __init__(
158158
self,
159159
left: np.ndarray,
160160
right: np.ndarray,
161-
inclusive: IntervalClosedType = ...,
161+
inclusive: IntervalInclusiveType = ...,
162162
leaf_size: int = ...,
163163
) -> None: ...
164164
@property

pandas/_typing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def closed(self) -> bool:
314314

315315
# Interval closed type
316316
IntervalLeftRight = Literal["left", "right"]
317-
IntervalClosedType = Union[IntervalLeftRight, Literal["both", "neither"]]
317+
IntervalInclusiveType = Union[IntervalLeftRight, Literal["both", "neither"]]
318318

319319
# datetime and NaTType
320320
DatetimeNaTType = Union[datetime, "NaTType"]

pandas/core/arrays/arrow/_arrow_utils.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import numpy as np
77
import pyarrow
88

9+
from pandas._typing import IntervalInclusiveType
910
from pandas.errors import PerformanceWarning
1011
from pandas.util._decorators import deprecate_kwarg
1112
from pandas.util._exceptions import find_stack_level
@@ -107,11 +108,11 @@ def to_pandas_dtype(self):
107108

108109
class ArrowIntervalType(pyarrow.ExtensionType):
109110
@deprecate_kwarg(old_arg_name="closed", new_arg_name="inclusive")
110-
def __init__(self, subtype, inclusive: str) -> None:
111+
def __init__(self, subtype, inclusive: IntervalInclusiveType) -> None:
111112
# attributes need to be set first before calling
112113
# super init (as that calls serialize)
113114
assert inclusive in VALID_CLOSED
114-
self._closed = inclusive
115+
self._closed: IntervalInclusiveType = inclusive
115116
if not isinstance(subtype, pyarrow.DataType):
116117
subtype = pyarrow.type_for_alias(str(subtype))
117118
self._subtype = subtype
@@ -124,11 +125,11 @@ def subtype(self):
124125
return self._subtype
125126

126127
@property
127-
def inclusive(self) -> str:
128+
def inclusive(self) -> IntervalInclusiveType:
128129
return self._closed
129130

130131
@property
131-
def closed(self):
132+
def closed(self) -> IntervalInclusiveType:
132133
warnings.warn(
133134
"Attribute `closed` is deprecated in favor of `inclusive`.",
134135
FutureWarning,

pandas/core/arrays/interval.py

+12-10
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from pandas._typing import (
3333
ArrayLike,
3434
Dtype,
35-
IntervalClosedType,
35+
IntervalInclusiveType,
3636
NpDtype,
3737
PositionalIndexer,
3838
ScalarIndexer,
@@ -230,7 +230,7 @@ def ndim(self) -> Literal[1]:
230230
def __new__(
231231
cls: type[IntervalArrayT],
232232
data,
233-
inclusive: str | None = None,
233+
inclusive: IntervalInclusiveType | None = None,
234234
dtype: Dtype | None = None,
235235
copy: bool = False,
236236
verify_integrity: bool = True,
@@ -277,7 +277,7 @@ def _simple_new(
277277
cls: type[IntervalArrayT],
278278
left,
279279
right,
280-
inclusive=None,
280+
inclusive: IntervalInclusiveType | None = None,
281281
copy: bool = False,
282282
dtype: Dtype | None = None,
283283
verify_integrity: bool = True,
@@ -431,7 +431,7 @@ def _from_factorized(
431431
def from_breaks(
432432
cls: type[IntervalArrayT],
433433
breaks,
434-
inclusive: IntervalClosedType | None = None,
434+
inclusive: IntervalInclusiveType | None = None,
435435
copy: bool = False,
436436
dtype: Dtype | None = None,
437437
) -> IntervalArrayT:
@@ -513,7 +513,7 @@ def from_arrays(
513513
cls: type[IntervalArrayT],
514514
left,
515515
right,
516-
inclusive: IntervalClosedType | None = None,
516+
inclusive: IntervalInclusiveType | None = None,
517517
copy: bool = False,
518518
dtype: Dtype | None = None,
519519
) -> IntervalArrayT:
@@ -586,7 +586,7 @@ def from_arrays(
586586
def from_tuples(
587587
cls: type[IntervalArrayT],
588588
data,
589-
inclusive=None,
589+
inclusive: IntervalInclusiveType | None = None,
590590
copy: bool = False,
591591
dtype: Dtype | None = None,
592592
) -> IntervalArrayT:
@@ -1364,15 +1364,15 @@ def overlaps(self, other):
13641364
# ---------------------------------------------------------------------
13651365

13661366
@property
1367-
def inclusive(self) -> IntervalClosedType:
1367+
def inclusive(self) -> IntervalInclusiveType:
13681368
"""
13691369
Whether the intervals are closed on the left-side, right-side, both or
13701370
neither.
13711371
"""
13721372
return self.dtype.inclusive
13731373

13741374
@property
1375-
def closed(self) -> IntervalClosedType:
1375+
def closed(self) -> IntervalInclusiveType:
13761376
"""
13771377
Whether the intervals are closed on the left-side, right-side, both or
13781378
neither.
@@ -1426,7 +1426,9 @@ def closed(self) -> IntervalClosedType:
14261426
),
14271427
}
14281428
)
1429-
def set_closed(self: IntervalArrayT, closed: IntervalClosedType) -> IntervalArrayT:
1429+
def set_closed(
1430+
self: IntervalArrayT, closed: IntervalInclusiveType
1431+
) -> IntervalArrayT:
14301432
warnings.warn(
14311433
"set_closed is deprecated and will be removed in a future version. "
14321434
"Use set_inclusive instead.",
@@ -1478,7 +1480,7 @@ def set_closed(self: IntervalArrayT, closed: IntervalClosedType) -> IntervalArra
14781480
}
14791481
)
14801482
def set_inclusive(
1481-
self: IntervalArrayT, inclusive: IntervalClosedType
1483+
self: IntervalArrayT, inclusive: IntervalInclusiveType
14821484
) -> IntervalArrayT:
14831485
if inclusive not in VALID_CLOSED:
14841486
msg = f"invalid option for 'inclusive': {inclusive}"

pandas/core/dtypes/dtypes.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from pandas._typing import (
3939
Dtype,
4040
DtypeObj,
41+
IntervalInclusiveType,
4142
Ordered,
4243
npt,
4344
type_t,
@@ -1091,7 +1092,7 @@ class IntervalDtype(PandasExtensionDtype):
10911092
def __new__(
10921093
cls,
10931094
subtype=None,
1094-
inclusive: str_type | None = None,
1095+
inclusive: IntervalInclusiveType | None = None,
10951096
closed: None | lib.NoDefault = lib.no_default,
10961097
):
10971098
from pandas.core.dtypes.common import (
@@ -1140,7 +1141,11 @@ def __new__(
11401141
"'inclusive' keyword does not match value "
11411142
"specified in dtype string"
11421143
)
1143-
inclusive = gd["inclusive"]
1144+
# Incompatible types in assignment (expression has type
1145+
# "Union[str, Any]", variable has type
1146+
# "Optional[Union[Literal['left', 'right'],
1147+
# Literal['both', 'neither']]]")
1148+
inclusive = gd["inclusive"] # type: ignore[assignment]
11441149

11451150
try:
11461151
subtype = pandas_dtype(subtype)

pandas/core/generic.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
IgnoreRaise,
4949
IndexKeyFunc,
5050
IndexLabel,
51-
IntervalClosedType,
51+
IntervalInclusiveType,
5252
JSONSerializable,
5353
Level,
5454
Manager,
@@ -8066,7 +8066,7 @@ def between_time(
80668066
end_time,
80678067
include_start: bool_t | lib.NoDefault = lib.no_default,
80688068
include_end: bool_t | lib.NoDefault = lib.no_default,
8069-
inclusive: IntervalClosedType | None = None,
8069+
inclusive: IntervalInclusiveType | None = None,
80708070
axis=None,
80718071
) -> NDFrameT:
80728072
"""
@@ -8172,7 +8172,7 @@ def between_time(
81728172
left = True if include_start is lib.no_default else include_start
81738173
right = True if include_end is lib.no_default else include_end
81748174

8175-
inc_dict: dict[tuple[bool_t, bool_t], IntervalClosedType] = {
8175+
inc_dict: dict[tuple[bool_t, bool_t], IntervalInclusiveType] = {
81768176
(True, True): "both",
81778177
(True, False): "left",
81788178
(False, True): "right",

pandas/core/indexes/datetimes.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from pandas._typing import (
3636
Dtype,
3737
DtypeObj,
38-
IntervalClosedType,
38+
IntervalInclusiveType,
3939
IntervalLeftRight,
4040
npt,
4141
)
@@ -920,7 +920,7 @@ def date_range(
920920
normalize: bool = False,
921921
name: Hashable = None,
922922
closed: Literal["left", "right"] | None | lib.NoDefault = lib.no_default,
923-
inclusive: IntervalClosedType | None = None,
923+
inclusive: IntervalInclusiveType | None = None,
924924
**kwargs,
925925
) -> DatetimeIndex:
926926
"""
@@ -1126,7 +1126,7 @@ def bdate_range(
11261126
weekmask=None,
11271127
holidays=None,
11281128
closed: IntervalLeftRight | lib.NoDefault | None = lib.no_default,
1129-
inclusive: IntervalClosedType | None = None,
1129+
inclusive: IntervalInclusiveType | None = None,
11301130
**kwargs,
11311131
) -> DatetimeIndex:
11321132
"""

pandas/core/indexes/interval.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from pandas._typing import (
3131
Dtype,
3232
DtypeObj,
33-
IntervalClosedType,
33+
IntervalInclusiveType,
3434
npt,
3535
)
3636
from pandas.errors import InvalidIndexError
@@ -198,7 +198,7 @@ class IntervalIndex(ExtensionIndex):
198198
_typ = "intervalindex"
199199

200200
# annotate properties pinned via inherit_names
201-
inclusive: IntervalClosedType
201+
inclusive: IntervalInclusiveType
202202
is_non_overlapping_monotonic: bool
203203
closed_left: bool
204204
closed_right: bool
@@ -217,7 +217,7 @@ class IntervalIndex(ExtensionIndex):
217217
def __new__(
218218
cls,
219219
data,
220-
inclusive=None,
220+
inclusive: IntervalInclusiveType | None = None,
221221
dtype: Dtype | None = None,
222222
copy: bool = False,
223223
name: Hashable = None,
@@ -266,7 +266,7 @@ def closed(self):
266266
def from_breaks(
267267
cls,
268268
breaks,
269-
inclusive=None,
269+
inclusive: IntervalInclusiveType | None = None,
270270
name: Hashable = None,
271271
copy: bool = False,
272272
dtype: Dtype | None = None,
@@ -302,7 +302,7 @@ def from_arrays(
302302
cls,
303303
left,
304304
right,
305-
inclusive=None,
305+
inclusive: IntervalInclusiveType | None = None,
306306
name: Hashable = None,
307307
copy: bool = False,
308308
dtype: Dtype | None = None,
@@ -337,7 +337,7 @@ def from_arrays(
337337
def from_tuples(
338338
cls,
339339
data,
340-
inclusive=None,
340+
inclusive: IntervalInclusiveType | None = None,
341341
name: Hashable = None,
342342
copy: bool = False,
343343
dtype: Dtype | None = None,
@@ -989,7 +989,7 @@ def interval_range(
989989
periods=None,
990990
freq=None,
991991
name: Hashable = None,
992-
inclusive: IntervalClosedType | None = None,
992+
inclusive: IntervalInclusiveType | None = None,
993993
) -> IntervalIndex:
994994
"""
995995
Return a fixed frequency IntervalIndex.

pandas/io/formats/style.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
Axis,
2626
FilePath,
2727
IndexLabel,
28+
IntervalInclusiveType,
2829
Level,
2930
QuantileInterpolation,
3031
Scalar,
@@ -3479,7 +3480,7 @@ def highlight_between(
34793480
axis: Axis | None = 0,
34803481
left: Scalar | Sequence | None = None,
34813482
right: Scalar | Sequence | None = None,
3482-
inclusive: str = "both",
3483+
inclusive: IntervalInclusiveType = "both",
34833484
props: str | None = None,
34843485
) -> Styler:
34853486
"""
@@ -3584,7 +3585,7 @@ def highlight_quantile(
35843585
q_left: float = 0.0,
35853586
q_right: float = 1.0,
35863587
interpolation: QuantileInterpolation = "linear",
3587-
inclusive: str = "both",
3588+
inclusive: IntervalInclusiveType = "both",
35883589
props: str | None = None,
35893590
) -> Styler:
35903591
"""
@@ -3969,7 +3970,7 @@ def _highlight_between(
39693970
props: str,
39703971
left: Scalar | Sequence | np.ndarray | NDFrame | None = None,
39713972
right: Scalar | Sequence | np.ndarray | NDFrame | None = None,
3972-
inclusive: bool | str = True,
3973+
inclusive: bool | IntervalInclusiveType = True,
39733974
) -> np.ndarray:
39743975
"""
39753976
Return an array of css props based on condition of data values within given range.

pandas/util/_validators.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import numpy as np
1616

17+
from pandas._typing import IntervalInclusiveType
1718
from pandas.util._exceptions import find_stack_level
1819

1920
from pandas.core.dtypes.common import (
@@ -487,7 +488,7 @@ def validate_endpoints(closed: str | None) -> tuple[bool, bool]:
487488
return left_closed, right_closed
488489

489490

490-
def validate_inclusive(inclusive: str | None) -> tuple[bool, bool]:
491+
def validate_inclusive(inclusive: IntervalInclusiveType | None) -> tuple[bool, bool]:
491492
"""
492493
Check that the `inclusive` argument is among {"both", "neither", "left", "right"}.
493494

0 commit comments

Comments
 (0)