mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-04-17 07:55:15 +00:00
Use documentation generation tools that are available for Windows and Linux. Use python instead of shell scripts to generate documentation. For ReadTheDocs make generated documentation content static to avoid running scripts outside of the docs/ path which is the default path for ReadTheDOcs. Add tests that check if generated content does go out of sync with latest source. Use tabs to show commands for Windows and Linux to improve user experience. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
166 lines
5.7 KiB
Python
Executable File
166 lines
5.7 KiB
Python
Executable File
#!.venv/bin/python
|
|
"""Utility functions for Configuration specification generation."""
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
from akkudoktoreos.config.config import get_config
|
|
from akkudoktoreos.core.logging import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
config_eos = get_config()
|
|
|
|
# Fixed set of prefixes to filter configuration values and their respective titles
|
|
CONFIG_PREFIXES = {
|
|
"battery": "Battery Device Simulation Configuration",
|
|
"bev": "Battery Electric Vehicle Device Simulation Configuration",
|
|
"dishwasher": "Dishwasher Device Simulation Configuration",
|
|
"inverter": "Inverter Device Simulation Configuration",
|
|
"measurement": "Measurement Configuration",
|
|
"optimization": "General Optimization Configuration",
|
|
"server": "Server Configuration",
|
|
"elecprice": "Electricity Price Prediction Configuration",
|
|
"load": "Load Prediction Configuration",
|
|
"logging": "Logging Configuration",
|
|
"prediction": "General Prediction Configuration",
|
|
"pvforecast": "PV Forecast Configuration",
|
|
"weather": "Weather Forecast Configuration",
|
|
}
|
|
|
|
# Static set of configuration names to include in a separate table
|
|
GENERAL_CONFIGS = [
|
|
"config_default_file_path",
|
|
"config_file_path",
|
|
"config_folder_path",
|
|
"config_keys",
|
|
"config_keys_read_only",
|
|
"data_cache_path",
|
|
"data_cache_subpath",
|
|
"data_folder_path",
|
|
"data_output_path",
|
|
"data_output_subpath",
|
|
"latitude",
|
|
"longitude",
|
|
"package_root_path",
|
|
"timezone",
|
|
]
|
|
|
|
|
|
def generate_config_table_md(configs, title):
|
|
"""Generate a markdown table for given configurations.
|
|
|
|
Args:
|
|
configs (dict): Configuration values with keys and their descriptions.
|
|
title (str): Title for the table.
|
|
|
|
Returns:
|
|
str: The markdown table as a string.
|
|
"""
|
|
if not configs:
|
|
return ""
|
|
|
|
table = f"## {title}\n\n"
|
|
table += ":::{table} " + f"{title}\n:widths: 10 10 5 5 30\n:align: left\n\n"
|
|
table += "| Name | Type | Read-Only | Default | Description |\n"
|
|
table += "| ---- | ---- | --------- | ------- | ----------- |\n"
|
|
for name, config in sorted(configs.items()):
|
|
type_name = config["type"]
|
|
if type_name.startswith("typing."):
|
|
type_name = type_name[len("typing.") :]
|
|
table += f"| `{config['name']}` | `{type_name}` | `{config['read-only']}` | `{config['default']}` | {config['description']} |\n"
|
|
table += ":::\n\n" # Add an empty line after the table
|
|
return table
|
|
|
|
|
|
def generate_config_md() -> str:
|
|
"""Generate configuration specification in Markdown with extra tables for prefixed values.
|
|
|
|
Returns:
|
|
str: The Markdown representation of the configuration spec.
|
|
"""
|
|
configs = {}
|
|
config_keys = config_eos.config_keys
|
|
config_keys_read_only = config_eos.config_keys_read_only
|
|
for config_key in config_keys:
|
|
config = {}
|
|
config["name"] = config_key
|
|
config["value"] = getattr(config_eos, config_key)
|
|
|
|
if config_key in config_keys_read_only:
|
|
config["read-only"] = "ro"
|
|
computed_field_info = config_eos.__pydantic_decorators__.computed_fields[
|
|
config_key
|
|
].info
|
|
config["default"] = "N/A"
|
|
config["description"] = computed_field_info.description
|
|
config["type"] = str(computed_field_info.return_type)
|
|
else:
|
|
config["read-only"] = "rw"
|
|
field_info = config_eos.model_fields[config_key]
|
|
config["default"] = field_info.default
|
|
config["description"] = field_info.description
|
|
config["type"] = str(field_info.annotation)
|
|
|
|
configs[config_key] = config
|
|
|
|
# Generate markdown for the main table
|
|
markdown = "# Configuration Table\n\n"
|
|
|
|
# Generate table for general configuration names
|
|
general_configs = {k: v for k, v in configs.items() if k in GENERAL_CONFIGS}
|
|
for k in general_configs.keys():
|
|
del configs[k] # Remove general configs from the main configs dictionary
|
|
markdown += generate_config_table_md(general_configs, "General Configuration Values")
|
|
|
|
non_prefixed_configs = {k: v for k, v in configs.items()}
|
|
|
|
# Generate tables for each prefix (sorted by value) and remove prefixed configs from the main dictionary
|
|
sorted_prefixes = sorted(CONFIG_PREFIXES.items(), key=lambda item: item[1])
|
|
for prefix, title in sorted_prefixes:
|
|
prefixed_configs = {k: v for k, v in configs.items() if k.startswith(prefix)}
|
|
for k in prefixed_configs.keys():
|
|
del non_prefixed_configs[k]
|
|
markdown += generate_config_table_md(prefixed_configs, title)
|
|
|
|
# Generate markdown for the remaining non-prefixed configs if any
|
|
if non_prefixed_configs:
|
|
markdown += generate_config_table_md(non_prefixed_configs, "Other Configuration Values")
|
|
|
|
# Assure the is no double \n at end of file
|
|
markdown = markdown.rstrip("\n")
|
|
markdown += "\n"
|
|
|
|
return markdown
|
|
|
|
|
|
def main():
|
|
"""Main function to run the generation of the Configuration specification as Markdown."""
|
|
parser = argparse.ArgumentParser(description="Generate Configuration Specification as Markdown")
|
|
parser.add_argument(
|
|
"--output-file",
|
|
type=str,
|
|
default=None,
|
|
help="File to write the Configuration Specification to",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
config_md = generate_config_md()
|
|
if args.output_file:
|
|
# Write to file
|
|
with open(args.output_file, "w") as f:
|
|
f.write(config_md)
|
|
else:
|
|
# Write to std output
|
|
print(config_md)
|
|
|
|
except Exception as e:
|
|
print(f"Error during Configuration Specification generation: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|