Skip to content

Commit dfe973b

Browse files
simplify slice overloads
1 parent 282b1a8 commit dfe973b

File tree

2 files changed

+85
-124
lines changed

2 files changed

+85
-124
lines changed
Lines changed: 83 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,22 @@
1-
"""
2-
Assuming X, Y and Z are types other than None, the following rules apply to the slice type:
3-
4-
- The type hint `slice` should be compatible with all slices, including:
5-
- `slice(None)`, `slice(None, None)` and `slice(None, None, None)`. (⟿ `slice[?, ?, ?]`)
6-
- The type hint `slice[T]` should be compatible with:
7-
- `slice(None)`, `slice(None, None)` and `slice(None, None, None)` (⟿ `slice[?, ?, ?]`)
8-
- `slice(t)`, `slice(None, t)` and `slice(None, t, None)`. (⟿ `slice[?, T, ?]`)
9-
- `slice(t, None)` and `slice(t, None, None)`. (⟿ `slice[T, ?, ?]`)
10-
- `slice(t, t)` and `slice(t, t, None)`. (⟿ `slice[T, T, ?]`)
11-
- The type hint `slice[X, Y]` should be compatible with:
12-
- `slice(None)`, `slice(None, None)` and `slice(None, None, None)` (⟿ `slice[?, ?, ?]`)
13-
- `slice(y)`, `slice(None, y)` and `slice(None, y, None)`. (⟿ `slice[?, Y, ?]`)
14-
- `slice(x, None)` and `slice(x, None, None)` (⟿ `slice[X, ?, ?]`)
15-
- `slice(x, y)` and `slice(x, y, None)`. (⟿ `slice[X, Y, ?]`)
16-
- The type hint `slice[X, Y, Z]` should be compatible with:
17-
- `slice(None)`, `slice(None, None)` and `slice(None, None, None)`. (⟿ `slice[?, ?, ?]`)
18-
- `slice(y)`, `slice(None, y)` and `slice(None, y, None)`. (⟿ `slice[?, Y, ?]`)
19-
- `slice(x, None)` and `slice(x, None, None)` (⟿ `slice[X, ?, ?]`)
20-
- `slice(x, y)` and `slice(x, y, None)`. (⟿ `slice[X, Y, ?]`)
21-
- `slice(None, None, z)` (⟿ `slice[?, ?, Z]`)
22-
- `slice(None, y, z)` (⟿ `slice[?, Y, Z]`)
23-
- `slice(x, None, z)` (⟿ `slice[X, ?, Z]`)
24-
- `slice(x, y, z)` (⟿ `slice[X, Y, Z]`)
25-
26-
Consistency criterion: Assuming now X, Y, Z can potentially be None, the following rules apply:
27-
28-
- `slice(x)` must be compatible with `slice[None, X, None]`, even if X is None.
29-
- `slice(x, y)` must be compatible with `slice[X,Y,None]`, even if X is None or Y is None.
30-
- `slice(x, y, z)` must be compatible with `slice[X, Y, Z]`, even if X, Y, or Z are `None`.
31-
"""
32-
331
from __future__ import annotations
342

353
from datetime import date, datetime as DT, timedelta as TD
364
from typing import Any, SupportsIndex, cast
37-
from typing_extensions import assert_type
5+
from typing_extensions import assert_never, assert_type
386

