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

Proposal: custom coerce-methods #102

Closed
funkyfuture opened this issue May 26, 2015 · 13 comments
Closed

Proposal: custom coerce-methods #102

funkyfuture opened this issue May 26, 2015 · 13 comments

Comments

@funkyfuture
Copy link
Member

i think it's better to include this feature before 0.9 is released. and as there is a reliable pattern for types, it wouldn't be much effort i guess.

one could also add an example to the docs and tests that illustrates a subclassed Validator that makes use of coercing in conjunction with contextual instance-properties.

@nicolaiarocci
Copy link
Member

Design/usage example? Thanks!

@funkyfuture
Copy link
Member Author

class MyValidator(Validator):
    def _corce_none_to_string(self, field, value):
        if value is None:
            self.document[field] = "N/A"

    def _coerce_expand_avatar_path(self, field, value):
        self.document[field] = os.path.join(self.avatar_dir, value)

schema = {'avatar': {'coerce': 'expand_avatar_path', 'type': 'accessible_image_file'},
          'phone': {'coerce': 'none_to_string'}}

@nicolaiarocci
Copy link
Member

👍

@nicolaiarocci
Copy link
Member

Type coercion allows this already, as you can pass any callable to the coerce method. You can also confine coercion within a custom validator:

class MyValidator(Validator):
    def __init__(self, *args, **kwargs):
        super(MyValidator, self).__init__(*args, **kwargs)
        self.avatar_dir = '~/avatars'

   def _validate_expand_avatar(self, expand_avatar, field, value):
       self.document[field] = os.path.join(self.avatar_dir, value)

s = {'a': {'type': 'string', 'expand_avatar': True}

Alternatively you could create a new avatar type:

class MyValidator(Validator):
    def __init__(self, *args, **kwargs):
        super(MyValidator, self).__init__(*args, **kwargs)
        self.avatar_dir = '~/avatars'

   def _validate_type_avatar(self, field, value):
       self.document[field] = os.path.join(self.avatar_dir, value)

s = {'a': {'type': 'avatar'}}

Do we really need to add yet another way to achieve this?

@funkyfuture
Copy link
Member Author

imo yes, as i think that normalization and validation should be clearer segregated in the code. you're proposal is more a workaround where normalization is applied while validation, right?

@nicolaiarocci
Copy link
Member

Yes, I think you are right.

@funkyfuture funkyfuture mentioned this issue Jul 13, 2015
@manugarri
Copy link

👍

One example would be for those fields in which you want a default value.
Since there is no default keyword this could be easily implemented with coerce.

Also, i agree that makes sense the separation of validation (no data changes) versus coerce (data is modified).

@funkyfuture
Copy link
Member Author

i wouldn't see why a default-normalization-rule shouldn't be contributed with the vanilla Validator.

@manugarri
Copy link

it could, but it is more aligned with coerce in which it would silently alter the original data.

@funkyfuture
Copy link
Member Author

i don't understand. i thought you mean:

>>> schema = {'amount': {'default': 1}}
>>> document = {'amount': None}
>>> v.validated(document, schema)
{'amount': 1}
>>> document = {'model': 'The Robots'}
>>> v.normalized(document, schema)
{'model': 'The Robots', 'amount': 1}

yes, it alters values like coerce, but in a different way.

@manugarri
Copy link

yeah that's what i meant. I guess both coerce and default are same level citizens.

@lelit
Copy link

lelit commented Sep 24, 2015

I'd take advantage of this: I'm loading the schema from an external file (actually, from a schema in a RAML document), and there's no easy way to express a callable (although I could use a YAML tag like {a: !!python/name:__builtin__.int}, that's quite ugly, difficult to understand to non-Python-introduced people who read the schema, and most Python RAML loaders use yaml.SafeLoader so that's not a generic option even).

Ideally I'd like to have a way to inject custom coercer functions on Validator, that _coerce_values() could lookup by name.

@funkyfuture
Copy link
Member Author

closing this in favor of #188 where i argue that this is a 1.0-must-have.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants