|
1 | 1 | """Type and interface declarations that are not specific to options."""
|
2 | 2 |
|
3 |
| -from typing import Any, Optional, TypeVar, Sequence |
4 |
| -from typing_extensions import Protocol, Self, runtime_checkable, TypeGuard |
| 3 | +import sys |
| 4 | +from typing import Any, NoReturn, Optional, Type, TypeVar, Sequence, TYPE_CHECKING |
| 5 | +from typing_extensions import Protocol, Self, TypeGuard |
5 | 6 |
|
6 | 7 |
|
7 | 8 | def is_nonstringy_sequence(it: Any) -> TypeGuard[Sequence]:
|
@@ -36,25 +37,45 @@ def __gt__(self, __other: Self) -> bool:
|
36 | 37 | ...
|
37 | 38 |
|
38 | 39 |
|
39 |
| -_Cmp_co = TypeVar("_Cmp_co", bound=Comparable, covariant=True) |
| 40 | +_T = TypeVar("_T") |
| 41 | +_T_co = TypeVar("_T_co", covariant=True) |
40 | 42 |
|
41 | 43 |
|
42 |
| -@runtime_checkable |
43 |
| -class Slice(Protocol[_Cmp_co]): |
| 44 | +class Slice(Protocol[_T_co]): |
44 | 45 | """A slice which stores a certain type of object.
|
45 | 46 |
|
46 | 47 | This protocol describes the built in ``slice`` type, with a hint to callers
|
47 |
| - about what type they should put *inside* the slice. |
| 48 | + about what type they should put *inside* the slice. It is for type |
| 49 | + annotations only and is not runtime-checkable (i.e., you can't do |
| 50 | + ``isinstance(thing, Slice)``), because ``range`` objects also have |
| 51 | + ``start``/``stop``/``step`` and would match, but are *not* slices. |
48 | 52 | """
|
49 | 53 |
|
50 | 54 | @property
|
51 |
| - def start(self) -> Optional[_Cmp_co]: |
| 55 | + def start(self) -> Optional[_T_co]: |
52 | 56 | ...
|
53 | 57 |
|
54 | 58 | @property
|
55 |
| - def stop(self) -> Optional[_Cmp_co]: |
| 59 | + def stop(self) -> Optional[_T_co]: |
56 | 60 | ...
|
57 | 61 |
|
58 | 62 | @property
|
59 |
| - def step(self) -> Optional[_Cmp_co]: |
| 63 | + def step(self) -> Optional[_T_co]: |
60 | 64 | ...
|
| 65 | + |
| 66 | + if sys.version_info < (3, 10) and not TYPE_CHECKING: |
| 67 | + # Python 3.9 and below have a bug where any Protocol with an @property |
| 68 | + # was always regarded as runtime-checkable. |
| 69 | + @classmethod |
| 70 | + def __subclasscheck__(cls, __subclass: type) -> NoReturn: |
| 71 | + raise TypeError("Slice is not a runtime-checkable protocol") |
| 72 | + |
| 73 | + |
| 74 | +def is_slice_of(__obj: object, __typ: Type[_T]) -> TypeGuard[Slice[_T]]: |
| 75 | + return ( |
| 76 | + # We only respect `slice`s proper. |
| 77 | + isinstance(__obj, slice) |
| 78 | + and (__obj.start is None or isinstance(__obj.start, __typ)) |
| 79 | + and (__obj.stop is None or isinstance(__obj.stop, __typ)) |
| 80 | + and (__obj.step is None or isinstance(__obj.step, __typ)) |
| 81 | + ) |
0 commit comments