397
# region Tests for slice constructor overloads -----------------------------------------
40-
assert_type(slice(None), "slice[Any, Any, Any]")
41-
assert_type(slice(1234), "slice[Any, int, Any]")
42-
43-
assert_type(slice(None, None), "slice[Any, Any, Any]")
44-
assert_type(slice(None, 5678), "slice[Any, int, Any]")
45-
assert_type(slice(1234, None), "slice[int, Any, Any]")
46-
assert_type(slice(1234, 5678), "slice[int, int, Any]")
47-
48-
assert_type(slice(None, None, None), "slice[Any, Any, Any]")
49-
assert_type(slice(None, 5678, None), "slice[Any, int, Any]")
50-
assert_type(slice(1234, None, None), "slice[int, Any, Any]")
51-
assert_type(slice(1234, 5678, None), "slice[int, int, Any]")
8+
assert_type(slice(None), "slice[None, None, None]")
9+
assert_type(slice(1234), "slice[None, int, None]")
10+
11+
assert_type(slice(None, None), "slice[None, None, None]")
12+
assert_type(slice(None, 5678), "slice[None, int, None]")
13+
assert_type(slice(1234, None), "slice[int, None, None]")
14+
assert_type(slice(1234, 5678), "slice[int, int, None]")
15+
16+
assert_type(slice(None, None, None), "slice[None, None, None]")
17+
assert_type(slice(None, 5678, None), "slice[None, int, None]")
18+
assert_type(slice(1234, None, None), "slice[int, None, None]")
19+
assert_type(slice(1234, 5678, None), "slice[int, int, None]")
5220
assert_type(slice(1234, 5678, 9012), "slice[int, int, int]")
5321
# endregion Tests for slice constructor overloads --------------------------------------
5422

@@ -126,61 +94,61 @@
12694

12795

12896
# region Tests for slice[T] assignments ------------------------------------------------
129-
sXNX: "slice[int]" = slice(None)
130-
sXIX: "slice[int]" = slice(1234)
131-
132-
sNNX: "slice[int]" = slice(None, None)
133-
sNIX: "slice[int]" = slice(None, 5678)
134-
sINX: "slice[int]" = slice(1234, None)
135-
sIIX: "slice[int]" = slice(1234, 5678)
136-
137-
sNNN: "slice[int]" = slice(None, None, None)
138-
sNIN: "slice[int]" = slice(None, 5678, None)
139-
sNNS: "slice[int]" = slice(None, None, 9012)
140-
sINN: "slice[int]" = slice(1234, None, None)
141-
sINS: "slice[int]" = slice(1234, None, 9012)
142-
sIIN: "slice[int]" = slice(1234, 5678, None)
143-
sIIS: "slice[int]" = slice(1234, 5678, 9012)
97+
sXNX: "slice[int | None]" = slice(None)
98+
sXIX: "slice[int | None]" = slice(1234)
99+
100+
sNNX: "slice[int | None]" = slice(None, None)
101+
sNIX: "slice[int | None]" = slice(None, 5678)
102+
sINX: "slice[int | None]" = slice(1234, None)
103+
sIIX: "slice[int | None]" = slice(1234, 5678)
104+
105+
sNNN: "slice[int | None]" = slice(None, None, None)
106+
sNIN: "slice[int | None]" = slice(None, 5678, None)
107+
sNNS: "slice[int | None]" = slice(None, None, 9012)
108+
sINN: "slice[int | None]" = slice(1234, None, None)
109+
sINS: "slice[int | None]" = slice(1234, None, 9012)
110+
sIIN: "slice[int | None]" = slice(1234, 5678, None)
111+
sIIS: "slice[int | None]" = slice(1234, 5678, 9012)
144112
# endregion Tests for slice[T] assignments ---------------------------------------------
145113

146114

147115
# region Tests for slice[X, Y] assignments ---------------------------------------------
148116
# Note: start=int is illegal and hence we add an explicit "type: ignore" comment.
149-
tXNX: "slice[None, int]" = slice(None) # since slice(None) is slice[Any, Any, Any]
117+
tXNX: "slice[None, int]" = slice(None) # type: ignore
150118
tXIX: "slice[None, int]" = slice(1234)
151119

152-
tNNX: "slice[None, int]" = slice(None, None)
120+
tNNX: "slice[None, int]" = slice(None, None) # type: ignore
153121
tNIX: "slice[None, int]" = slice(None, 5678)
154122
tINX: "slice[None, int]" = slice(1234, None) # type: ignore
155123
tIIX: "slice[None, int]" = slice(1234, 5678) # type: ignore
156124

