Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validation Decorator #1179

Merged
merged 17 commits into from Feb 5, 2020
Merged

Validation Decorator #1179

merged 17 commits into from Feb 5, 2020

Conversation

samuelcolvin
Copy link
Member

@samuelcolvin samuelcolvin commented Jan 19, 2020

Change Summary

This adds a validate_arguments function decorator which checks the arguments to a function matches type annotations.

I'm intending to get an MVP ready and merge that with a note saying this is in open beta and may change.

Still, there's quite a lot here. Feedback very welcome.

Related issue number

fix #347

TODO

  • proper error on position only arguments
  • better error when extra kwargs, or args are provided.
  • Unit tests complete
  • evaluate string annotations, or raise an error?
  • check async functions work
  • agree on the name, is validate_arguments the best option? unless someone has a better idea???
  • add documentation
  • Tests pass on CI and coverage remains at 100%
  • changes/<pull request or issue id>-<github username>.md file

To be done in future (I think this should be done after the initial release of this feature): see #1205

@codecov
Copy link

codecov bot commented Jan 19, 2020

Codecov Report

Merging #1179 into master will decrease coverage by 0.05%.
The diff coverage is 100%.

@@            Coverage Diff             @@
##           master    #1179      +/-   ##
==========================================
- Coverage     100%   99.94%   -0.06%     
==========================================
  Files          21       21              
  Lines        3666     3666              
  Branches      718      718              
==========================================
- Hits         3666     3664       -2     
- Misses          0        2       +2
Impacted Files Coverage Δ
pydantic/class_validators.py 100% <ø> (ø) ⬆️
pydantic/types.py 100% <100%> (ø) ⬆️
pydantic/fields.py 100% <100%> (ø) ⬆️
pydantic/networks.py 100% <100%> (ø) ⬆️
pydantic/typing.py 98% <0%> (-2%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a0006ed...09258b5. Read the comment docs.

@samuelcolvin samuelcolvin changed the title starting validation decorator Validation Decorator Jan 20, 2020
@dmontagu
Copy link
Contributor

This looks great to me!

@samuelcolvin
Copy link
Member Author

For me this is ready to merge.

I'll leave it a few days for any further feedback, then merge.

@samuelcolvin samuelcolvin merged commit 6914410 into master Feb 5, 2020
@samuelcolvin samuelcolvin deleted the validate_arguments-decorator branch February 5, 2020 17:27
@tiangolo
Copy link
Member

tiangolo commented Apr 7, 2020

I hadn't seen this. It looks awesome!

@StephenBrown2
Copy link
Contributor

Just noticed that the decorator is called validate_arguments, but in the docs it's referred to as validate_assignment.

@samuelcolvin
Copy link
Member Author

@tiangolo thanks!

@StephenBrown2 thanks for pointing that out 🤦‍♂ PR welcome to fix that.

@samuelcolvin
Copy link
Member Author

don't worry, I'll fix the docs.

@mpkocher
Copy link

Are there any concerns about memory issues with this?

Currently, every function that is wrapped via validate_arguments has an instance of ValidatedFunction as well as instance of a BaseModel bolted on to it.

In [31]: @validate_arguments
    ...: def f2(a: int, b: int) -> int:
    ...:     return a + b
    ...: 

In [32]: f2
Out[32]: <function __main__.f2(a: int, b: int) -> int>

In [33]: f2.__dict__
Out[33]: 
{'__wrapped__': <function __main__.f2(a: int, b: int) -> int>,
 'vd': <pydantic.decorator.ValidatedFunction at 0x7fd0586e64f0>,
 'raw_function': <function __main__.f2(a: int, b: int) -> int>,
 'model': F2}

In [34]: f2.model.__fields__
Out[34]: 
{'a': ModelField(name='a', type=int, required=True),
 'b': ModelField(name='b', type=int, required=True),
 'args': ModelField(name='args', type=Optional[List[Any]], required=False, default=None),
 'kwargs': ModelField(name='kwargs', type=Optional[Mapping[Any, Any]], required=False, default=None)}

@stonecharioteer
Copy link

This feature seems to allow values that can be cast from one form to another.

@validate_arguments
def something(x: str, y: Dict[str, str]):
    print(x, y)

Testing this with the following: something(10, {"x": 20}) doesn't give a ValidationError,
but testing it with something("x", {"x":None}) does.

Is that by design? Is there a way to enable stricter type checking?

@eonu
Copy link
Contributor

eonu commented Aug 29, 2022

This feature seems to allow values that can be cast from one form to another.

@validate_arguments
def something(x: str, y: Dict[str, str]):
    print(x, y)

Testing this with the following: something(10, {"x": 20}) doesn't give a ValidationError, but testing it with something("x", {"x":None}) does.

Is that by design? Is there a way to enable stricter type checking?

@stonecharioteer late reply, but this is not actually an issue with validate_arguments specifically, but rather a feature of Pydantic in general.

When you specify types like str, float and int, Pydantic will try to coerce the input to that type if possible. In your example, the integer 20 is coercible to string, but None is not – you can test this with BaseModel.

from pydantic import BaseModel

class Test(BaseModel):
    x: str
        
Test(x=20) # no error
Test(x=None) # error

If you want stricter checking, consider using constrained types with strict=True (which prevents coercion), e.g.

from pydantic import BaseModel, constr, validate_arguments
from pydantic.typing import Dict

strict_str = constr(strict=True)

@validate_arguments
def something(x: strict_str, y: Dict[strict_str, strict_str]):
    print(x, y)

RajatRajdeep pushed a commit to RajatRajdeep/pydantic that referenced this pull request May 14, 2024
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

type checking decorator
7 participants