diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index acc7db31..22d11cda 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -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 @@ -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 diff --git a/README.md b/README.md index 4851e981..a5f3773a 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,19 @@ 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, openapi 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+**. diff --git a/docs/source/tour.rst b/docs/source/tour.rst index 256e7bf8..792ac927 100644 --- a/docs/source/tour.rst +++ b/docs/source/tour.rst @@ -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:: @@ -58,7 +62,9 @@ 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]' New in Responder `1.4.0`:: diff --git a/responder/api.py b/responder/api.py index 4311c8f9..62beeb3d 100644 --- a/responder/api.py +++ b/responder/api.py @@ -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 @@ -110,6 +109,8 @@ def __init__( self.add_middleware(SessionMiddleware, secret_key=self.secret_key) if openapi or docs_route: + from .ext.schema import OpenAPISchema + self.openapi = OpenAPISchema( app=self, title=title, diff --git a/setup.py b/setup.py index 10755132..17f5f902 100644 --- a/setup.py +++ b/setup.py @@ -132,7 +132,9 @@ def run(self): "sphinx-design-elements", "sphinxext.opengraph", ], + "full": ["responder[graphql,openapi]"], "graphql": ["graphene"], + "openapi": ["apispec>=1.0.0b1"], "release": ["build", "twine"], "test": ["flask", "mypy", "pytest", "pytest-cov", "pytest-mock"], }, diff --git a/tests/conftest.py b/tests/conftest.py index 74addee8..953a352b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -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 diff --git a/tests/test_responder.py b/tests/test_responder.py index c125da2b..730a9f9c 100644 --- a/tests/test_responder.py +++ b/tests/test_responder.py @@ -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.schema import OpenAPISchema api = responder.API() @@ -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 @@ -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.schema import OpenAPISchema description = "This is a sample server for a pet store." terms_of_service = "http://example.com/terms/" @@ -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