Coverage for docs/utilities/settings_to_md.py: 0%
88 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-01 10:24 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-01 10:24 +0000
1"""Simple script for automatically creating Markdown-tables for the
2documentation of SimSettings in
3bim2sim/docs/source/advanced-user-guide/concepts/sim_settings.md . To run the
4script, please specify a base path for where to save the Markdown table files
5for each SimSetting class (Base / Building/ PluginEnergyPlus / PluginComfort).
6"""
7import importlib
8import importlib.util
9import pandas as pd
10from pathlib import Path
11import textwrap
12from typing import Union
14from bim2sim.sim_settings import (BooleanSetting, ChoiceSetting,
15 NumberSetting, PathSetting,
16 GuidListSetting, Setting)
19def load_module(source: str):
20 """Load a bim2sim module.
22 Load a module within bim2sim containing SimSettings either from the
23 module name or from a file path and return it.
25 Args:
26 source: source file or module name as a string
28 Returns:
29 module: loaded module
30 """
31 if source.endswith(".py"):
32 spec = importlib.util.spec_from_file_location("temp_module", source)
33 module = importlib.util.module_from_spec(spec)
34 spec.loader.exec_module(module)
35 return module
36 else:
37 return importlib.import_module(source)
40def simplify_type_name(setting_obj) -> str:
41 """ Simplify SimSetting types.
43 Simplify SimSetting types to shorter names as strings for `Type`
44 column.
46 Args:
47 setting_obj: bim2sim SimSetting object
49 Returns:
50 string defining the simplified SimSetting type
51 """
52 if isinstance(setting_obj, BooleanSetting):
53 return "Boolean"
54 if isinstance(setting_obj, NumberSetting):
55 return "Number"
56 if isinstance(setting_obj, ChoiceSetting):
57 return "Choice"
58 if isinstance(setting_obj, PathSetting):
59 return "Path"
60 if isinstance(setting_obj, GuidListSetting):
61 return "GuidList"
62 if isinstance(setting_obj, Setting):
63 return "Base"
64 return type(setting_obj).__name__
67def wrap_for_md(text: str, width: int) -> str:
68 """Wrap text sections after specified length.
70 Wrap longer texts in the Description or Choices column after `width`
71 characters for better readability.
73 Args:
74 text: string to be wrapped
75 width: number of characters after which text is wrapped
77 Returns:
78 reformatted string with automatic linebreaks
79 """
80 if text is None:
81 return ""
82 text = str(text).strip()
83 if not text:
84 return ""
85 # automatic linebreaks
86 paragraphs = text.split("\n\n")
87 wrapped_paragraphs = []
88 for p in paragraphs:
89 p_single = " ".join(line.strip() for line in p.splitlines())
90 wrapped = textwrap.wrap(p_single, width=width)
91 if not wrapped:
92 wrapped_paragraphs.append("")
93 else:
94 wrapped_paragraphs.append("<br>".join(wrapped))
95 return "<br><br>".join(wrapped_paragraphs)
98def choices_to_string(choices: Union[dict, list, None], wrap_width: int) -> str:
99 """Convert SimSetting Choices to a string.
101 Convert a dictionary or list of Choices for a SimSetting to a string
102 for Markdown-tables. If there are more than 10 settings, the short
103 description of each choice is not adopted.
105 Args:
106 choices: list or dict of Choices for a SimSetting to be converted
107 wrap_width: number of characters after which text is wrapped
109 Returns:
110 formatted string containing Choices as text
111 """
112 s = ""
113 if not choices:
114 return ""
115 if len(choices) > 10 and isinstance(choices, dict):
116 choices = list(choices.keys())
117 if isinstance(choices, dict):
118 entries = [f"'{k}': {v}" if v else f"{k}" for k, v in choices.items()]
119 s = "<br>".join(entries)
120 elif isinstance(choices, (list, tuple)):
121 entries = [str(f"'{e}'") for e in choices]
122 s = ", ".join(entries)
123 s = wrap_for_md(s, wrap_width)
124 return s
127def extract_settings_from_class(cls, wrap_width: int = 60):
128 """Get SimSettings from a bim2sim class.
130 Extract all Settings of a SimSetting class `cls` and put the
131 properties Setting Name, Type, Default, Description and Choices in to a
132 list.
134 Args:
135 cls: class to extract Settings from
136 wrap_width: number of characters after which text is wrapped
138 Returns:
139 list of Settings objectssorted in Setting Name, Type, Default,
140 Description, and Choices columns
141 """
142 rows = []
143 for name, value in list(cls.__dict__.items()):
144 if name.startswith("_"):
145 continue
146 if isinstance(value, (BooleanSetting, ChoiceSetting, NumberSetting,
147 PathSetting, GuidListSetting, Setting)):
148 stype = simplify_type_name(value)
149 default = getattr(value, "default", "")
150 default = f"'{default}'" if isinstance(default, str) else default
151 description = getattr(value, "description", "") or ""
152 description = wrap_for_md(description, width=wrap_width)
153 choices_col = ""
154 if isinstance(value, ChoiceSetting):
155 choices_col = choices_to_string(getattr(value, "choices",
156 None), wrap_width)
157 rows.append({"Setting Name": name, "Type": stype, "Default":
158 default, "Description": description, "Choices":
159 choices_col})
160 return rows
163def settings_to_markdown(source: str, class_name: str,
164 output_md: str = "settings.md", wrap_width: int = 60):
165 """Generate Markdown-tables from SimSettings.
167 Generate a markdown table for SimSettings defined in `class_name`
168 found in `source`. `source` can be a dotted module name (e.g.
169 "bim2sim.sim_settings") or a path to a .py file. Save table to output.md
170 file with text wrapping in the `Description` and `Choices` columns after
171 wrap_width characters.
173 Args:
174 source: name of a bim2sim SimSettings module or a path to a .py file
175 class_name: name of the class containing the SimSettings objects
176 output_md: path to output Markdown-tables
177 wrap_width: number of characters after which text is wrapped
178 """
179 mod = load_module(source)
180 cls = getattr(mod, class_name)
181 rows = extract_settings_from_class(cls, wrap_width=wrap_width)
182 df = pd.DataFrame(rows)
183 df = df[["Setting Name", "Type", "Default", "Description", "Choices"]]
184 markdown_str = df.to_markdown(index=False)
185 Path(output_md).write_text(markdown_str, encoding="utf-8")
186 print(f"Markdown table written to {output_md}")
189if __name__ == "__main__":
190 save_path = "" # Add path to save markdown tables here
191 settings_to_markdown(
192 "bim2sim.plugins.PluginComfort.bim2sim_comfort.sim_settings",
193 "ComfortSimSettings",
194 save_path + "comfort_settings.md")
195 settings_to_markdown("bim2sim.sim_settings",
196 "BaseSimSettings",
197 save_path + "base_settings.md")
198 settings_to_markdown("bim2sim.sim_settings",
199 "BuildingSimSettings",
200 save_path + "building_settings.md")
201 settings_to_markdown(
202 "bim2sim.plugins.PluginEnergyPlus.bim2sim_energyplus.sim_settings",
203 "EnergyPlusSimSettings",
204 save_path + "eplus_settings.md")