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

Question - How do I define conditional rules? #286

Open
fopguy41 opened this issue Sep 23, 2022 · 1 comment
Open

Question - How do I define conditional rules? #286

fopguy41 opened this issue Sep 23, 2022 · 1 comment

Comments

@fopguy41
Copy link

fopguy41 commented Sep 23, 2022

Say I have a dictionary where the keys are conditional. How do I write a schema to check it?

For example, the following 2 are ok.

{
    'name': 'x',
    'x_val': 1
}

{
    'name': 'y',
    'y_val': 1
}

But the following 2 are not

{
    'name': 'x',
    'y_val': 1
}

{
    'name': 'y',
    'x_val': 1
}

The existence of what keys need to be in the dict is conditional on the value of name. I can't just say this is a dict with these keys. Name x has a certain set of keys (in this case, x_val), and name y has a different set of keys (y_val).

Of course, I can write my own lambda function that takes in such a dictionary and performs the checks. But I was wondering if there's some kind of out of the box solution for this type of validation.

thanks

@LandingEllipse
Copy link

I'm a new user, so there might be a neater way to take care of conditional rules, but here's an approach based on the Customized Validation section of the readme:

from schema import Schema, SchemaMissingKeyError, Or

class ConditionalSchema(Schema):
    def validate(self, data, _is_conditional_schema=True, **kwargs):
        data = super().validate(data, _is_conditional_schema=False, **kwargs)
        if _is_conditional_schema:
            if data["name"] == "x" and "x_val" not in data:
                raise SchemaMissingKeyError("x_val")
            elif data["name"] == "y" and "y_val" not in data:
                raise SchemaMissingKeyError("y_val")
        return data


sch = ConditionalSchema(
    {
        "name": Or("x", "y"),
        Or("y_val", "x_val", only_one=True): int,
    }
)
sch.validate({"name": "x", "x_val": 1})  # => {'name': 'x', 'x_val': 1}
sch.validate({"name": "y", "y_val": 1})  # => {'name': 'y', 'y_val': 1}
sch.validate({"name": "x", "y_val": 1})  # => schema.SchemaMissingKeyError: x_val
sch.validate({"name": "y", "x_val": 1})  # => schema.SchemaMissingKeyError: y_val

This approach is pretty flexible, but comes at the cost a level of indirection with respect to where the rules are defined.

Note that the passing through of kwargs is only necessary when nesting different Schema subclasses and could have been omitted from the above example.

Cheers!

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

2 participants