Coverage for /usr/local/lib/python3.12/site-packages/prefect/utilities/render_swagger.py: 0%
63 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 13:38 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 13:38 +0000
1##
2## THIS FILE WAS COPIED FROM https://github.com/bharel/mkdocs-render-swagger-plugin/blob/main/render_swagger.py
3## TO ALLOW FOR CUSTOM MODIFICATION TO THE SWAGGERUIBUNDLE OBJECT
4##
6import os
7import re
8import string
9import urllib.parse
10from pathlib import Path
11from typing import Any, Optional, cast
12from xml.sax.saxutils import escape
14import mkdocs.plugins
15from mkdocs.config.defaults import MkDocsConfig
16from mkdocs.structure.files import File, Files
17from mkdocs.structure.pages import Page
19USAGE_MSG = (
20 "Usage: '!!swagger <filename>!!' or '!!swagger-http <url>!!'. "
21 "File must either exist locally and be placed next to the .md that contains "
22 "the swagger statement, or be an http(s) URL."
23)
25TEMPLATE = string.Template(
26 """
28<link type="text/css" rel="stylesheet" href="$swagger_lib_css">
29<div id="swagger-ui">
30</div>
31<script src="$swagger_lib_js" charset="UTF-8"></script>
32<script>
33 const ui = SwaggerUIBundle({
34 url: '$path',
35 defaultModelsExpandDepth: -1,
36 dom_id: '#swagger-ui',
37 docExpansion: 'none',
38 deepLinking: true,
39 supportedSubmitMethods: [],
40 })
41</script>
43"""
44)
46ERROR_TEMPLATE = string.Template("!! SWAGGER ERROR: $error !!")
48# Used for JS. Runs locally on end-user. RFI / LFI not possible, no security risk.
49# Restrict to local file.
50TOKEN = re.compile(r"!!swagger(?: (?P<path>[^\\/\s><&:]+))?!!")
52# HTTP(S) variant
53TOKEN_HTTP = re.compile(r"!!swagger-http(?: (?P<path>https?://[^\s]+))?!!")
56def swagger_lib(config: MkDocsConfig) -> dict[str, Any]:
57 """
58 Provides the actual swagger library used
59 """
60 lib_swagger = {
61 "css": "https://unpkg.com/swagger-ui-dist@3/swagger-ui.css",
62 "js": "https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js",
63 }
65 extra_javascript = config.extra_javascript
66 extra_css = cast(list[str], config.extra_css) # pyright: ignore[reportUnknownMemberType] incomplete type hint
67 for lib in extra_javascript:
68 if (
69 os.path.basename(urllib.parse.urlparse(str(lib)).path)
70 == "swagger-ui-bundle.js"
71 ):
72 lib_swagger["js"] = str(lib)
73 break
75 for css in extra_css:
76 if os.path.basename(urllib.parse.urlparse(css).path) == "swagger-ui.css":
77 lib_swagger["css"] = css
78 break
79 return lib_swagger
82class SwaggerPlugin(mkdocs.plugins.BasePlugin[Any]):
83 def on_page_markdown(
84 self, markdown: str, /, *, page: Page, config: MkDocsConfig, files: Files
85 ) -> Optional[str]:
86 is_http = False
87 match = TOKEN.search(markdown)
89 if match is None:
90 match = TOKEN_HTTP.search(markdown)
91 is_http = True
93 if match is None:
94 return markdown
96 pre_token = markdown[: match.start()]
97 post_token = markdown[match.end() :]
99 def _error(message: str) -> str:
100 return (
101 pre_token
102 + escape(ERROR_TEMPLATE.substitute(error=message))
103 + post_token
104 )
106 path = match.group("path")
108 if path is None:
109 return _error(USAGE_MSG)
111 if is_http:
112 url = path
113 else:
114 base = page.file.abs_src_path
115 assert base is not None
116 try:
117 api_file = Path(base).with_name(path)
118 except ValueError as exc:
119 return _error(f"Invalid path. {exc.args[0]}")
121 if not api_file.exists():
122 return _error(f"File {path} not found.")
124 src_dir = api_file.parent
125 dest_dir = Path(page.file.abs_dest_path).parent
127 new_file = File(api_file.name, str(src_dir), str(dest_dir), False)
128 files.append(new_file)
129 url = Path(new_file.abs_dest_path).name
131 lib = swagger_lib(config)
133 markdown = (
134 pre_token
135 + TEMPLATE.substitute(
136 path=url, swagger_lib_js=lib["js"], swagger_lib_css=lib["css"]
137 )
138 + post_token
139 )
141 # If multiple swaggers exist.
142 return self.on_page_markdown(markdown, page=page, config=config, files=files)