2

I am using voluptuous 0.9.2 and I have a problem with Exclusive class. I need that if there is none of the keys, it should give an error. However, this is okay for voluptuous. Is this a bug of voluptuous? If not, how I can write a script for that?

In order to clarify my problem, assume we built a schema like that:

schema = Schema({Exclusive('a', 'z'): int, Exclusive('b', 'z'): int, 'c': int}, required=True)

I need one and only one of the keys in exclusion group to be given. But when I test with {'c': 5}, it seems to be valid even though I did not give either a or b. I do not know how to make it works especially for this situation.

  • 1
    As of today, there is still an open issue asking for this functionality: https://github.com/alecthomas/voluptuous/issues/115 – VPfB Jul 02 '17 at 14:27

2 Answers2

1

According to the documentation, Exclusive inherits from Optional, which means that a and b are optional in your schema; that's why {'c': 5} is a valid input. To get around this problem, you need to explicitly specify them as required:

from voluptuous import Schema, Exclusive, Required
schema = Schema({Required(Exclusive('a', 'z')): int, Required(Exclusive('b', 'z')): int, 'c': int}, required=True)
Alex Mitrevski
  • 223
  • 3
  • 7
1

A trick that works here is to use two different schemas that need to validate at the same time:

from voluptuous import All, Any, Exclusive, Required                                                                                                                         

schema = All(                                                                                                                                                                
    {                                                                                                                                                                        
        Exclusive('a', 'z'): int,                                                                                                                                            
        Exclusive('b', 'z'): int,                                                                                                                                            
        Required('c'): int,                                                                                                                                                  
    },                                                                                                                                                                       
    {                                                                                                                                                                        
        Required(Any('a', 'b')): int,                                                                                                                                        
        Required('c'): int,                                                                                                                                                  
    },                                                                                                                                                                       
)

The first schema fails to validate when both a and b are present and the second schema fails when neither a nor b are present. Hence, either a or b need to be present.

jcollado
  • 39,419
  • 8
  • 102
  • 133
  • 1
    I would make 3 minor modifications to your solution: 1. You don't need to define 'c' in both schemas. You can choose one. 2. The keys-validation schema (the second one) should probably have `object` as types to avoid repeating values schema. 3. For error reporting sake, I would put the keys-validation schema first, so if you neglected to specify one of the keys you'll get the error first. – Guy Jan 28 '19 at 07:55
  • 1
    @guyarad Thanks for the suggestions. I agree on that there's no need to define `c` in both schemas and that only one of them needs to be specific on type while the other can just use `object`. However, I'm not sure if that would be more readable. Maybe a helper function that generates the final schema based on one without duplication would be a better solution. – jcollado Jan 28 '19 at 23:19