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