157-
tNNN: "slice[None, int]" = slice(None, None, None)
125+
tNNN: "slice[None, int]" = slice(None, None, None) # type: ignore
158126
tNIN: "slice[None, int]" = slice(None, 5678, None)
159127
tINN: "slice[None, int]" = slice(1234, None, None) # type: ignore
160128
tIIN: "slice[None, int]" = slice(1234, 5678, None) # type: ignore
161-
tNNS: "slice[None, int]" = slice(None, None, 9012)
129+
tNNS: "slice[None, int]" = slice(None, None, 9012) # type: ignore
162130
tINS: "slice[None, int]" = slice(None, 5678, 9012)
163131
tNIS: "slice[None, int]" = slice(1234, None, 9012) # type: ignore
164132
tIIS: "slice[None, int]" = slice(1234, 5678, 9012) # type: ignore
165133
# endregion Tests for slice[X, Y] assignments ------------------------------------------
166134

167135

168136
# region Tests for slice[X, Y, Z] assignments ------------------------------------------
169-
uXNX: "slice[int, int, int]" = slice(None)
170-
uXIX: "slice[int, int, int]" = slice(1234)
171-
172-
uNNX: "slice[int, int, int]" = slice(None, None)
173-
uNIX: "slice[int, int, int]" = slice(None, 5678)
174-
uINX: "slice[int, int, int]" = slice(1234, None)
175-
uIIX: "slice[int, int, int]" = slice(1234, 5678)
176-
177-
uNNN: "slice[int, int, int]" = slice(None, None, None)
178-
uNNI: "slice[int, int, int]" = slice(None, None, 9012)
179-
uNIN: "slice[int, int, int]" = slice(None, 5678, None)
180-
uNII: "slice[int, int, int]" = slice(None, 5678, 9012)
181-
uINN: "slice[int, int, int]" = slice(1234, None, None)
182-
uINI: "slice[int, int, int]" = slice(1234, None, 9012)
183-
uIIN: "slice[int, int, int]" = slice(1234, 5678, None)
137+
uXNX: "slice[None, None, None]" = slice(None)
138+
uXIX: "slice[None, int, None]" = slice(1234)
139+
140+
uNNX: "slice[None, None, None]" = slice(None, None)
141+
uNIX: "slice[None, int, None]" = slice(None, 5678)
142+
uINX: "slice[int, None, None]" = slice(1234, None)
143+
uIIX: "slice[int, int, None]" = slice(1234, 5678)
144+
145+
uNNN: "slice[None, None, None]" = slice(None, None, None)
146+
uNNI: "slice[None, None, int]" = slice(None, None, 9012)
147+
uNIN: "slice[None, int, None]" = slice(None, 5678, None)
148+
uNII: "slice[None, int, int]" = slice(None, 5678, 9012)
149+
uINN: "slice[int, None, None]" = slice(1234, None, None)
150+
uINI: "slice[int, None, int]" = slice(1234, None, 9012)
151+
uIIN: "slice[int, int, None]" = slice(1234, 5678, None)
184152
uIII: "slice[int, int, int]" = slice(1234, 5678, 9012)
185153
# endregion Tests for slice[X, Y, Z] assignments ---------------------------------------
186154

@@ -219,33 +187,44 @@ def __getitem__(self, key: "slice[DT, DT, TD | None]") -> Any:
219187
...
220188

221189

222-
# tests slices as an argument
223-
start = DT(1970, 1, 1)
224-
stop = DT(1971, 1, 10)
225-
step = TD(days=1)
226-
# see: https://pandas.pydata.org/docs/user_guide/timeseries.html#partial-string-indexing
227-
# FIXME: https://github.com/python/mypy/issues/2410 (use literal slices)
228-
series = TimeSeries()
229-
_ = series[slice(None, "1970-01-10")]
230-
_ = series[slice("1970-01-01", None)]
231-
_ = series[slice("1970-01-01", "1971-01-10")]
232-
_ = series[slice(None, stop)]
233-
_ = series[slice(start, None)]
234-
_ = series[slice(start, stop)]
235-
_ = series[slice(None)]
190+
def test_datetime_slices() -> None:
191+
# tests slices as an argument
192+
start = DT(1970, 1, 1)
193+
stop = DT(1971, 1, 10)
194+
step = TD(days=1)
195+
# see: https://pandas.pydata.org/docs/user_guide/timeseries.html#partial-string-indexing
196+
# FIXME: https://github.com/python/mypy/issues/2410 (use literal slices)
197+
series = TimeSeries()
198+
_ = series[slice(None, "1970-01-10")]
199+
_ = series[slice("1970-01-01", None)]
200+
_ = series[slice("1970-01-01", "1971-01-10")]
201+
_ = series[slice(None, stop)]
202+
_ = series[slice(start, None)]
203+
_ = series[slice(start, stop)]
204+
_ = series[slice(None)]
205+
206+
model = TimeSeriesInterpolator()
207+
_ = model[slice(start, stop)]
208+
_ = model[slice(start, stop, step)]
209+
_ = model[slice(start, stop, None)]
210+
211+
212+
def tests_return_union_datetime_slices() -> None:
213+
def _(flag: bool, value: DT) -> "slice[DT, None] | slice[None, DT]":
214+
if flag:
215+
return slice(value, None) # slice[DT, DT|Any, Any] incompatible
216+
else:
217+
return slice(None, value) # slice[DT|Any, DT, Any] incompatible
236218

