Skip to main content

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 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 C:
    x: int

C(x=1) # ok

C(x=1.0) # TypeCheckError: C.x = float(1.0) is not int

Super friendly stack trace

This is the output of test cases. You can run the test yourself!

================================== 01-simple ===================================
       
[ PASS ] 1 is int => True
       
[ PASS ] 1.0 is int => False
[REASON] float(1.0) is not int
       
[ PASS ] [1, 2, 3] is list[int] => True
       
[ PASS ] [1, 2, 3.0] is list[int] => False
[REASON] list[2] = float(3.0) is not int
       
[ PASS ] 1 is Literal[1] => True
       
[ PASS ] 2 is Literal[1] => False
[REASON] int(2) is not Literal[1]
       
[ PASS ] 'alex' is Literal['alex', 'bob'] => True
       
[ PASS ] 'alex' is Literal['bob'] => False
[REASON] str('alex') is not Literal['bob']
       
================================= 02-multiple ==================================
       
[ PASS ] [1, '2', 3.0] is list[int, str, float] => True
       
[ PASS ] [1, '2', '3'] is list[int, str, float] => False
[REASON] list[2] = str('3') is not float
       
[ PASS ] [1, '2'] is list[int, str, float] => False
[REASON] list([1, '2']) is not list[int, str, float]
       
[ PASS ] (1, '2', 3.0) is tuple[int, str, float] => True
       
[ PASS ] (1, '2', '3') is tuple[int, str, float] => False
[REASON] tuple[2] = str('3') is not float
       
[ PASS ] {1, 3.0, '2'} is set[int | str | float] => True
       
[ PASS ] {None, 1, '2'} is set[int | str | float] => False
[REASON] set['?'] = NoneType(None) is not int | str | float
       
[ PASS ] {1: '2', 3: 4.0} is dict[int, str | float] => True
       
[ PASS ] {1: '2', '3': 4.0} is dict[int, str | float] => False
[REASON] dict<key> = str('3') is not int
       
[ PASS ] {1: '2', 3: None} is dict[int, str | float] => False
[REASON] dict[3] = NoneType(None) is not str | float
       
================================== 03-nested ===================================
       
[ PASS ] [[1, 2], [3, 4]] is list[list[int]] => True
       
[ PASS ] [[1, 2], [3, '4']] is list[list[int]] => False
[REASON] list[1][1] = str('4') is not int
       
================================== 04-unions ===================================
       
[ PASS ] [[1, 2], [3.0, 4.0]] is list[list[int] | list[float]] => True
       
[ PASS ] [[1, 2.0], [3, 4.0]] is list[list[int] | list[float]] => False
[REASON] list[0] = list([1, 2.0]) is not list[int] | list[float]
       
================================== 05-inherit ==================================
       
[ PASS ] [1, 2, 3] is A => True
       
[ PASS ] [1, 2, 0.0] is A => False
[REASON] A[2] = float(0.0) is not int
       
[ PASS ] B(x=1, y='2') is tests.05-inherit.B[int, str] => True
       
[ PASS ] B(x=1, y=2.0) is tests.05-inherit.B[int, str] => False
[REASON] B.y = float(2.0) is not str
       
=================================== 06-guard ===================================
       
[ PASS ] C([1, 2, 3]) is C => True
       
[ PASS ] C([1, 2, 0.0]) is C => False
[REASON] C[2] = float(0.0) is not int
       
[ PASS ] C(x=1, y=2.0) is C => True
       
[ PASS ] C(x=1.0, y=2) is C => False
[REASON] C.x = float(1.0) is not int
       
[ PASS ] add(1, 2) is int => True
       
[ PASS ] add('1', '2') is str => True
       
[ PASS ] add([1], [2]) is int | str => False
[REASON] list([1, 2]) is not int | str
       
[ PASS ] All 33 tests passed

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

rttc-1.0.3.tar.gz (7.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rttc-1.0.3-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file rttc-1.0.3.tar.gz.

File metadata

  • Download URL: rttc-1.0.3.tar.gz
  • Upload date:
  • Size: 7.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for rttc-1.0.3.tar.gz
Algorithm Hash digest
SHA256 3e4c390595ecb2e024495a44af1456c200005a9ae22b6e0ce0eb27f088ddbe31
MD5 eb3f3cb875d2b17ed5d5db4db0adcde5
BLAKE2b-256 e518f977a49e28d694b862ba4c8a0befb0e2f5662aeaa2e096ab8ee773f22c7a

See more details on using hashes here.

File details

Details for the file rttc-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: rttc-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for rttc-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3e939b947d662b42533ee5a4a5ee33b82c24ec6d9928a33a72caa005aba945e2
MD5 3743f6b2bf5a5f88f7c44e9952b755eb
BLAKE2b-256 7639cb170eb60ccd4afa45c0bacace0a6fc9ceeac29703c27cb64af1fde7b99d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page