stoplight-fastapi 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tho Nguyen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
6
+ software and associated documentation files (the "Software"), to deal in the Software
7
+ without restriction, including without limitation the rights to use, copy, modify, merge,
8
+ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
9
+ to whom the Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or
12
+ substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
17
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,129 @@
1
+ Metadata-Version: 2.4
2
+ Name: stoplight-fastapi
3
+ Version: 0.1.0
4
+ Summary: Seamlessly integrate Stoplight Elements for beautiful, interactive API documentation in FastAPI.
5
+ Keywords: fastapi,api,documentation,stoplight,openapi,interactive-docs,api-docs,rest-api,swagger
6
+ Author: Tho Nguyen
7
+ Author-email: Tho Nguyen <contact@naiwaaa.simplelogin.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Framework :: FastAPI
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Information Technology
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Topic :: Documentation
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Typing :: Typed
26
+ Requires-Dist: fastapi>=0.115.0
27
+ Requires-Python: >=3.10
28
+ Project-URL: Homepage, https://codeberg.org/naiwaaa/stoplight-fastapi
29
+ Project-URL: Documentation, https://codeberg.org/naiwaaa/stoplight-fastapi
30
+ Project-URL: Repository, https://codeberg.org/naiwaaa/stoplight-fastapi
31
+ Project-URL: Issues, https://codeberg.org/naiwaaa/stoplight-fastapi/issues
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Stoplight Elements API Documentation Plugin for FastAPI
35
+
36
+ [![Package - Version](https://img.shields.io/pypi/v/stoplight-fastapi)](https://pypi.python.org/pypi/stoplight-fastapi)
37
+ [![Package - Supported Python Versions](https://img.shields.io/pypi/pyversions/stoplight-fastapi)](https://codeberg.org/naiwaaa/stoplight-fastapi)
38
+ [![Package - License](https://img.shields.io/pypi/l/stoplight-fastapi)](https://codeberg.org/naiwaaa/stoplight-fastapi/src/branch/main/LICENSE)
39
+
40
+ ## Installation
41
+
42
+ Install `stoplight-fastapi` using your preferred package manager:
43
+
44
+ ### Using uv (recommended)
45
+
46
+ ```bash
47
+ uv add stoplight-fastapi
48
+ ```
49
+
50
+ ### Using pip
51
+
52
+ ```bash
53
+ pip install stoplight-fastapi
54
+ ```
55
+
56
+ ### Requirements
57
+
58
+ - Python 3.10 or higher
59
+ - FastAPI 0.115.0 or higher
60
+
61
+ ## Quick Start
62
+
63
+ ### Basic Setup
64
+
65
+ ```python
66
+ from fastapi import FastAPI
67
+ from stoplight_fastapi import get_stoplight_api_reference
68
+
69
+ app = FastAPI(
70
+ title="My API",
71
+ description="Welcome to My Awesome API.",
72
+ version="1.0.0",
73
+ )
74
+
75
+ @app.get("/items/{item_id}")
76
+ def read_item(item_id: int, q: str = None):
77
+ """Get an item by ID."""
78
+ return {"item_id": item_id, "q": q}
79
+
80
+ @app.get("/stoplight", include_in_schema=False)
81
+ def get_stoplight_html():
82
+ """Render API documentation with Stoplight Elements."""
83
+ return get_stoplight_api_reference(
84
+ openapi_url=app.openapi_url,
85
+ title=app.title,
86
+ )
87
+
88
+ if __name__ == "__main__":
89
+ import uvicorn
90
+ uvicorn.run(app, host="0.0.0.0", port=8000)
91
+ ```
92
+
93
+ Then visit `http://localhost:8000/stoplight` to view your API documentation.
94
+
95
+ ### Advanced Configuration
96
+
97
+ Customize the Stoplight Elements UI with
98
+ [advanced options](https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options):
99
+
100
+ ```python
101
+ from stoplight_fastapi import get_stoplight_api_reference, StoplightConfig
102
+
103
+ @app.get("/docs", include_in_schema=False)
104
+ def get_stoplight_html():
105
+ """Advanced Stoplight Elements configuration."""
106
+ return get_stoplight_api_reference(
107
+ openapi_url=app.openapi_url,
108
+ stoplight_config=StoplightConfig(
109
+ router="hash", # Enable hash-based routing for shareable links
110
+ layout="stacked", # Choose between 'sidebar', 'responsive', and 'stacked' layouts
111
+ # Additional Stoplight configuration options available
112
+ ),
113
+ )
114
+ ```
115
+
116
+ ## Live Example
117
+
118
+ ![demo](https://codeberg.org/naiwaaa/stoplight-fastapi/raw/branch/main/assets/screenshot.png)
119
+
120
+ ```bash
121
+ uv run https://codeberg.org/naiwaaa/stoplight-fastapi/raw/branch/main/scripts/playground.py
122
+ ```
123
+
124
+ Visit `http://localhost:8000/stoplight` to see Stoplight Elements in action.
125
+
126
+ ## Resources
127
+
128
+ - [FastAPI Documentation](https://fastapi.tiangolo.com)
129
+ - [Stoplight Elements Documentation](https://docs.stoplight.io/docs/elements/d6a8ba3f3c186-stoplight-elements)
@@ -0,0 +1,96 @@
1
+ # Stoplight Elements API Documentation Plugin for FastAPI
2
+
3
+ [![Package - Version](https://img.shields.io/pypi/v/stoplight-fastapi)](https://pypi.python.org/pypi/stoplight-fastapi)
4
+ [![Package - Supported Python Versions](https://img.shields.io/pypi/pyversions/stoplight-fastapi)](https://codeberg.org/naiwaaa/stoplight-fastapi)
5
+ [![Package - License](https://img.shields.io/pypi/l/stoplight-fastapi)](https://codeberg.org/naiwaaa/stoplight-fastapi/src/branch/main/LICENSE)
6
+
7
+ ## Installation
8
+
9
+ Install `stoplight-fastapi` using your preferred package manager:
10
+
11
+ ### Using uv (recommended)
12
+
13
+ ```bash
14
+ uv add stoplight-fastapi
15
+ ```
16
+
17
+ ### Using pip
18
+
19
+ ```bash
20
+ pip install stoplight-fastapi
21
+ ```
22
+
23
+ ### Requirements
24
+
25
+ - Python 3.10 or higher
26
+ - FastAPI 0.115.0 or higher
27
+
28
+ ## Quick Start
29
+
30
+ ### Basic Setup
31
+
32
+ ```python
33
+ from fastapi import FastAPI
34
+ from stoplight_fastapi import get_stoplight_api_reference
35
+
36
+ app = FastAPI(
37
+ title="My API",
38
+ description="Welcome to My Awesome API.",
39
+ version="1.0.0",
40
+ )
41
+
42
+ @app.get("/items/{item_id}")
43
+ def read_item(item_id: int, q: str = None):
44
+ """Get an item by ID."""
45
+ return {"item_id": item_id, "q": q}
46
+
47
+ @app.get("/stoplight", include_in_schema=False)
48
+ def get_stoplight_html():
49
+ """Render API documentation with Stoplight Elements."""
50
+ return get_stoplight_api_reference(
51
+ openapi_url=app.openapi_url,
52
+ title=app.title,
53
+ )
54
+
55
+ if __name__ == "__main__":
56
+ import uvicorn
57
+ uvicorn.run(app, host="0.0.0.0", port=8000)
58
+ ```
59
+
60
+ Then visit `http://localhost:8000/stoplight` to view your API documentation.
61
+
62
+ ### Advanced Configuration
63
+
64
+ Customize the Stoplight Elements UI with
65
+ [advanced options](https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options):
66
+
67
+ ```python
68
+ from stoplight_fastapi import get_stoplight_api_reference, StoplightConfig
69
+
70
+ @app.get("/docs", include_in_schema=False)
71
+ def get_stoplight_html():
72
+ """Advanced Stoplight Elements configuration."""
73
+ return get_stoplight_api_reference(
74
+ openapi_url=app.openapi_url,
75
+ stoplight_config=StoplightConfig(
76
+ router="hash", # Enable hash-based routing for shareable links
77
+ layout="stacked", # Choose between 'sidebar', 'responsive', and 'stacked' layouts
78
+ # Additional Stoplight configuration options available
79
+ ),
80
+ )
81
+ ```
82
+
83
+ ## Live Example
84
+
85
+ ![demo](https://codeberg.org/naiwaaa/stoplight-fastapi/raw/branch/main/assets/screenshot.png)
86
+
87
+ ```bash
88
+ uv run https://codeberg.org/naiwaaa/stoplight-fastapi/raw/branch/main/scripts/playground.py
89
+ ```
90
+
91
+ Visit `http://localhost:8000/stoplight` to see Stoplight Elements in action.
92
+
93
+ ## Resources
94
+
95
+ - [FastAPI Documentation](https://fastapi.tiangolo.com)
96
+ - [Stoplight Elements Documentation](https://docs.stoplight.io/docs/elements/d6a8ba3f3c186-stoplight-elements)
@@ -0,0 +1,204 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.10.2,<0.11.0"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "stoplight-fastapi"
7
+ version = "0.1.0"
8
+ description = "Seamlessly integrate Stoplight Elements for beautiful, interactive API documentation in FastAPI."
9
+ readme = "README.md"
10
+ keywords = [
11
+ "fastapi",
12
+ "api",
13
+ "documentation",
14
+ "stoplight",
15
+ "openapi",
16
+ "interactive-docs",
17
+ "api-docs",
18
+ "rest-api",
19
+ "swagger",
20
+ ]
21
+ license = "MIT"
22
+ license-files = ["LICENSE"]
23
+ authors = [
24
+ { name = "Tho Nguyen", email = "contact@naiwaaa.simplelogin.com" },
25
+ ]
26
+ classifiers = [
27
+ "Framework :: FastAPI",
28
+ "Intended Audience :: Developers",
29
+ "Intended Audience :: Information Technology",
30
+ "License :: OSI Approved :: MIT License",
31
+ "Operating System :: OS Independent",
32
+ "Programming Language :: Python",
33
+ "Programming Language :: Python :: 3",
34
+ "Programming Language :: Python :: 3 :: Only",
35
+ "Programming Language :: Python :: 3.10",
36
+ "Programming Language :: Python :: 3.11",
37
+ "Programming Language :: Python :: 3.12",
38
+ "Programming Language :: Python :: 3.13",
39
+ "Programming Language :: Python :: 3.14",
40
+ "Topic :: Documentation",
41
+ "Topic :: Software Development :: Libraries :: Python Modules",
42
+ "Typing :: Typed",
43
+ ]
44
+ requires-python = ">=3.10"
45
+ dependencies = [
46
+ "fastapi>=0.115.0",
47
+ ]
48
+
49
+ [project.urls]
50
+ Homepage = "https://codeberg.org/naiwaaa/stoplight-fastapi"
51
+ Documentation = "https://codeberg.org/naiwaaa/stoplight-fastapi"
52
+ Repository = "https://codeberg.org/naiwaaa/stoplight-fastapi"
53
+ Issues = "https://codeberg.org/naiwaaa/stoplight-fastapi/issues"
54
+
55
+ [dependency-groups]
56
+ dev = [
57
+ "ipykernel>=7.2.0",
58
+ "uvicorn>=0.41.0",
59
+ # code quality
60
+ "ruff>=0.15.1",
61
+ "mypy[dmypy,faster-cache]>=1.19.1",
62
+ # tests
63
+ "hypothesis>=6.151.6",
64
+ "inline-snapshot>=0.31.1",
65
+ "pytest>=9.0.2",
66
+ "pytest-asyncio>=1.3.0",
67
+ "pytest-benchmark>=5.2.3",
68
+ "pytest-cov>=7.0.0",
69
+ "pytest-instafail>=0.5.0",
70
+ "pytest-memray>=1.8.0",
71
+ "pytest-mock>=3.15.1",
72
+ "pytest-randomly>=4.0.1",
73
+ "pytest-sugar>=1.1.1",
74
+ "pytest-timeout>=2.4.0",
75
+ "pytest-xdist>=3.8.0",
76
+ "respx>=0.22.0",
77
+ ]
78
+
79
+ [tool.mypy]
80
+ exclude = [".cache/", ".venv/"]
81
+ # disallow dynamic typing
82
+ disallow_any_unimported = true
83
+ disallow_any_expr = false
84
+ disallow_any_decorated = true
85
+ disallow_any_explicit = false
86
+ disallow_any_generics = true
87
+ disallow_subclassing_any = true
88
+ # untyped definitions and calls
89
+ disallow_untyped_calls = true
90
+ disallow_untyped_defs = true
91
+ disallow_incomplete_defs = true
92
+ check_untyped_defs = true
93
+ disallow_untyped_decorators = true
94
+ # none and optional handling
95
+ implicit_optional = false
96
+ strict_optional = true
97
+ # configuring warnings
98
+ warn_redundant_casts = true
99
+ warn_unused_ignores = true
100
+ warn_no_return = true
101
+ warn_return_any = true
102
+ warn_unreachable = true
103
+ # miscellaneous strictness flags
104
+ allow_redefinition = false
105
+ enable_error_code = [
106
+ "redundant-self",
107
+ "redundant-expr",
108
+ "possibly-undefined",
109
+ "truthy-bool",
110
+ "truthy-iterable",
111
+ "ignore-without-code",
112
+ "unused-awaitable",
113
+ "unused-ignore",
114
+ "explicit-override",
115
+ "mutable-override",
116
+ "unimported-reveal",
117
+ "exhaustive-match",
118
+ ]
119
+ implicit_reexport = false
120
+ strict_concatenate = true
121
+ strict_equality = true
122
+ strict_equality_for_none = true
123
+ strict = true
124
+ # configuring error messages
125
+ show_error_context = true
126
+ show_column_numbers = true
127
+ # incremental mode
128
+ cache_dir = ".cache/mypy"
129
+ # advanced options
130
+ plugins = []
131
+
132
+ [tool.pytest.ini_options]
133
+ addopts = [
134
+ # general
135
+ "--exitfirst",
136
+ "--strict",
137
+ "--failed-first",
138
+ # reporting
139
+ "--durations=5",
140
+ "-vv",
141
+ "--no-header",
142
+ "-ra",
143
+ "--showlocals",
144
+ "--junitxml=.cache/pytest/report.xml",
145
+ # collection
146
+ "--ignore-glob=**/fixtures/*",
147
+ "--import-mode=importlib",
148
+ "--doctest-modules",
149
+ "--doctest-continue-on-failure",
150
+ # pytest-benchmark
151
+ "--benchmark-warmup=on",
152
+ "--benchmark-disable-gc",
153
+ "--benchmark-storage=file://./.cache/benchmarks",
154
+ "--benchmark-sort=mean",
155
+ "--benchmark-columns=min,mean,stddev,outliers,rounds,iterations",
156
+ "--benchmark-disable",
157
+ # pytest-cov
158
+ "--cov",
159
+ "--cov-report=term-missing:skip-covered",
160
+ "--cov-report=xml:.cache/pytest/coverage.xml",
161
+ "--cov-config=pyproject.toml",
162
+ # pytest-instafail
163
+ "--instafail",
164
+ # pytest-memray
165
+ "--memray",
166
+ "--most-allocations=5",
167
+ # pytest-timeout
168
+ "--timeout=15",
169
+ # pytest-xdist
170
+ "-n=auto",
171
+ # hypothesis
172
+ "--hypothesis-show-statistics",
173
+ "--hypothesis-explain",
174
+ ]
175
+ cache_dir = ".cache/pytest"
176
+ doctest_optionflags = "NUMBER IGNORE_EXCEPTION_DETAIL"
177
+ pythonpath = ["."]
178
+ markers = [
179
+ "slow: marks tests as slow",
180
+ "network: marks tests that require network access",
181
+ ]
182
+ testpaths = ["tests"]
183
+ # pytest-asyncio
184
+ asyncio_default_fixture_loop_scope = "function"
185
+
186
+ [tool.coverage.run]
187
+ source = ["src/", "tests/"]
188
+ branch = true
189
+ data_file = ".cache/pytest/coverage"
190
+ relative_files = true
191
+
192
+ [tool.coverage.report]
193
+ fail_under = 0
194
+ show_missing = true
195
+ skip_covered = true
196
+ exclude_also = [
197
+ "raise NotImplementedError",
198
+ "if __name__ == .__main__.:",
199
+ ]
200
+
201
+ [tool.commitizen]
202
+ name = "cz_conventional_commits"
203
+ version_scheme = "pep440"
204
+ version_provider = "uv"
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from stoplight_fastapi.__version__ import __version__
4
+ from stoplight_fastapi.stoplight import StoplightConfig, get_stoplight_api_reference
5
+
6
+
7
+ __all__ = ["StoplightConfig", "__version__", "get_stoplight_api_reference"]
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.metadata import version as _metadata_version
4
+
5
+
6
+ __version__ = _metadata_version("stoplight-fastapi")
File without changes
@@ -0,0 +1,132 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Annotated, Literal
5
+
6
+ from annotated_doc import Doc
7
+ from fastapi.responses import HTMLResponse
8
+
9
+
10
+ _default_style = "<style>body { margin: 0; padding: 0; height: 100vh; }</style>"
11
+
12
+
13
+ @dataclass(frozen=True, kw_only=True, slots=True)
14
+ class StoplightConfig:
15
+ """Stoplight Elements configuration options.
16
+
17
+ Read more about it in the
18
+ [Stoplight Elements Configuration Options document](https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options)
19
+ """
20
+
21
+ base_path: str | None = None
22
+ hide_internal: bool = False
23
+ hide_try_it: bool = False
24
+ hide_try_it_panel: bool = False
25
+ hide_schemas: bool = False
26
+ hide_export: bool = False
27
+ try_it_cors_proxy: str | None = None
28
+ try_it_credentials_policy: Literal["omit", "include", "same-origin"] = "omit"
29
+ layout: Literal["sidebar", "responsive", "stacked"] = "sidebar"
30
+ logo: str | None = None
31
+ router: Literal["history", "hash", "memory", "static"] = "hash"
32
+
33
+ def to_html_attributes(self) -> list[str]:
34
+ attributes: list[str] = []
35
+
36
+ for field in self.__annotations__:
37
+ value = getattr(self, field)
38
+ if value:
39
+ attributes.append(f'{field.replace("_", "")}="{value}"')
40
+
41
+ return attributes
42
+
43
+
44
+ def get_stoplight_api_reference(
45
+ *,
46
+ openapi_url: Annotated[
47
+ str | None,
48
+ Doc(
49
+ """
50
+ The OpenAPI URL that Stoplight Elements should load and use.
51
+ """
52
+ ),
53
+ ],
54
+ title: Annotated[
55
+ str,
56
+ Doc(
57
+ """
58
+ The HTML `<title>` content, normally shown in the browser tab.
59
+
60
+ Defaults to "Stoplight Elements" if not provided.
61
+ """
62
+ ),
63
+ ] = "Stoplight Elements",
64
+ stoplight_js_url: Annotated[
65
+ str,
66
+ Doc(
67
+ """
68
+ The URL to use to load the Stoplight Elements JavaScript.
69
+ """
70
+ ),
71
+ ] = "https://unpkg.com/@stoplight/elements/web-components.min.js",
72
+ stoplight_css_url: Annotated[
73
+ str,
74
+ Doc(
75
+ """
76
+ The URL to use to load the Stoplight Elements CSS.
77
+ """
78
+ ),
79
+ ] = "https://unpkg.com/@stoplight/elements/styles.min.css",
80
+ stoplight_favicon_url: Annotated[
81
+ str,
82
+ Doc(
83
+ """
84
+ The URL of the favicon to use. It is normally shown in the browser tab.
85
+ """
86
+ ),
87
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
88
+ stoplight_config: Annotated[
89
+ StoplightConfig | None,
90
+ Doc(
91
+ """
92
+ Configuration options for Stoplight Elements.
93
+
94
+ Read more about it in the
95
+ [Stoplight Elements Configuration Options document](https://docs.stoplight.io/docs/elements/b074dc47b2826-elements-configuration-options)
96
+ """
97
+ ),
98
+ ] = None,
99
+ style: Annotated[
100
+ str,
101
+ Doc(
102
+ """
103
+ Additional CSS styles to apply to the page.
104
+
105
+ By default, it sets the body to have no margin or padding and a height of
106
+ 100vh.
107
+ """
108
+ ),
109
+ ] = _default_style,
110
+ ) -> HTMLResponse:
111
+ config = stoplight_config or StoplightConfig()
112
+
113
+ html = f"""
114
+ <!DOCTYPE html>
115
+ <html>
116
+ <head>
117
+ <meta charset="utf-8"/>
118
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
119
+ <title>{title or "Stoplight Elements"}</title>
120
+ <link rel="shortcut icon" href="{stoplight_favicon_url}">
121
+ <link rel="stylesheet" href="{stoplight_css_url}">
122
+ <script src="{stoplight_js_url}" crossorigin></script>
123
+
124
+ {style}
125
+ </head>
126
+ <body>
127
+ <elements-api apiDescriptionUrl="{openapi_url}" {" ".join(config.to_html_attributes())}/>
128
+ </body>
129
+ </html>
130
+ """ # noqa: E501
131
+
132
+ return HTMLResponse(html)