#13008 made slice.__new__ more precise. Generic slice[T] accepts T | None as arguments when creating a slice.
However, properties .start, .stop, . step of (generic) slice[...] are typed as there respective types, i.e. T in above example.
Consequence
This leads to typecheckers accepting:
def test(s: slice[int]) -> None:
assert_type(s.start, int)
if s.start is None:
assert_never(s.start)
whereas below obviously breaks:
test(slice(42))
Solution
Therefore, I suggest properties .start, .stop, . step should have optional (| None) return types:
defslice_slice(old_slice: slice, applied_slice: slice, size: int) ->slice:
"""Given a slice and the size of the dimension to which it will be applied, index it with another slice to return a new slice equivalent to applying the slices sequentially """old_slice=slice(*old_slice.indices(size))
size_after_old_slice=len(range(old_slice.start, old_slice.stop, old_slice.step))
ifsize_after_old_slice==0:
# nothing left after applying first slicereturnslice(0)
applied_slice=slice(*applied_slice.indices(size_after_old_slice))
start=old_slice.start+applied_slice.start*old_slice.stepifstart<0:
# nothing left after applying second slice# (can only happen for old_slice.step < 0, e.g. [10::-1], [20:])returnslice(0)
stop=old_slice.start+applied_slice.stop*old_slice.stepifstop<0:
stop=Nonestep=old_slice.step*applied_slice.stepreturnslice(start, stop, step)
Activity
srittau commented on Mar 19, 2026
I'm unsure why we're using Any instead of None for the return type annotations of slice.__new__. The comment says:
But I'm not sure what that means.
srittau commented on Mar 19, 2026
Cc @randolf-scholz
randolf-scholz commented on Mar 19, 2026
Using T | None for start/stop/step was my initial instinct as well, but there were cases in mypy primer that got hit by that: #12899 (comment)
See for example this commit: 3010eda
and the mypy primer output: #12899 (comment)
If we make None implicit, this means we force every user of slices to accept open-ended slice, but there are users who seem to rely on only using bounded slices in some cases, for example, code like this in xarray: (https://github.com/pydata/xarray/blob/a1c0617051260cc84789bfc6c31a7fef3d64f01b/xarray/core/indexing.py#L318
)
randolf-scholz commented on Mar 19, 2026
This was a result of this discussion: #12899 (comment)
randolf-scholz commented on Mar 22, 2026
This is what the primer looks like if we drastically simplify towards (#15536)
randolf-scholz commented on Mar 22, 2026
some of these actually seem to be problems with mypy rather than anything else, for example:
makes mypy complain, but this should just be slice[None, None, None] | slice[None | None | int]
EDIT: This seems to be fixed on mypy master branch, maybe we wait for 1.20 which should release soon and then check primer again.