Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenAPI: Refactor module to responder.ext.openapi #555

Merged
merged 2 commits into from
Oct 30, 2024
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
31 changes: 27 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ concurrency:
cancel-in-progress: true

jobs:
test:
name: "Python ${{ matrix.python-version }} on ${{ matrix.os }}"

test-full:
name: "Full: Python ${{ matrix.python-version }} on ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -65,11 +66,33 @@ jobs:
- name: Install package and run software tests (Python 3.6)
if: matrix.python-version == '3.6'
run: |
pip install '.[graphql,develop,test]'
pip install '.[full,develop,test]'
poe test

- name: Install and completely validate package (Python >=3.6)
if: matrix.python-version != '3.6'
run: |
uv pip install '.[graphql,develop,test]' --system
uv pip install '.[full,develop,test]' --system
poe check


test-minimal:
name: "Minimal: Python ${{ matrix.python-version }} on ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest"]
python-version: ["3.13"]

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: yezz123/setup-uv@v4

- name: Install and completely validate package
run: |
uv pip install '.[develop,test]' --system
poe check
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,20 @@ for more details on features available in Responder.

Install the most recent stable release:

uv pip install --upgrade 'responder'
pip install --upgrade 'responder'

Include support for all extensions and interfaces:

pip install --upgrade 'responder[full]'

Individual optional installation extras are:

- graphql: Adds GraphQL support via Graphene
- openapi: Adds OpenAPI/Swagger interface support

Or, install directly from the repository:

uv pip install --upgrade 'responder @ git+https://github.com/kennethreitz/responder.git'
pip install 'responder[full] @ git+https://github.com/kennethreitz/responder.git'

Responder supports **Python 3.6+**.

Expand Down
27 changes: 19 additions & 8 deletions docs/source/tour.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ Here, you can spawn off a background thread to run any function, out-of-request:

GraphQL
-------
responder supports GraphQL::

pip install 'responder[graphql]'


Serve a GraphQL API::

Expand All @@ -58,12 +62,20 @@ You can make use of Responder's Request and Response objects in your GraphQL res
OpenAPI Schema Support
----------------------

Responder comes with built-in support for OpenAPI / marshmallow
Responder comes with built-in support for OpenAPI / marshmallow::

pip install 'responder[openapi]'

.. note::

New in Responder `1.4.0`::
If you're upgrading from a previous version, note that the OpenAPI module
has been renamed from ``responder.ext.schema`` to ``responder.ext.openapi``.
Update your imports accordingly.

New in Responder 1.4.0::

import responder
from responder.ext.schema import Schema as OpenAPISchema
from responder.ext.openapi import OpenAPISchema
from marshmallow import Schema, fields

contact = {
Expand Down Expand Up @@ -194,12 +206,11 @@ Responder can automatically supply API Documentation for you. Using the example

The new and recommended way::

...
from responder.ext.schema import Schema
...
from responder.ext.openapi import OpenAPISchema

api = responder.API()

schema = Schema(
schema = OpenAPISchema(
app=api,
title="Web Service",
version="1.0",
Expand All @@ -214,7 +225,7 @@ The new and recommended way::
)


The old way ::
The old way::

api = responder.API(
title="Web Service",
Expand Down
9 changes: 8 additions & 1 deletion responder/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

from . import status_codes
from .background import BackgroundQueue
from .ext.schema import OpenAPISchema as OpenAPISchema
from .formats import get_formats
from .routes import Router
from .staticfiles import StaticFiles
Expand Down Expand Up @@ -110,6 +109,14 @@ def __init__(
self.add_middleware(SessionMiddleware, secret_key=self.secret_key)

if openapi or docs_route:
try:
from .ext.openapi import OpenAPISchema
except ImportError as ex:
raise ImportError(
"The dependencies for the OpenAPI extension are not installed. "
"Install them using: pip install 'responder[openapi]'"
) from ex

Comment on lines +112 to +119
Copy link

@coderabbitai coderabbitai bot Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling for OpenAPI dependencies.

While the error handling is good, consider making it more specific to help users troubleshoot dependency issues more effectively.

 try:
     from .ext.openapi import OpenAPISchema
 except ImportError as ex:
     raise ImportError(
-        "The dependencies for the OpenAPI extension are not installed. "
-        "Install them using: pip install 'responder[openapi]'"
+        f"Failed to import OpenAPI dependencies: {ex}. "
+        "Install the required packages using: pip install 'responder[openapi]'. "
+        "Required packages include: apispec, pyyaml, and jinja2."
     ) from ex
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
from .ext.openapi import OpenAPISchema
except ImportError as ex:
raise ImportError(
"The dependencies for the OpenAPI extension are not installed. "
"Install them using: pip install 'responder[openapi]'"
) from ex
try:
from .ext.openapi import OpenAPISchema
except ImportError as ex:
raise ImportError(
f"Failed to import OpenAPI dependencies: {ex}. "
"Install the required packages using: pip install 'responder[openapi]'. "
"Required packages include: apispec, pyyaml, and jinja2."
) from ex

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amotl, understood. Let me know if you need any further assistance.

(_/)
( •_•)
/>💔

self.openapi = OpenAPISchema(
app=self,
title=title,
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ def run(self):
"sphinx-design-elements",
"sphinxext.opengraph",
],
"full": ["responder[graphql,openapi]"],
"graphql": ["graphene"],
"openapi": ["apispec>=1.0.0"],
"release": ["build", "twine"],
"test": ["flask", "mypy", "pytest", "pytest-cov", "pytest-mock"],
},
Expand Down
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,13 @@ def template_path(tmpdir):
template_file = tmpdir.mkdir("static").join(template_name)
template_file.write("{{ var }}")
return template_file


@pytest.fixture
def needs_openapi() -> None:
try:
import apispec

_ = apispec.APISpec
except ImportError as ex:
raise pytest.skip("apispec package not installed") from ex
12 changes: 6 additions & 6 deletions tests/test_responder.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,11 @@ def route(req, resp):
assert yaml.safe_load(r.content) == dump


def test_schema_generation_explicit():
def test_schema_generation_explicit(needs_openapi):
import marshmallow

import responder
from responder.ext.schema import OpenAPISchema as OpenAPISchema
from responder.ext.openapi import OpenAPISchema

api = responder.API()

Expand Down Expand Up @@ -357,7 +357,7 @@ def route(req, resp):
assert dump["openapi"] == "3.0.2"


def test_schema_generation():
def test_schema_generation(needs_openapi):
from marshmallow import Schema, fields

import responder
Expand Down Expand Up @@ -389,11 +389,11 @@ def route(req, resp):
assert dump["openapi"] == "3.0.2"


def test_documentation_explicit():
def test_documentation_explicit(needs_openapi):
import marshmallow

import responder
from responder.ext.schema import OpenAPISchema as OpenAPISchema
from responder.ext.openapi import OpenAPISchema

description = "This is a sample server for a pet store."
terms_of_service = "http://example.com/terms/"
Expand Down Expand Up @@ -443,7 +443,7 @@ def route(req, resp):
assert "html" in r.text


def test_documentation():
def test_documentation(needs_openapi):
from marshmallow import Schema, fields

import responder
Expand Down
Loading