Skip to content

Commit

Permalink
nullable implementation based on clarified OAS 3.0.3 definition
Browse files Browse the repository at this point in the history
  • Loading branch information
p1c2u committed Jan 7, 2023
1 parent e213079 commit 0356b51
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 37 deletions.
43 changes: 8 additions & 35 deletions openapi_schema_validator/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,6 @@
from jsonschema.protocols import Validator


def include_nullable_validator(
schema: Dict[Hashable, Any]
) -> ItemsView[Hashable, Any]:
"""
Include ``nullable`` validator always.
Suitable for use with `create`'s ``applicable_validators`` argument.
"""
_schema = deepcopy(schema)

# append defaults to trigger nullable validator, except where $ref in the schema checks null
if "nullable" not in _schema \
and "$ref" not in _schema \
and "oneOf" not in _schema \
and "anyOf" not in _schema \
and "allOf" not in _schema:
_schema.update(
{
"nullable": False,
}
)

return _schema.items()


def handle_discriminator(
validator: Validator, _: Any, instance: Any, schema: Mapping[Hashable, Any]
) -> Iterator[ValidationError]:
Expand Down Expand Up @@ -131,7 +107,14 @@ def type(
schema: Mapping[Hashable, Any],
) -> Iterator[ValidationError]:
if instance is None:
return
# nullable implementation based on OAS 3.0.3l
# * nullable is only meaningful if its value is true
# * nullable: true is only meaningful in combination with a type
# assertion specified in the same Schema Object.
# * nullable: true operates within a single Schema Object
if "nullable" in schema and schema["nullable"] == True:
return
yield ValidationError("None for not nullable")

if not validator.is_type(instance, data_type):
data_repr = repr(data_type)
Expand Down Expand Up @@ -167,16 +150,6 @@ def items(
yield from validator.descend(item, items, path=index)


def nullable(
validator: Validator,
is_nullable: bool,
instance: Any,
schema: Mapping[Hashable, Any],
) -> Iterator[ValidationError]:
if instance is None and not is_nullable:
yield ValidationError("None for not nullable")


def required(
validator: Validator,
required: List[str],
Expand Down
2 changes: 0 additions & 2 deletions openapi_schema_validator/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
# TODO: adjust default
"$ref": _validators.ref,
# fixed OAS fields
"nullable": oas_validators.nullable,
"discriminator": oas_validators.not_implemented,
"readOnly": oas_validators.readOnly,
"writeOnly": oas_validators.writeOnly,
Expand All @@ -59,7 +58,6 @@
# See https://github.com/p1c2u/openapi-schema-validator/pull/12
# version="oas30",
id_of=lambda schema: schema.get("id", ""),
applicable_validators=oas_validators.include_nullable_validator,
)

OAS31Validator = extend(
Expand Down
27 changes: 27 additions & 0 deletions tests/integration/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ def test_null(self, schema_type):
with pytest.raises(ValidationError):
validator.validate(value)

@pytest.mark.parametrize("is_nullable", [True, False])
def test_nullable_untyped(self, is_nullable):
schema = {"nullable": is_nullable}
validator = OAS30Validator(schema)
value = None

result = validator.validate(value)

assert result is None

@pytest.mark.parametrize(
"schema_type",
[
Expand All @@ -50,6 +60,23 @@ def test_nullable(self, schema_type):

assert result is None

def test_nullable_enum_without_none(self):
schema = {"type": "integer", "nullable": True, "enum": [1, 2, 3]}
validator = OAS30Validator(schema)
value = None

with pytest.raises(ValidationError):
validator.validate(value)

def test_nullable_enum_with_none(self):
schema = {"type": "integer", "nullable": True, "enum": [1, 2, 3, None]}
validator = OAS30Validator(schema)
value = None

result = validator.validate(value)

assert result is None

@pytest.mark.parametrize(
"value",
[
Expand Down

0 comments on commit 0356b51

Please sign in to comment.