Skip to content

Commit

Permalink
Dataclasses refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
p1c2u committed May 24, 2021
1 parent e9e43eb commit 251b972
Show file tree
Hide file tree
Showing 18 changed files with 106 additions and 72 deletions.
14 changes: 9 additions & 5 deletions openapi_core/contrib/django/requests.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""OpenAPI core contrib django requests module"""
import re

from urllib.parse import urljoin

from werkzeug.datastructures import ImmutableMultiDict, Headers

from openapi_core.contrib.django.compat import (
get_request_headers, get_current_scheme_host,
)
Expand Down Expand Up @@ -43,13 +44,16 @@ def create(cls, request):
route = route[:-1]
path_pattern = '/' + route

request_headers = get_request_headers(request)
path = request.resolver_match and request.resolver_match.kwargs or {}
headers = get_request_headers(request)
query = ImmutableMultiDict(request.GET)
header = Headers(request_headers.items())
cookie = ImmutableMultiDict(dict(request.COOKIES))
parameters = RequestParameters(
path=path,
query=request.GET,
header=list(headers.items()),
cookie=request.COOKIES,
query=query,
header=header,
cookie=cookie,
)
current_scheme_host = get_current_scheme_host(request)
full_url_pattern = urljoin(current_scheme_host, path_pattern)
Expand Down
5 changes: 4 additions & 1 deletion openapi_core/contrib/django/responses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""OpenAPI core contrib django responses module"""
from werkzeug.datastructures import Headers

from openapi_core.contrib.django.compat import get_response_headers
from openapi_core.validation.response.datatypes import OpenAPIResponse

Expand All @@ -9,9 +11,10 @@ class DjangoOpenAPIResponseFactory:
def create(cls, response):
mimetype = response["Content-Type"]
headers = get_response_headers(response)
header = Headers(headers.items())
return OpenAPIResponse(
data=response.content,
status_code=response.status_code,
headers=list(headers.items()),
headers=header,
mimetype=mimetype,
)
5 changes: 3 additions & 2 deletions openapi_core/contrib/falcon/requests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""OpenAPI core contrib falcon responses module"""
from json import dumps

from werkzeug.datastructures import ImmutableMultiDict
from werkzeug.datastructures import ImmutableMultiDict, Headers

from openapi_core.contrib.falcon.compat import get_request_media
from openapi_core.validation.request.datatypes import (
Expand Down Expand Up @@ -29,11 +29,12 @@ def create(cls, request, default_when_empty={}):
mimetype = request.content_type.partition(";")[0]

query = ImmutableMultiDict(list(request.params.items()))
header = Headers(request.headers)

# Path gets deduced by path finder against spec
parameters = RequestParameters(
query=query,
header=request.headers,
header=header,
cookie=request.cookies,
)
url_pattern = request.prefix + request.path
Expand Down
5 changes: 4 additions & 1 deletion openapi_core/contrib/falcon/responses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""OpenAPI core contrib falcon responses module"""
from werkzeug.datastructures import Headers

from openapi_core.contrib.falcon.compat import get_response_text
from openapi_core.validation.response.datatypes import OpenAPIResponse

Expand All @@ -15,10 +17,11 @@ def create(cls, response):
mimetype = response.options.default_media_type

data = get_response_text(response)
headers = Headers(response.headers)

