subtype 0.1.0__tar.gz

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.
@@ -0,0 +1,8 @@
1
+ # python sources
2
+ *.py text diff=python
3
+
4
+ # documents
5
+ *.md text diff=markdown
6
+
7
+ # serialization
8
+ *.toml text
@@ -0,0 +1,18 @@
1
+ name: release
2
+
3
+ on:
4
+ release:
5
+ types: [released]
6
+
7
+ permissions:
8
+ id-token: write
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ - uses: astral-sh/setup-uv@v7
17
+ - run: uv build
18
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # this project
13
+ extern/
@@ -0,0 +1,5 @@
1
+ [submodule "extern/typeshed"]
2
+ path = extern/typeshed
3
+ url = https://github.com/python/typeshed
4
+ ignore = untracked
5
+ shallow = true
@@ -0,0 +1 @@
1
+ prune extern/typeshed
subtype-0.1.0/PKG-INFO ADDED
@@ -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,88 @@
1
+ Provides a metaclass that extends runtime type checking to the full Python typing spec.
2
+
3
+ ## Usage
4
+
5
+ ### `isinstance`
6
+
7
+ `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.
8
+
9
+ ```python
10
+ import subtype
11
+
12
+ assert subtype.isinstance([[1, 2], [3]], list[list[int]])
13
+ assert not subtype.isinstance([[1, 2], ["3"]], list[list[int]])
14
+ ```
15
+
16
+ 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.
17
+
18
+ ```python
19
+ from collections.abc import Iterator
20
+
21
+ assert subtype.isinstance(zip(range(3), "abc"), Iterator[tuple[int, str]])
22
+ ```
23
+
24
+ `subtype.isinstance` infers an iterator's item type from the objects the iterator was built from, without advancing it.
25
+
26
+ ```python
27
+ from collections.abc import Callable
28
+ from typing import Protocol
29
+
30
+
31
+ class StrCall(Protocol):
32
+ def __call__(self, o: object, /) -> str:
33
+ return str(o)
34
+
35
+
36
+ assert subtype.isinstance(str, StrCall)
37
+ assert subtype.isinstance(str, Callable[[object], str])
38
+ ```
39
+
40
+ A class matches a `__call__` protocol by its constructor, the same way it matches `Callable[...]`.
41
+
42
+ ### `subtype`
43
+
44
+ `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.
45
+
46
+ ```python
47
+ from collections.abc import Sequence
48
+
49
+ from subtype import subtype
50
+
51
+ assert issubclass(list[bool], subtype(Sequence[int]))
52
+ assert not issubclass(list[bool], subtype(list[int]))
53
+ ```
54
+
55
+ `issubclass` takes a type expression as its first argument, and compares type arguments by the variance of their type parameters.
56
+
57
+ ```python
58
+ from typing import Self
59
+
60
+ assert issubclass(str, subtype(Sequence[Self]))
61
+ ```
62
+
63
+ `subtype` binds `Self` to the class being checked, so `str` is checked against `Sequence[str]`.
64
+
65
+ ```python
66
+ from collections.abc import Callable
67
+ from typing import Protocol, overload
68
+
69
+
70
+ class Decode(Protocol):
71
+ @overload
72
+ def __call__(self, data: bytes) -> str: ...
73
+ @overload
74
+ def __call__(self, data: None) -> None: ...
75
+
76
+
77
+ assert issubclass(Decode, subtype(Callable[[bytes], str]))
78
+ ```
79
+
80
+ 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.
81
+
82
+ ## Installation
83
+
84
+ Install the package via `pip`:
85
+
86
+ ```shell
87
+ pip install subtype
88
+ ```
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80", "setuptools-scm[simple]>=9.2"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "subtype"
7
+ dynamic = ["version"]
8
+ readme = "README.md"
9
+ authors = [{ name = "crypt0lith" }]
10
+ requires-python = ">=3.14"
11
+ dependencies = [
12
+ "typing-extensions>=4.15",
13
+ ]
14
+
15
+ [dependency-groups]
16
+ tests = [
17
+ "pytest>=9.1.1",
18
+ ]
19
+
20
+ [tool.setuptools.packages.find]
21
+ include = ["subtype*"]
22
+
23
+ [tool.black]
24
+ preview = true
25
+ skip-magic-trailing-comma = true
26
+ target-version = ["py314"]
27
+ extend-exclude = "^/subtype/typeshed/"
28
+
29
+ [tool.isort]
30
+ profile = "black"
31
+ split_on_trailing_comma = false
32
+ combine_as_imports = true
33
+ skip_gitignore = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+