subtype 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
subtype/__init__.pyi ADDED
@@ -0,0 +1,18 @@
1
+ __all__ = ["isinstance", "subtype"]
2
+
3
+ import typing as tp
4
+
5
+ from typing_extensions import TypeForm
6
+
7
+ class subtype(type):
8
+ __subtype_form__: tp.Any
9
+ __subtype_instancecheck__: tp.Callable[[object], bool]
10
+ __subtype_subclasscheck__: tp.Callable[[object], bool]
11
+
12
+ def __new__[T](mcls: type[T], typx, /) -> T: ...
13
+ def __instancecheck__(cls, obj, /) -> bool: ...
14
+ def __subclasscheck__(cls, typx, /) -> bool: ...
15
+ def __or__[T](cls: T, other, /) -> T: ...
16
+ def __ror__[T](cls: T, other, /) -> T: ...
17
+
18
+ def isinstance[T](obj: object, typx: TypeForm[T], /) -> tp.TypeGuard[T]: ...
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: subtype
3
+ Version: 0.1.0
4
+ Author: crypt0lith
5
+ Requires-Python: >=3.14
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: typing-extensions>=4.15
8
+
9
+ Provides a metaclass that extends runtime type checking to the full Python typing spec.
10
+
11
+ ## Usage
12
+
13
+ ### `isinstance`
14
+
15
+ `subtype.isinstance(obj, T)` answers whether `obj` is assignable to the type expression `T` under the typing spec, and narrows `obj` to `T` for a static checker when it is. Code can then enforce its own annotations on values that only exist at runtime, where a static checker can't see them.
16
+
17
+ ```python
18
+ import subtype
19
+
20
+ assert subtype.isinstance([[1, 2], [3]], list[list[int]])
21
+ assert not subtype.isinstance([[1, 2], ["3"]], list[list[int]])
22
+ ```
23
+
24
+ Where the builtin `isinstance` raises `TypeError` for a parameterized generic, `subtype.isinstance` checks the items of a collection against its type arguments, including nested collections.
25
+
26
+ ```python
27
+ from collections.abc import Iterator
28
+
29
+ assert subtype.isinstance(zip(range(3), "abc"), Iterator[tuple[int, str]])
30
+ ```
31
+
32
+ `subtype.isinstance` infers an iterator's item type from the objects the iterator was built from, without advancing it.
33
+
34
+ ```python
35
+ from collections.abc import Callable
36
+ from typing import Protocol
37
+
38
+
39
+ class StrCall(Protocol):
40
+ def __call__(self, o: object, /) -> str:
41
+ return str(o)
42
+
43
+
44
+ assert subtype.isinstance(str, StrCall)
45
+ assert subtype.isinstance(str, Callable[[object], str])
46
+ ```
47
+
48
+ A class matches a `__call__` protocol by its constructor, the same way it matches `Callable[...]`.
49
+
50
+ ### `subtype`
51
+
52
+ `subtype(T)` turns the type expression `T` into a class that `issubclass` accepts, and answers whether a type is assignable to `T` under the typing spec.
53
+
54
+ ```python
55
+ from collections.abc import Sequence
56
+
57
+ from subtype import subtype
58
+
59
+ assert issubclass(list[bool], subtype(Sequence[int]))
60
+ assert not issubclass(list[bool], subtype(list[int]))
61
+ ```
62
+
63
+ `issubclass` takes a type expression as its first argument, and compares type arguments by the variance of their type parameters.
64
+
65
+ ```python
66
+ from typing import Self
67
+
68
+ assert issubclass(str, subtype(Sequence[Self]))
69
+ ```
70
+
71
+ `subtype` binds `Self` to the class being checked, so `str` is checked against `Sequence[str]`.
72
+
73
+ ```python
74
+ from collections.abc import Callable
75
+ from typing import Protocol, overload
76
+
77
+
78
+ class Decode(Protocol):
79
+ @overload
80
+ def __call__(self, data: bytes) -> str: ...
81
+ @overload
82
+ def __call__(self, data: None) -> None: ...
83
+
84
+
85
+ assert issubclass(Decode, subtype(Callable[[bytes], str]))
86
+ ```
87
+
88
+ Protocols are matched by the signatures of their members, not only by member names as with `runtime_checkable`. A protocol's `__call__` is checked against `Callable[...]` like any other callable, overloads included.
89
+
90
+ ## Installation
91
+
92
+ Install the package via `pip`:
93
+
94
+ ```shell
95
+ pip install subtype
96
+ ```
@@ -0,0 +1,6 @@
1
+ subtype/__init__.py,sha256=ldSZeCEwRq1Efp0_u8Wtl8bLora-ZZQTjkehmdx8MmM,67069
2
+ subtype/__init__.pyi,sha256=UBJlAIclklBq9E2oHBeg4fesFCHIhvxfE-nPN4O1jHg,596
3
+ subtype-0.1.0.dist-info/METADATA,sha256=lX3WKt73_DKCXOcDrkVk2GanlbLpMV1eyv8qW7BvELM,2826
4
+ subtype-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
5
+ subtype-0.1.0.dist-info/top_level.txt,sha256=CFlRm4pgtN4aiGm6Lm_qpPhw0IEKO4Ejp-aFacPywPw,8
6
+ subtype-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ subtype