pyoload¶
pyoload provides an intuitive and easy way to add type and value checking to function arguments and class attributes.
usage¶
pyoload base provides two simple use functions
pyoload.annotate¶
pyoload.annotate used as a decorator over a simple function it returns a wrapper function which on each call - get the function’s annotations - resolve the annotations if stringified, on error raises
a pyoload.AnnotationResolutionError
check for matches between the passed arguments and annotations with the recursive pyoload.typeMatch function
if all matches, then calls the function, else raises a pyoload.AnnotationError
if the return annotation specified then returns it else raises an annotation error.
Example
>>> from pyoload import *
>>> from pathlib import Path
>>> @annotate
... def add_eof(eof: str, file: Cast(Path)) -> int:
... '''
... :param eof: the string to append
... :param file: the file to add content to
... :returns: the new file size
... '''
... data = file.read_text()
... return file.write_text(data + eof)
...
>>> print(add_eof)
<function add_eof at 0x017B2D48>
>>> print(add_eof.__pyod_annotate__)
<function add_eof at 0x0109D7F8>
>>> print(add_eof('@EOF@', 'del.txt'))
17
pyoload.overload¶
pyoload.overload used as a decorator over a simple function 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 register dictionarry value in pyoload.__overloads__[name] and stores a copy in the function’s .__pyod_overloads__
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.
>>> from pyoload import *
>>> from pathlib import Path
>>> @overload
... def div(a: float|int, b: Checks(eq=0)):
... raise ZeroDivisionError()
...
checks={'eq': 0}
>>> @overload
... def div(a: int, b: int) -> int:
... return a // b
...
>>> @overload
... def div(a: float, b: float) -> float:
... return a / b
...
>>> @overload
... def div(a: Any, b: Any):
... raise NotImplementedError()
...
>>> print(div.__pyo_overloads__)
[<function div at 0x019C2D48>, <function div at 0x01B5EE38>, <function div at 0x01B65E88>, <function div at 0x01B65F78>]
>>> print(div.__pyod_overloads_name__)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute '__pyod_overloads_name__'. Did you mean: '__pyo_overloads_name__'?
>>> print(repr(div(1, 2)))
2
{'eq': 0} 2
<class 'pyoload.Check'> eq 0 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\pyoload\src\pyoload\__init__.py", line 399, in wrapper
val = f(*args, **kw)
^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 348, in wrapper
if not typeMatch(v, anno[k]):
^^^^^^^^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 225, in typeMatch
spec(val)
File "C:\pyoload\src\pyoload\__init__.py", line 146, in __call__
Check.check(name, params, val)
File "C:\pyoload\src\pyoload\__init__.py", line 72, in check
raise Check.CheckDoesNotExistError(name)
pyoload.Check.CheckDoesNotExistError: eq
>>> print(repr(div(1.0, 2.0)))
2.0
{'eq': 0} 2.0
<class 'pyoload.Check'> eq 0 2.0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\pyoload\src\pyoload\__init__.py", line 399, in wrapper
val = f(*args, **kw)
^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 348, in wrapper
if not typeMatch(v, anno[k]):
^^^^^^^^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 225, in typeMatch
spec(val)
File "C:\pyoload\src\pyoload\__init__.py", line 146, in __call__
Check.check(name, params, val)
File "C:\pyoload\src\pyoload\__init__.py", line 72, in check
raise Check.CheckDoesNotExistError(name)
pyoload.Check.CheckDoesNotExistError: eq
>>> print(repr(div(1.0, 2)))
2
{'eq': 0} 2
<class 'pyoload.Check'> eq 0 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\pyoload\src\pyoload\__init__.py", line 399, in wrapper
val = f(*args, **kw)
^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 348, in wrapper
if not typeMatch(v, anno[k]):
^^^^^^^^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 225, in typeMatch
spec(val)
File "C:\pyoload\src\pyoload\__init__.py", line 146, in __call__
Check.check(name, params, val)
File "C:\pyoload\src\pyoload\__init__.py", line 72, in check
raise Check.CheckDoesNotExistError(name)
pyoload.Check.CheckDoesNotExistError: eq
>>> print(repr(div('0', 0)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\pyoload\src\pyoload\__init__.py", line 399, in wrapper
val = f(*args, **kw)
^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 360, in wrapper
ret = func(**vals)
^^^^^^^^^^^^
File "<stdin>", line 3, in div
NotImplementedError
>>> print(repr(div('0', 1j)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\pyoload\src\pyoload\__init__.py", line 399, in wrapper
val = f(*args, **kw)
^^^^^^^^^^^^^^
File "C:\pyoload\src\pyoload\__init__.py", line 360, in wrapper
ret = func(**vals)
^^^^^^^^^^^^
File "<stdin>", line 3, in div
NotImplementedError