Skip to content

Commit

Permalink
Setup GH actions (#242)
Browse files Browse the repository at this point in the history
* Setup GH actions

* Remove 3.6

* Code cleanup
  • Loading branch information
ahopkins committed Aug 2, 2021
1 parent 15e8af6 commit bc0562e
Show file tree
Hide file tree
Showing 19 changed files with 387 additions and 173 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Python package

on:
- push
- pull_request

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
run: tox
31 changes: 31 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

name: Upload Python Package

on:
release:
types: [created]

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pretty:
black --line-length 79 --target-version=py39 sanic_openapi tests
isort --line-length 79 --trailing-comma -m 3 sanic_openapi tests
4 changes: 3 additions & 1 deletion sanic_openapi/autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def _parse_yaml(self, doc: str) -> dict:
try:
return yaml.safe_load(doc)
except Exception as e:
warnings.warn("error parsing openAPI yaml, ignoring it. ({})".format(e))
warnings.warn(
"error parsing openAPI yaml, ignoring it. ({})".format(e)
)
return {}

def _parse_all(self) -> dict:
Expand Down
267 changes: 170 additions & 97 deletions sanic_openapi/openapi2/api.py

Large diffs are not rendered by default.

33 changes: 26 additions & 7 deletions sanic_openapi/openapi2/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@


class Field:
def __init__(self, description=None, required=None, name=None, choices=None):
def __init__(
self, description=None, required=None, name=None, choices=None
):
self.name = name
self.description = description
self.required = required
Expand Down Expand Up @@ -73,7 +75,10 @@ def __init__(self, fields=None, **kwargs):
def serialize(self):
return {
"type": "object",
"properties": {key: serialize_schema(schema) for key, schema in self.fields.items()},
"properties": {
key: serialize_schema(schema)
for key, schema in self.fields.items()
},
**super().serialize(),
}

Expand All @@ -87,7 +92,10 @@ def serialize(self):
return {
"schema": {
"type": "object",
"properties": {key: serialize_schema(schema) for key, schema in self.fields.items()},
"properties": {
key: serialize_schema(schema)
for key, schema in self.fields.items()
},
},
**super().serialize(),
}
Expand Down Expand Up @@ -125,7 +133,9 @@ def __init__(self, cls, *args, object_name=None, **kwargs):
self.cls = cls
self.object_name = object_name or cls.__name__

register_as = object_name or "{}.{}".format(cls.__module__, cls.__qualname__)
register_as = object_name or "{}.{}".format(
cls.__module__, cls.__qualname__
)
if register_as not in definitions:
definitions[register_as] = (self, self.definition)

Expand All @@ -136,7 +146,11 @@ def definition(self):
"properties": {
key: serialize_schema(schema)
for key, schema in chain(
{key: getattr(self.cls, key) for key in dir(self.cls) if not key.startswith("_")}.items(),
{
key: getattr(self.cls, key)
for key in dir(self.cls)
if not key.startswith("_")
}.items(),
typing.get_type_hints(self.cls).items(),
)
if not key.startswith("_")
Expand Down Expand Up @@ -191,7 +205,10 @@ def serialize_schema(schema):
return Dictionary(schema).serialize()
elif schema_type is list:
return List(schema).serialize()
elif getattr(schema, "__origin__", None) in (list, collections.abc.Sequence):
elif getattr(schema, "__origin__", None) in (
list,
collections.abc.Sequence,
):
# Type hinting with either List or Sequence
return List(list(schema.__args__)).serialize()

Expand Down Expand Up @@ -298,7 +315,9 @@ def inner(func):
return inner


def consumes(*args, content_type="application/json", location="query", required=False):
def consumes(
*args, content_type="application/json", location="query", required=False
):
def inner(func):
if args:
for arg in args:
Expand Down
5 changes: 3 additions & 2 deletions sanic_openapi/openapi3/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from sanic.blueprints import Blueprint
from sanic.response import json, redirect

from ..autodoc import YamlStyleParametersParser
from ..utils import get_all_routes, get_blueprinted_routes
from . import operations, specification

Expand Down Expand Up @@ -85,7 +84,9 @@ def build_spec(app, loop):
# operation ID must be unique, and it isnt currently used for
# anything in UI, so dont add something meaningless
# if not hasattr(operation, "operationId"):
# operation.operationId = "%s_%s" % (method.lower(), route.name)
# operation.operationId = "%s_%s" % (
# method.lower(), route.name
# )

for _parameter in route_parameters:
operation.parameter(
Expand Down
9 changes: 5 additions & 4 deletions sanic_openapi/openapi3/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
for breaking user experience
"""
from collections import defaultdict
from typing import Optional

from ..autodoc import YamlStyleParametersParser
from ..utils import remove_nulls, remove_nulls_from_kwargs
Expand Down Expand Up @@ -112,8 +113,8 @@ class SpecificationBuilder:
_urls: List[str]
_title: str
_version: str
_description: str
_terms: str
_description: Optional[str]
_terms: Optional[str]
_contact: Contact
_license: License
_paths: Dict[str, Dict[str, OperationBuilder]]
Expand All @@ -134,8 +135,8 @@ def describe(
self,
title: str,
version: str,
description: str = None,
terms: str = None,
description: Optional[str] = None,
terms: Optional[str] = None,
):
self._title = title
self._version = version
Expand Down
16 changes: 12 additions & 4 deletions sanic_openapi/openapi3/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ def make(value: Any):

@staticmethod
def all(content: Any):
media_types = content if isinstance(content, dict) else {"*/*": content or {}}
media_types = (
content if isinstance(content, dict) else {"*/*": content or {}}
)

return {x: MediaType.make(v) for x, v in media_types.items()}

Expand All @@ -91,7 +93,9 @@ def make(content, description: str = None, **kwargs):
if not description:
description = "Default Response"

return Response(MediaType.all(content), description=description, **kwargs)
return Response(
MediaType.all(content), description=description, **kwargs
)


class RequestBody(Definition):
Expand Down Expand Up @@ -230,8 +234,12 @@ class Server(Definition):
description: str
variables: Dict[str, ServerVariable]

def __init__(self, url: str, description: str = None, variables: dict = None):
super().__init__(url=url, description=description, variables=variables or [])
def __init__(
self, url: str, description: str = None, variables: dict = None
):
super().__init__(
url=url, description=description, variables=variables or []
)


class Tag(Definition):
Expand Down
32 changes: 15 additions & 17 deletions sanic_openapi/openapi3/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@
from typing import Any

from . import operations
from .types import ( # noqa
Array,
Binary,
Boolean,
Byte,
Date,
DateTime,
Double,
Email,
Float,
Integer,
Long,
Object,
Password,
String,
Time,
)
from .types import Array # noqa
from .types import Binary # noqa
from .types import Boolean # noqa
from .types import Byte # noqa
from .types import Date # noqa
from .types import DateTime # noqa
from .types import Double # noqa
from .types import Email # noqa
from .types import Float # noqa
from .types import Integer # noqa
from .types import Long # noqa
from .types import Object # noqa
from .types import Password # noqa
from .types import String # noqa
from .types import Time # noqa


def operation(name: str):
Expand Down
2 changes: 1 addition & 1 deletion sanic_openapi/openapi3/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
from enum import Enum
from datetime import date, datetime, time
from enum import Enum
from typing import Any, Dict, List, Union, get_type_hints


Expand Down
21 changes: 16 additions & 5 deletions sanic_openapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ def remove_nulls(dictionary, deep=True):
"""
Removes all null values from a dictionary.
"""
return {k: remove_nulls(v, deep) if deep and type(v) is dict else v for k, v in dictionary.items() if v is not None}
return {
k: remove_nulls(v, deep) if deep and type(v) is dict else v
for k, v in dictionary.items()
if v is not None
}


def remove_nulls_from_kwargs(**kwargs):
Expand All @@ -53,7 +57,9 @@ def get_blueprinted_routes(app):
# before sanic 21.3, route.handler could be a number of
# different things, so have to type check
for http_method in route.methods:
_handler = getattr(route.handler.view_class, http_method.lower(), None)
_handler = getattr(
route.handler.view_class, http_method.lower(), None
)
if _handler:
yield (blueprint.name, _handler)
else:
Expand Down Expand Up @@ -97,7 +103,9 @@ def get_all_routes(app, skip_prefix):
if route.name and "static" in route.name:
continue

method_handlers = [(method, route.handler) for method in route.methods]
method_handlers = [
(method, route.handler) for method in route.methods
]

_, name = route.name.split(".", 1)
yield (uri, name, route.params.values(), method_handlers)
Expand Down Expand Up @@ -125,10 +133,13 @@ def get_all_routes(app, skip_prefix):

elif hasattr(route.handler, "view_class"):
method_handlers = {
method: getattr(route.handler.view_class, method.lower()) for method in route.methods
method: getattr(route.handler.view_class, method.lower())
for method in route.methods
}
else:
method_handlers = {method: route.handler for method in route.methods}
method_handlers = {
method: route.handler for method in route.methods
}

for parameter in route.parameters:
uri = re.sub(
Expand Down
10 changes: 7 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ def test_message_api_response():
)
assert app_response.headers == benchmark_response.headers
assert (
app_response.json == benchmark_response.json == {"message": "Message received."}
app_response.json
== benchmark_response.json
== {"message": "Message received."}
)


Expand Down Expand Up @@ -111,10 +113,12 @@ def test_documentation():
for path in benchmark_response.json["paths"]:
for method in benchmark_response.json["paths"][path]:
assert (
app_response.json["paths"][path][method]["operationId"].split(".")[-1]
== benchmark_response.json["paths"][path][method]["operationId"].split(
app_response.json["paths"][path][method]["operationId"].split(
"."
)[-1]
== benchmark_response.json["paths"][path][method][
"operationId"
].split(".")[-1]
)
app_response.json["paths"][path][method][
"operationId"
Expand Down
5 changes: 4 additions & 1 deletion tests/test_autodoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
"""

tests.append(
{"doc": _, "expects": {"summary": "first line", "description": "more lines"}}
{
"doc": _,
"expects": {"summary": "first line", "description": "more lines"},
}
)


Expand Down
1 change: 1 addition & 0 deletions tests/test_decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
from sanic.response import text
from sanic.views import HTTPMethodView

from sanic_openapi import doc


Expand Down
Loading

0 comments on commit bc0562e

Please sign in to comment.