Skip to main content

Prototyping for functions

Project description

Prototypes

py3.6 py3.7 py3.8 py3.9 py3.10

Summary

Prototypes allow you to define signatures for your functions and verify those signatures during both static type checking and runtime.

Installation

$ pip install prototypes

Requirements

Basic usage

To validate your function against prototype, decorate your function with the prototype decorator and pass the prototype function as a parameter.

from prototypes import prototype

def add(x: int, y: int) -> int:
    ...

@prototype(add)
def custom_add(x: int, y: int) -> int:
    return x + y

Static type checking is fully supported thanks to usage of both typing.TypeVar (PEP 484) and typing.ParamSpec (PEP 612) under the hood.

from prototypes import prototype

def add(x: int, y: int) -> int:
    ...

# This will report type error by static type checkers like `mypy` in the future
@prototype(add)
def compute() -> None:
    pass

Advanced usage

Prototype functions does not have to be empty. They can be regular functions that already contain specific implementation. The prototype function act more like a signature template for the function, rather than an empty shell to be filled with the implementation.

from prototypes import prototype

def add(x: int, y: int) -> int:
    return x + y

@prototype(add)
def custom_add(x: int, y: int) -> int:
    ...
    return add(x, y)

By default, the prototype decorator verifies the signatures during runtime. Since decorators are executed during the function definition, this validation is performed right away, even if function is never called.

>>> from prototypes import prototype
>>>
>>> def add(x: int, y: int) -> int: ...
...
>>> @prototype(add)
... def compute() -> None:
...     pass
...
Traceback (most recent call last):
    ...
prototypes.PrototypeError: Incompatible function implementation for given prototype

Function:
def compute() -> None @ compute

Prototype:
def add(x: int, y: int) -> int @ add

However, since closures (inner functions) are defined on function execution, using prototype decorator in the closure will have no effect until the outer function is called.

>>> from prototypes import prototype
>>>
>>> def add(x: int, y: int) -> int: ...
...
>>> def func() -> None:
...     @prototype(add)
...     def compute() -> None:
...         ...
...
>>> # No exception is raised at that point
>>> func()
Traceback (most recent call last):
    ...
prototypes.PrototypeError: Incompatible function implementation for given prototype

Function:
def compute() -> None @ func.<locals>.compute

Prototype:
def add(x: int, y: int) -> int @ add

The runtime validation can be turned off when static type checking is performed to increase the code performance during runtime.

>>> from prototypes import prototype
>>>
>>> def add(x: int, y: int) -> int: ...
...
>>> @prototype(add, runtime=False)
... def compute() -> None:
...     pass
...
>>> # No exception is raised during runtime

Bugs/Requests

Please use the GitHub issue tracker to submit bugs or request features.

License

Copyright Krzysztof Przybyła, 2021.

Distributed under the terms of the MIT license.

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

prototypes-1.0.0.tar.gz (4.8 kB view hashes)

Uploaded Source

Built Distribution

prototypes-1.0.0-py3-none-any.whl (3.4 kB view hashes)

Uploaded Python 3

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