237-
model = TimeSeriesInterpolator()
238-
_ = model[slice(start, stop)]
239-
_ = model[slice(start, stop, step)]
240-
_ = model[slice(start, stop, None)]
241219

220+
# endregion Integration tests for slices with datetimes --------------------------------
242221

243-
# test slices as a return type
244-
def foo(flag: bool, value: DT) -> "slice[DT, None] | slice[None, DT]":
245-
if flag:
246-
return slice(value, None) # slice[DT, DT|Any, Any] incompatible
247-
else:
248-
return slice(None, value) # slice[DT|Any, DT, Any] incompatible
249222

223+
def test_bad_slice_raises() -> None:
224+
# gh-15526
225+
def test(s: "slice[int]") -> None:
226+
assert_type(s.start, int)
227+
if s.start is None: # pyright: ignore[reportUnnecessaryComparison]
228+
assert_never(s.start)
250229

251-
# endregion Integration tests for slices with datetimes --------------------------------
230+
test(slice(42)) # type: ignore

stdlib/builtins.pyi

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,28 +1007,10 @@ class slice(Generic[_StartT_co, _StopT_co, _StepT_co]):
10071007
def step(self) -> _StepT_co: ...
10081008
@property
10091009
def stop(self) -> _StopT_co: ...
1010-
# Note: __new__ overloads map `None` to `Any`, since users expect slice(x, None)
1011-
# to be compatible with slice(None, x).
1012-
# generic slice --------------------------------------------------------------------
10131010
@overload
1014-
def __new__(cls, start: None, stop: None = None, step: None = None, /) -> slice[Any, Any, Any]: ...
1015-
# unary overloads ------------------------------------------------------------------
1011+
def __new__(cls, stop: _T2, /) -> slice[None, _T2, None]: ...
10161012
@overload
1017-
def __new__(cls, stop: _T2, /) -> slice[Any, _T2, Any]: ...
1018-
# binary overloads -----------------------------------------------------------------
1019-
@overload
1020-
def __new__(cls, start: _T1, stop: None, step: None = None, /) -> slice[_T1, Any, Any]: ...
1021-
@overload
1022-
def __new__(cls, start: None, stop: _T2, step: None = None, /) -> slice[Any, _T2, Any]: ...
1023-
@overload
1024-
def __new__(cls, start: _T1, stop: _T2, step: None = None, /) -> slice[_T1, _T2, Any]: ...
1025-
# ternary overloads ----------------------------------------------------------------
1026-
@overload
1027-
def __new__(cls, start: None, stop: None, step: _T3, /) -> slice[Any, Any, _T3]: ...
1028-
@overload
1029-
def __new__(cls, start: _T1, stop: None, step: _T3, /) -> slice[_T1, Any, _T3]: ...
1030-
@overload
1031-
def __new__(cls, start: None, stop: _T2, step: _T3, /) -> slice[Any, _T2, _T3]: ...
1013+
def __new__(cls, start: _T1, stop: _T2, /) -> slice[_T1, _T2, None]: ...
10321014
@overload
10331015
def __new__(cls, start: _T1, stop: _T2, step: _T3, /) -> slice[_T1, _T2, _T3]: ...
10341016
def __eq__(self, value: object, /) -> bool: ...

0 commit comments

Comments
 (0)