Skip to content

Commit

Permalink
Merge pull request #690 from python-openapi/feature/move-to-jsonschem…
Browse files Browse the repository at this point in the history
…a-path

Move to jsonschema-path
  • Loading branch information
p1c2u authored Oct 13, 2023
2 parents 4fac4d1 + 86f8218 commit 0abae09
Show file tree
Hide file tree
Showing 66 changed files with 424 additions and 387 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ Firstly create your specification object.

.. code-block:: python
from openapi_core import Spec
from jsonschema_path import SchemaPath
spec = Spec.from_file_path('openapi.json')
spec = SchemaPath.from_file_path('openapi.json')
Now you can use it to validate and unmarshal against requests and/or responses.

Expand Down
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ Firstly create your specification object.

.. code-block:: python
from openapi_core import Spec
from jsonschema_path import SchemaPath
spec = Spec.from_file_path('openapi.json')
spec = SchemaPath.from_file_path('openapi.json')
Now you can use it to validate and unmarshal your requests and/or responses.

Expand Down
8 changes: 4 additions & 4 deletions docs/integrations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,29 +54,29 @@ Django can be integrated by middleware. Add ``DjangoOpenAPIMiddleware`` to your
:emphasize-lines: 6,9
# settings.py
from openapi_core import Spec
from jsonschema_path import SchemaPath
MIDDLEWARE = [
# ...
'openapi_core.contrib.django.middlewares.DjangoOpenAPIMiddleware',
]
OPENAPI_SPEC = Spec.from_dict(spec_dict)
OPENAPI_SPEC = SchemaPath.from_dict(spec_dict)
You can skip response validation process: by setting ``OPENAPI_RESPONSE_CLS`` to ``None``

.. code-block:: python
:emphasize-lines: 10
# settings.py
from openapi_core import Spec
from jsonschema_path import SchemaPath
MIDDLEWARE = [
# ...
'openapi_core.contrib.django.middlewares.DjangoOpenAPIMiddleware',
]
OPENAPI_SPEC = Spec.from_dict(spec_dict)
OPENAPI_SPEC = SchemaPath.from_dict(spec_dict)
OPENAPI_RESPONSE_CLS = None
After that you have access to unmarshal result object with all validated request data from Django view through request object.
Expand Down
11 changes: 7 additions & 4 deletions openapi_core/casting/schemas/casters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
from typing import Callable
from typing import List

from jsonschema_path import SchemaPath

from openapi_core.casting.schemas.datatypes import CasterCallable
from openapi_core.casting.schemas.exceptions import CastError
from openapi_core.spec import Spec

if TYPE_CHECKING:
from openapi_core.casting.schemas.factories import SchemaCastersFactory


class BaseSchemaCaster:
def __init__(self, schema: Spec):
def __init__(self, schema: SchemaPath):
self.schema = schema

def __call__(self, value: Any) -> Any:
Expand All @@ -26,7 +27,7 @@ def cast(self, value: Any) -> Any:


class CallableSchemaCaster(BaseSchemaCaster):
def __init__(self, schema: Spec, caster_callable: CasterCallable):
def __init__(self, schema: SchemaPath, caster_callable: CasterCallable):
super().__init__(schema)
self.caster_callable = caster_callable

Expand All @@ -43,7 +44,9 @@ def cast(self, value: Any) -> Any:


class ComplexCaster(BaseSchemaCaster):
def __init__(self, schema: Spec, casters_factory: "SchemaCastersFactory"):
def __init__(
self, schema: SchemaPath, casters_factory: "SchemaCastersFactory"
):
super().__init__(schema)
self.casters_factory = casters_factory

Expand Down
5 changes: 3 additions & 2 deletions openapi_core/casting/schemas/factories.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from typing import Dict

from jsonschema_path import SchemaPath

from openapi_core.casting.schemas.casters import ArrayCaster
from openapi_core.casting.schemas.casters import BaseSchemaCaster
from openapi_core.casting.schemas.casters import CallableSchemaCaster
from openapi_core.casting.schemas.casters import DummyCaster
from openapi_core.casting.schemas.datatypes import CasterCallable
from openapi_core.spec import Spec
from openapi_core.util import forcebool


Expand All @@ -24,7 +25,7 @@ class SchemaCastersFactory:
"array": ArrayCaster,
}

def create(self, schema: Spec) -> BaseSchemaCaster:
def create(self, schema: SchemaPath) -> BaseSchemaCaster:
schema_type = schema.getkey("type", "any")

if schema_type in self.DUMMY_CASTERS:
Expand Down
6 changes: 3 additions & 3 deletions openapi_core/contrib/falcon/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

from falcon.request import Request
from falcon.response import Response
from jsonschema_path import SchemaPath

