Skip to main content

Simple runtime typechecker

Project description

Runtime typechecker for Python methods

This package provides a simple wrapper for methods to enforce type checking at runtime

PyPi publishing

Limitations

Let's talk about the limitations of this package first

  • The type checking only works with the new python 3.10 syntax. For older versions basic type checking still works. But Generics and Unions are not working with the old systax. Have a look at PEP 604 for more information.
  • Performance: Of course checking something at runtime comes with a performance penalty. This module is intended to be used for only a few methods were type checking is absolutely necessary. If you need typechecking for everything consider using something like mypy
  • Non-callable object: normal function are callable object in python but a function with the @classmethod decorator is not callable. This Package only supports callable objects.

Installation

pip install lazy_runtime_typechecker

Basic Usage

This module contains one wrapper. This wrapper can be used to type check a function.

from lazy_runtime_typechecker import static_typed

@static_typed(init_check=True)
def my_function(x: str) -> str:
    return x

if __name__ == '__main__':
    my_function(x="hello world") # ok
    my_function(12) # will raise an exception

Documentation

The @static_typed wrapper takes different arguments to configure how the types are checked. The default is always True because the assumption is, that if someone adds this wrapper to a function, they want to be really sure that nearly all cases are checked. Of course every single parameter that is set to true will add a performance penalty to the type checker (except defined_by_class).

init_check: bool

If the parameter is set to true the signature of the arguments and the return type is checked even before the first call. Also, the default values are checked against the signature of the arguments.
Example:

from lazy_runtime_typechecker import static_typed

@static_typed(init_check=False)
def my_function(x: str = 12) -> str:
    return x
# this will not raise an exception

@static_typed(init_check=True)
def my_function(x: str = 12) -> str:
    return x
# this will raise an exception because 12 is not a str

@static_typed(init_check=True)
def my_function(x: str = "hi"):
    return x
# this will raise an exception because no return type was specified

The exception that is raised for the initial validation is from type runtime_typechecker.TypeingError. All other exceptions from this module are inheritance form this exception.

check_input_args: bool = True

If this parameter is set to True then the input values are checked each time the function is called. The exception that is raised by an input validation is from type runtime_typechecker.InputTypeingError.

from lazy_runtime_typechecker import static_typed, InputTypeingError

@static_typed(init_check=True, check_input_args=False)
def my_function(x: str = "hi"):
    return x
# this will not raise an exception
my_function(12) 

@static_typed(init_check=True, check_input_args=True)
def my_function(x: str = "hi"):
    return x
# this will raise an exception
my_function(12) 

# or catch the exception
try:
    my_function(12)
except InputTypeingError:
    pass

check_return_value: bool = True

If this parameter is set to True then the return value is checked each time the function is called. The exception that is raised by an input validation is from type runtime_typechecker.InputTypeingError.

from lazy_runtime_typechecker import static_typed, OutputTypeingError

@static_typed(init_check=True, check_return_value=False)
def my_function(x: int) -> int:
    return str(x)
# this will not raise an exception
my_function(12)

@static_typed(init_check=True, check_return_value=True)
def my_function(x: int) -> int:
    return str(x)
# this will raise an exception
my_function(12)

# or catch the exception
try:
    my_function(12)
except OutputTypeingError:
    pass

check_generic_types: bool = True

Until now all examples only showed some basic types. But python also has a rich selection of types to represent nearly every possible typing expression. Of course with these more complex and nested types the performance penalty increases. If this parameter is set to True generic types are also check in full depth. If set to False only the first level of the generic type is matched. This behavior is applied for the input and the output stream.

from lazy_runtime_typechecker import static_typed

@static_typed(init_check=True, check_generic_types=False)
def my_function(x: list[str]) -> list[str]:
    return x
# this will not raise an exception
my_function([12, "hello world"])

@static_typed(init_check=True, check_generic_types=True)
def my_function(x: list[str]) -> list[str]:
    return x
# this will raise an exception
my_function([12, "hello world"])


# also multiple level of depth are supported
@static_typed(init_check=True, check_generic_types=True)
def my_function(x: tuple[str | list[int | float]]) -> dict[str, int]:
    return {"abc": 12}

defined_by_class: bool = False

If a method is defined by a class, then set this parameter to True. This means the first parameter for passing the instance of the class to the method is not checked.

from lazy_runtime_typechecker import static_typed

class MyTestClass:
    @static_typed(init_check=True, defined_by_class=True)
    def my_function(self, x: str) -> int:
        return int(x)


    @static_typed(init_check=True, defined_by_class=False)
    @staticmethod
    def my_static_function(x: str) -> str:
        return x

    # this does not work because a class method is not callable
    @static_typed(init_check=True, defined_by_class=False)
    @classmethod
    def my_class_method(cls, x: str) -> str:
        return cls()

Exception

Three exception are part of this module.

  • TypeingError(TypeError): is the base exception
  • InputTypeingError(TypeingError): this exception is raised if an input parameter validation fails
  • OutputTypeingError(TypeingError): this exception is raised if a return value validation fails

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

lazy_runtime_typechecker-0.0.3.tar.gz (6.6 kB view details)

Uploaded Source

Built Distribution

lazy_runtime_typechecker-0.0.3-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file lazy_runtime_typechecker-0.0.3.tar.gz.

File metadata

File hashes

Hashes for lazy_runtime_typechecker-0.0.3.tar.gz
Algorithm Hash digest
SHA256 7a14cc0bb582050215c71144bb974ffa5879639011f6592bc89e89860e0af18e
MD5 287c16cadc33eabbfe16fe6b2303278d
BLAKE2b-256 aea355877e8423cbfb77f810dde63e5f80b92a5b3ffa20dc7a118348ddf44551

See more details on using hashes here.

File details

Details for the file lazy_runtime_typechecker-0.0.3-py3-none-any.whl.

File metadata

File hashes

Hashes for lazy_runtime_typechecker-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 3881a90038efd3b09d355e3ae70171a23f40e5239f18e8a1f72256ab02b701c8
MD5 0335555debe3c676eaf8e51b1e6ea9c5
BLAKE2b-256 05720b5949e7a5f0a2c23f7c87de0be2abbb16af49530c07eba1e72984d42edc

See more details on using hashes here.

Supported by

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