Skip to content

better unmarshaller finders with refactor #447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions openapi_core/schema/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@
from openapi_core.spec import Spec


def get_all_properties(schema: Spec) -> Dict[str, Any]:
def get_properties(schema: Spec) -> Dict[str, Any]:
properties = schema.get("properties", {})
properties_dict = dict(list(properties.items()))

if "allOf" not in schema:
return properties_dict

for subschema in schema / "allOf":
subschema_props = get_all_properties(subschema)
properties_dict.update(subschema_props)

return properties_dict
90 changes: 65 additions & 25 deletions openapi_core/unmarshalling/schemas/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Type
from typing import Union

from backports.cached_property import cached_property
from jsonschema.protocols import Validator
from openapi_schema_validator import OAS30Validator

Expand Down Expand Up @@ -41,6 +42,42 @@
from openapi_core.unmarshalling.schemas.util import build_format_checker


class SchemaValidatorsFactory:

CONTEXTS = {
UnmarshalContext.REQUEST: "write",
UnmarshalContext.RESPONSE: "read",
}

def __init__(
self,
schema_validator_class: Type[Validator],
custom_formatters: Optional[CustomFormattersDict] = None,
context: Optional[UnmarshalContext] = None,
):
self.schema_validator_class = schema_validator_class
if custom_formatters is None:
custom_formatters = {}
self.custom_formatters = custom_formatters
self.context = context

def create(self, schema: Spec) -> Validator:
resolver = schema.accessor.resolver # type: ignore
custom_format_checks = {
name: formatter.validate
for name, formatter in self.custom_formatters.items()
}
format_checker = build_format_checker(**custom_format_checks)
kwargs = {
"resolver": resolver,
"format_checker": format_checker,
}
if self.context is not None:
kwargs[self.CONTEXTS[self.context]] = True
with schema.open() as schema_dict:
return self.schema_validator_class(schema_dict, **kwargs)


class SchemaUnmarshallersFactory:

UNMARSHALLERS: Dict[str, Type[BaseSchemaUnmarshaller]] = {
Expand All @@ -60,11 +97,6 @@ class SchemaUnmarshallersFactory:
"any": AnyUnmarshaller,
}

CONTEXT_VALIDATION = {
UnmarshalContext.REQUEST: "write",
UnmarshalContext.RESPONSE: "read",
}

def __init__(
self,
schema_validator_class: Type[Validator],
Expand All @@ -77,6 +109,14 @@ def __init__(
self.custom_formatters = custom_formatters
self.context = context

@cached_property
def validators_factory(self) -> SchemaValidatorsFactory:
return SchemaValidatorsFactory(
self.schema_validator_class,
self.custom_formatters,
self.context,
)

def create(
self, schema: Spec, type_override: Optional[str] = None
) -> BaseSchemaUnmarshaller:
Expand All @@ -87,7 +127,7 @@ def create(
if schema.getkey("deprecated", False):
warnings.warn("The schema is deprecated", DeprecationWarning)

validator = self.get_validator(schema)
validator = self.validators_factory.create(schema)

schema_format = schema.getkey("format")
formatter = self.custom_formatters.get(schema_format)
Expand All @@ -97,29 +137,29 @@ def create(
schema_type, str
):
return MultiTypeUnmarshaller(
schema, validator, formatter, self, context=self.context
schema,
validator,
formatter,
self.validators_factory,
self,
context=self.context,
)
if schema_type in self.COMPLEX_UNMARSHALLERS:
complex_klass = self.COMPLEX_UNMARSHALLERS[schema_type]
return complex_klass(
schema, validator, formatter, self, context=self.context
schema,
validator,
formatter,
self.validators_factory,
self,
context=self.context,
)

klass = self.UNMARSHALLERS[schema_type]
return klass(schema, validator, formatter)

def get_validator(self, schema: Spec) -> Validator:
resolver = schema.accessor.resolver # type: ignore
custom_format_checks = {
name: formatter.validate
for name, formatter in self.custom_formatters.items()
}
format_checker = build_format_checker(**custom_format_checks)
kwargs = {
"resolver": resolver,
"format_checker": format_checker,
}
if self.context is not None:
kwargs[self.CONTEXT_VALIDATION[self.context]] = True
with schema.open() as schema_dict:
return self.schema_validator_class(schema_dict, **kwargs)
return klass(
schema,
validator,
formatter,
self.validators_factory,
self,
)
Loading