Skip to content

Commit 907682d

Browse files
committed
Add custom template parameter
1 parent e5fa8f2 commit 907682d

File tree

5 files changed

+345
-25
lines changed

5 files changed

+345
-25
lines changed

openapidocs/commands/docs.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,20 @@
3131
default="MKDOCS",
3232
show_default=True,
3333
)
34-
def generate_documents_command(source: str, destination: str, style: Union[int, str]):
34+
@click.option(
35+
"-T",
36+
"--templates",
37+
help=(
38+
"Path to a custom templates directory. "
39+
"Templates in this directory will override default templates with matching names. "
40+
"Unspecified templates will use defaults."
41+
),
42+
required=False,
43+
default=None,
44+
)
45+
def generate_documents_command(
46+
source: str, destination: str, style: Union[int, str], templates: Union[str, None]
47+
):
3548
"""
3649
Generates other kinds of documents from source OpenAPI Documentation files.
3750
@@ -48,7 +61,7 @@ def generate_documents_command(source: str, destination: str, style: Union[int,
4861
https://github.com/Neoteroi/essentials-openapi
4962
"""
5063
try:
51-
generate_document(source, destination, style)
64+
generate_document(source, destination, style, templates)
5265
except KeyboardInterrupt: # pragma: nocover
5366
logger.info("User interrupted")
5467
exit(1)

openapidocs/mk/generate.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
from typing import Optional
2+
13
from openapidocs.mk.v3 import OpenAPIV3DocumentationHandler
24
from openapidocs.utils.source import read_from_source
35

46

5-
def generate_document(source: str, destination: str, style: int | str):
7+
def generate_document(
8+
source: str,
9+
destination: str,
10+
style: int | str,
11+
templates_path: Optional[str] = None,
12+
):
613
# Note: if support for more kinds of OAD versions will be added, handle a version
714
# parameter in this function
815

916
data = read_from_source(source)
10-
handler = OpenAPIV3DocumentationHandler(data, style=style, source=source)
17+
handler = OpenAPIV3DocumentationHandler(
18+
data, style=style, source=source, templates_path=templates_path
19+
)
1120

1221
html = handler.write()
1322

openapidocs/mk/jinja.py

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
"""
22
This module provides a Jinja2 environment.
33
"""
4+
45
import os
56
from enum import Enum
6-
7-
from jinja2 import Environment, PackageLoader, Template, select_autoescape
7+
from pathlib import Path
8+
from typing import Optional
9+
10+
from jinja2 import (
11+
ChoiceLoader,
12+
Environment,
13+
FileSystemLoader,
14+
PackageLoader,
15+
Template,
16+
select_autoescape,
17+
)
818

919
from . import get_http_status_phrase, highlight_params, read_dict, sort_dict
1020
from .common import DocumentsWriter, is_reference
@@ -62,29 +72,50 @@ def __init__(
6272

6373

6474
def get_environment(
65-
package_name: str, views_style: OutputStyle = OutputStyle.MKDOCS
75+
package_name: str,
76+
views_style: OutputStyle = OutputStyle.MKDOCS,
77+
custom_templates_path: Optional[str] = None,
6678
) -> Environment:
6779
templates_folder = f"views_{views_style.name}".lower()
6880

81+
loaders = []
82+
83+
# If custom templates path is provided, validate and add FileSystemLoader first
84+
if custom_templates_path:
85+
custom_path = Path(custom_templates_path)
86+
if not custom_path.exists():
87+
raise ValueError(
88+
f"Custom templates path does not exist: {custom_templates_path}"
89+
)
90+
if not custom_path.is_dir():
91+
raise ValueError(
92+
f"Custom templates path is not a directory: {custom_templates_path}"
93+
)
94+
loaders.append(FileSystemLoader(str(custom_path)))
95+
96+
# Always add the package loader as fallback
6997
try:
70-
loader = PackageLoader(package_name, templates_folder)
98+
loaders.append(PackageLoader(package_name, templates_folder))
7199
except ValueError as package_loading_error: # pragma: no cover
72-
raise PackageLoadingError(
73-
views_style, templates_folder
74-
) from package_loading_error
75-
else:
76-
env = Environment(
77-
loader=loader,
78-
autoescape=select_autoescape(["html", "xml"])
79-
if os.environ.get("SELECT_AUTOESCAPE") in {"YES", "Y", "1"}
80-
else False,
81-
auto_reload=True,
82-
enable_async=False,
83-
)
84-
configure_filters(env)
85-
configure_functions(env)
100+
if not custom_templates_path:
101+
raise PackageLoadingError(
102+
views_style, templates_folder
103+
) from package_loading_error
104+
105+
loader = ChoiceLoader(loaders)
106+
107+
env = Environment(
108+
loader=loader,
109+
autoescape=select_autoescape(["html", "xml"])
110+
if os.environ.get("SELECT_AUTOESCAPE") in {"YES", "Y", "1"}
111+
else False,
112+
auto_reload=True,
113+
enable_async=False,
114+
)
115+
configure_filters(env)
116+
configure_functions(env)
86117

87-
return env
118+
return env
88119

89120

90121
class Jinja2DocumentsWriter(DocumentsWriter):
@@ -97,8 +128,9 @@ def __init__(
97128
self,
98129
package_name: str,
99130
views_style: OutputStyle = OutputStyle.MKDOCS,
131+
custom_templates_path: Optional[str] = None,
100132
) -> None:
101-
self._env = get_environment(package_name, views_style)
133+
self._env = get_environment(package_name, views_style, custom_templates_path)
102134

103135
@property
104136
def env(self) -> Environment:

openapidocs/mk/v3/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
This module provides functions to generate Markdown for OpenAPI Version 3.
33
"""
4+
45
import copy
56
import os
67
import warnings
@@ -95,11 +96,14 @@ def __init__(
9596
writer: Optional[DocumentsWriter] = None,
9697
style: Union[int, str] = 1,
9798
source: str = "",
99+
templates_path: Optional[str] = None,
98100
) -> None:
99101
self._source = source
100102
self.texts = texts or EnglishTexts()
101103
self._writer = writer or Jinja2DocumentsWriter(
102-
__name__, views_style=style_from_value(style)
104+
__name__,
105+
views_style=style_from_value(style),
106+
custom_templates_path=templates_path,
103107
)
104108
self.doc = self.normalize_data(copy.deepcopy(doc))
105109

0 commit comments

Comments
 (0)