return OpenAPIResponse(
data=data,
status_code=status_code,
headers=response.headers,
headers=headers,
mimetype=mimetype,
)
6 changes: 4 additions & 2 deletions openapi_core/contrib/flask/requests.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""OpenAPI core contrib flask requests module"""
import re

from urllib.parse import urljoin

from werkzeug.datastructures import Headers

from openapi_core.validation.request.datatypes import (
RequestParameters, OpenAPIRequest,
)
Expand All @@ -24,10 +25,11 @@ def create(cls, request):
else:
path_pattern = cls.path_regex.sub(r'{\1}', request.url_rule.rule)

header = Headers(request.headers)
parameters = RequestParameters(
path=request.view_args,
query=request.args,
header=request.headers,
header=header,
cookie=request.cookies,
)
full_url_pattern = urljoin(request.host_url, path_pattern)
Expand Down
5 changes: 4 additions & 1 deletion openapi_core/contrib/flask/responses.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
"""OpenAPI core contrib flask responses module"""
from werkzeug.datastructures import Headers

from openapi_core.validation.response.datatypes import OpenAPIResponse


class FlaskOpenAPIResponseFactory:

@classmethod
def create(cls, response):
header = Headers(response.headers)
return OpenAPIResponse(
data=response.data,
status_code=response._status_code,
headers=response.headers,
headers=header,
mimetype=response.mimetype,
)
6 changes: 3 additions & 3 deletions openapi_core/contrib/requests/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from urllib.parse import urlparse, parse_qs

from werkzeug.datastructures import ImmutableMultiDict
from werkzeug.datastructures import ImmutableMultiDict, Headers
from requests import Request

from openapi_core.validation.request.datatypes import (
Expand Down Expand Up @@ -43,9 +43,9 @@ def create(cls, request):
mimetype = request.headers.get('Content-Type') or \
request.headers.get('Accept')

# Headers - request.headers is not an instance of dict
# Headers - request.headers is not an instance of Headers
# which is expected
header = dict(request.headers)
header = Headers(dict(request.headers))

# Body
# TODO: figure out if request._body_position is relevant
Expand Down
4 changes: 3 additions & 1 deletion openapi_core/contrib/requests/responses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""OpenAPI core contrib requests responses module"""
from werkzeug.datastructures import Headers

from openapi_core.validation.response.datatypes import OpenAPIResponse


