Type checking in runtime without stupid games
Project description
Python type checking tools are usually very complex. In this case, we have thrown out almost all the places where there is a lot of complexity, and left only the most obvious and necessary things for runtime.
Table of contents
Why?
It's been a long time since static type checking tools like mypy for Python have been available, and they've become very complex. The typing system has also become noticeably more complicated, providing us with more and more new types of annotations, new syntax and other tools. It seems that Python devs procrastinate endlessly, postponing all the really important CPyhton improvements in order to add more garbage to typing.
A separate difficulty arises for those who try to use type annotations in runtime. Many data types make sense only in the context of static validation, and there is no way to verify these aspects in runtime. And some checks, although theoretically possible, would be extremely expensive. For example, to verify the validity of annotation List[int] in relation to a list, you would need to go through all its objects linearly to make sure that none of them violates the contract from the annotation.
So, why do we need this package? There is only one function where you can pass a type or a type annotation + a specific value, and you will find out if one corresponds to the other. That's it! You can use this feature as a support when creating runtime type checking tools, however, we do not offer these tools here. You decide for yourself whether to wrap this function in syntactic sugar like decorators with automatic type checking.
Also, we are not trying to cover the whole chasm of semantics that, for example, mypy can track. Our approach is to make type checking as stupid as possible. This is the only way to avoid the stupid typing games that complex tools impose on us.
What exactly does this library support:
- The basis of everything is the simplest type checking via
isinstance. If you don't use any special types fromtyping, expect direct type matching. Unionsupport. You can combine the two types through a logical OR.- Checking the
Optionaltype andNoneas an annotation. - Using
Anyannotation.
And that's what's not here:
- Supports types with complex semantics from the
typingmodule. - Checking the contents of collections. In normal mode, collections are checked only for the base type (in strict mode, the contents for some base collections are also checked).
- Support for string annotations.
If you need more complex semantics, use static validation tools. If you need strange and expensive runtime checks that try to confuse static semantics by adding thousands of exceptions, use other runtime tools. Use this library if you need a MINIMUM.
Installation
You can install simtypes using pip:
pip install simtypes
You can also quickly try out this and other packages without having to install using instld.
Usage
Import the check function:
from simtypes import check
And pass there 2 arguments, a value + a type or type annotation:
print(check(1, int))
#> True
print(check(1, str))
#> False
print(check(1, Any))
#> True
print(check('kek', Any))
#> True
print(check(1, List))
#> False
print(check([1], List))
#> True
print(check([1], List[int]))
#> True
print(check(['kek'], List[int])) # Attention! The content of the list is not checked in normal mode.
#> True
print(check(1, Optional[int]))
#> True
print(check(None, Optional[int]))
#> True
print(check(1, Optional[str]))
#> False
print(check(1, None))
#> False
print(check(None, None))
#> True
↑ As you can see, the function returns
TrueorFalse, depending on whether the value matches its annotation.
In normal mode, the contents of collections are not checked. However, if strict mode is activated, the contents of lists, dicts and tuples will also start to be checked:
print(check(['kek'], List[str]), strict=True)
#> True
print(check({'lol': 'kek'}, Dict[str, str]), strict=True)
#> True
print(check([1, 2, 3], List[str]), strict=True)
#> False
print(check({'lol': 123}, Dict[str, str]), strict=True)
#> False
print(check((1, 2, 3), Tuple[int, int, int]), strict=True)
#> True
print(check((1, 2, 3), Tuple[int, ...]), strict=True)
#> True
print(check((1, 2, "text"), Tuple[int, ...]), strict=True)
#> False
Special types
Some non-trivial runtime checks can be shifted to the type system. This library offers several additional types, which can be checked for membership via the check function:
NaturalNumber— as the name implies, only objects of typeintgreater than zero will be checked for this type.NonNegativeInt— the same asNaturalNumber, but0is also a valid value.
Here are some usage examples:
from simtypes import NaturalNumber, NonNegativeInt
print(check(13, NaturalNumber))
#> True
print(check(0, NaturalNumber))
#> False
print(check(13, NonNegativeInt))
#> True
print(check(0, NonNegativeInt))
#> True
print(check(-11, NonNegativeInt))
#> False
String deserialization
The library also provides primitive deserialization. Conversion of strings into several basic types in any combinations is supported:
str- any string can be interpreted as astrtype.int- any integers.float- any floating-point numbers, including infinities andNaN.bool- the strings"yes","True", and"true"are interpreted asTrue, while"no","False", or"false"are interpreted asFalse.list- lists injsonformat are expected.tuple- lists injsonformat are expected. This is the only type where the value produced does not match the passed type, the returned value is always a list.dict- dicts injsonformat are expected.
Examples:
from simtypes import from_string
# ints
print(from_string('13', int))
#> 13
print(from_string('-13', int))
#> -13
# floats
print(from_string('13', float))
#> 13.0
print(from_string('13.5', float))
#> 13.5
print(from_string('nan', float))
#> nan
print(from_string('∞', float))
#> inf
print(from_string('-∞', float))
#> -inf
print(from_string('inf', float))
#> inf
print(from_string('-inf', float))
#> -inf
# strings
print(from_string('I am the danger', str))
#> "I am the danger"
print(from_string('I am the danger', Any)) # Any is interpreted as a string.
#> "I am the danger"
# bools
print(from_string('yes', bool))
#> True
print(from_string('no', bool))
#> False
print(from_string('True', bool))
#> True
# collections
print(from_string('[1, 2, 3]', list[int]))
#> [1, 2, 3]
print(from_string('[1, 2, 3]', tuple[int, ...]))
#> [1, 2, 3]
print(from_string('{"123": [1, 2, 3]}', dict[str, tuple[int, ...]]))
#> {"123": [1, 2, 3]}
👀 If the passed string cannot be interpreted as an object of the specified type, a
TypeErrorexception will be raised.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file simtypes-0.0.6.tar.gz.
File metadata
- Download URL: simtypes-0.0.6.tar.gz
- Upload date:
- Size: 10.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21f7b95eb42ffe97c1f960935c71d097807a260d79ff9cc5d3b8e77e11cd70b5
|
|
| MD5 |
96584ed391ff9f10ec9e3ac05d917285
|
|
| BLAKE2b-256 |
419b6f50dd0624c123ec7985d3b36e80ad66626a250cd7954daf3d6ad1d8a2c6
|
Provenance
The following attestation bundles were made for simtypes-0.0.6.tar.gz:
Publisher:
release.yml on pomponchik/simtypes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
simtypes-0.0.6.tar.gz -
Subject digest:
21f7b95eb42ffe97c1f960935c71d097807a260d79ff9cc5d3b8e77e11cd70b5 - Sigstore transparency entry: 676746963
- Sigstore integration time:
-
Permalink:
pomponchik/simtypes@3d0b691900772c2b76b747fef00a39bdd05846f4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pomponchik
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3d0b691900772c2b76b747fef00a39bdd05846f4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file simtypes-0.0.6-py3-none-any.whl.
File metadata
- Download URL: simtypes-0.0.6-py3-none-any.whl
- Upload date:
- Size: 8.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eed56b03d51ba9d9c84f1d9736dc23ea44c92475935f439d213448d418caffab
|
|
| MD5 |
0a5f8cbdc990a730644d46e1a9a4860b
|
|
| BLAKE2b-256 |
39cba46d57fad61be79475820cd41d2076fa580ac78c78129390697128f4c8ae
|
Provenance
The following attestation bundles were made for simtypes-0.0.6-py3-none-any.whl:
Publisher:
release.yml on pomponchik/simtypes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
simtypes-0.0.6-py3-none-any.whl -
Subject digest:
eed56b03d51ba9d9c84f1d9736dc23ea44c92475935f439d213448d418caffab - Sigstore transparency entry: 676746966
- Sigstore integration time:
-
Permalink:
pomponchik/simtypes@3d0b691900772c2b76b747fef00a39bdd05846f4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/pomponchik
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3d0b691900772c2b76b747fef00a39bdd05846f4 -
Trigger Event:
push
-
Statement type: