Skip to content

Commit

Permalink
add multiple return types
Browse files Browse the repository at this point in the history
  • Loading branch information
tmeiczin committed Aug 30, 2024
1 parent c12bc49 commit 9181c2c
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 39 deletions.
3 changes: 2 additions & 1 deletion example/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def main():

args = parser.parse_args()
middleware = [auth]
middleware = []
if args.config:
config = load_config(args.config)
for k, v in config.items():
Expand All @@ -81,7 +82,7 @@ def main():
version="1.0.0",
desc="Example API",
title="Reliqua Example",
loglevel="debug",
loglevel="info",
middleware=middleware,
license="3-Clause BSD License",
license_url="https://opensource.org/license/bsd-3-clause",
Expand Down
13 changes: 7 additions & 6 deletions example/resources/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ def on_get_by_id(self, _req, resp, id=None):
"""
Return a user.
:param str id: [in=path, required] User ID
:response 200 user: User was retrieved
:response 400: Invalid query parameter
:param str id: [in=path, required] User ID
:response 200 user: User was retrieved
:response 400: Invalid query parameter
:return json:
:return [json,xml]:
"""
try:
resp.media = users[int(id)]
Expand Down Expand Up @@ -104,10 +104,10 @@ def on_get(self, req, resp):
:param str username: [in=query] Username
:param str email: [in=query [email protected]] Email
:param list[int] ids: [in=query] List of IDs
:response 200 users: Users were retrieved
:response 401: Invalid Authorization
:return json:
:return [json xml]: Return JSON of users
"""
results = []
p = req.params
Expand All @@ -131,6 +131,7 @@ def on_post(self, req, resp):
:param str email: [in=body required=true] Email
:param object config: [in=body] Configuration data
:accepts [json xml]: The body content type
:return json:
"""
p = req.params
Expand Down
2 changes: 1 addition & 1 deletion src/reliqua/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def __init__(
"workers": 5,
"api_url": None,
"resource_path": "resource",
"loglevel": "info",
"loglevel": "critical",
}

api_url = api_url or options["api_url"]
Expand Down
57 changes: 35 additions & 22 deletions src/reliqua/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def camelcase(string):
"json": "application/json",
"yaml": "application/yaml",
"xml": "application/xml",
"gzip": "application/gzip",
"html": "text/html; charset=utf-8",
"text": "text/plain; charset=utf-8",
"jpeg": "image/jpeg",
Expand All @@ -32,6 +33,9 @@ def camelcase(string):
}


BINARY_TYPES = ["binary", "gzip", "jpeg", "gif"]


