From 07214fe8822fecf98cbdd8aa80fac9932591c8ab Mon Sep 17 00:00:00 2001
From: Adam Williamson <awilliam@redhat.com>
Date: Tue, 17 Oct 2023 17:17:16 -0700
Subject: [PATCH] Make flasgger dep optional (#26)
As discussed in the ticket, the flasgger dep is a pretty heavy
one which is not needed when using httpbin as a library. It's
only really needed to produce the fancy homepage and API docs
for httpbin.org.
This makes the dependency optional, and falls back to the old
static HTML page for / if flasgger is not available. The flasgger
dependency is moved from the main set of dependencies to the
'mainapp' extras (to ensure we *do* get the shiny new homepage
when we want it).
Signed-off-by: Adam Williamson <awilliam@redhat.com>
---
httpbin/core.py | 150 +++++++++++++++++++++++++-----------------------
pyproject.toml | 2 +-
2 files changed, 80 insertions(+), 72 deletions(-)
diff --git a/httpbin/core.py b/httpbin/core.py
index a82c1b8..ca4a845 100644
--- a/httpbin/core.py
+++ b/httpbin/core.py
@@ -33,7 +33,10 @@ try:
except ImportError: # werkzeug < 2.1
from werkzeug.wrappers import BaseResponse as Response
-from flasgger import Swagger, NO_SANITIZER
+try:
+ from flasgger import Swagger, NO_SANITIZER
+except ImportError:
+ Swagger = False
from . import filters
from .helpers import (
@@ -95,77 +98,78 @@ app.add_template_global("HTTPBIN_TRACKING" in os.environ, name="tracking_enabled
app.config["SWAGGER"] = {"title": "httpbin.org", "uiversion": 3}
-template = {
- "swagger": "2.0",
- "info": {
- "title": "httpbin.org",
- "description": (
- "A simple HTTP Request & Response Service."
- "<br/> A <a href='http://kennethreitz.com/'>Kenneth Reitz</a> project."
- "<br/> <br/> <b>Run locally: </b> <br/> "
- "<code>$ docker pull ghcr.io/psf/httpbin</code> <br/>"
- "<code>$ docker run -p 80:8080 ghcr.io/psf/httpbin</code>"
- ),
- "contact": {
- "responsibleOrganization": "Python Software Foundation",
- "responsibleDeveloper": "Kenneth Reitz",
- "url": "https://github.com/psf/httpbin/",
- },
- # "termsOfService": "http://me.com/terms",
- "version": version,
- },
- "host": "httpbin.org", # overrides localhost:5000
- "basePath": "/", # base bash for blueprint registration
- "schemes": ["https"],
- "protocol": "https",
- "tags": [
- {
- "name": "HTTP Methods",
- "description": "Testing different HTTP verbs",
- # 'externalDocs': {'description': 'Learn more', 'url': 'https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html'}
- },
- {"name": "Auth", "description": "Auth methods"},
- {
- "name": "Status codes",
- "description": "Generates responses with given status code",
- },
- {"name": "Request inspection", "description": "Inspect the request data"},
- {
- "name": "Response inspection",
- "description": "Inspect the response data like caching and headers",
- },
- {
- "name": "Response formats",
- "description": "Returns responses in different data formats",
+if Swagger:
+ template = {
+ "swagger": "2.0",
+ "info": {
+ "title": "httpbin.org",
+ "description": (
+ "A simple HTTP Request & Response Service."
+ "<br/> A <a href='http://kennethreitz.com/'>Kenneth Reitz</a> project."
+ "<br/> <br/> <b>Run locally: </b> <br/> "
+ "<code>$ docker pull ghcr.io/psf/httpbin</code> <br/>"
+ "<code>$ docker run -p 80:8080 ghcr.io/psf/httpbin</code>"
+ ),
+ "contact": {
+ "responsibleOrganization": "Python Software Foundation",
+ "responsibleDeveloper": "Kenneth Reitz",
+ "url": "https://github.com/psf/httpbin/",
+ },
+ # "termsOfService": "http://me.com/terms",
+ "version": version,
},
- {"name": "Dynamic data", "description": "Generates random and dynamic data"},
- {"name": "Cookies", "description": "Creates, reads and deletes Cookies"},
- {"name": "Images", "description": "Returns different image formats"},
- {"name": "Redirects", "description": "Returns different redirect responses"},
- {
- "name": "Anything",
- "description": "Returns anything that is passed to request",
- },
- ],
-}
-
-swagger_config = {
- "headers": [],
- "specs": [
- {
- "endpoint": "spec",
- "route": "/spec.json",
- "rule_filter": lambda rule: True, # all in
- "model_filter": lambda tag: True, # all in
- }
- ],
- "static_url_path": "/flasgger_static",
- # "static_folder": "static", # must be set by user
- "swagger_ui": True,
- "specs_route": "/",
-}
+ "host": "httpbin.org", # overrides localhost:5000
+ "basePath": "/", # base bash for blueprint registration
+ "schemes": ["https"],
+ "protocol": "https",
+ "tags": [
+ {
+ "name": "HTTP Methods",
+ "description": "Testing different HTTP verbs",
+ # 'externalDocs': {'description': 'Learn more', 'url': 'https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html'}
+ },
+ {"name": "Auth", "description": "Auth methods"},
+ {
+ "name": "Status codes",
+ "description": "Generates responses with given status code",
+ },
+ {"name": "Request inspection", "description": "Inspect the request data"},
+ {
+ "name": "Response inspection",
+ "description": "Inspect the response data like caching and headers",
+ },
+ {
+ "name": "Response formats",
+ "description": "Returns responses in different data formats",
+ },
+ {"name": "Dynamic data", "description": "Generates random and dynamic data"},
+ {"name": "Cookies", "description": "Creates, reads and deletes Cookies"},
+ {"name": "Images", "description": "Returns different image formats"},
+ {"name": "Redirects", "description": "Returns different redirect responses"},
+ {
+ "name": "Anything",
+ "description": "Returns anything that is passed to request",
+ },
+ ],
+ }
+
+ swagger_config = {
+ "headers": [],
+ "specs": [
+ {
+ "endpoint": "spec",
+ "route": "/spec.json",
+ "rule_filter": lambda rule: True, # all in
+ "model_filter": lambda tag: True, # all in
+ }
+ ],
+ "static_url_path": "/flasgger_static",
+ # "static_folder": "static", # must be set by user
+ "swagger_ui": True,
+ "specs_route": "/",
+ }
-swagger = Swagger(app, sanitizer=NO_SANITIZER, template=template, config=swagger_config)
+ swagger = Swagger(app, sanitizer=NO_SANITIZER, template=template, config=swagger_config)
# Set up Bugsnag exception tracking, if desired. To use Bugsnag, install the
# Bugsnag Python client with the command "pip install bugsnag", and set the
@@ -243,8 +247,12 @@ def set_cors_headers(response):
# Routes
# ------
+if Swagger:
+ staticroute = "/legacy"
+else:
+ staticroute = "/"
-@app.route("/legacy")
+@app.route(staticroute)
def view_landing_page():
"""Generates Landing Page in legacy layout."""
return render_template("index.html")
diff --git a/pyproject.toml b/pyproject.toml
index 9454e56..d63f994 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,7 +34,6 @@ dependencies = [
"flask >= 2.2.4",
"brotlicffi",
"decorator",
- "flasgger",
'greenlet < 3.0; python_version<"3.12"',
'greenlet >= 3.0.0a1; python_version>="3.12.0rc0"',
'importlib-metadata; python_version<"3.8"',
@@ -44,6 +43,7 @@ dependencies = [
[project.optional-dependencies]
test = ["pytest", "tox"]
mainapp = [
+ "flasgger",
"gunicorn",
"gevent",
]
--
2.41.0