-
Notifications
You must be signed in to change notification settings - Fork 238
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
Type coercion validator #71
Conversation
This seems very similar to what is already achievable with function based custom validation. |
The difference is that the coercion always runs first and the value returned by the coerce function is set in the model/document for that key. That means the other validators always check against the coerced value in the model rather than the original value. It's helpful for things like http query parameters which always come in as strings and so you can sanitize and validate them in one step. |
I use it like this so when I get the friend_ids from the request.values its already converted to a list. schema = {
'friend_ids': {'type': 'table_id_list', 'coerce': utils.parse_csv}
}
values = validate(request.values.to_dict(), schema)
friend_ids = values.get('friend_ids', []) |
I think that Cerberus should focus on validation. Transformation is a different thing, and we want to follow the "separation of concern" principle in this case. |
It's a pretty common feature to similar frameworks: https://github.com/alecthomas/voluptuous#validation-functions This is extemely convenient: schema = {"num": "2", "type": "number"} // broken
schema = {"num": "2", "type": "number", "coerce": int} // yay! |
Yup there has been someone else proposing something like this in the past.Let's see if more people would like to add transformation features. |
To my mind such type coercion has the same semantics as schema validation. And I'd like to see such errors along with schema errors. So as for me I see no reasons to separate these concerns. In addition it is possible to |
Alright folks. Looks like the feedback we've been waiting for has arrived, and I stand corrected 😄. @brettatoms would you also update the documentation? |
@nicolaiarocci Thanks! Should be good to go. |
@nicolaiarocci @brettatoms Thanks you very much |
some thoughts concerning the design:
seems redundant as it will be of
or
or
what about defining coerce similar like custome type-checks? that would require a sub-class to use it, but the design is more stringent. there should be some tests. |
@@ -327,6 +333,13 @@ def validate_schema(self, schema): | |||
raise SchemaError(errors.ERROR_UNKNOWN_RULE % ( | |||
constraint, field)) | |||
|
|||
def _validate_coerce(self, coerce, field, value): | |||
try: | |||
value = coerce(value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is coerce
implemented? it should propably be a method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The coerce
argument is the callable that you define in the schema. See https://github.com/nicolaiarocci/cerberus/pull/71/files#diff-aebc53cd4926f3a579adb7ba188de369R214
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, yeah. with a definition of methods like for checking types, these functions / then methods can be designed to consider context. i guess sooner or later someone will need that.
oh, can schema-validation improve fool-proofness? |
|
|
Only concern I have on this is that it transforms the input. Of course there's a note in the docs, and that's probably enough. Also, in several scenarios this might actually the desired behaviour, which leads me back to my original concern that we this update we are, in fact, transitioning from a pure validation tool to a validation and transformation utility. I wonder if we should make transformation an explicit opt-in, like setting up a |
in short: i have my doubts that just calling a function is enough to achieve that properly and to fit more complex use-cases. i pointed at my concerns before. if anybody wants, i can elaborate more on these which are unclear. |
@nicolaiarocci How about doing a |
since referenced objects are potentially changed one should use |
@brettatoms yes, absolutely. I initially ruled it out because I thought that people might actually want to apply transformations (we also had requests like that in the past). Also agree with @funkyfuture that deepcopy is better. Would you update the PR and docs? |
For reference, an older similar request was #3 |
How about subclassing |
if there was an extra-class, wouldn't it be simpler to leave the class CoerceValidator():
def __init__(self, *args, **kwargs):
self.validator = Validator(*args, **kwargs)
def validate(…):
do_coersion()
self.validator.validate(…) but i don't see much harm in this now. however, it'd be easy to and i still think that it's also a good idea to implement checks in also, i can anticipate that if i wanted to use that feature (and atm there is actually one project where i would), i would have to rely on context (e.g. a basepath to resolve a path), which is hardly accessible from a function and sould be available as properties of a class-instance. so i'm absolutely pro an extendibility like for type-checking. but that can be added later too. |
Thanks, this has been merged in 8fc11a1. Feel free to update both AUTHORS and CHANGES with your full name. |
By adding a
coerce: <some callable>
validator to a schema the return value of the callable will be used as the value to validate against in the document. This overwrite the value in the document so requires that you make a copy of the document before passing it to the validator if you don't want your original document changed.This isn't fool proof as it only catches TypeError and ValueError in coercion validator but it is incredibly handy to have for sanitizing and validating HTTP request data.