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

Conditional Validation #325

Open
HorridModz opened this issue Aug 24, 2024 · 1 comment
Open

Conditional Validation #325

HorridModz opened this issue Aug 24, 2024 · 1 comment

Comments

@HorridModz
Copy link

HorridModz commented Aug 24, 2024

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.

@mutricyl
Copy link

mutricyl commented Aug 25, 2024

Can you change your input data logic ?

If your input data was coming this way :

{'lib_file': {'path': "C:\lib.so", 'offset': "0xFFF"}}

it would be much easier to validate with schema

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