ATLAS Offline Software
Loading...
Searching...
No Matches
python.AutogenDocumentation Namespace Reference

Functions

Dict[str, List[Dict[str, Any]]] load_output_variables (str yaml_filepath)
Dict[str, Any] extract_block_options (Type block_class)
Optional[str] interpret_physical_unit (str info)
str process_info_links (str info)
str link_jira_tickets (str info)
List[Dict[str, Any]] extract_from_classes (List[Type] block_classes, Optional[Union[str, List[str]]] output_vars_yaml=None)
None save_as_yaml (List[Dict[str, Any]] data, str filepath)
str generate_block_markdown (Dict[str, Any] block_info)
None process_markdown_with_autogen (str input_filepath, str output_filepath, List[Dict[str, Any]] block_data)

Variables

 logger = logging.getLogger("AutogenDocumentation")

Detailed Description

Core methods to extract options information from ConfigBlock classes and merge with
output variables metadata from a YAML file.

Function Documentation

◆ extract_block_options()

Dict[str, Any] extract_block_options ( Type block_class)
Extract options information from a ConfigBlock subclass.

Args:
    block_class: A class that inherits from ConfigBlock

Returns:
    A dictionary containing the class name and its options

Definition at line 40 of file AutogenDocumentation.py.

40def extract_block_options(block_class: Type) -> Dict[str, Any]:
41 """
42 Extract options information from a ConfigBlock subclass.
43
44 Args:
45 block_class: A class that inherits from ConfigBlock
46
47 Returns:
48 A dictionary containing the class name and its options
49 """
50 # Create a temporary instance to access the options
51 instance = block_class()
52
53 # Get the options dictionary
54 options_dict = instance.getOptions()
55
56 # Extract information for each option
57 options_list = []
58 for option_name, option_obj in options_dict.items():
59 # skip some specific options
60 if option_name in ["groupName", "propertyOverrides", "ignoreDependencies"]:
61 continue
62 option_info = {
63 "label": option_name,
64 "type": option_obj.type.__name__ if option_obj.type is not None else "None",
65 "default": option_obj.default,
66 "info": option_obj.info,
67 "required": option_obj.required,
68 "noneAction": option_obj.noneAction,
69 "physicalUnit": interpret_physical_unit(option_obj.info),
70 "meta": option_obj.meta,
71 }
72 # Check if this option has expert mode settings
73 if (
74 hasattr(instance, "_expertModeSettings")
75 and option_name in instance._expertModeSettings
76 ):
77 expert_rule = instance._expertModeSettings[option_name]
78 if not isinstance(expert_rule, list):
79 expert_rule = [expert_rule]
80 else:
81 expert_rule = None
82 option_info["expertMode"] = expert_rule
83 options_list.append(option_info)
84
85 return {
86 "class": block_class.__name__,
87 "module": block_class.__module__,
88 "docstring": inspect.getdoc(block_class),
89 "options": options_list,
90 }
91
92

◆ extract_from_classes()

List[Dict[str, Any]] extract_from_classes ( List[Type] block_classes,
Optional[Union[str, List[str]]] output_vars_yaml = None )
Extract options information from a list of ConfigBlock classes and merge
with output variables metadata.

Args:
    block_classes: List of classes that inherit from ConfigBlock
    output_vars_yaml: Optional path to YAML file or list of paths to YAML files
                     containing output variables. If multiple files provided,
                     their contents will be merged. Files are located using
                     find_datafile.

Returns:
    List of dictionaries, each containing information about a block class

Definition at line 192 of file AutogenDocumentation.py.

194) -> List[Dict[str, Any]]:
195 """
196 Extract options information from a list of ConfigBlock classes and merge
197 with output variables metadata.
198
199 Args:
200 block_classes: List of classes that inherit from ConfigBlock
201 output_vars_yaml: Optional path to YAML file or list of paths to YAML files
202 containing output variables. If multiple files provided,
203 their contents will be merged. Files are located using
204 find_datafile.
205
206 Returns:
207 List of dictionaries, each containing information about a block class
208 """
209 # Load output variables if YAML file(s) provided
210 output_vars_map = {}
211 if output_vars_yaml:
212 # Normalize to list for uniform processing
213 yaml_files = (
214 [output_vars_yaml]
215 if isinstance(output_vars_yaml, str)
216 else output_vars_yaml
217 )
218
219 # Load and merge all YAML files
220 for yaml_file in yaml_files:
221 # Locate the file
222 resolved_path = find_datafile(yaml_file)
223 if resolved_path is None:
224 raise FileNotFoundError(f"Could not locate YAML file: {yaml_file}")
225
226 file_vars = load_output_variables(resolved_path)
227 # Merge with existing map (later files can override earlier ones)
228 for class_name, variables in file_vars.items():
229 if class_name in output_vars_map:
230 # Merge variable lists, avoiding duplicates if needed
231 output_vars_map[class_name].extend(variables)
232 else:
233 output_vars_map[class_name] = variables
234
235 results = []
236 for block_class in block_classes:
237 info = extract_block_options(block_class)
238 # Merge output variables if available
239 class_name = block_class.__name__
240 info["output_variables"] = output_vars_map.get(class_name, [])
241
242 results.append(info)
243
244 return results
245
246

