field_1
must be 0 by default, but not allowed with field_2
. My try:
from cerberus import Validator
schema = {
'value_1': {
'type': 'integer',
'default': 0
},
'value_2': {
'type': 'integer',
'excludes': ['value_1', ]
}
}
v = Validator(schema)
for doc in [{}, {'value_2': 1}, {'value_2': 1, 'value_2': 1}]:
if not v.validate(doc, schema):
print(v.errors)
else:
print(v.normalized(doc))
I got:
{'value_1': 0}
{'value_2': ["'value_1' must not be present with 'value_2'"]}
{'value_2': ["'value_1' must not be present with 'value_2'"]}
I want to validate second document without errors with normalized result {'value_1': 0, 'value_2': 1}
. How can I achieve the desired result?
EDIT More clear explanation of my goals:
- I want to raise error if value_1
and value_2
exists in incoming document, but set 0
to value_1
if this key not exists in document.
- I want to do it inside cerberus validation/normalization procedure and want to solve it by changing validation schema or validator
Quick Answer (TL;DR)
- validation and normalization can always be separated into distinct steps
Detailed Answer
Context
- python 2.7
- cerberus data-structure validation and normalization tool
Problem
- Scenario: Developer ElRusoDevoWoze wishes to combine validation with data normalization, in order to provide default values for missing fields.
Solution
- separate data validation from data normalization
Rationale
- rationale ;; validation and normalization can be thought of as separate processes
- proc1 ;; distinguish unacceptable inputs from acceptable inputs
- (garbage vs treasure)
- (authenticated vs unauthenticated)
- (well-formed vs non-well-formed)
- proc2 ;; optimize the content of acceptable inputs
Example
- The following example creates and applies two schemas
One schema provides the default values, the other does the validation
import pprint
import yaml
from cerberus import Validator
pass
schema_vali = yaml.safe_load('''
value_1:
type: integer
excludes: value_2
required: True
value_2:
type: integer
excludes: value_1
required: True
''')
pass
schema_norm = yaml.safe_load('''
value_1:
default: 0
''')
pass
sample_docs = yaml.safe_load('''
¯ {} ## doc0
¯ {'value_1': 1} ## doc1
¯ {'value_2': 1} ## doc2
¯ {'value_1': 1, 'value_2': 1} ## doc3
''')
pass
vccvali = Validator(schema_vali)
vccnorm = Validator(schema_norm)
pass
for ijj,doc in enumerate(sample_docs):
if vccnorm.validate(doc):
print("{ijj} NORM-YESS! -->".format(ijj=ijj)),
print(vccnorm.normalized(doc))
doc = vccnorm.normalized(doc)
if not vccvali.validate(doc):
print("{ijj} VALI-NOPE! -->".format(ijj=ijj)),
print(vccvali.errors)
else:
print("{ijj} VALI-YESS! -->".format(ijj=ijj)),
print(vccvali.normalized(doc))
doc = vccnorm.normalized(doc)
pass
Output result
0 NORM-YESS! --> {'value_1': 0}
0 VALI-YESS! --> {'value_1': 0}
1 NORM-YESS! --> {'value_1': 1}
1 VALI-YESS! --> {'value_1': 1}
2 VALI-YESS! --> {'value_2': 1}
3 VALI-NOPE! --> {'value_1': ["'value_2' must not be present with 'value_1'"], 'value_2': ["'value_1' must not be present with 'value_2'"]}
This is just upon understanding your requirement. And this works.
from cerberus import Validator
schema = {
'value_1': {
'type': 'integer',
'default': 0,
},
'value_2': {
'type': 'integer',
'excludes': ['value_1']
}
}
v = Validator(schema)
for doc in [{}, {'value_2': 1}, {'value_2': 2, 'value_1': 3}]:
print('Doc: {}'.format(doc))
n_doc = {}
if not v.validate(doc, schema):
print('Error: {}'.format(v.errors))
n_doc = v.normalized(doc)
n_doc.update(v.normalized({}))
else:
n_doc = v.normalized(doc)
print('Result: {}'.format(n_doc))
Result:
Doc: {}
Result: {'value_1': 0}
Doc: {'value_2': 1}
Error: {'value_2': ["'value_1' must not be present with 'value_2'"]}
Result: {'value_1': 0, 'value_2': 1}
Doc: {'value_1': 3, 'value_2': 2}
Error: {'value_2': ["'value_1' must not be present with 'value_2'"]}
Result: {'value_1': 0, 'value_2': 2}