Skip to content

Feature: Support requiring anyOf a list of keys#534

Merged
alecthomas merged 3 commits intoalecthomas:masterfrom
cibernox:support-requiring-anyOf-some-keys
Dec 14, 2025
Merged

Feature: Support requiring anyOf a list of keys#534
alecthomas merged 3 commits intoalecthomas:masterfrom
cibernox:support-requiring-anyOf-some-keys

Conversation

@cibernox
Copy link
Copy Markdown
Contributor

@cibernox cibernox commented Sep 1, 2025

This adds a new feature to Voluptuous, which is somewhat akin to what json-schema does with the special key anyOf.

Schema({Required(Any('color', 'temperature', 'brightness')): object}) will validate that AT LEAST ONE of these three values is present. That doesn't preclude any individual validation on each of those fields to still apply.
That means that in the above example, if color is present, brightness doesn't need to be present. But if brightness is present, all other validations of brightness (like checking that its value is a number between 0 and 100) still apply.

This is easier to understand with an example:

    schema = Schema({
        # Validates the presence of at least one of these properties
        Required(Any("color", "temperature", "brightness")): object,

        # Validates the type of these properties when present
        Optional("color"): str,
        Optional("temperature"): int,
        Optional("brightness"): int,

        # Other props
        Optional("name"): str,
        Optional("area"): str,
        Optional("floor"): str,
    })
    
    schema({"brightness": "80", "device_id": "light1"}) # validates without errors
   
    schema({"device_id": "light1"}) # Fails the validation with: "at least one of ['color', 'temperature', 'brightness'] is required"

    schema({"brightness": "Medium", "device_id": "light1"}) # Fails because brightness is not a number, as per usual.

That schema above is equivalent in json schema to:

  {
        "type": "object",
        "properties": {
            "color": {"type": "string"},
            "temperature": {"type": "integer"},
            "brightness": {"type": "integer"},
            "name": {"type": "string"},
            "area": {"type": "string"},
            "floor": {"type": "string"},
        },
        "required": [],
        "anyOf": [
            {"required": ["color"]},
            {"required": ["temperature"]},
            {"required": ["brightness"]},
        ]
    }

Support to converting voluptuous schemas into json schema is also being added to voluptuous-openapi in home-assistant-libs/voluptuous-openapi#60

@cibernox
Copy link
Copy Markdown
Contributor Author

cibernox commented Sep 3, 2025

Is this something that you're interested in? From the readme, i'm not sure how amenable you'd be to this. I'm not sure if this qualifies as a new feature, as it's using roughly the existing building blocks to wrap in vol.Required complex keys like vol.Any.

None of the pieces is new, but it enables a new kind of validation that wasn't possible before.

@cibernox
Copy link
Copy Markdown
Contributor Author

Ping! I wanted a last check to know if this is something that can happen. It would be a shame.

Thanks.

@alecthomas
Copy link
Copy Markdown
Owner

Hey! Yep, sounds reasonable to me, thanks

Comment thread voluptuous/tests/tests.py

error_message = humanize_error(data, ctx.value)
assert "expected a dictionary" in error_message

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of tests, most of which seem redundant. Can you reduce the number of tests to the minial set please?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure thing!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I reduced que number of tests and eliminated some asserts that were kind of redundant with other ones.

There's still a fair amount of assertions but because I wanted to be thorough in that we weren't regressing in any subtle way.

This adds a new feature to Voluptuous, which is somewhat akin to what json-schema does with the special key `anyOf`.

`Schema({Required(Any('color', 'temperature', 'brightness')): str})` will validate that AT LEAST ONE of these three values is present. That doesn't preclude any individual validation on each of those fields to still apply.
That means that in the above example, if `color` is present, brightness doesn't need to be present. But if brightness is present, all other validations of brightness (like checking that its value is a number between 0 and 100) still apply.
@cibernox cibernox force-pushed the support-requiring-anyOf-some-keys branch from ff95a36 to bfb6ae6 Compare December 12, 2025 19:52
@alecthomas
Copy link
Copy Markdown
Owner

Thanks for doing that, LGTM!

@alecthomas
Copy link
Copy Markdown
Owner

BTW I know that Voluptuous is used heavily by Home Assistant, so if any developers would be interested in becoming maintainers of this repo, I'd be happy to chat about it.

@cibernox
Copy link
Copy Markdown
Contributor Author

I know someone in the HA community who might be interested in adopting it, I'll ask.

BTW, I fixed the formatting issue, CI should be green now.

@cibernox
Copy link
Copy Markdown
Contributor Author

The error in the mypy CI scenario seems to steam from pytest itself, not from this project's code. Looks like an incompatibility between certain versions of some dependencies

@alecthomas alecthomas merged commit 4cef6ce into alecthomas:master Dec 14, 2025
7 of 8 checks passed
@cibernox cibernox deleted the support-requiring-anyOf-some-keys branch December 14, 2025 20:22
@cibernox
Copy link
Copy Markdown
Contributor Author

Thank you sir 🙇

May we get a new release cut?

@cibernox
Copy link
Copy Markdown
Contributor Author

@alecthomas ping on pushing this new version to pypi 👍

@cibernox
Copy link
Copy Markdown
Contributor Author

FWIW, I brought this up with HomeAssistant / Open Home Foundation and they are going to discuss if they want / can become maintainers.

@alecthomas
Copy link
Copy Markdown
Owner

Just to be clear - I'd add them as maintainers to the GitHub project and PyPi project

@cibernox
Copy link
Copy Markdown
Contributor Author

Noted. I was just the messenger.

@spacegaier
Copy link
Copy Markdown
Collaborator

@alecthomas ping on pushing this new version to pypi 👍

I will prepare a new 0.16.0 release

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

Successfully merging this pull request may close these issues.

3 participants