from openapi_core.contrib.falcon.handlers import FalconOpenAPIErrorsHandler
from openapi_core.contrib.falcon.handlers import (
FalconOpenAPIValidRequestHandler,
)
from openapi_core.contrib.falcon.requests import FalconOpenAPIRequest
from openapi_core.contrib.falcon.responses import FalconOpenAPIResponse
from openapi_core.spec import Spec
from openapi_core.unmarshalling.processors import UnmarshallingProcessor
from openapi_core.unmarshalling.request.types import RequestUnmarshallerType
from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType
Expand All @@ -28,7 +28,7 @@ class FalconOpenAPIMiddleware(UnmarshallingProcessor[Request, Response]):

def __init__(
self,
spec: Spec,
spec: SchemaPath,
request_unmarshaller_cls: Optional[RequestUnmarshallerType] = None,
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
Expand All @@ -51,7 +51,7 @@ def __init__(
@classmethod
def from_spec(
cls,
spec: Spec,
spec: SchemaPath,
request_unmarshaller_cls: Optional[RequestUnmarshallerType] = None,
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
request_cls: Type[FalconOpenAPIRequest] = FalconOpenAPIRequest,
Expand Down
6 changes: 3 additions & 3 deletions openapi_core/contrib/flask/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
from flask.globals import request
from flask.wrappers import Request
from flask.wrappers import Response
from jsonschema_path import SchemaPath

from openapi_core.contrib.flask.handlers import FlaskOpenAPIErrorsHandler
from openapi_core.contrib.flask.handlers import FlaskOpenAPIValidRequestHandler
from openapi_core.contrib.flask.providers import FlaskRequestProvider
from openapi_core.contrib.flask.requests import FlaskOpenAPIRequest
from openapi_core.contrib.flask.responses import FlaskOpenAPIResponse
from openapi_core.spec import Spec
from openapi_core.unmarshalling.processors import UnmarshallingProcessor
from openapi_core.unmarshalling.request.types import RequestUnmarshallerType
from openapi_core.unmarshalling.response.types import ResponseUnmarshallerType
Expand All @@ -28,7 +28,7 @@ class FlaskOpenAPIViewDecorator(UnmarshallingProcessor[Request, Response]):

def __init__(
self,
spec: Spec,
spec: SchemaPath,
request_unmarshaller_cls: Optional[RequestUnmarshallerType] = None,
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
request_cls: Type[FlaskOpenAPIRequest] = FlaskOpenAPIRequest,
Expand Down Expand Up @@ -85,7 +85,7 @@ def _validate_response(self) -> bool:
@classmethod
def from_spec(
cls,
spec: Spec,
spec: SchemaPath,
request_unmarshaller_cls: Optional[RequestUnmarshallerType] = None,
response_unmarshaller_cls: Optional[ResponseUnmarshallerType] = None,
request_cls: Type[FlaskOpenAPIRequest] = FlaskOpenAPIRequest,
Expand Down
4 changes: 2 additions & 2 deletions openapi_core/contrib/flask/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
from typing import Any

from flask.views import MethodView
from jsonschema_path import SchemaPath

from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator
from openapi_core.contrib.flask.handlers import FlaskOpenAPIErrorsHandler
from openapi_core.spec import Spec


class FlaskOpenAPIView(MethodView):
"""Brings OpenAPI specification validation and unmarshalling for views."""

openapi_errors_handler = FlaskOpenAPIErrorsHandler

def __init__(self, spec: Spec, **unmarshaller_kwargs: Any):
def __init__(self, spec: SchemaPath, **unmarshaller_kwargs: Any):
super().__init__()

self.decorator = FlaskOpenAPIViewDecorator(
Expand Down
5 changes: 3 additions & 2 deletions openapi_core/deserializing/styles/deserializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
from typing import List
from typing import Optional

from jsonschema_path import SchemaPath

from openapi_core.deserializing.exceptions import DeserializeError
from openapi_core.deserializing.styles.datatypes import DeserializerCallable
from openapi_core.deserializing.styles.exceptions import (
EmptyQueryParameterValue,
)
from openapi_core.schema.parameters import get_aslist
from openapi_core.schema.parameters import get_explode
from openapi_core.spec import Spec


class CallableStyleDeserializer:
def __init__(
self,
param_or_header: Spec,
param_or_header: SchemaPath,
style: str,
deserializer_callable: Optional[DeserializerCallable] = None,
):
Expand Down
5 changes: 3 additions & 2 deletions openapi_core/deserializing/styles/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from functools import partial
from typing import Dict

from jsonschema_path import SchemaPath

from openapi_core.deserializing.styles.datatypes import DeserializerCallable
from openapi_core.deserializing.styles.deserializers import (
CallableStyleDeserializer,
)
from openapi_core.deserializing.styles.util import split
from openapi_core.schema.parameters import get_style
from openapi_core.spec import Spec


class StyleDeserializersFactory:
Expand All @@ -20,7 +21,7 @@ class StyleDeserializersFactory:
"deepObject": partial(re.split, pattern=r"\[|\]"),
}

def create(self, param_or_header: Spec) -> CallableStyleDeserializer:
def create(self, param_or_header: SchemaPath) -> CallableStyleDeserializer:
style = get_style(param_or_header)

deserialize_callable = self.STYLE_DESERIALIZERS.get(style)
Expand Down
9 changes: 5 additions & 4 deletions openapi_core/extensions/models/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@
from typing import Optional
from typing import Type

from jsonschema_path import SchemaPath

from openapi_core.extensions.models.types import Field
from openapi_core.spec import Spec


class DictFactory:
base_class = dict

def create(
self, schema: Spec, fields: Iterable[Field]
self, schema: SchemaPath, fields: Iterable[Field]
) -> Type[Dict[Any, Any]]:
return self.base_class


class ModelFactory(DictFactory):
def create(
self,
schema: Spec,
schema: SchemaPath,
fields: Iterable[Field],
) -> Type[Any]:
name = schema.getkey("x-model")
Expand All @@ -37,7 +38,7 @@ def create(
class ModelPathFactory(ModelFactory):
def create(
self,
schema: Spec,
schema: SchemaPath,
fields: Iterable[Field],
) -> Any:
model_class_path = schema.getkey("x-model-path")
Expand Down
5 changes: 3 additions & 2 deletions openapi_core/finders.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from typing import Optional
from typing import Type

from jsonschema_path import SchemaPath

from openapi_core.exceptions import SpecError
from openapi_core.spec import Spec
from openapi_core.unmarshalling.request.types import RequestUnmarshallerType
from openapi_core.unmarshalling.request.types import (
WebhookRequestUnmarshallerType,
Expand Down Expand Up @@ -42,7 +43,7 @@ class SpecFinder:
def __init__(self, specs: Mapping[SpecVersion, SpecClasses]) -> None:
self.specs = specs

def get_classes(self, spec: Spec) -> SpecClasses:
def get_classes(self, spec: SchemaPath) -> SpecClasses:
for v, classes in self.specs.items():
if v.name in spec and spec[v.name].startswith(v.version):
return classes
Expand Down
9 changes: 5 additions & 4 deletions openapi_core/schema/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
from typing import Mapping
from typing import Optional

from jsonschema_path import SchemaPath

from openapi_core.schema.protocols import SuportsGetAll
from openapi_core.schema.protocols import SuportsGetList
from openapi_core.spec import Spec


def get_aslist(param_or_header: Spec) -> bool:
def get_aslist(param_or_header: SchemaPath) -> bool:
"""Checks if parameter/header is described as list for simpler scenarios"""
# if schema is not defined it's a complex scenario
if "schema" not in param_or_header:
Expand All @@ -21,7 +22,7 @@ def get_aslist(param_or_header: Spec) -> bool:
return schema_type in ["array", "object"]


def get_style(param_or_header: Spec) -> str:
def get_style(param_or_header: SchemaPath) -> str:
"""Checks parameter/header style for simpler scenarios"""
if "style" in param_or_header:
assert isinstance(param_or_header["style"], str)
Expand All @@ -34,7 +35,7 @@ def get_style(param_or_header: Spec) -> str:
return "simple" if location in ["path", "header"] else "form"


def get_explode(param_or_header: Spec) -> bool:
def get_explode(param_or_header: SchemaPath) -> bool:
"""Checks parameter/header explode for simpler scenarios"""
if "explode" in param_or_header:
assert isinstance(param_or_header["explode"], bool)
Expand Down
4 changes: 2 additions & 2 deletions openapi_core/schema/schemas.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import Any
from typing import Dict

from openapi_core.spec import Spec
from jsonschema_path import SchemaPath


def get_properties(schema: Spec) -> Dict[str, Any]:
def get_properties(schema: SchemaPath) -> Dict[str, Any]:
properties = schema.get("properties", {})
properties_dict = dict(list(properties.items()))
return properties_dict
6 changes: 3 additions & 3 deletions openapi_core/schema/servers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from typing import Any
from typing import Dict

from openapi_core.spec import Spec
from jsonschema_path import SchemaPath


def is_absolute(url: str) -> bool:
return url.startswith("//") or "://" in url


def get_server_default_variables(server: Spec) -> Dict[str, Any]:
def get_server_default_variables(server: SchemaPath) -> Dict[str, Any]:
if "variables" not in server:
return {}

Expand All @@ -19,7 +19,7 @@ def get_server_default_variables(server: Spec) -> Dict[str, Any]:
return defaults


def get_server_url(server: Spec, **variables: Any) -> str:
def get_server_url(server: SchemaPath, **variables: Any) -> str:
if not variables:
variables = get_server_default_variables(server)
assert isinstance(server["url"], str)
Expand Down
5 changes: 3 additions & 2 deletions openapi_core/schema/specs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from jsonschema_path import SchemaPath

from openapi_core.schema.servers import get_server_url
from openapi_core.spec import Spec


def get_spec_url(spec: Spec, index: int = 0) -> str:
def get_spec_url(spec: SchemaPath, index: int = 0) -> str:
servers = spec / "servers"
return get_server_url(servers / 0)
Loading

0 comments on commit 0abae09

Please sign in to comment.