Skip to content

fix: intersect OneOf and Equal choices in field2choices - #1069

Open
alexchen-sys wants to merge 2 commits into
marshmallow-code:devfrom
alexchen-sys:fix-198-field2choices-intersection
Open

fix: intersect OneOf and Equal choices in field2choices#1069
alexchen-sys wants to merge 2 commits into
marshmallow-code:devfrom
alexchen-sys:fix-198-field2choices-intersection

Conversation

@alexchen-sys

Copy link
Copy Markdown

Fixes #198

When multiple choice validators are defined on a field (such as multiple validate.OneOf, multiple validate.Equal, or a mix of OneOf and Equal), the allowed choices should be the intersection of the values allowed by each validator.

Previously:

  • validate.Equal overrode any preceding validate.OneOf choices.
  • Multiple validate.Equal validators concatenated their values rather than intersecting them.

Changes

  • Treat validate.Equal comparable values as single-element choice sets and intersect all choice sets via OrderedSet.
  • Added unit tests for multiple OneOf, OneOf + Equal, and multiple Equal validators (both intersecting and non-intersecting).

…llow-code#198)

Calculate intersection across all choice validators (both validate.OneOf and
validate.Equal) present on field.validators.

Signed-off-by: Alex Chen <l46983284@gmail.com>

@lafrech lafrech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

100+ PRs a month is a bit of a reg flag, but this PR makes sense, so...

Comment thread tests/test_ext_marshmallow_field.py Outdated
)
res = spec_fixture.openapi.field2property(field)
assert set(res["enum"]) == {"brian", "john"}
assert res["enum"] == ["brian", "john"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess the use of set here was intentional as we don't want to ensure the order.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done — reverted to set() comparison.

Comment thread tests/test_ext_marshmallow_field.py Outdated
assert res["enum"] == ["brian", "john"]


def test_field_with_choices_multiple_non_intersecting(spec_fixture):

@lafrech lafrech Aug 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd write oneof instead of choices in the test name.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Renamed.

Comment thread tests/test_ext_marshmallow_field.py Outdated
assert res["enum"] == []


def test_field_with_multiple_equal_matching(spec_fixture):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think the whole thing could be factorized in three tests:

  • multiple oneof
  • multiple equal
  • oneof and equal

using parametrization to pass inputs and expected output.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Factorized into three parametrized tests: multiple_oneof, multiple_equal, oneof_and_equal.

]
if choices:
attributes["enum"] = list(functools.reduce(operator.and_, choices))
choices = []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I've been wondering why we don't use a set here and update it in the loop.

This is probably due to a slight performance advantage doing it this way.

@lafrech
lafrech self-requested a review August 17, 2026 23:15

@lafrech lafrech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See review comments.

@alexchen-sys

Copy link
Copy Markdown
Author

Thanks for the review. Comments addressed in e485237 — set comparison restored, tests renamed to oneof, factorized into three parametrized tests.

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.

Minor issues with field2choices

2 participants