|
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 | | - |
33 | 1 | from __future__ import annotations |
34 | 2 |
|
35 | 3 | from datetime import date, datetime as DT, timedelta as TD |
36 | 4 | from typing import Any, SupportsIndex, cast |
37 | | -from typing_extensions import assert_type |
| 5 | +from typing_extensions import assert_never, assert_type |
38 | 6 |
|
39 | 7 | # 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]") |
52 | 20 | assert_type(slice(1234, 5678, 9012), "slice[int, int, int]") |
53 | 21 | # endregion Tests for slice constructor overloads -------------------------------------- |
54 | 22 |
|
|
126 | 94 |
|
127 | 95 |
|
128 | 96 | # 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) |
144 | 112 | # endregion Tests for slice[T] assignments --------------------------------------------- |
145 | 113 |
|
146 | 114 |
|
147 | 115 | # region Tests for slice[X, Y] assignments --------------------------------------------- |
148 | 116 | # 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 |
150 | 118 | tXIX: "slice[None, int]" = slice(1234) |
151 | 119 |
|
152 | | -tNNX: "slice[None, int]" = slice(None, None) |
| 120 | +tNNX: "slice[None, int]" = slice(None, None) # type: ignore |
153 | 121 | tNIX: "slice[None, int]" = slice(None, 5678) |
154 | 122 | tINX: "slice[None, int]" = slice(1234, None) # type: ignore |
155 | 123 | tIIX: "slice[None, int]" = slice(1234, 5678) # type: ignore |
156 | 124 |
|
157 | | -tNNN: "slice[None, int]" = slice(None, None, None) |
| 125 | +tNNN: "slice[None, int]" = slice(None, None, None) # type: ignore |
158 | 126 | tNIN: "slice[None, int]" = slice(None, 5678, None) |
159 | 127 | tINN: "slice[None, int]" = slice(1234, None, None) # type: ignore |
160 | 128 | 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 |
162 | 130 | tINS: "slice[None, int]" = slice(None, 5678, 9012) |
163 | 131 | tNIS: "slice[None, int]" = slice(1234, None, 9012) # type: ignore |
164 | 132 | tIIS: "slice[None, int]" = slice(1234, 5678, 9012) # type: ignore |
165 | 133 | # endregion Tests for slice[X, Y] assignments ------------------------------------------ |
166 | 134 |
|
167 | 135 |
|
168 | 136 | # 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) |
184 | 152 | uIII: "slice[int, int, int]" = slice(1234, 5678, 9012) |
185 | 153 | # endregion Tests for slice[X, Y, Z] assignments --------------------------------------- |
186 | 154 |
|
@@ -219,33 +187,44 @@ def __getitem__(self, key: "slice[DT, DT, TD | None]") -> Any: |
219 | 187 | ... |
220 | 188 |
|
221 | 189 |
|
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 |
236 | 218 |
|
237 | | -model = TimeSeriesInterpolator() |
238 | | -_ = model[slice(start, stop)] |
239 | | -_ = model[slice(start, stop, step)] |
240 | | -_ = model[slice(start, stop, None)] |
241 | 219 |
|
| 220 | +# endregion Integration tests for slices with datetimes -------------------------------- |
242 | 221 |
|
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 |
249 | 222 |
|
| 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) |
250 | 229 |
|
251 | | -# endregion Integration tests for slices with datetimes -------------------------------- |
| 230 | + test(slice(42)) # type: ignore |
0 commit comments