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

Support for Cerberus 1.1 #1001

Closed
wants to merge 1 commit into from
Closed

Conversation

bcrochet
Copy link

(Based on original patch from dkellner)

This is a rather big change. I still decided to do a single commit, as
intermediate commits would be in a non-working state anyway.

Breaking changes:

  • keyschema was renamed to valueschema and propertyschema to
    keyschema (following changes in Cerberus).
  • A PATCH on a document which misses a field having a default value will
    now result in setting this value, even if the field was not provided
    in the PATCH's payload.
  • Error messages for keyschema are now returned as dictionary.
    Before: {'propertyschema_dict': 'propertyschema_dict'}
    Now: {'keyschema_dict': {'AAA': "value does not match regex '[a-z]+'"}}
  • Error messages for type validations are different now (following
    changes in Cerberus).
  • It is no longer valid to have a field with default = None and
    nullable = False.
    (see patch.py:test_patch_nested_document_nullable_missing)

In a nutshell, changes to the codebase are as follows:

  • Add data layer independent subclass of cerberus.Validator

    • Support new signature of __init__ and validate
    • Use _config-aware properties instead of bare member attributes to
      pass the resource, document_id and persisted_document to make
      them available to child validators
    • Add schema-docstrings to all _validate_* methods
  • Adjust Mongo-specific Validator subclass

    • Adjust _validate_type_* methods (following changes in Cerberus)
    • Add schema-docstrings to all _validate_* methods
  • Add custom ErrorHandler to support VALIDATION_ERROR_AS_LIST

  • A few renames:

    • ValidationError -> DocumentError
    • propertyschema -> keyschema and keyschema -> valueschema
  • Adjust tests due to different validation error messages
    (mostly for type)

  • Remove transparent_schema_rules without replacement

  • Remove default-handling, as Cerberus takes care of this now

@dkellner
Copy link
Contributor

Great, thank you for re-opening this! I've quite busy with Eve-SQLAlchemy for now so did not have time myself to look into this again.

I just saw that setup.py and tox.ini still use dependency_links to install my development branch of Cerberus for testing - we should remove this. And AFAIK dependency link processing has been removed from pip.

@nicolaiarocci
Copy link
Member

Excellent. Thank you @bcrochet for taking up the torch. @dkellner I'd appreciate a thoughtful review when you have time (use the Review feature).

@bcrochet
Copy link
Author

@dkellner Removed the dependency_links lines from setup.py and tox.ini.

Copy link
Member

@funkyfuture funkyfuture left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i made a review from a cerberus-only pov. it's encouraging to see client code to be reduced. :-)

i also found two possible leverages for more:

  • cerberus could look up the rule constrains schemas from overridden methods when an overriding method doesn't provide one
  • cerberus could auto-create the properties that map to self._config keys or implement __getattr__ and __setattr__

i noted these.

self._config['resource'] = value

@property
def document_id(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's not a bad idea to add this property along with a schema_id to the vanilla Validator. essentially to have canonically named properties that extensions like error handlers can hook to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify: This is nothing concerning this very PR, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's correct.

self._config['persisted_document'] = value


class DefaultErrorHandler(cerberus.errors.BasicErrorHandler):
Copy link
Member

@funkyfuture funkyfuture Mar 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assuming that config.VALIDATION_ERROR_AS_LIST doesn't change during runtime, you could reduce overhead with roughly this:

class SingleElementListMixin(object):
    def pretty_tree(self):
        ...

if not config.VALIDATION_ERROR_AS_LIST:
    DefaultErrorHandler = type('DefaultErrorHandler', (cerberus.errors.BasicErrorHandler, SingleElementListMixin), {})
else:
    DefaultErrorHandler = cerberus.errors.BasicErrorHandler

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we could do this check only one time at application startup. But I wonder if creating a dynamic type based on a config item can get confusing once someone will subclass this again.

How about renaming DefaultErrorHandler to something like SingleErrorsAsStringErrorHandler (or a better name if you can come with one) and then amend Validator.__init__ as follows?

if not config.VALIDATION_ERROR_AS_LIST:
    kwargs['error_handler'] = SingleErrorsAsStringErrorHandler

But again I cannot see a "real" issue with your (definitely more sophisticated) suggestion.

return field not in self.document and \
self.persisted_document and \
field in self.persisted_document
return list(filter(persisted_but_not_in_document, fields))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't list comprehensions the common idioms for such expressions nowadays?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, and it should make it more readable, too.

""" {'type': ['dict', 'hashable', 'hashables']} """
persisted = self._filter_persisted_fields_not_in_document(dependencies)
if persisted:
dcopy = copy.copy(self.document)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would a deepcopy be less error prone here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, especially regarding the fact that the child validator can do normalization, too. I just looked into this and copy.copy was used in the original code as well. I think that's the reason I kept in there in the beginning. A "real" fix would include a test case where a plain copy fails so we never need to wonder about this again.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm leaving this for later. I'm not familiar enough with the code to be able to make an informed change here.

@dkellner
Copy link
Contributor

@nicolaiarocci I will review this during the next days.

In the meantime we can discuss about updating the documentation (as already mentioned here: #917 (comment)). Additionally, we should add a section about upgrading, as this will introduce some breaking changes.

@nicolaiarocci
Copy link
Member

Yes docs need to be amended and upgrading should be covered.

@dkellner
Copy link
Contributor

I looked into this again, but this is my code without changes (so far) - so I'm not sure if I'm really the right person to review it ;). Nonetheless, I took some notes regarding needed documentation changes. The list is probably not complete, but a hopefully a good start:

  • _validate_type_uuid in custom_idfields.rst is wrong now (signature + return value)
  • same for _validate_type_objectid in validation.rst
  • still contains references to 'propertyschema' (should be 'keyschema' now),
    this is probably true for other renames as well
  • remove references to TRANSPARENT_SCHEMA_RULES (config.rst, validation.rst)

@bcrochet Can you implement @funkyfuture's suggestions (amend to my commit if you want, I think that's fine in this case) and add another commit for the documentation changes?

