Skip to main content

Python package for function argument overload, typechecking and casting

Project description

Release status PyPI package Supported Python versions Build Status Coverage Status Documentation Status Pypi downloads

pyoload

pyoload is a little initiative to integrate tools for typechecking and casting in python functions and classes.

usage

pyoload.annotate

Simple decorator over functions and classes

functions

e.g

from pyoload import *

@annotate
def foo(bar: int) -> str:
    ...

@annotate
def bar(foo: str):
    ...

raises pyoload.AnnotationError when type mismatch

classes

When annotating a class, pyoload wraps the classes __setattr__ with a typechecker function which typechecks the passed value on each assignment.

It also calls annotate on each of it's methods, except the class has a __annotate_norecur__ attribute.

But if the assigned attribute does not yet have annotations, it gets them using type(val) and adds them to the annotations.

from pyoload import *

@annotate
class Person:
    age: 'int'

    def __init__(self: Any, age: int, name: str):
        self.age = age
        self.name = name


djamago = Person(15, 'djamago')  # {'age': <class 'int'>, 'name': <class 'str'>}

print(djamago.__annotations__)

pyoload.overload

When decorating a function it:

  • annotates the function with the special kwarg is_overload=True
  • gets the function's name using pyoload.get_name and if needed creates a new dictionarry value in pyoload.__overloads__[name] where it stores all overloads and stores a copy in the function's .__pyod_overloads__ attribute.

And on each call it simply loops through each function entry, while it catches a pyoload.InternalAnnotationError which is raised when the special is_overload is set to true

tip you may raise pyoload.InternalAnnotationError inside an overloaded function after carrying out some other checks and pyoload will switch to the next oveload.

@overload
def foo(a: int):
    ...

@overload
def foo(b: str, c: float):
    ...

@foo.overload
def foo_hello(d: dict[str, list[int]]):
    ...

type checking with pyoload.typeMatch(val, type)

this function simply finds type compatibility between the passes arguments

the type could be:

  • a class
  • a Union e.g int|str
  • a generic alias e.g dict[str, int]
  • a subclass of pyoload.PyoloadAnnotation as:
    • pyoload.Checks
    • pyoload.Values

Casting with pyoload.Cast

Most pyoload decorators support pyoload.Cast instances, When used as an annotation the value is casted to the specified type.

def foo(a: str):
    print(repr(a))

foo(3.5)  # '3.5'

casting recursiion

Using recursion it supports Generic Aliases of dict and builtin iterable types as list and tuple.

from pyoload import Cast

caster = Cast(dict[str, list[tuple[float]]]) # a dictionary of names of
                                             # places[str] to a list of their
                                             # (x, y) coordinates
                                             #             [list[tuple[float]]]

raw = {
    4: (
        ['1.5', 10],
        [10, '1.5'],
    )
}
print(caster(raw))  # {'4': [(1.5, 10.0), (10.0, 1.5)]}

Note When pyoload.Cast receives a Union as int|str it tries to cast to the listed forms in the specific order, thus if we have test = (3j, 11.0) and caster = Cast(tuple[float|str]) casting with caster(test) will give ('3j', 11.0), since complex 3j can not be converted to float, and pyoload.Cast.cast will fallback to str

writing checks pyoload.Checks

It provides a simple API for writing custom functions for checking.

from pyoload import *

Check.register('is_equal')
def isnonecheck(param, value):
    print(f'{param=}, {value=}')
    if param != value:
        raise Check.CheckError(f'{param!r} not equal to {value!r}')

@annotate
def foo(bar: Checks(is_equal=3)):
    pass

foo(3)  # param=3 value=3
foo('4')

Traceback (most recent call last):
  File "C:\pyoload\src\del.py", line 77, in <module>
    foo('4')
  File "C:\pyoload\src\pyoload\__init__.py", line 514, in wrapper
    raise AnnotationErrors(errors)
pyoload.AnnotationErrors: [AnnotationError("Value: '4' does not match annotation: <Checks(is_equal=3)> for argument 'bar' of function __main__.foo")]

It provides builtin checkes as: lt, gt, ge, le, eq, func:Callable, type:Any|PyoloadAnnotation

using pyoload.CheckedAttr and pyoload.CastedAttr

pyoload provides:

  • pyoload.CheckedAttr A descriptor which does the type checking on assignment, and
  • pyoload.CastedAttr Another descriptor Which stores a casted copy of the values it is assigned
class Person:
    age = CheckedAttr(gt=0)
    phone = CastedAttr(tuple[int])

    def __init__(self, age, phone):
        self.age = age
        self.phone = phone

temeze = Person(17, "678936798")

print(temeze.age)  # 17
print(temeze.phone)  # (6, 7, 8, 9, 3, 6, 7, 9, 8)

mballa = Person(0, "123456")
Traceback (most recent call last):
  File "C:\pyoload\src\del.py", line 92, in <module>
    mballa = Person(0, "123456")
             ^^^^^^^^^^^^^^^^^^^
  File "C:\pyoload\src\del.py", line 84, in __init__
    self.age = age
    ^^^^^^^^
  File "C:\pyoload\src\pyoload\__init__.py", line 264, in __set__
    self(value)
  File "C:\pyoload\src\pyoload\__init__.py", line 227, in __call__
    Check.check(name, params, val)
  File "C:\pyoload\src\pyoload\__init__.py", line 132, in check
    check(params, val)
  File "C:\pyoload\src\pyoload\__init__.py", line 187, in gt_check
    raise Check.CheckError(f'{val!r} not gt {param!r}')
pyoload.Check.CheckError: 0 not gt 0

ko-fi

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

pyoload-1.1.2.tar.gz (12.6 kB view hashes)

Uploaded Source

Built Distribution

pyoload-1.1.2-py3-none-any.whl (9.2 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