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 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

rttc-1.0.6.tar.gz (7.7 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.6-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: rttc-1.0.6.tar.gz
  • Upload date:
  • Size: 7.7 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.6.tar.gz
Algorithm Hash digest
SHA256 aa493cd47a22209a90936f3c62bbf8aa0d02f9eaf114b7034a4c4cf2c8dd9e63
MD5 967025b4b5b64bbbbdc6f623b84cfcf5
BLAKE2b-256 6af6204a7da8929007857b691ad50d0a1f2217772cf4712747597bbce4924c90

See more details on using hashes here.

File details

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

File metadata

  • Download URL: rttc-1.0.6-py3-none-any.whl
  • Upload date:
  • Size: 9.4 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.6-py3-none-any.whl
Algorithm Hash digest
SHA256 5a5b7140f4c8f379b7f27e546e589b30a2c24a93b6be92dbffb38188efae7f62
MD5 d8a4417d2690be24dae4b82785c8f5f4
BLAKE2b-256 91b5f4032291dd47fa79a147a55566f2575813bc1604b75779f5413823dcb4ec

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