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.2.tar.gz (6.6 kB view details)

Uploaded Source

Built Distribution

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

Uploaded Python 3

File details

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

File metadata

File hashes

Hashes for lazy_runtime_typechecker-0.0.2.tar.gz
Algorithm Hash digest
SHA256 dcfb7eb662424823c5c859708fda0a17246de5874e315d50bb4ecd0e4e48c243
MD5 8cbf55f27851486650ef1700fe4a0c54
BLAKE2b-256 da7a08e623e1d634d937d36a9bb4e9b8c1eda169ebf29530312d64dac422bbca

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lazy_runtime_typechecker-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 fdc914daa446110541acd2b30c04df1e2cc26927d8f9dca25f1efd12adf719bf
MD5 786e8a031a3cdd79367eb0918ccc4a9b
BLAKE2b-256 1674fb8eec8f86a96184973689240e5843ff19a06fc9a8f99f31af8f3ba7e666

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