|
9 | 9 |
|
10 | 10 | # pyoload |
11 | 11 |
|
12 | | -Hy pythonista! I'm happy to present to you `pyoload`, as from my words: |
| 12 | +This adds some runtime type checking and warnings when enabled. It is disabled |
| 13 | +by default. |
13 | 14 |
|
14 | | - A python module for extended and recursive type checking and casting of |
15 | | - function arguments and class attributes during runtime |
| 15 | +Pyoload permits you to add runtime checking to classes on instance attribute |
| 16 | +assignment and functions. |
16 | 17 |
|
17 | | -Here we use some of the beautiful and clean features offered by python, including |
18 | | -decorators and descriptors to help you type check during runtime |
| 18 | +## usage |
19 | 19 |
|
20 | | -Here are some simple usage examples to fill this pypi page. |
| 20 | +pyoload provides two basic methods: |
| 21 | +- `pyoload.annotate`: decorator over functions or methods. |
| 22 | +- `pyoload.annotate_class`: decorator over classes. |
| 23 | +All wrapped by `pyoload()` which checks what to be called. |
21 | 24 |
|
22 | | -## annotate |
| 25 | +```py |
| 26 | +import pyoload |
23 | 27 |
|
24 | | -This decorator function uses the power of `inspect.signature` to check the arguments |
25 | | -passed to the function using it's annotations with support for default values, generic aliase |
26 | | -and annotations adding some more annotation types for convenience, lower some code. |
| 28 | +pyoload.debug() |
27 | 29 |
|
28 | | -```python |
29 | | -from pyoload import * |
| 30 | +@pyoload |
| 31 | +def foo(a: int, b, c: str) -> tuple[str, int]: |
| 32 | + return ("ab", 23) |
30 | 33 |
|
31 | | -@annotate |
32 | | -def foo( |
33 | | - a: str, # this has an annotation |
34 | | - b=3, # this uses a default value |
35 | | - c: int = 0 # here both |
36 | | -) -> tuple[str, int]: # The return type |
37 | | - ... |
| 34 | +@pyoload |
| 35 | +class myclass: |
| 36 | + pass |
38 | 37 | ``` |
39 | 38 |
|
40 | | -```python |
41 | | -from pyoload import * |
| 39 | +## pyolaod modes |
42 | 40 |
|
43 | | -@annotate |
44 | | -def foo( |
45 | | - b=dict[str | int, float], # here a GenericAlias |
46 | | - c: Cast(list[int]) = '12345' # here a recursive cast |
47 | | -): # No return type |
48 | | - ... |
49 | | -``` |
50 | | - |
51 | | -## multimethod |
52 | | - |
53 | | -This uses the same principles as annotate but allows multiple dispatching |
54 | | -(a.k.a runtime overloading?) of functions. |
55 | | - |
56 | | -```python |
57 | | -from pyoload import * |
58 | | - |
59 | | -@multimethod |
60 | | -def foo(a, b): |
61 | | - print("two arguments") |
62 | | - |
63 | | -@multimethod |
64 | | -def foo(a: Values((1, 2, 3))): |
65 | | - print('either 1, 2 or 3') |
66 | | - |
67 | | -@foo.overload |
68 | | -def _(a: Any): |
69 | | - raise ValueError() |
70 | | -``` |
71 | | - |
72 | | -## annotations |
73 | | - |
74 | | -These are what pyoload adds to the standard annotations: |
75 | | - |
76 | | -> [!NOTE] |
77 | | -> The added annotations are still not mergeable with the standard types. |
78 | | -
|
79 | | -### `pyoload.Values` |
80 | | - |
81 | | -A simple `tuple` subclass, use them as annotation and it will validate only |
82 | | -included values. |
83 | | -```python |
84 | | -@annotate |
85 | | -def foo(bar: Values(range(5))): |
86 | | - ... |
87 | | -``` |
88 | | - |
89 | | -### `pyoload.Cast` |
90 | | - |
91 | | -This performs recursive casting of the passed arguments into the specified type |
92 | | -It supports `dict` generic aliases as `dict[str, int | str] ` and tries cast in |
93 | | -the specified order when the type is a Union. |
94 | | - |
95 | | -```python |
96 | | -@annotate |
97 | | -def foo(bar: Cast(tuple[int | str])): |
98 | | - print(bar) |
99 | | - |
100 | | -foo((3, "3")) # (3, 3) |
101 | | -foo((3j, " ")) # ('3j', ' ') |
102 | | -``` |
103 | | - |
104 | | -### `pyoload.Checks` |
| 41 | +Pyoload includes three modes of enum type `pyoload.Mode` and where the current |
| 42 | +mode is in `pyoload.MODE`. |
105 | 43 |
|
106 | | -Permits You tou use custom checker methods, e.g |
| 44 | +* **DEBUG**: Shows warnings, comments, exceptions activate via `pyoload.debug()` |
| 45 | +* **DEV** : Does not call upon validatore |
| 46 | +* **PROD**(*DEFAULT*): `@pyoload` simply does nothing. |
107 | 47 |
|
108 | | -```python |
109 | | -from pyoload import * |
| 48 | +## Adding validators |
110 | 49 |
|
111 | | -test = lambda val: True # put your check here |
112 | | - |
113 | | -def foo(a: Checks(func=test): |
114 | | - ... |
115 | | -``` |
116 | | - |
117 | | -If the check name is prepended with a `_`, it will be negated, and an exception |
118 | | -is raised if it fails. |
119 | | -You can register your own checks using `Check.register`, as |
120 | | - |
121 | | -```python |
122 | | -@Check.register('mycheck') |
123 | | -def _(param, value): |
124 | | - print(param, value) |
125 | | - |
126 | | -Checks(mycheck='param')('val') # Will raise error on check failure |
127 | | - |
128 | | -@annotate |
129 | | -def foo(a: Checks(mycheck='param')): |
130 | | - ... |
131 | | -``` |
132 | | - |
133 | | -Checks can be used as annotations; |
134 | | -called using `pyoload.Checks` as `Checks(foo=bar)(val)`; or |
135 | | -Invoked directly using `pyoload.Checks` as: |
136 | | -`Check.check(name, param, arg)` |
137 | | - |
138 | | -#### len |
139 | | - |
140 | | -Receives as argument an integer value specified the expected length or |
141 | | -a slice in which the length should be found |
142 | | - |
143 | | -#### gt, lt, eq |
144 | | - |
145 | | -Compares grater than, less than and aqual to from the parameter |
146 | | -to the value. |
147 | | - |
148 | | -#### func |
149 | | - |
150 | | -Uses a function for validation, the function could return a boolean |
151 | | -or raise an error. |
152 | | -It could be passed directly as positional arguments to pyoload.Checks |
153 | | -as: `Checks(func1, func2, foo=bar, foo2=bar2)` |
154 | | - |
155 | | -### Checked and casted attributes |
156 | | - |
157 | | -`CheckedAttr` and `CastedAttr`, are simple descriptors which will perform |
158 | | -the casting or checks on assignment. |
159 | | - |
160 | | -```python |
161 | | -from pyoload import * |
162 | | - |
163 | | -class address: |
164 | | - number = CastedAttr(tuple[int]) |
165 | | - |
166 | | -``` |
| 50 | +You may add validators to check values furthermore. |
167 | 51 |
|
168 | | -The values are checked or casted on assignment |
| 52 | +```py |
| 53 | +def validator(value) -> Optional[str]: |
| 54 | + if value.is_ok(): |
| 55 | + return None |
| 56 | + else: |
| 57 | + return "Value is not Ok! pass a value which is Ok please." |
169 | 58 |
|
170 | | -> [!NOTE] |
171 | | -> The attributes will return `None` if not yet initialized |
| 59 | +@pyoload(comments=dict(val=validator)) |
| 60 | +def func(val): |
| 61 | + pass |
| 62 | +``` |
0 commit comments