◆ generate_block_markdown()

str generate_block_markdown ( Dict[str, Any] block_info)
Generate Markdown documentation for a single block.

Args:
    block_info: Dictionary containing block information with keys:
        - class: Block class name
        - module: Module containing the block
        - options: List of option dictionaries
        - output_variables: List of output variable dictionaries

Returns:
    Markdown string for this block

Definition at line 254 of file AutogenDocumentation.py.

254def generate_block_markdown(block_info: Dict[str, Any]) -> str:
255 """
256 Generate Markdown documentation for a single block.
257
258 Args:
259 block_info: Dictionary containing block information with keys:
260 - class: Block class name
261 - module: Module containing the block
262 - options: List of option dictionaries
263 - output_variables: List of output variable dictionaries
264
265 Returns:
266 Markdown string for this block
267 """
268 markdown = ""
269
270 # Options section
271 if block_info.get("options"):
272 for opt in block_info["options"]:
273 name = opt["label"]
274
275 # Skip these settings unless they are True
276 if name in ["skipOnData", "skipOnMC", "skipWithSystematics"]:
277 if not opt["default"] is True:
278 continue
279 # Skip these settings unless they are set
280 if name in ["onlyForDSIDs"]:
281 if opt["default"] == []:
282 continue
283
284 # Option label with type, expert flag, required flag
285 label = f"`{opt['label']}` ({opt['type']})"
286 if opt["expertMode"] is not None:
287 expertOptions = list(opt["expertMode"])
288 label += f" **[expert-only options: {','.join(['`' + str(x) + '`' for x in expertOptions])}]**"
289 if opt["required"] is True or opt["noneAction"] != "ignore":
290 label += " **[REQUIRED]**"
291
292 markdown += f"{label}\n"
293 info_string = opt["info"]
294 info_string = process_info_links(info_string)
295 info_string = link_jira_tickets(info_string)
296 markdown += f": {info_string}"
297
298 if opt.get("default") != "":
299 default_val = opt["default"]
300 default_str = repr(default_val)
301
302 # Add unit information if available
303 unit = opt.get("physicalUnit")
304 if unit is None or default_val is None:
305 default_display = f"`{default_str}`"
306 elif unit == "GeV":
307 default_display = f"`{default_str}` GeV"
308 elif unit == "MeV":
309 # Convert MeV to GeV for simplified display
310 try:
311 if isinstance(default_val, (list, tuple)):
312 converted = [float(x) / 1000 for x in default_val]
313 converted_str = (
314 "[" + ", ".join(f"{x}" for x in converted) + "]"
315 )
316 else:
317 converted = float(default_val) / 1000
318 converted_str = f"{converted}"
319 except (TypeError, ValueError):
320 converted_str = "?"
321 default_display = f"`{default_str}` MeV (`{converted_str}` GeV)"
322 else:
323 default_display = f"`{default_str}` {unit}"
324
325 markdown += f" Default: {default_display}."
326
327 markdown += "\n\n"
328
329 # Output variables section
330 if block_info.get("output_variables"):
331 # Separate variables into always-saved and toggled
332 always_saved = []
333 toggled_vars = {} # toggled_by condition -> list of variables
334
335 for var in block_info["output_variables"]:
336 if var.get("toggled_by"):
337 condition = var["toggled_by"]
338 if condition not in toggled_vars:
339 toggled_vars[condition] = []
340 toggled_vars[condition].append(var)
341 else:
342 always_saved.append(var)
343
344 # Always-saved variables section
345 if always_saved:
346 markdown += '!!! success "Registers the following variables:"\n'
347 for var in always_saved:
348 var_name = var.get("name", "N/A")
349 var_desc = var.get("description", "")
350 markdown += f" - `{var_name}`: {var_desc}\n"
351 markdown += "\n"
352
353 # Toggled variables sections
354 for condition, vars_list in toggled_vars.items():
355 markdown += (
356 f'!!! success "Additional variables toggled by `{condition}`:"\n'
357 )
358 for var in vars_list:
359 var_name = var.get("name", "N/A")
360 var_desc = var.get("description", "")
361 markdown += f" - `{var_name}`: {var_desc}\n"
362 markdown += "\n"
363 else:
364 logger.warning(
365 f"Block {block_info.get('class')} didn't register any output variables."
366 )
367
368 return markdown
369
370

