I have a value that I only want to validate if a different argument is provided. Here is a simplified version of my code:
schema = Schema({ Optional("lib_file"): Use(open),
Optional("offset"): Use(lambda "offset": int(offset, 16))
})
schema.validate({"lib_file": "C:\lib.so", offset: "0xFFF"})
Here, offset is dependent on lib_file: It is required if lib_file is provided, but it should not be provided if lib_file is not provided - an "exclusive nor" relationship. Thus, offset should be validated conditionally, rather than being simply required or optional.
I have figured out a quite hacky way to do this, namely:
lib_file = "C:\lib.so"
offset = "0xFFF"
schema = Schema({ Optional("lib_file"): Use(open),
"offset": Or(And(lambda offset: offset is not None or lib_file is None,
error="If you provide a libfile, you must also provide an offset"),
Use(lambda offset: int(offset, 16)))
}, ignore_extra_keys=True)
schema.validate({"lib_file": lib_file, "offset": offset})
This yields the desired effects:
# Okay
lib_file = "C:\lib.so"
offset = "0xFFF"
schema.validate({"lib_file": lib_file, "offset": offset})
# Okay
lib_file = None
offset = None
schema.validate({"lib_file": lib_file, "offset": offset})
# Not okay - offset but no lib
lib_file = "C:\lib.so"
offset = None
schema.validate({"lib_file": lib_file, "offset": offset})
schema.SchemaError: If you provide a libfile, you must also provide an offset
However, this way is not at all ideal. First off, I need to access the store lib_file value in a variable and access it inside the schema, since I'm accessing it inside offset's validation logic. Second, this is extremely ugly and bulky. It would be great if there was some way to create relations (mutually exclusive, jointly exhaustive, exclusive nor) between keys, and make a key optional or required depending on if another key exists or not:
Required_if("other_key", "this_key")
Optional_if("other_key", "this_key")
# Perhaps more complex logic could be implemented around a type of design pattern, allowing for more complicated conditions (just like with the validation itself)
Or maybe a dictionary of relationships passed to the Schema constructor:
relationships=[{schema.MUTUALLY_EXCLUSIVE: ["key1", "key2", "key3"]},
{schema.JOINTLY_EXHAUSTIVE: ["key7", "key8"]}]
This would make my code as simple as:
# Idea 1
schema = Schema({ Optional("lib_file"): Use(open),
Required_if("lib_file", "offset"): Use(lambda "offset": int(offset, 16))
})
# OR:
# Idea 2
schema = Schema({ Optional("lib_file"): Use(open),
Optional("offset"): Use(lambda "offset": int(offset, 16))
}, relationships=[{schema.EXCLUSIVE_NOR: ["offset", "lib_file"]}])
Or maybe there's already a way to do what I want that I'm not aware of?
Thanks.
I have a value that I only want to validate if a different argument is provided. Here is a simplified version of my code:
Here,
offsetis dependent onlib_file: It is required iflib_fileis provided, but it should not be provided iflib_fileis not provided - an "exclusive nor" relationship. Thus,offsetshould be validated conditionally, rather than being simply required or optional.I have figured out a quite hacky way to do this, namely:
This yields the desired effects:
However, this way is not at all ideal. First off, I need to access the store
lib_filevalue in a variable and access it inside the schema, since I'm accessing it insideoffset's validation logic. Second, this is extremely ugly and bulky. It would be great if there was some way to create relations (mutually exclusive, jointly exhaustive, exclusive nor) between keys, and make a key optional or required depending on if another key exists or not:Or maybe a dictionary of relationships passed to the
Schemaconstructor:This would make my code as simple as:
Or maybe there's already a way to do what I want that I'm not aware of?
Thanks.