diff --git a/src/apispec/ext/marshmallow/field_converter.py b/src/apispec/ext/marshmallow/field_converter.py index 527fa9da..6fd76a63 100644 --- a/src/apispec/ext/marshmallow/field_converter.py +++ b/src/apispec/ext/marshmallow/field_converter.py @@ -242,21 +242,14 @@ def field2choices( """ attributes = {} - comparable = [ - validator.comparable - for validator in field.validators - if hasattr(validator, "comparable") - ] - if comparable: - attributes["enum"] = comparable - else: - choices = [ - OrderedSet(validator.choices) - for validator in field.validators - if hasattr(validator, "choices") - ] - if choices: - attributes["enum"] = list(functools.reduce(operator.and_, choices)) + choices = [] + for validator in field.validators: + if hasattr(validator, "choices"): + choices.append(OrderedSet(validator.choices)) + elif hasattr(validator, "comparable"): + choices.append(OrderedSet([validator.comparable])) + if choices: + attributes["enum"] = list(functools.reduce(operator.and_, choices)) if field.allow_none: enum = attributes.get("enum") diff --git a/tests/test_ext_marshmallow_field.py b/tests/test_ext_marshmallow_field.py index dfe16311..eddb89e9 100644 --- a/tests/test_ext_marshmallow_field.py +++ b/tests/test_ext_marshmallow_field.py @@ -190,15 +190,79 @@ def test_only_allows_valid_properties_in_metadata(spec_fixture): assert "not_valid" not in res -def test_field_with_choices_multiple(spec_fixture): - field = fields.Str( - validate=[ - validate.OneOf(["freddie", "brian", "john"]), - validate.OneOf(["brian", "john", "roger"]), - ] - ) +@pytest.mark.parametrize( + ("validators", "expected_enum"), + [ + ( + [ + validate.OneOf(["freddie", "brian", "john"]), + validate.OneOf(["brian", "john", "roger"]), + ], + {"brian", "john"}, + ), + ( + [ + validate.OneOf(["freddie", "brian"]), + validate.OneOf(["john", "roger"]), + ], + set(), + ), + ], +) +def test_field_with_multiple_oneof(spec_fixture, validators, expected_enum): + field = fields.Str(validate=validators) + res = spec_fixture.openapi.field2property(field) + assert set(res["enum"]) == expected_enum + + +@pytest.mark.parametrize( + ("validators", "expected_enum"), + [ + ( + [ + validate.Equal("brian"), + validate.Equal("brian"), + ], + {"brian"}, + ), + ( + [ + validate.Equal("freddie"), + validate.Equal("brian"), + ], + set(), + ), + ], +) +def test_field_with_multiple_equal(spec_fixture, validators, expected_enum): + field = fields.Str(validate=validators) + res = spec_fixture.openapi.field2property(field) + assert set(res["enum"]) == expected_enum + + +@pytest.mark.parametrize( + ("validators", "expected_enum"), + [ + ( + [ + validate.OneOf(["freddie", "brian", "john"]), + validate.Equal("brian"), + ], + {"brian"}, + ), + ( + [ + validate.OneOf(["freddie", "brian"]), + validate.Equal("john"), + ], + set(), + ), + ], +) +def test_field_with_oneof_and_equal(spec_fixture, validators, expected_enum): + field = fields.Str(validate=validators) res = spec_fixture.openapi.field2property(field) - assert set(res["enum"]) == {"brian", "john"} + assert set(res["enum"]) == expected_enum def test_field_with_additional_metadata(spec_fixture):