◆ interpret_physical_unit()

Optional[str] interpret_physical_unit ( str info)
Extract a physical unit from an info string.
Currently looks for energy units like MeV or GeV.

Args:
    info: The information string from an option.

Returns:
    The detected unit as a string ("MeV", "GeV", etc.) or None if no unit is found.

Definition at line 93 of file AutogenDocumentation.py.

93def interpret_physical_unit(info: str) -> Optional[str]:
94 """
95 Extract a physical unit from an info string.
96 Currently looks for energy units like MeV or GeV.
97
98 Args:
99 info: The information string from an option.
100
101 Returns:
102 The detected unit as a string ("MeV", "GeV", etc.) or None if no unit is found.
103 """
104 if not info:
105 return None
106
107 # Check for specific units
108 patterns = [
109 r"\‍[MeV\‍]",
110 r"\‍(MeV\‍)",
111 r"\‍(in MeV\‍)",
112 r"\‍[in MeV\‍]",
113 r"\‍[GeV\‍]",
114 r"\‍(GeV\‍)",
115 r"\‍(in GeV\‍)",
116 r"\‍[in GeV\‍]",
117 r"\‍[mm\‍]",
118 r"\‍(mm\‍)",
119 r"\‍(in mm\‍)",
120 r"\‍[in mm\‍]",
121 ]
122 for pattern in patterns:
123 if re.search(pattern, info):
124 if "MeV" in pattern:
125 return "MeV"
126 elif "GeV" in pattern:
127 return "GeV"
128 elif "mm" in pattern:
129 return "mm"
130 return None
131
132

◆ link_jira_tickets()

str link_jira_tickets ( str info)
Convert JIRA ticket references in a string to Markdown links.

