Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ from typing import Annotated, Union, Optional, Any
def public_function(
# validate against built-in or custom types
a: str,
/, # support for positional-only arguments
# support for type unions
b: Union[int, float], # or from Python 3.10 `int | float`
# validate type of container items
Expand Down Expand Up @@ -61,7 +62,7 @@ def public_function(
return {"a":a, "b":b, "c":c, "d":d, "e":e, "f":f, "g":g, "h":h, "i":i, "args":args, "j":j, "k":k}

public_function(
# NB parameters 'a' through 'i' can be passed positionally
# NB 'a' must be passed positionally, 'b' through 'i' can be passed positionally
"zero", # a
1.0, # b
{"two": 2}, # c
Expand Down Expand Up @@ -95,7 +96,7 @@ returns:
And if there are invalid inputs...
```python
public_function(
a=["not a string"], # INVALID
["not a string"], # INVALID
b="not an int or a float", # INVALID
c={2: "two"}, # INVALID, key not a str and value not an int or float
d=3.2, # valid input
Expand Down Expand Up @@ -134,19 +135,22 @@ public_function(
{"two": 2},
3.2,
# no argument passed for required positional args 'e', 'f', 'g', 'h' and 'i'
a="a again", # passing multiple values for parameter 'a'
# no argument passed for required keyword arg 'j'
a="a again", # 'a' is positional-only: cannot be passed as a kwarg unless sig has **kwargs
c={"three": 3}, # passing multiple values for 'c'
not_a_kwarg="not a kwarg", # including an unexpected kwarg
# no argument passed for required keyword arg 'j'
)
```
raises:
```
InputsError: Inputs to 'public_function' do not conform with the function signature:

Got multiple values for argument: 'a'.
Got multiple values for argument: 'c'.

Got unexpected keyword argument: 'not_a_kwarg'.

Got positional-only argument as keyword argument (and signature makes no provision for **kwargs that would otherwise receive it): 'a'.

Missing 5 positional arguments: 'e', 'f', 'g', 'h' and 'i'.

Missing 1 keyword-only argument: 'j'.
Expand Down Expand Up @@ -232,6 +236,18 @@ In short, if you only want to validate the type of function inputs then Pydantic
* `collections.abc.Mapping`
* packing and optionally coercing, parsing and validating packed objects, i.e. objects
received to, for example, *args and **kwargs.
* full verification of signature compliance in accordance with standard Python, i.e.
verifies:
- no excess positional arguments
- no unexpected keyword arguments (if the signature does not provide for **kwargs)
- no missing 'required' arguments (i.e. arguments that do not otherwise have a default value)
- no duplicate arguments
- postional-only arguments are passed positionally. (If a keyword argument is passed
with the same name as a positional-only argument then it will be considered valid if
the signature provides for **kwargs (and in this case it will be received by
**kwargs), whilst if the signature does not provide for **kwargs then the argument
will be considered invalid.)
- positional arguments are passed either positionally or by keyword argument

`valimp` does NOT support:
- Validation of subscripted types in `collections.abc.Callable`. Any subscriptions to
Expand All @@ -241,12 +257,6 @@ In short, if you only want to validate the type of function inputs then Pydantic
verify that an object passed to a parameter annotated as `Callable` is in fact
callable).

`valimp` does NOT currently support:
- Positional-only arguments. Any '/' in the signature (to define
positional-only arguments) will be ignored. Consequently valimp DOES
allow intended positional-only arguments to be passed as keyword
arguments.

The library has been built with development in mind and PRs are very much welcome!

## License
Expand Down
15 changes: 10 additions & 5 deletions docs/tutorials/tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1714,6 +1714,7 @@
"* A keyword argument is passed that is not represented in the signature (unexpected keyword argument).\n",
"* More arguments are passed positionally than accommodated for by the signature (excess positional arguments).\n",
"* A parameter is passed both positionally and as a keyword argument (got multiple values).\n",
"* A positional-only argument is passed as a keyword argument. (Note that if a keyword argument is passed with the same name as a positional-only argument then it will be considered _valid_ if the signature provides for **kwargs (and in this case it will be received by those **kwargs), whilst if the signature does not provide for **kwargs then the error will be included in the raised `InputsError`.)\n",
"\n",
"All signature errors are advised in the error message, together with any errors relating to invalid types."
]
Expand All @@ -1727,8 +1728,10 @@
"source": [
"@parse\n",
"def pf(\n",
" a: int,\n",
" a: int, # positional_only\n",
" /,\n",
" b: int,\n",
" c: int,\n",
" *,\n",
" kw_a: int,\n",
"):\n",
Expand All @@ -1742,7 +1745,7 @@
"metadata": {},
"outputs": [],
"source": [
"pf(3, \"not an int\", 5, a=3, not_a_kwarg=3)"
"pf(3, \"not an int\", 4, 5, a=3, c=2, not_a_kwarg=3)"
]
},
{
Expand All @@ -1754,17 +1757,19 @@
"---------------------------------------------------------------------------\n",
"InputsError Traceback (most recent call last)\n",
"Cell In[47], line 1\n",
"----> 1 pf(3, \"not an int\", 5, a=3, not_a_kwarg=3)\n",
"----> 1 pf(3, \"not an int\", 4, 5, a=3, c=2, not_a_kwarg=3)\n",
"\n",
"InputsError: Inputs to 'pf' do not conform with the function signature:\n",
"\n",
"Got multiple values for argument: 'a'.\n",
"Got multiple values for argument: 'c'.\n",
"\n",
"Received 1 excess positional argument as:\n",
"\t'5' of type <class 'int'>.\n",
"\n",
"Got unexpected keyword argument: 'not_a_kwarg'.\n",
"\n",
"Got positional-only argument as keyword argument (and signature makes no provision for **kwargs that would otherwise receive it): 'a'.\n",
"\n",
"Missing 1 keyword-only argument: 'kw_a'.\n",
"\n",
"The following inputs to 'pf' do not conform with the corresponding type annotation:\n",
Expand Down Expand Up @@ -1797,7 +1802,7 @@
"\n",
"InputsError: Inputs to 'pf' do not conform with the function signature:\n",
"\n",
"Missing 1 positional argument: 'b'.\n",
"Missing 2 positional arguments: 'b' and 'c'.\n",
"```"
]
},
Expand Down
Loading
Loading