diff --git a/src/openapi_parser/builders/schema.py b/src/openapi_parser/builders/schema.py index efc5dbf..fcb60ba 100644 --- a/src/openapi_parser/builders/schema.py +++ b/src/openapi_parser/builders/schema.py @@ -139,6 +139,7 @@ def __init__(self, strict_enum: bool = True) -> None: def create(self, data: dict[str, Any]) -> Schema: """Create a schema object from a raw dict.""" data = merge_all_of_schemas(data) + not_data = data.pop("not", None) if "oneOf" in data: data["type"] = DataType.ONE_OF @@ -166,7 +167,12 @@ def create(self, data: dict[str, Any]) -> Schema: logger.debug(f"Building schema [type={data_type}]") - return builder_func(data) + schema = builder_func(data) + + if not_data is not None: + schema.not_schema = self.create(not_data) + + return schema def _null(self, data: dict[str, Any]) -> Null: return Null(**extract_attrs(data, {})) diff --git a/src/openapi_parser/specification.py b/src/openapi_parser/specification.py index f277dc1..892a6cb 100644 --- a/src/openapi_parser/specification.py +++ b/src/openapi_parser/specification.py @@ -94,13 +94,9 @@ class Schema: read_only: bool | None = field(default=False) write_only: bool | None = field(default=False) deprecated: bool | None = field(default=False) + not_schema: Schema | None = None extensions: dict[str, Any] | None = field(default_factory=dict) - # all_of: Any # TODO - # one_of: Any # TODO - # any_of: Any # TODO - # not: Any # TODO - @dataclass class Integer(Schema): diff --git a/tests/builders/test_not.py b/tests/builders/test_not.py new file mode 100644 index 0000000..0abf158 --- /dev/null +++ b/tests/builders/test_not.py @@ -0,0 +1,75 @@ +from typing import Any + +import pytest + +from openapi_parser.builders.schema import SchemaFactory +from openapi_parser.enumeration import DataType +from openapi_parser.specification import ( + AnyOf, + Array, + Boolean, + Integer, + Number, + Object, + Property, + Schema, + String, +) + +data_provider = ( + ( + { + "type": "string", + "not": {"type": "integer"}, + }, + String( + type=DataType.STRING, + not_schema=Integer(type=DataType.INTEGER), + ), + ), + ( + { + "type": "object", + "properties": { + "name": {"type": "string"}, + }, + "not": {"type": "integer"}, + }, + Object( + type=DataType.OBJECT, + properties=[ + Property(name="name", schema=String(type=DataType.STRING)), + ], + not_schema=Integer(type=DataType.INTEGER), + ), + ), + ( + { + "not": {"type": "integer"}, + }, + AnyOf( + type=DataType.ANY_OF, + schemas=[ + Integer(type=DataType.INTEGER), + Number(type=DataType.NUMBER), + String(type=DataType.STRING), + Boolean(type=DataType.BOOLEAN), + Array(type=DataType.ARRAY), + Object(type=DataType.OBJECT), + ], + not_schema=Integer(type=DataType.INTEGER), + ), + ), + ( + { + "type": "string", + }, + String(type=DataType.STRING), + ), +) + + +@pytest.mark.parametrize(["data", "expected"], data_provider) +def test_not_builder(data: dict[str, Any], expected: Schema) -> None: + factory = SchemaFactory() + assert expected == factory.create(data) diff --git a/tests/data/swagger.yml b/tests/data/swagger.yml index c72775f..8e711c0 100644 --- a/tests/data/swagger.yml +++ b/tests/data/swagger.yml @@ -120,6 +120,8 @@ components: allowReserved: true schema: type: integer + not: + type: string Offset: name: offset diff --git a/tests/openapi_fixture.py b/tests/openapi_fixture.py index 961f1ad..ae0b03e 100644 --- a/tests/openapi_fixture.py +++ b/tests/openapi_fixture.py @@ -341,7 +341,10 @@ def create_specification() -> Specification: style=QueryParameterStyle.FORM, allow_reserved=True, example=10, - schema=Integer(type=DataType.INTEGER), + schema=Integer( + type=DataType.INTEGER, + not_schema=String(type=DataType.STRING), + ), ), Parameter( name="offset",