@bcrochet
Copy link
Author

@dkellner You're absolutely right. It is mostly your original patch. I think I maybe changed 2 lines, just to get it working with the latest cerebrus. But yes, I will take @funkyfuture 's suggestions and amend this commit.

@funkyfuture
Copy link
Member

actually, i'm not sure whether this errorhandler is really needed. in cerberus the argument was that current client code should already be ready to deal with such structures as they were used for 2+ errors.

@nicolaiarocci
Copy link
Member

@bcrochet is this work ready for merge, or you still have work left to do?

@bcrochet
Copy link
Author

bcrochet commented May 6, 2017

@nicolaiarocci I'm currently rebasing and will have some changes, so it's not quite ready.

@bcrochet bcrochet force-pushed the cerberus-1.1 branch 3 times, most recently from 35e774f to 33c3415 Compare May 6, 2017 19:09
@bcrochet
Copy link
Author

bcrochet commented May 6, 2017

I'd consider this ready. However, the python2.6 job is not passing, due to python2.6 being not found. Should this be dropped from tox.ini?

@nicolaiarocci
Copy link
Member

nicolaiarocci commented May 7, 2017

Looks like the latest Travis update broke our .travis.yml. Can you please rebase (again) on top of master? Thanks!

@bcrochet bcrochet force-pushed the cerberus-1.1 branch 2 times, most recently from b5e33b2 to 43cf038 Compare May 7, 2017 22:52
@bcrochet
Copy link
Author

bcrochet commented May 7, 2017

Rebase done. I also went ahead and included doc changes.

@nicolaiarocci
Copy link
Member

Excellent. One last effort and we're done. Please, update the 'breaking changes' section in the changelog. I guess a good reference would be Cerberus' own "upgrading to 1.0" page at https://cerberus.readthedocs.io/en/stable/upgrading.html.

(Based on original patch from dkellner)

This is a rather big change. I still decided to do a single commit, as
intermediate commits would be in a non-working state anyway.

Breaking changes:

- `keyschema` was renamed to `valueschema` and `propertyschema` to
  `keyschema` (following changes in Cerberus).
- A PATCH on a document which misses a field having a default value will
  now result in setting this value, even if the field was not provided
  in the PATCH's payload.
- Error messages for `keyschema` are now returned as dictionary.
  Before: {'propertyschema_dict': 'propertyschema_dict'}
  Now: {'keyschema_dict': {'AAA': "value does not match regex '[a-z]+'"}}
- Error messages for `type` validations are different now (following
  changes in Cerberus).
- It is no longer valid to have a field with `default` = None and
  `nullable` = False.
  (see patch.py:test_patch_nested_document_nullable_missing)

In a nutshell, changes to the codebase are as follows:

- Add data layer independent subclass of `cerberus.Validator`
  * Support new signature of `__init__` and `validate`
  * Use `_config`-aware properties instead of bare member attributes to
    pass the `resource`, `document_id` and `persisted_document` to make
    them available to child validators
  * Add schema-docstrings to all `_validate_*` methods

- Adjust Mongo-specific `Validator` subclass
  * Adjust `_validate_type_*` methods (following changes in Cerberus)
  * Add schema-docstrings to all `_validate_*` methods

- Add custom ErrorHandler to support `VALIDATION_ERROR_AS_LIST`

- A few renames:
  * `ValidationError` -> `DocumentError`
  * `propertyschema` -> `keyschema` and `keyschema` -> `valueschema`

- Adjust tests due to different validation error messages
  (mostly for `type`)

- Remove `transparent_schema_rules` without replacement
- Remove `default`-handling, as Cerberus takes care of this now
@bcrochet
Copy link
Author

@nicolaiarocci Updated

@nicolaiarocci
Copy link
Member

Merged after rebase,see 3bfff77.

Stellar, thank you.

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.

4 participants