Skip to content
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
13 changes: 10 additions & 3 deletions src/openapi_parser/builders/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,21 @@ def cast_value(
type_cast_func: Callable[..., Any] | None,
) -> Any:
try:
return type_cast_func(value) if type_cast_func is not None else value
if type_cast_func is not None:
return type_cast_func(value)

return value
except ValueError:
raise ParserError(
f"Invalid value for '{name}' property, got '{value}'"
f"Invalid value for '{name}' property, got '{value}'",
) from None

custom_attrs = {
attr_name: cast_value(attr_info.name, data[attr_info.name], attr_info.cast)
attr_name: cast_value(
attr_info.name,
data[attr_info.name],
attr_info.cast,
)
for attr_name, attr_info in attrs_map.items()
if data.get(attr_info.name) is not None
}
Expand Down
44 changes: 23 additions & 21 deletions src/openapi_parser/builders/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from openapi_parser.builders.encoding import EncodingBuilder
from openapi_parser.builders.schema import SchemaFactory
from openapi_parser.enumeration import ContentType
from openapi_parser.logging import log_ctx
from openapi_parser.loose_types import LooseContentType
from openapi_parser.specification import Content

Expand Down Expand Up @@ -38,13 +39,13 @@ def __init__(
self._encoding_builder = encoding_builder
self._strict_enum = strict_enum

def build_list(self, data: dict[str, Any]) -> list[Content]:
def build_list(
self,
data: dict[str, Any],
) -> list[Content]:
"""Build a list of content objects from a dict of media types."""
return [
self._create_content(
content_type,
content_value,
)
self._create_content(content_type, content_value)
for content_type, content_value in data.items()
]

Expand All @@ -53,22 +54,23 @@ def _create_content(
content_type: str,
content_value: dict[str, Any],
) -> Content:
logger.debug(f"Content building [type={content_type}]")
with log_ctx("content", content_type):
logger.debug(f"Content building [type={content_type}]")

ContentTypeCls: ContentTypeType = (
ContentType if self._strict_enum else LooseContentType
)
ContentTypeCls: ContentTypeType = (
ContentType if self._strict_enum else LooseContentType
)

encoding = (
self._encoding_builder.build_dict(content_value["encoding"])
if content_value.get("encoding")
else None
)
encoding = (
self._encoding_builder.build_dict(content_value["encoding"])
if content_value.get("encoding")
else None
)

return Content(
type=ContentTypeCls(content_type),
schema=self._schema_factory.create(content_value.get("schema", {})),
example=content_value.get("example"),
examples=content_value.get("examples", {}),
encoding=encoding,
)
return Content(
type=ContentTypeCls(content_type),
schema=self._schema_factory.create(content_value.get("schema", {})),
example=content_value.get("example"),
examples=content_value.get("examples", {}),
encoding=encoding,
)
17 changes: 12 additions & 5 deletions src/openapi_parser/builders/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
extract_typed_props,
)
from openapi_parser.builders.header import HeaderBuilder
from openapi_parser.logging import log_ctx
from openapi_parser.specification import Encoding

logger = logging.getLogger(__name__)
Expand All @@ -27,12 +28,18 @@ def __init__(self, header_builder: HeaderBuilder) -> None:
"""
self._header_builder = header_builder

def build_dict(self, data: dict[str, dict[str, Any]]) -> dict[str, Encoding]:
def build_dict(
self,
data: dict[str, dict[str, Any]],
) -> dict[str, Encoding]:
"""Build a dict of encodings from a dict of raw encoding definitions."""
return {
property_name: self._build(encoding_data)
for property_name, encoding_data in data.items()
}
result: dict[str, Encoding] = {}

for property_name, encoding_data in data.items():
with log_ctx("encoding", property_name):
result[property_name] = self._build(encoding_data)

return result

def _build(self, data: dict[str, Any]) -> Encoding:
logger.debug("Encoding building")
Expand Down
43 changes: 28 additions & 15 deletions src/openapi_parser/builders/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
extract_typed_props,
)
from openapi_parser.builders.schema import SchemaFactory
from openapi_parser.logging import log_ctx
from openapi_parser.specification import Header

logger = logging.getLogger(__name__)
Expand All @@ -27,29 +28,41 @@ def __init__(self, schema_factory: SchemaFactory) -> None:
"""
self._schema_factory = schema_factory

def build_list(self, data: dict[str, Any]) -> list[Header]:
def build_list(
self,
data: dict[str, Any],
) -> list[Header]:
"""Build a list of headers from a dict of header definitions."""
return [
self._build(header_name, header_value)
for header_name, header_value in data.items()
]

def _build(self, name: str, data: dict[str, Any]) -> Header:
logger.debug(f"Header parsing: {name}")
def _build(
self,
name: str,
data: dict[str, Any],
) -> Header:
with log_ctx("headers", name):
logger.debug(f"Header parsing: {name}")

