Skip to content

Commit a91a8ae

Browse files
committed
✨[#64] add setup config rst templates
1 parent 3a07693 commit a91a8ae

File tree

6 files changed

+198
-22
lines changed

6 files changed

+198
-22
lines changed

open_api_framework/management/commands/generate_envvar_docs.py

Lines changed: 141 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.template import loader
77
from django.utils.module_loading import import_string
88

9+
from django_setup_configuration.config_settings import ConfigSettings
910
from django_setup_configuration.management.commands.generate_config_docs import (
1011
ConfigDocBase,
1112
)
@@ -27,7 +28,140 @@ def convert_variables_to_rst(variables: list[EnvironmentVariable]) -> str:
2728
return template.render({"vars": vars})
2829

2930

30-
class Command(ConfigDocBase, BaseCommand):
31+
class SetupConfigDocs(ConfigDocBase):
32+
33+
def generate_config_file(self) -> str:
34+
35+
full_rendered_content = ""
36+
37+
if not hasattr(settings, "SETUP_CONFIGURATION_STEPS"):
38+
return full_rendered_content
39+
40+
for config_string in settings.SETUP_CONFIGURATION_STEPS:
41+
config_step = import_string(config_string)
42+
43+
config_settings = getattr(config_step, "config_settings", None)
44+
if not config_settings or not config_settings.independent:
45+
continue
46+
47+
rendered_content = self.render_doc(config_settings, config_step)
48+
full_rendered_content += rendered_content
49+
50+
template = loader.get_template("open_api_framework/setup_config.rst")
51+
rendered = template.render(
52+
{"rendered_configuration_steps": full_rendered_content}
53+
)
54+
55+
return rendered
56+
57+
def render_doc(self, config_settings, config_step) -> str:
58+
"""
59+
Render a `ConfigSettings` documentation template with the following variables:
60+
1. enable_setting
61+
2. required_settings
62+
3. optional_settings
63+
4. detailed_info
64+
5. title
65+
"""
66+
# 1.
67+
enable_setting = getattr(config_settings, "enable_setting", None)
68+
69+
# 2.
70+
required_settings = [
71+
name for name in getattr(config_settings, "required_settings", [])
72+
]
73+
74+
# additional settings from related configuration steps to embed
75+
# the documentation of several steps into one
76+
related_config_settings = [
77+
config for config in getattr(config_settings, "related_config_settings", [])
78+
]
79+
required_settings_related = self.extract_unique_settings(
80+
[config.required_settings for config in related_config_settings]
81+
)
82+
# optional_settings_related = self.extract_unique_settings(
83+
# [config.optional_settings for config in related_config_settings]
84+
# )
85+
86+
required_settings.extend(required_settings_related)
87+
required_settings.sort()
88+
89+
optional_settings = config_settings.optional_settings
90+
optional_settings.sort()
91+
92+
# 4.
93+
detailed_info = self.get_detailed_info(
94+
config_settings,
95+
related_config_settings,
96+
)
97+
98+
# 5.
99+
title = self.format_display_name(config_step.verbose_name)
100+
101+
template_variables = {
102+
"enable_setting": enable_setting,
103+
"required_settings": required_settings,
104+
"optional_settings": optional_settings,
105+
"detailed_info": detailed_info,
106+
"title": title,
107+
}
108+
109+
template = loader.get_template(
110+
"open_api_framework/components/setup_config_step.rst"
111+
)
112+
rendered = template.render(template_variables)
113+
114+
return rendered
115+
116+
def format_display_name(self, display_name: str) -> str:
117+
"""Underlines title with '=' to display as heading in rst file"""
118+
119+
heading_bar = "-" * len(display_name)
120+
display_name_formatted = f"{display_name}\n{heading_bar}"
121+
return display_name_formatted
122+
123+
def get_detailed_info(
124+
self,
125+
config_settings: ConfigSettings,
126+
related_config_settings: list[ConfigSettings],
127+
) -> dict[dict[str]]:
128+
"""
129+
Get information about the configuration settings:
130+
1. from model fields associated with the `ConfigSettings`
131+
2. from information provided manually in the `ConfigSettings`
132+
3. from information provided manually in the `ConfigSettings` of related
133+
configuration steps
134+
"""
135+
result = dict()
136+
for field in config_settings.config_fields:
137+
part = dict()
138+
variable = config_settings.get_config_variable(field.name)
139+
part["setting"] = field.verbose_name
140+
part["description"] = field.description or 'No description'
141+
part["possible_values"] = field.field_description
142+
part["default_value"] = field.default_value
143+
144+
result[variable] = part
145+
146+
self.add_additional_info(config_settings, result)
147+
for config_settings in related_config_settings:
148+
self.add_additional_info(config_settings, result)
149+
150+
return result
151+
152+
@staticmethod
153+
def add_additional_info(
154+
config_settings: ConfigSettings, result: dict[dict[str]]
155+
) -> None:
156+
"""Convenience/helper function to retrieve additional documentation info"""
157+
158+
additional_info = config_settings.additional_info
159+
160+
for key, value in additional_info.items():
161+
result[key] = value
162+
163+
164+
class Command(BaseCommand):
31165
help = "Generate documentation for all used envvars"
32166

33167
def add_arguments(self, parser):
@@ -55,7 +189,8 @@ def handle(self, *args, **options):
55189
self.generate_regular_config_docs(*args, **options)
56190
self.generate_setup_config_docs(*args, **options)
57191

58-
def generate_regular_config_docs(self, *args, **options):
192+
@staticmethod
193+
def generate_regular_config_docs(*args, **options):
59194
from open_api_framework.conf.utils import ENVVAR_REGISTRY
60195

61196
file_path = options["envvar_file"]
@@ -77,22 +212,13 @@ def _sort(envvar):
77212
with open(file_path, "w") as f:
78213
f.write(convert_variables_to_rst(sorted_registry))
79214

80-
def generate_setup_config_docs(self, *args, **options) -> None:
81-
full_rendered_content = ""
215+
@staticmethod
216+
def generate_setup_config_docs(*args, **options) -> None:
82217

83218
file_path = options["config_file"]
84-
if not hasattr(settings, "SETUP_CONFIGURATION_STEPS"):
85-
return
219+
doc_generator = SetupConfigDocs()
86220

87-
for config_string in settings.SETUP_CONFIGURATION_STEPS:
88-
config_step = import_string(config_string)
89-
90-
config_settings = getattr(config_step, "config_settings", None)
91-
if not config_settings or not config_settings.independent:
92-
continue
93-
94-
rendered_content = self.render_doc(config_settings, config_step)
95-
full_rendered_content += rendered_content
221+
full_rendered_content = doc_generator.generate_config_file()
96222

97223
if len(full_rendered_content) > 0:
98224
with open(file_path, "w") as f:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{% load doc_tags %}
2+
{% spaceless %}
3+
{{ title }}
4+
5+
Enable/Disable configuration:
6+
"""""""""""""""""""""""""""""
7+
8+
::
9+
10+
{{ enable_setting }}
11+
12+
{% if required_settings %}
13+
Required settings
14+
"""""""""""""""""
15+
{% for setting in required_settings %}
16+
* ``{{ setting }}``: {% config_var_description setting detailed_info %}
17+
{% endfor %}{% endif %}
18+
19+
{% if optional_settings %}
20+
Optional Settings
21+
"""""""""""""""""
22+
{% for setting in optional_settings %}
23+
* ``{{ setting }}``: {% config_var_description setting detailed_info %}
24+
{% endfor %}{% endif %}
25+
26+
{% endspaceless %}

open_api_framework/templates/open_api_framework/env_config.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ Available environment variables
1111

1212
{% for group_name, group_vars in vars %}
1313
{{group_name}}
14-
{{group_name|repeat_char:"-"}}{% for subgroup_name, subgroup_vars in group_vars %}
15-
{% if subgroup_name is not null %}
14+
{{group_name|repeat_char:"-"}}
15+
16+
{% spaceless %}{% for subgroup_name, subgroup_vars in group_vars %}{% if subgroup_name is not null %}
1617
{{subgroup_name}}
17-
{{subgroup_name|repeat_char:"^"}}
18-
{% endif %}
19-
{% for var in subgroup_vars %}* ``{{var.name}}``: {% if var.help_text %}{{var.help_text|safe|ensure_endswith:"."}}{% endif %}{% if var.auto_display_default and not var.default|is_undefined %} Defaults to: ``{{var.default|to_str|safe}}``.{% endif %}
20-
{% endfor %}{% endfor %}
18+
{{subgroup_name|repeat_char:"^"}}{% endif %}
19+
20+
{% spaceless %}
21+
{% for var in subgroup_vars %}
22+
* ``{{var.name}}``: {% if var.help_text %}{{var.help_text|safe|ensure_endswith:"."}}{% endif %}{% if var.auto_display_default and not var.default|is_undefined %} Defaults to: ``{{var.default|to_str|safe}}``.{% endif %}{% endfor %}{% endspaceless %}{% endfor %}{% endspaceless %}
23+
2124
{% endfor %}
2225

2326
{% block extra %}{% endblock %}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{% load doc_tags %}.. _installation_setup_config:
2+
3+
=============================
4+
Setup configuration reference
5+
=============================
6+
7+
{% block intro %}
8+
Setup configuration description
9+
{% endblock %}
10+
11+
Configuration Environment Variables
12+
===================================
13+
14+
All configuration steps currently available:
15+
16+
{{ rendered_configuration_steps | safe }}

open_api_framework/templatetags/doc_tags.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ def ensure_endswith(value, char):
3333
if not value.endswith(char):
3434
value += char
3535
return value
36+
37+
@register.filter()
38+
def config_var_description(variable, details):
39+
40+
return details[variable].get("description")

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ extras =
2727
deps =
2828
django42: Django~=4.2.0
2929
commands =
30-
py.test tests \
30+
py.test tests -vv \
3131
--cov --cov-report xml:reports/coverage-{envname}.xml \
3232
{posargs}
3333

0 commit comments

Comments
 (0)