[13.0][FIX] base_rest_datamodel: modify validation of responses to allow dump_only fields#169
Conversation
|
@fdegrave Validation is IMO a requirement since I want to be sure that the data returned by the service are conform to the schema. I understand that the current one is not right but how can we provide such a validation.? |
|
The simple fact that the schema is used to dump the data is already a validation. Here is a simple example: from marshmallow import Schema, fields
class MySchema(Schema):
my_string = fields.Str()
my_integer = fields.Integer()
class DataClass:
def __init__(self, my_string, my_integer):
self.my_string = my_string
self.my_integer = my_integerNow let's dump a valid instance: As expected. Now let's do it with an instance that does not conform to the schema: As you can see, validation is included in the |
|
However you are right that not everything is validated (see there for example). In the same thread, people have the exact same issue we are discussing here (link) but they don't come up with a solution (unfortunately)... One thing that we could do is list the names of I'll try that tomorrow. |
|
What they do there is instantiating the schema with a Therefore a second solution would be to add a new @classmethod
def validate(cls, data, context=None, many=None, partial=None):
schema = cls.__get_schema_class__(context=context, partial=partial)
return schema.validate(data, many=many, partial=partial)And we could simply do: @classmethod
def validate(cls, data, context=None, many=None, partial=None, unknown=None):
schema = cls.__get_schema_class__(context=context, partial=partial, unknown=unknown)
return schema.validate(data, many=many, partial=partial)And modify the current validation with: from marshmallow import EXCLUDE
...
errors = ModelClass.validate(json, many=self._is_list, unknown=EXCLUDE)Since after some thoughts I doubt the first solution would work, I'll try this one tomorrow. |
|
I implemented my latest proposition, but it was trickier than I though because of nested models (no control on the schema for those, no way to easily override them during validation -- had to be creative, I think it's the cleanest I can do). |
|
I rebased my branch after the fix of the tests have been merged. Hopefully everything should work OK. |
|
Nearly there :-D |
dump_only fields
|
Victory! |
lmignon
left a comment
There was a problem hiding this comment.
@fdegrave Thank you for this fix and all your experiments to provide the right one. First of all, feel free to add your name into the list of contributors!
Before merging I propose to add some tests and change the existing one (see my comments)
In marshmallow, `dump` (serialization) and `load` (deserialization) operations using the same schema are not symmetrical in general. That is because fields can be declared as `dump_only` or `load_only`. That means that trying to `load` data you just `dumped` can result in errors, and vice-versa. And that is exactly what is (was) wrong with this validation: the `validate` method on the `ModelClass` uses `load` to validate the data. That means that if you declared some fields to be `dump_only`, this validation necessarily crash. Moreover, it seems that this validation is not only incorrect but also useless (if it worked as intended), since it bases its verification on the very same schema as the one that was just used used to serialize the data. [FIX] base_rest_datamodel: change response validation to use a schema with `unknown=EXCLUDE` This modification prevents fields that are declared as `dump_only` to mess with the validation (`dump_only` fields are seen as "unknown" during validation, since marshmallow validation is designed to be used during loading only). [FIX] base_rest_datamodel: change response validation to use a schema with `unknown=EXCLUDE` Nested model required extra care because the `unknown=EXCLUDE` is not passed down to the nested schemas when validating data, and this behavior could not easily be overridden. I ended up removing `dump_only` fields from value during `NestedModel` deserialization. [ADD] base_rest_demo: add test for new api [ADD] base_rest_demo: test [FIX] datamodel: allow to instantiate datamodel with dump_only fields as well [IMP] datamodel: improved 'validate' method, propagating 'unknown' value to nested schemas [IMP] base_rest_demo: rename test class
…modelRegistryCase" and move them from base_rest_demo to base_rest_datamodel
|
Is there anything still preventing the merge? |
|
/ocabot merge patch |
|
On my way to merge this fine PR! |
|
times to merge a pending merge for a long time |
|
Congratulations, your PR was merged at 5362630. Thanks a lot for contributing to OCA. ❤️ |
In marshmallow,
dump(serialization) andload(deserialization) operations using the same schema are not symmetrical in general. That is because fields can be declared asdump_onlyorload_only. That means that if you try toloaddata you justdumpedit could fail, and vice-versa.And that is exactly what is (was) wrong with this validation: the
validatemethod on theModelClassusesloadto validate the data. That means that if you declare some fields to bedump_only, this validation necessarily crashes.Moreover, it seems that this validation is not only incorrect but also useless (if it worked as intended), since it bases its verification on the very same schema as the one that was just used to serialize the data.