Python run-time type check
Project description
Python run-time type checking utility
Author: Yuxuan Zhang | GitHub Repository
The rttc project originates from this post on the python discussion forum.
Usage
Want to do something like this?
>>> isinstance(["hello type check"], list[str])
TypeError: isinstance() argument 2 cannot be a parameterized generic
Just drop-in replace isinstance() with type_check()
from type_check import type_check
type_check(["hello type check"], list[str]) # True
type_check([1], list[str]) # False
And of course you can use type variables!
DataType = list[tuple[float, str]]
type_check([(1.0, "hello rttc")], DataType) # True
type_check([(1, 2), [3.0, "4"]] , DataType) # False
Wondering how far you can go?
These features all work recursively with each other!
-
Union types are supported:
type_check(1 , int | bool) # True type_check(True, int | bool) # True type_check("1" , int | bool) # False
-
Literals are supported:
type_check("alex", Literal["alex", "bob"]) # True type_check("hack", Literal["alex", "bob"]) # False
-
Inherited classes are supported:
class C(list[int]): pass type_check(C([1]) , C) # True type_check(C([1.0]), C) # False
-
Type-hinted classes are supported:
from typing import TypeVar, Generic, Literal from dataclasses import dataclass T = TypeVar("T") P = TypeVar("P") @dataclass class C(Generic[T, P]): x: T y: P z: Literal[1] type_check(C(x=1 , y="y", z=1), C[int, str]) # True type_check(C(x=1.0, y="y", z=1), C[int, str]) # False - C.x = float(1.0) is not int type_check(C(x=1 , y="y", z=2), C[int, str]) # False - C.z = int(2) is not Literal[1]
-
Custom checking hooks:
Examples coming soon...
For now, please refer to type_check/builtin_checks.py.
Other tools in the box
type_assert()
Similar to type_check(), but it raises TypeCheckError instead of returns bool.
The raised TypeCheckError contains debug-friendly information indicating what caused type check to fail (check below for details).
type_guard
This decorator allows you to convert a class or a function into a type-guarded object.
It is analogous to performing a type_assert on function return values or on returned class instances.
from type_check import type_guard
@type_guard
def fn(x) -> int | float | str:
return x
fn(1) # ok
fn([]) # TypeCheckError: list([]) is not int | float | str
from dataclasses import dataclass
@type_guard
@dataclass
class A:
x: int
A(x=1) # ok
A(x=1.0) # TypeCheckError: A.x = float(1.0) is not int
Since 1.0.4, the following is made possible:
@type_guard
@dataclass
class B:
x: int
B[int](x=1) # ok
B[int](x=1.0) # TypeCheckError: A.x = float(1.0) is not int
B[float](x=1) # TypeCheckError: A.x = int(1) is not float
Info-rich return values and exceptions
TypeCheckResult
TypeCheckResult is the return type of type_check() function.
It can be used directly as a bool or compared with a bool.
For example:
from type_check import type_check
result = type_check([1], list[int])
print(bool(result), result == True, result == False)
# True, True, False
print(str(result))
# [1] is list[int] => True
print(repr(result))
# type_check([1] is list[int] => True)
And when a result evaluates to False, you can use TypeCheckResult.reason to know why:
result = type_check(["1"], list[int])
print(result)
# ['1'] is list[int] => False
print(result.reason)
# list[0] = str('1') is not int
TypeCheckError
TypeCheckError is inherited from TypeError, it will be raised by type_assert() and @type_guard when type check fails.
It contains chained attributes and keys to help you locate the data that cause type check to fail:
from type_check import type_assert
type_assert([1, 2, '3', 4], list[int])
Will raise:
TypeCheckError Traceback (most recent call last)
Cell In[47], line 10
6 print(result.reason)
8 from type_check import type_assert
---> 10 type_assert([1, 2, "3", 4], list[int])
File rttc/type_check/core.py:45, in type_assert(obj, t, chain)
43 # Clear traceback to avoid confusion
44 type_check_error = e.with_traceback(None)
---> 45 raise type_check_error
46 except TypeError as e:
47 type_error = e.with_traceback(None)
TypeCheckError: list[2] = str('3') is not int
Testing
Test cases live under tests/ and are grouped by categories. Test results are available at docs/test-results.txt. PRs to add more test cases to it will be deeply appreciated.
Instructions to run tests locally
git clone git@github.com:zhangyx1998/rttc.git
cd rttc && python3 -m pip install -r tests/requirements.txt # termcolor
python3 -m tests
Testing against well-known library typeguard:
pip3 install typeguard
TARGET=typegurad python3 -m tests
Project details
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 rttc-1.0.5.tar.gz.
File metadata
- Download URL: rttc-1.0.5.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38ec04ffdc55b56a71966824eda27658fca54bc1bbe6fd92bcc42eaeb1a4f304
|
|
| MD5 |
88b3c3ebac203437f77404c350aa245e
|
|
| BLAKE2b-256 |
d1a428b598cf61f3fd9bd37dfaec7d96856695d19495405bf8009f66fe97a5f7
|
File details
Details for the file rttc-1.0.5-py3-none-any.whl.
File metadata
- Download URL: rttc-1.0.5-py3-none-any.whl
- Upload date:
- Size: 8.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cecc32b29c2b24bb6fd001c379d8a4ccc8557cfe82877fb560f757ca71a77ace
|
|
| MD5 |
4650f0cf9eabb8c3bdcb73b355fe26f0
|
|
| BLAKE2b-256 |
fb73a8c1090c6f3d69de6e215d1d531a413054578c06dd01a6ff090366e9a1eb
|