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
271 if block_info.get("options"):
272 for opt in block_info["options"]:
273 name = opt["label"]
274
275
276 if name in ["skipOnData", "skipOnMC", "skipWithSystematics"]:
277 if not opt["default"] is True:
278 continue
279
280 if name in ["onlyForDSIDs"]:
281 if opt["default"] == []:
282 continue
283
284
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
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
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
330 if block_info.get("output_variables"):
331
332 always_saved = []
333 toggled_vars = {}
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
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
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