attrs_map = {
"schema": PropertyMeta(name="schema", cast=self._schema_factory.create),
"description": PropertyMeta(name="description", cast=str),
"deprecated": PropertyMeta(name="deprecated", cast=bool),
"required": PropertyMeta(name="required", cast=bool),
}
attrs_map = {
"description": PropertyMeta(name="description", cast=str),
"deprecated": PropertyMeta(name="deprecated", cast=bool),
"required": PropertyMeta(name="required", cast=bool),
}

attrs = extract_typed_props(data, attrs_map)
attrs = extract_typed_props(data, attrs_map)

attrs["name"] = name
attrs["extensions"] = extract_extension_attributes(data)
if data.get("schema") is not None:
attrs["schema"] = self._schema_factory.create(data["schema"])

if attrs["extensions"]:
logger.debug(f"Extracted custom properties [{attrs['extensions'].keys()}]")
attrs["name"] = name
attrs["extensions"] = extract_extension_attributes(data)

return Header(**attrs)
if attrs["extensions"]:
logger.debug(
f"Extracted custom properties [{attrs['extensions'].keys()}]"
)

return Header(**attrs)
52 changes: 29 additions & 23 deletions src/openapi_parser/builders/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
extract_typed_props,
)
from openapi_parser.errors import ParserError
from openapi_parser.logging import log_ctx
from openapi_parser.specification import Contact, Info, License

logger = logging.getLogger(__name__)
Expand All @@ -19,29 +20,34 @@ class InfoBuilder:

def build(self, data: dict[str, Any]) -> Info:
"""Build an Info object from a raw dict."""
title = data.get("title")

if title is None:
raise ParserError("Info section is missing required 'title' property")

logger.debug(f"Info section parsing [title={title}]")

attrs_map = {
"title": PropertyMeta(name="title", cast=str),
"version": PropertyMeta(name="version", cast=str),
"description": PropertyMeta(name="description", cast=str),
"terms_of_service": PropertyMeta(name="termsOfService", cast=str),
"license": PropertyMeta(name="license", cast=self._create_license),
"contact": PropertyMeta(name="contact", cast=self._create_contact),
}

attrs = extract_typed_props(data, attrs_map)
attrs["extensions"] = extract_extension_attributes(data)

if attrs["extensions"]:
logger.debug(f"Extracted custom properties [{attrs['extensions'].keys()}]")

return Info(**attrs)
with log_ctx("info"):
title = data.get("title")

if title is None:
raise ParserError(
"Info section is missing required 'title' property",
)

logger.debug(f"Info section parsing [title={title}]")

attrs_map = {
"title": PropertyMeta(name="title", cast=str),
"version": PropertyMeta(name="version", cast=str),
"description": PropertyMeta(name="description", cast=str),
"terms_of_service": PropertyMeta(name="termsOfService", cast=str),
"license": PropertyMeta(name="license", cast=self._create_license),
"contact": PropertyMeta(name="contact", cast=self._create_contact),
}

attrs = extract_typed_props(data, attrs_map)
attrs["extensions"] = extract_extension_attributes(data)

if attrs["extensions"]:
logger.debug(
f"Extracted custom properties [{attrs['extensions'].keys()}]"
)

return Info(**attrs)

@staticmethod
def _create_license(data: dict[str, Any]) -> License:
Expand Down
16 changes: 12 additions & 4 deletions src/openapi_parser/builders/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
extract_extension_attributes,
extract_typed_props,
)
from openapi_parser.logging import log_ctx
from openapi_parser.specification import Link, Server

logger = logging.getLogger(__name__)
Expand All @@ -24,11 +25,18 @@ def build_server(value: dict[str, Any]) -> Server:
class LinkBuilder:
"""Builds link objects from raw specification data."""

def build_dict(self, data: dict[str, dict[str, Any]]) -> dict[str, Link]:
def build_dict(
self,
data: dict[str, dict[str, Any]],
) -> dict[str, Link]:
"""Build a dict of links from a dict of raw link definitions."""
return {
link_name: self._build(link_data) for link_name, link_data in data.items()
}
result: dict[str, Link] = {}

for link_name, link_data in data.items():
with log_ctx("links", link_name):
result[link_name] = self._build(link_data)

return result

def _build(self, data: dict[str, Any]) -> Link:
logger.debug("Link building")
Expand Down
7 changes: 5 additions & 2 deletions src/openapi_parser/builders/oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ class OAuthFlowBuilder:
"""Builds OAuth flow collections from raw specification data."""

@staticmethod
def build_collection(data: dict[str, Any]) -> dict[OAuthFlowType, OAuthFlow]:
def build_collection(
data: dict[str, Any],
) -> dict[OAuthFlowType, OAuthFlow]:
"""Build a dict of OAuthFlow objects from a raw dict."""
logger.debug(f"Parsing OAuth items collection: {data.keys()}")

Expand All @@ -45,7 +47,8 @@ def build_collection(data: dict[str, Any]) -> dict[OAuthFlowType, OAuthFlow]:

for extension in extensions:
result_oauth_dict[cast(OAuthFlowType, extension)] = cast(
OAuthFlow, extensions[extension]
OAuthFlow,
extensions[extension],
)

return result_oauth_dict
Loading
Loading