- JIRA tickets are of the form: all-caps letters, a dash, then digits (e.g., ATLASG-2358)
- Converted to Markdown links: [ATLASG-2358](https://its.cern.ch/jira/browse/ATLASG-2358)

Args:
    info: Input string that may contain JIRA tickets.

Returns:
    The string with JIRA tickets converted to Markdown links.

Definition at line 165 of file AutogenDocumentation.py.

165def link_jira_tickets(info: str) -> str:
166 """
167 Convert JIRA ticket references in a string to Markdown links.
168
169 - JIRA tickets are of the form: all-caps letters, a dash, then digits (e.g., ATLASG-2358)
170 - Converted to Markdown links: [ATLASG-2358](https://its.cern.ch/jira/browse/ATLASG-2358)
171
172 Args:
173 info: Input string that may contain JIRA tickets.
174
175 Returns:
176 The string with JIRA tickets converted to Markdown links.
177 """
178 if not info:
179 return info
180
181 # Regex pattern: one or more uppercase letters, dash, one or more digits
182 pattern = r"\b([A-Z]+-\d+)\b"
183
184 def replace_match(match):
185 ticket = match.group(1)
186 url = f"https://its.cern.ch/jira/browse/{ticket}"
187 return f"[{ticket}]({url})"
188
189 return re.sub(pattern, replace_match, info)
190
191

◆ load_output_variables()

Dict[str, List[Dict[str, Any]]] load_output_variables ( str yaml_filepath)
Load output variables metadata from YAML file.

Expected YAML format:
    BlockClassName:
      - name: variable_name
        description: Variable description
        toggled_by: Optional condition description

Args:
    yaml_filepath: Path to the YAML file

Returns:
    Dictionary mapping block class names to their output variables

Definition at line 19 of file AutogenDocumentation.py.

19def load_output_variables(yaml_filepath: str) -> Dict[str, List[Dict[str, Any]]]:
20 """
21 Load output variables metadata from YAML file.
22
23 Expected YAML format:
24 BlockClassName:
25 - name: variable_name
26 description: Variable description
27 toggled_by: Optional condition description
28
29 Args:
30 yaml_filepath: Path to the YAML file
31
32 Returns:
33 Dictionary mapping block class names to their output variables
34 """
35 with open(yaml_filepath, "r") as f:
36 data = yaml.safe_load(f)
37 return data if data else {}
38
39

◆ process_info_links()

str process_info_links ( str info)
Scan an info string for backtick-enclosed substrings of the form `A::B`.
Turn them into a link to the appropriate module/files.

Args:
    info: The input info string.

Returns:
    The processed string with Markdown links where applicable.

Definition at line 133 of file AutogenDocumentation.py.

133def process_info_links(info: str) -> str:
134 """
135 Scan an info string for backtick-enclosed substrings of the form `A::B`.
136 Turn them into a link to the appropriate module/files.
137
138 Args:
139 info: The input info string.
140
141 Returns:
142 The processed string with Markdown links where applicable.
143 """
144 if not info:
145 return info
146
147 # Regex to match `A::B` inside backticks
148 pattern = r"`([^`]+)::([^`]+)`"
149
150 def replace_match(match):
151 A, B = match.group(1), match.group(2)
152 if A == "CP" or A == "ORUtils":
153 url = f"https://acode-browser1.usatlas.bnl.gov/lxr/search?%21v=head&_filestring=**{B}**&_string="
154 return f"[`{A}::{B}`]({url})"
155 elif A == "xAOD" or A == "AthOnnx":
156 url = f"https://acode-browser1.usatlas.bnl.gov/lxr/ident?v=head&_i={B}&_identdefonly=1&_remember=1"
157 return f"[`{A}::{B}`]({url})"
158 else:
159 # TODO: any other cases to handle?
160 return f"`{A}::{B}`"
161
162 return re.sub(pattern, replace_match, info)
163
164

◆ process_markdown_with_autogen()

None process_markdown_with_autogen ( str input_filepath,
str output_filepath,
List[Dict[str, Any]] block_data )
Process an input markdown file, replacing AUTOGEN<BlockName> markers
with generated block documentation.

Looks for lines of the form "AUTOGEN<BlockName>" and replaces them
with the generated markdown for that block. All other content is
left untouched.

Args:
    input_filepath: Path to the input markdown file
    output_filepath: Path to write the processed output
    block_data: List of extracted block information dictionaries

Raises:
    FileNotFoundError: If input file does not exist
    ValueError: If a referenced block is not found in block_data

Definition at line 371 of file AutogenDocumentation.py.

373) -> None:
374 """
375 Process an input markdown file, replacing AUTOGEN<BlockName> markers
376 with generated block documentation.
377
378 Looks for lines of the form "AUTOGEN<BlockName>" and replaces them
379 with the generated markdown for that block. All other content is
380 left untouched.
381
382 Args:
383 input_filepath: Path to the input markdown file
384 output_filepath: Path to write the processed output
385 block_data: List of extracted block information dictionaries
386
387 Raises:
388 FileNotFoundError: If input file does not exist
389 ValueError: If a referenced block is not found in block_data
390 """
391 # Create a mapping of block names to their markdown
392 block_markdown_map = {
393 block["class"]: generate_block_markdown(block) for block in block_data
394 }
395
396 # Read input file
397 with open(input_filepath, "r") as f:
398 lines = f.readlines()
399
400 output_lines = []
401 for line in lines:
402 stripped = line.strip()
403
404 # Check if this line is an AUTOGEN marker
405 if stripped.startswith("AUTOGEN<") and stripped.endswith(">"):
406 # Extract block name from AUTOGEN<BlockName>
407 block_name = stripped[8:-1] # Remove 'AUTOGEN<' and '>'
408
409 if block_name in block_markdown_map:
410 output_lines.append(block_markdown_map[block_name])
411 else:
412 raise ValueError(
413 f"Block '{block_name}' not found in extracted block data"
414 )
415 else:
416 output_lines.append(line)
417
418 # Write output file
419 with open(output_filepath, "w") as f:
420 f.writelines(output_lines)
421
422 logger.info(f"Processed markdown saved to {output_filepath}.")

◆ save_as_yaml()

None save_as_yaml ( List[Dict[str, Any]] data,
str filepath )
Save extracted data as YAML.

Definition at line 247 of file AutogenDocumentation.py.

247def save_as_yaml(data: List[Dict[str, Any]], filepath: str) -> None:
248 """Save extracted data as YAML."""
249 with open(filepath, "w") as f:
250 yaml.dump(data, f, default_flow_style=False, sort_keys=False)
251 logger.info(f"Saved YAML to {filepath}")
252
253

Variable Documentation

◆ logger

python.AutogenDocumentation.logger = logging.getLogger("AutogenDocumentation")

Definition at line 17 of file AutogenDocumentation.py.