From 3d46848c77f29e274f889db280929d9dbd4aa7ff Mon Sep 17 00:00:00 2001 From: George Mamalakis Date: Tue, 10 Sep 2019 16:57:55 +0300 Subject: [PATCH 1/4] support for schema_kwargs keyword argument dictionary which passes keyword arguments on marshmallow schema instantiation --- CHANGES.txt | 2 +- CONTRIBUTORS.txt | 1 + cornice/validators/_marshmallow.py | 24 ++++++++++++++++++++---- tests/validationapp.py | 22 ++++++++++------------ 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 036ae566..ba5bd6be 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,7 +5,7 @@ CHANGELOG 3.7.0 (unreleased) ================== -- Nothing changed yet. +- Add support for passing keyword arguments to marshmallow validator. 3.6.1 (2019-11-13) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index f9ce6d12..a836657d 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -29,6 +29,7 @@ Cornice: * Gabriela Surita * Gael Pasgrimaud * George V. Reilly +* George Mamalakis * Graham Higgins * G.Tjebbes * Guillaume Gauvrit diff --git a/cornice/validators/_marshmallow.py b/cornice/validators/_marshmallow.py index 4f950334..b4f8a113 100644 --- a/cornice/validators/_marshmallow.py +++ b/cornice/validators/_marshmallow.py @@ -26,6 +26,9 @@ def _validator(request, schema=None, deserializer=None, **kwargs): The content of the location is deserialized, validated and stored in the ``request.validated`` attribute. + Keyword arguments to be included when initialising the marshmallow + schema can be passed as a dict in kwargs['schema_kwargs'] variable. + .. note:: If no schema is defined, this validator does nothing. @@ -46,10 +49,14 @@ def _validator(request, schema=None, deserializer=None, **kwargs): if schema is None: return - schema = _instantiate_schema(schema) + # see if the user wants to set any keyword arguments for their schema + schema_kwargs = {} + if 'schema_kwargs' in kwargs: + schema_kwargs = kwargs['schema_kwargs'] + schema = _instantiate_schema(schema, **schema_kwargs) class ValidatedField(marshmallow.fields.Field): - def _deserialize(self, value, attr, data): + def _deserialize(self, value, attr, data, **kwargs): schema.context.setdefault('request', request) deserialized = schema.load(value) # marshmallow 2.x returns a tuple, 3/x will always throw @@ -185,8 +192,17 @@ def validator(request, schema=None, deserializer=None, **kwargs): request.validated.update(deserialized) -def _instantiate_schema(schema): +def _instantiate_schema(schema, **kwargs): + """ + Returns an object of the given marshmallow schema. + + :param schema: The marshmallow schema class with which the request should + be validated + :param kwargs: The keyword arguments that will be provided to the + marshmallow schema's constructor + :return: The object of the marshmallow schema + """ if not inspect.isclass(schema): raise ValueError('You need to pass Marshmallow class instead ' 'of schema instance') - return schema() + return schema(**kwargs) diff --git a/tests/validationapp.py b/tests/validationapp.py index 3531ba2c..2dca1c02 100644 --- a/tests/validationapp.py +++ b/tests/validationapp.py @@ -348,16 +348,6 @@ class Meta: unknown = EXCLUDE username = marshmallow.fields.String() - class MSignupGroupSchema(marshmallow.Schema): - class Meta: - strict = True - unknown = EXCLUDE - username = marshmallow.fields.String() - - def __init__(self, *args, **kwargs): - kwargs['many'] = True - marshmallow.Schema.__init__(self, *args, **kwargs) - import random class MNeedsContextSchema(marshmallow.Schema): @@ -383,8 +373,15 @@ def m_bound_post(request): def signup_post(request): return request.validated - @m_group_signup.post( - schema=MSignupGroupSchema, validators=(marshmallow_body_validator,)) + # callback that returns a validator with keyword arguments for marshmallow + # schema initialisation. In our case it passes many=True to the desired + # schema + def get_my_marshmallow_validator_with_kwargs(request, **kwargs): + kwargs['schema'] = MSignupSchema + kwargs['schema_kwargs'] = {'many': True} + return marshmallow_body_validator(request, **kwargs) + + @m_group_signup.post(validators=(get_my_marshmallow_validator_with_kwargs,)) def m_group_signup_post(request): return {'data': request.validated} @@ -511,6 +508,7 @@ class Meta: def m_form(request): return request.validated + def includeme(config): config.include("cornice") config.scan("tests.validationapp") From eafd6ff749c32d60cb7a5c6a9ca66fb407c0e3cb Mon Sep 17 00:00:00 2001 From: George Mamalakis Date: Wed, 4 Dec 2019 12:04:05 +0200 Subject: [PATCH 2/4] Update cornice/validators/_marshmallow.py Co-Authored-By: Mathieu Leplatre --- cornice/validators/_marshmallow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cornice/validators/_marshmallow.py b/cornice/validators/_marshmallow.py index b4f8a113..82c20a80 100644 --- a/cornice/validators/_marshmallow.py +++ b/cornice/validators/_marshmallow.py @@ -27,7 +27,7 @@ def _validator(request, schema=None, deserializer=None, **kwargs): the ``request.validated`` attribute. Keyword arguments to be included when initialising the marshmallow - schema can be passed as a dict in kwargs['schema_kwargs'] variable. + schema can be passed as a dict in ``kwargs['schema_kwargs']`` variable. .. note:: From 975ba4a16eba364df77361fdbf22cbdfe3fcec30 Mon Sep 17 00:00:00 2001 From: George Mamalakis Date: Wed, 4 Dec 2019 12:04:38 +0200 Subject: [PATCH 3/4] Update cornice/validators/_marshmallow.py Co-Authored-By: Mathieu Leplatre --- cornice/validators/_marshmallow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cornice/validators/_marshmallow.py b/cornice/validators/_marshmallow.py index 82c20a80..81b871a9 100644 --- a/cornice/validators/_marshmallow.py +++ b/cornice/validators/_marshmallow.py @@ -52,7 +52,7 @@ def _validator(request, schema=None, deserializer=None, **kwargs): # see if the user wants to set any keyword arguments for their schema schema_kwargs = {} if 'schema_kwargs' in kwargs: - schema_kwargs = kwargs['schema_kwargs'] + schema_kwargs = kwargs.get('schema_kwargs', {}) schema = _instantiate_schema(schema, **schema_kwargs) class ValidatedField(marshmallow.fields.Field): From 236a6602fe83a8a84702da01d85a1763cf0e6f2e Mon Sep 17 00:00:00 2001 From: George Mamalakis Date: Thu, 5 Dec 2019 12:44:25 +0200 Subject: [PATCH 4/4] Update _marshmallow.py --- cornice/validators/_marshmallow.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cornice/validators/_marshmallow.py b/cornice/validators/_marshmallow.py index 81b871a9..b8dee7bf 100644 --- a/cornice/validators/_marshmallow.py +++ b/cornice/validators/_marshmallow.py @@ -50,9 +50,7 @@ def _validator(request, schema=None, deserializer=None, **kwargs): return # see if the user wants to set any keyword arguments for their schema - schema_kwargs = {} - if 'schema_kwargs' in kwargs: - schema_kwargs = kwargs.get('schema_kwargs', {}) + schema_kwargs = kwargs.get('schema_kwargs', {}) schema = _instantiate_schema(schema, **schema_kwargs) class ValidatedField(marshmallow.fields.Field):