TYPE_MAP = {
"str": "string",
"int": "integer",
Expand Down Expand Up @@ -235,7 +239,8 @@ def __init__(self, code=None, description=None, content=None, schema=None):
"""
self.code = code
self.description = description
self.content = content or "application/json"
self.content = content
print(f"RESPONSE ===> {content}")
self.schema = schema if schema else "default_response"

def __repr__(self):
Expand All @@ -244,9 +249,13 @@ def __repr__(self):

def dict(self):
"""Return dict of data."""
content_types = [CONTENT_MAP.get(x) for x in self.content]
schema = {"$ref": f"#/components/schemas/{self.schema}"}
content = {x: schema for x in content_types}

return {
"description": self.description,
"content": {self.content: {"schema": {"$ref": f"#/components/schemas/{self.schema}"}}},
"content": content,
}


Expand All @@ -263,34 +272,39 @@ def __init__(
tags=None,
responses=None,
callbacks=None,
return_type=None,
return_types=None,
accepts=None,
**_kwargs,
):
"""
Create operation instance.
:param str operation: HTTP operation
:param str summary: Summary
:param str description: Description
:param str operation_id: Operation ID
:param list parameters: List of parameter dicts
:param list tags: List of tags
:param list responses: List of response dicts
:param list callbacks: List of callbacks
:param str return_type: Return content type
:param str accepts: Accepts type
:param str operation: HTTP operation
:param str summary: Summary
:param str description: Description
:param str operation_id: Operation ID
:param list parameters: List of parameter dicts
:param list tags: List of tags
:param list responses: List of response dicts
:param list callbacks: List of callbacks
:param list[str] return_types: Return content type
:param list[str] accepts: Accept types
:return:
"""
self.operation = operation
self.summary = summary
self.description = description
self.operation_id = operation_id
self.return_types = return_types
self.tags = tags or []
self.callbacks = callbacks or {}
self.parameters = [Parameter(**x) for x in parameters or []]
self.responses = [Response(**x) for x in responses or []]
self.return_type = return_type
print(">>>>>>>>>>>>>>>")
print(responses)
print(f"accepts: {accepts}")
print(f"return_types {return_types}")
self.responses = [Response(**x, content=return_types) for x in responses or []]
print("<<<<<<<<<<<<<<<")
self._accepts = accepts
self.request_body_parameters = {x.name: x.dict() for x in self.parameters if x.in_request_body()}

Expand Down Expand Up @@ -330,20 +344,19 @@ def has_form(self):

def body(self):
"""Return request body."""
accepts = CONTENT_MAP.get(self.accepts)
accepts = [CONTENT_MAP.get(x) for x in self.accepts]
required = [k for k, v in self.request_body_parameters.items() if v.get("required") is True]
schema = {"type": "object", "required": required, "properties": self.request_body_parameters}
content = {x: schema for x in accepts}

return {
"description": self.description,
"content": {
accepts: {
"schema": {"type": "object", "required": required, "properties": self.request_body_parameters}
}
},
"content": content,
}

def request_body(self):
"""Return request body."""
if self.accepts in ["binary"]:
if self.accepts in BINARY_TYPES:
return self.binary_body()

return self.body()
Expand Down
24 changes: 15 additions & 9 deletions src/reliqua/sphinx_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
re.MULTILINE | re.DOTALL,
)
RESPONSE_ITER_REGEX = re.compile(r":response\s+(?P<code>\d+)\s*(?P<schema>\w+)?:\s+(?P<description>.*)")
RETURN_REGEX = re.compile(r"return\s+(\w+):|:return:\s+(.*)")
ACCEPT_REGEX = re.compile(r"accepts\s+(\w+):|:accepts:\s+(\w+)")
RETURN_REGEX = re.compile(r":return[s]*\s*(\[(.*?)\]|\w+)")
ACCEPT_REGEX = re.compile(r":accepts\s*(\[(.*?)\]|\w+)")
KEYVALUE_REGEX = re.compile(r"(?P<key>\w+)=(?P<value>\S+)")
OPERATION_REGEX = re.compile(r"on_(delete|get|patch|post|put)")
SUFFIX_REGEX = re.compile(r"on_(?:delete|get|patch|post|put)_([a-zA-Z0-9_]+)")
Expand Down Expand Up @@ -124,10 +124,13 @@ def parameters(self):
@property
def accepts(self):
"""Return accepts type."""
if match := ACCEPT_REGEX.search(self.doc):
return match.group(1) or match.group(2)
m = ACCEPT_REGEX.search(self.doc)

return ""
if not m:
return []

parsed = m.group(1).strip("[]") or "json"
return re.split(r",\s*|\s+", parsed)

@property
def responses(self):
Expand All @@ -144,10 +147,13 @@ def responses(self):
@property
def content(self):
"""Return content."""
if match := RETURN_REGEX.search(self.doc):
return match.group(1) or match.group(2)
m = RETURN_REGEX.search(self.doc)

if not m:
return ["json"]

return "json"
parsed = m.group(1).strip("[]") or "json"
return re.split(r",\s*|\s+", parsed)

@staticmethod
def generate_operation_id(method):
Expand Down Expand Up @@ -207,6 +213,6 @@ def parse(self, method, operation=None, operation_id=None):
"description": self.description,
"parameters": self.parameters,
"responses": self.responses,
"return_type": self.content,
"return_types": self.content,
"accepts": self.accepts,
}

0 comments on commit 9181c2c

Please sign in to comment.