Expand All @@ -7,7 +9,7 @@ class RequestsOpenAPIResponseFactory:
@classmethod
def create(cls, response):
mimetype = response.headers.get('Content-Type')
headers = dict(response.headers)
headers = Headers(dict(response.headers))
return OpenAPIResponse(
data=response.content,
status_code=response.status_code,
Expand Down
17 changes: 11 additions & 6 deletions openapi_core/testing/requests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""OpenAPI core testing requests module"""
from urllib.parse import urljoin

from werkzeug.datastructures import ImmutableMultiDict
from werkzeug.datastructures import Headers, ImmutableMultiDict

from openapi_core.validation.request.datatypes import (
RequestParameters, OpenAPIRequest,
Expand All @@ -15,13 +15,18 @@ def create(
cls, host_url, method, path, path_pattern=None, args=None,
view_args=None, headers=None, cookies=None, data=None,
mimetype='application/json'):
path_pattern = path_pattern or path

path = view_args or {}
query = ImmutableMultiDict(args or {})
header = Headers(headers or {})
cookie = ImmutableMultiDict(cookies or {})
parameters = RequestParameters(
path=view_args or {},
query=ImmutableMultiDict(args or []),
header=headers or {},
cookie=cookies or {},
path=path,
query=query,
header=header,
cookie=cookie,
)
path_pattern = path_pattern or path
method = method.lower()
body = data or ''
full_url_pattern = urljoin(host_url, path_pattern)
Expand Down
5 changes: 4 additions & 1 deletion openapi_core/testing/responses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""OpenAPI core testing responses module"""
from werkzeug.datastructures import Headers

from openapi_core.validation.response.datatypes import OpenAPIResponse


Expand All @@ -8,9 +10,10 @@ class MockResponseFactory:
def create(
cls, data, status_code=200, headers=None,
mimetype='application/json'):
headers = Headers(headers or {})
return OpenAPIResponse(
data=data,
status_code=status_code,
headers=headers or {},
headers=headers,
mimetype=mimetype,
)
8 changes: 5 additions & 3 deletions openapi_core/validation/datatypes.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""OpenAPI core validation datatypes module"""
import attr
from typing import List

from dataclasses import dataclass

@attr.s

@dataclass
class BaseValidationResult:
errors = attr.ib(factory=list)
errors: List[Exception]

def raise_for_errors(self):
for error in self.errors:
Expand Down
39 changes: 19 additions & 20 deletions openapi_core/validation/request/datatypes.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""OpenAPI core validation request datatypes module"""
import attr
from typing import Dict, Optional

from dataclasses import dataclass, field
from werkzeug.datastructures import ImmutableMultiDict, Headers

from openapi_core.validation.datatypes import BaseValidationResult


@attr.s
@dataclass
class RequestParameters:
"""OpenAPI request parameters dataclass.
Expand All @@ -15,20 +17,20 @@ class RequestParameters:
header
Request headers as Headers.
cookie
Request cookies as dict.
Request cookies as MultiDict.
path
Path parameters as dict. Gets resolved against spec if empty.
"""
query = attr.ib(factory=ImmutableMultiDict)
header = attr.ib(factory=Headers, converter=Headers)
cookie = attr.ib(factory=dict)
path = attr.ib(factory=dict)
query: ImmutableMultiDict = field(default_factory=ImmutableMultiDict)
header: Headers = field(default_factory=Headers)
cookie: ImmutableMultiDict = field(default_factory=ImmutableMultiDict)
path: Dict = field(default_factory=dict)

def __getitem__(self, location):
return getattr(self, location)


@attr.s
@dataclass
class OpenAPIRequest:
"""OpenAPI request dataclass.
Expand All @@ -51,18 +53,15 @@ class OpenAPIRequest:
the mimetype would be "text/html".
"""

full_url_pattern = attr.ib()
method = attr.ib()
body = attr.ib()
mimetype = attr.ib()
parameters = attr.ib(factory=RequestParameters)
full_url_pattern: str
method: str
body: str
mimetype: str
parameters: RequestParameters = field(default_factory=RequestParameters)


@attr.s
@dataclass
class RequestValidationResult(BaseValidationResult):
body = attr.ib(default=None)
parameters = attr.ib(factory=RequestParameters)
security = attr.ib(default=None)
server = attr.ib(default=None)
path = attr.ib(default=None)
operation = attr.ib(default=None)
body: Optional[str] = None
parameters: RequestParameters = field(default_factory=RequestParameters)
security: Dict[str, str] = None
19 changes: 10 additions & 9 deletions openapi_core/validation/response/datatypes.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""OpenAPI core validation response datatypes module"""
import attr
from typing import Dict, Optional
from dataclasses import dataclass, field
from werkzeug.datastructures import Headers

from openapi_core.validation.datatypes import BaseValidationResult


@attr.s
@dataclass
class OpenAPIResponse:
"""OpenAPI request dataclass.
Expand All @@ -19,13 +20,13 @@ class OpenAPIResponse:
mimetype
Lowercase content type without charset.
"""
data = attr.ib()
status_code = attr.ib()
mimetype = attr.ib()
headers = attr.ib(factory=Headers, converter=Headers)
data: str
status_code: int
mimetype: str
headers: Headers = field(default_factory=Headers)


@attr.s
@dataclass
class ResponseValidationResult(BaseValidationResult):
data = attr.ib(default=None)
headers = attr.ib(factory=dict)
data: Optional[str] = None
headers: Dict = field(default_factory=dict)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ openapi-schema-validator
attrs
parse==1.14.0
more-itertools>=5.0.0
dataclasses==0.8; python_version=="3.6"
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ install_requires =
werkzeug
parse
more-itertools
dataclasses; python_version=="3.6"
tests_require =
pytest>=5.0.0
pytest-flake8
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/contrib/flask/test_flask_requests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from urllib.parse import urljoin

from werkzeug.datastructures import EnvironHeaders, ImmutableMultiDict
from werkzeug.datastructures import Headers, ImmutableMultiDict

from openapi_core.contrib.flask import FlaskOpenAPIRequest
from openapi_core.validation.request.datatypes import RequestParameters
Expand All @@ -15,7 +15,7 @@ def test_simple(self, request_factory, request):

path = {}
query = ImmutableMultiDict([])
headers = EnvironHeaders(request.environ)
headers = Headers(request.headers)
cookies = {}
assert openapi_request.parameters == RequestParameters(
path=path,
Expand All @@ -39,7 +39,7 @@ def test_multiple_values(self, request_factory, request):
query = ImmutableMultiDict([
('a', 'b'), ('a', 'c'),
])
headers = EnvironHeaders(request.environ)
headers = Headers(request.headers)
cookies = {}
assert openapi_request.parameters == RequestParameters(
path=path,
Expand All @@ -60,7 +60,7 @@ def test_url_rule(self, request_factory, request):

path = {'id': 12}
query = ImmutableMultiDict([])
headers = EnvironHeaders(request.environ)
headers = Headers(request.headers)
cookies = {}
assert openapi_request.parameters == RequestParameters(
path=path,
Expand Down
Loading

0 comments on commit 251b972

Please sign in to comment.