Skip to content

Commit

Permalink
Merge pull request #123 from 0b01001001/dev
Browse files Browse the repository at this point in the history
support tag description and external doc url
  • Loading branch information
kemingy authored Apr 24, 2021
2 parents 12396b7 + d6cf2a0 commit 816539c
Show file tree
Hide file tree
Showing 14 changed files with 95 additions and 57 deletions.
8 changes: 5 additions & 3 deletions examples/falcon_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
import falcon
from pydantic import BaseModel, Field

from spectree import Response, SpecTree
from spectree import Response, SpecTree, Tag

api = SpecTree(
"falcon",
title="Demo Service",
version="0.1.2",
)

demo = Tag(name="demo", description="😊", externalDocs={"url": "https://github.com"})


class Query(BaseModel):
text: str = Field(
Expand Down Expand Up @@ -51,7 +53,7 @@ class Ping:
def check(self):
pass

@api.validate(tags=["demo"])
@api.validate(tags=[demo])
def on_get(self, req, resp):
"""
health check
Expand All @@ -66,7 +68,7 @@ class Classification:
classification demo
"""

@api.validate(tags=["demo"])
@api.validate(tags=[demo])
def on_get(self, req, resp, source, target):
"""
API summary
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

setup(
name="spectree",
version="0.4.2",
version="0.4.3",
author="Keming Yang",
author_email="[email protected]",
description=(
Expand Down
3 changes: 2 additions & 1 deletion spectree/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import logging

from .models import Tag
from .response import Response
from .spec import SpecTree

__all__ = ["SpecTree", "Response"]
__all__ = ["SpecTree", "Response", "Tag"]

# setup library logging
logging.getLogger(__name__).addHandler(logging.NullHandler())
46 changes: 46 additions & 0 deletions spectree/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from typing import Any, Dict, Sequence

from pydantic import BaseModel, Field


class ExternalDocs(BaseModel):
description: str = ""
url: str


class Tag(BaseModel):
"""OpenAPI tag object"""

name: str
description: str = ""
externalDocs: ExternalDocs = None

def __str__(self):
return self.name


class UnprocessableEntityElement(BaseModel):
"""Model of missing field description."""

loc: Sequence[str] = Field(
...,
title="Missing field name",
)
msg: str = Field(
...,
title="Error message",
)
type: str = Field( # noqa: WPS125
...,
title="Error type",
)
ctx: Dict[str, Any] = Field(
None,
title="Error context",
)


class UnprocessableEntity(BaseModel):
"""Model of 422 Unprocessable Entity error."""

__root__: Sequence[UnprocessableEntityElement]
32 changes: 2 additions & 30 deletions spectree/response.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,9 @@
from typing import Any, Dict, Sequence

from pydantic import BaseModel, Field
from pydantic import BaseModel

from .models import UnprocessableEntity
from .utils import parse_code


class UnprocessableEntityElement(BaseModel):
"""Model of missing field description."""

loc: Sequence[str] = Field(
...,
title="Missing field name",
)
msg: str = Field(
...,
title="Error message",
)
type: str = Field( # noqa: WPS125
...,
title="Error type",
)
ctx: Dict[str, Any] = Field(
None,
title="Error context",
)


class UnprocessableEntity(BaseModel):
"""Model of 422 Unprocessable Entity error."""

__root__: Sequence[UnprocessableEntityElement]


class Response:
"""
response object
Expand Down
11 changes: 7 additions & 4 deletions spectree/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pydantic import BaseModel

from .config import Config
from .models import Tag
from .plugins import PLUGINS
from .utils import (
default_after_handler,
Expand Down Expand Up @@ -113,7 +114,7 @@ def validate(
:param headers: `pydantic.BaseModel`, if you have specific headers
:param cookies: `pydantic.BaseModel`, if you have cookies for this route
:param resp: `spectree.Response`
:param tags: a tuple of tags string
:param tags: a tuple of strings or :class:`spectree.models.Tag`
:param before: :meth:`spectree.utils.default_before_handler` for
specific endpoint
:param after: :meth:`spectree.utils.default_after_handler` for
Expand Down Expand Up @@ -208,14 +209,16 @@ def _generate_spec(self):
summary, desc = parse_comments(func)
func_tags = getattr(func, "tags", ())
for tag in func_tags:
if tag not in tags:
tags[tag] = {"name": tag}
if str(tag) not in tags:
tags[str(tag)] = (
tag.dict() if isinstance(tag, Tag) else {"name": tag}
)

routes[path][method.lower()] = {
"summary": summary or f"{name} <{method}>",
"operationId": f"{method.lower()}_{path}",
"description": desc or "",
"tags": getattr(func, "tags", []),
"tags": [str(x) for x in getattr(func, "tags", ())],
"parameters": parse_params(func, parameters[:], self.models),
"responses": parse_resp(func),
}
Expand Down
4 changes: 4 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

from pydantic import BaseModel, Field, root_validator

from spectree import Tag

api_tag = Tag(name="API", description="🐱", externalDocs={"url": "https://pypi.org"})


class Order(IntEnum):
asce = 1
Expand Down
15 changes: 13 additions & 2 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ def test_plugin_spec(api):
for name, schema in models.items():
assert api.spec["components"]["schemas"][name] == schema

assert api.spec["tags"] == [{"name": tag} for tag in ("test", "health", "api")]
assert api.spec["tags"] == [
{"name": "test"},
{"name": "health"},
{
"description": "🐱",
"externalDocs": {
"description": "",
"url": "https://pypi.org",
},
"name": "API",
},
]

assert get_paths(api.spec) == [
"/api/user/{name}",
Expand All @@ -35,7 +46,7 @@ def test_plugin_spec(api):
assert ping["operationId"] == "get_/ping"

user = api.spec["paths"]["/api/user/{name}"]["post"]
assert user["tags"] == ["api", "test"]
assert user["tags"] == ["API", "test"]
assert (
user["requestBody"]["content"]["application/json"]["schema"]["$ref"]
== "#/components/schemas/JSON"
Expand Down
6 changes: 3 additions & 3 deletions tests/test_plugin_falcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from spectree import Response, SpecTree

from .common import JSON, Cookies, Headers, Query, Resp, StrDict
from .common import JSON, Cookies, Headers, Query, Resp, StrDict, api_tag


def before_handler(req, resp, err, instance):
Expand Down Expand Up @@ -54,7 +54,7 @@ def on_get(self, req, resp, name):
json=JSON,
cookies=Cookies,
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
)
def on_post(self, req, resp, name):
score = [randint(0, req.context.json.limit) for _ in range(5)]
Expand All @@ -77,7 +77,7 @@ def on_get(self, req, resp, name):

@api.validate(
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
)
def on_post(self, req, resp, name, query: Query, json: JSON, cookies: Cookies):
score = [randint(0, req.context.json.limit) for _ in range(5)]
Expand Down
6 changes: 3 additions & 3 deletions tests/test_plugin_flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from spectree import Response, SpecTree

from .common import JSON, Cookies, Headers, Query, Resp, StrDict
from .common import JSON, Cookies, Headers, Query, Resp, StrDict, api_tag


def before_handler(req, resp, err, _):
Expand Down Expand Up @@ -41,7 +41,7 @@ def ping():
json=JSON,
cookies=Cookies,
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
after=api_after_handler,
)
def user_score(name):
Expand All @@ -55,7 +55,7 @@ def user_score(name):
@app.route("/api/user_annotated/<name>", methods=["POST"])
@api.validate(
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
after=api_after_handler,
)
def user_score_annotated(name, query: Query, json: JSON, cookies: Cookies):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_plugin_flask_blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from spectree import Response, SpecTree

from .common import JSON, Cookies, Headers, Query, Resp, StrDict
from .common import JSON, Cookies, Headers, Query, Resp, StrDict, api_tag


def before_handler(req, resp, err, _):
Expand Down Expand Up @@ -40,7 +40,7 @@ def ping():
json=JSON,
cookies=Cookies,
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
after=api_after_handler,
)
def user_score(name):
Expand All @@ -54,7 +54,7 @@ def user_score(name):
@app.route("/api/user_annotated/<name>", methods=["POST"])
@api.validate(
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
after=api_after_handler,
)
def user_score_annotated(name, query: Query, json: JSON, cookies: Cookies):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_plugin_flask_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from spectree import Response, SpecTree

from .common import JSON, Cookies, Headers, Query, Resp, StrDict
from .common import JSON, Cookies, Headers, Query, Resp, StrDict, api_tag


def before_handler(req, resp, err, _):
Expand Down Expand Up @@ -44,7 +44,7 @@ class User(MethodView):
json=JSON,
cookies=Cookies,
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
after=api_after_handler,
)
def post(self, name):
Expand All @@ -58,7 +58,7 @@ def post(self, name):
class UserAnnotated(MethodView):
@api.validate(
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
after=api_after_handler,
)
def post(self, name, query: Query, json: JSON, cookies: Cookies):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_plugin_starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from spectree import Response, SpecTree

from .common import JSON, Cookies, Headers, Query, Resp, StrDict
from .common import JSON, Cookies, Headers, Query, Resp, StrDict, api_tag


def before_handler(req, resp, err, instance):
Expand Down Expand Up @@ -51,7 +51,7 @@ def get(self, request):
json=JSON,
cookies=Cookies,
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
)
async def user_score(request):
score = [randint(0, request.context.json.limit) for _ in range(5)]
Expand All @@ -63,7 +63,7 @@ async def user_score(request):

@api.validate(
resp=Response(HTTP_200=Resp, HTTP_401=None),
tags=["api", "test"],
tags=[api_tag, "test"],
)
async def user_score_annotated(request, query: Query, json: JSON, cookies: Cookies):
score = [randint(0, json.limit) for _ in range(5)]
Expand Down
1 change: 0 additions & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def demo_func_with_query():
a description
"""
pass


class DemoClass:
Expand Down

0 comments on commit 816539c

Please sign in to comment.