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

Unexpected behavior: Can not double validate keys #289

Open
MrChadMWood opened this issue Dec 29, 2022 · 3 comments
Open

Unexpected behavior: Can not double validate keys #289

MrChadMWood opened this issue Dec 29, 2022 · 3 comments

Comments

@MrChadMWood
Copy link

from schema import Schema, And, Or, Use, Optional, SchemaError, Forbidden


x = Schema({
    Or('request', 'requests', only_one=True) : dict,
    Optional('requests'): {Use(int): dict}
})

x.validate({
    'requests': {1:{}}
})

The expected result here is that a user can supply a dict using the key 'request' or 'requests'. If 'requests' is used, then the nested dict keys should be numbered.
I assumed that the dict would validate Or('request', 'requests', only_one=True) : dict, and then see the optional key 'requests' was supplied. It should also validate Optional('requests'): {Use(int): dict}. But the output seems to only allow one validation per key,

See output:

---------------------------------------------------------------------------
SchemaMissingKeyError                     Traceback (most recent call last)
Input In [298], in <cell line: 1>()
----> 1 x.validate({
      2     'requests': {1:{}}
      3 })

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\schema.py:420, in Schema.validate(self, data, **kwargs)
    418     message = "Missing key%s: %s" % (_plural_s(missing_keys), s_missing_keys)
    419     message = self._prepend_schema_name(message)
--> 420     raise SchemaMissingKeyError(message, e.format(data) if e else None)
    421 if not self._ignore_extra_keys and (len(new) != len(data)):
    422     wrong_keys = set(data.keys()) - set(new.keys())

SchemaMissingKeyError: Missing key: Or('request', 'requests')
@MrChadMWood
Copy link
Author

MrChadMWood commented Dec 29, 2022

Perhaps my expectation is impossible because of the need to support other functionalities. May I suggest adding some kind of "If Then" functionality?

Like this:

x = Schema({
    Or('request', 'requests', only_one=True) : dict,
    If('requests'): {Use(int): dict}
})

In this example, If would inherit the Optional() property of not being required. Though, maybe it's also worth enforcing that any If keys supplied should correspond with one of the keys supplied to an Or(). This way, users cant rely on If() instead of Optional(), thereby preserving consistency.

@MrChadMWood
Copy link
Author

MrChadMWood commented Dec 29, 2022

One potential workaround:

x = Schema({
    Optional(Or('request', 'requests', only_one=True)) : dict,
    Optional('requests'): {Use(int): dict}
})

Though, this will validate an empty dict. Perhaps this is still the best solution, as it shouldn't be too hard to include a

# Untested
if len(input_data) == 0:
    raise SchemaError('blah blah blah')

...or something of the sort.

Edit:
Damn it... nevermind.

x = Schema({
    Optional(Or('request', 'requests', only_one=True)) : dict,
    Optional('requests'): {Use(int): dict}
})

x.validate({'request':{},'requests':{1:{}}})

# {'request': {}, 'requests': {1: {}}}

@MrChadMWood
Copy link
Author

Well, I would have though this would work too. But no.

x = Schema({
    Optional(Or('request', 'requests', only_one=True)) : dict,
    Optional('requests'): {Use(int): dict},
    Forbidden(And('request', 'requests')): object
})

x.validate({'request':{},'requests':{1:{}}})

# {'request': {}, 'requests': {1: {}}}

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

No branches or pull requests

1 participant