-
Notifications
You must be signed in to change notification settings - Fork 18
Sync Config & Docs: Updated Parameters & Auto-Generated Docs #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c7b7186
f247b28
422e289
b3af95c
d6aab12
975bcd1
8b6f1ac
a39e1c6
de60795
4ea9cca
1fd12bb
8724603
d125573
bd7652c
1ba16cc
58c6e34
eda5fe1
f983ce0
735c5e9
7140c51
c05a929
95c0364
20a6f78
407b95c
0e27978
fd2841c
57b240b
ffcafc8
1af31a7
0f7b3c2
512f36f
8f316fc
8595e55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ docs/gallery | |
docs/generated | ||
docs/gallery_scripts | ||
docs/_build | ||
.qodo |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
#!/usr/bin/env python3 | ||
""" | ||
TSV updater with full inheritance handling, type normalization, and Git hook integration. | ||
Automatically updates TSV files when `_config.py` changes. | ||
""" | ||
|
||
import os | ||
import re | ||
import ast | ||
import logging | ||
from pathlib import Path | ||
from typing import Dict, List, Tuple | ||
|
||
# Configure logging | ||
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") | ||
|
||
# Paths | ||
CONFIG_PATH = Path("pyopenms_viz/_config.py") | ||
DOCS_DIR = Path("docs/Parameters") | ||
|
||
# Mapping dataclasses to TSV file names | ||
CLASS_TO_TSV_MAP = { | ||
"BasePlotConfig": "basePlot.tsv", | ||
"ChromatogramConfig": "chromatogramPlot.tsv", | ||
"MobilogramConfig": "mobilogramPlot.tsv", | ||
"PeakMapConfig": "peakmapPlot.tsv", | ||
"SpectrumConfig": "spectrumPlot.tsv", | ||
} | ||
|
||
def normalize_type(type_str: str) -> str: | ||
"""Simplify complex type annotations for consistency.""" | ||
type_str = re.sub(r"\bUnion\[([\w\s,]+)\]", r"\1", type_str) | ||
type_str = re.sub(r"\bLiteral\[[^\]]+\]", "str", type_str) | ||
type_str = re.sub(r"\bOptional\[([\w]+)\]", r"\1 | None", type_str) | ||
return type_str.strip() | ||
|
||
def parse_docstring(doc: str) -> Dict[str, str]: | ||
"""Extracts descriptions from class docstrings (Sphinx-style).""" | ||
attrs = {} | ||
current_param = None | ||
|
||
for line in doc.split("\n"): | ||
line = line.strip() | ||
match = re.match(r":(param|attr)\s+(\w+):\s*(.*)", line) | ||
if match: | ||
current_param = match.group(2) | ||
attrs[current_param] = match.group(3).strip() | ||
elif current_param and line: | ||
attrs[current_param] += f" {line}" | ||
|
||
return attrs | ||
|
||
def get_all_attributes(class_name, class_definitions, inheritance_map): | ||
"""Recursively retrieves all attributes from a given class, including inherited attributes. | ||
Ignores external classes like `ABC` that do not have a definition in _config.py. | ||
""" | ||
attributes = {} | ||
|
||
if class_name in ["ABC", "ABCMeta"]: # Ignore abstract base classes | ||
logging.info(f"⚠️ Skipping abstract base class: {class_name}") | ||
return attributes # Return empty to avoid breaking inheritance | ||
|
||
if class_name not in class_definitions: | ||
logging.warning(f"❌ Class {class_name} not found in class definitions!") | ||
return attributes | ||
|
||
node = class_definitions[class_name] | ||
logging.info(f"🔍 Extracting attributes for {class_name}") | ||
|
||
for stmt in node.body: | ||
if isinstance(stmt, ast.AnnAssign): | ||
name = stmt.target.id if isinstance(stmt.target, ast.Name) else None | ||
if name: | ||
type_annotation = normalize_type(ast.unparse(stmt.annotation)) | ||
default = ast.unparse(stmt.value) if stmt.value else "None" | ||
attributes[name] = (default, type_annotation) | ||
|
||
# Recursively retrieve attributes from parent classes | ||
for parent in inheritance_map.get(class_name, []): | ||
if parent in ["ABC", "ABCMeta"]: # Ignore ABC base class | ||
logging.info(f"⚠️ Skipping inherited abstract class: {parent}") | ||
continue # Skip processing this parent | ||
parent_attrs = get_all_attributes(parent, class_definitions, inheritance_map) | ||
for attr, values in parent_attrs.items(): | ||
if attr not in attributes: | ||
attributes[attr] = values | ||
|
||
return attributes | ||
|
||
|
||
def update_tsv_files(): | ||
"""Updates TSV files dynamically, ensuring inheritance is handled properly.""" | ||
try: | ||
logging.info("🔍 Reading _config.py...") | ||
config_content = CONFIG_PATH.read_text() | ||
parsed = ast.parse(config_content) | ||
|
||
# Extract class definitions and inheritance relationships | ||
inheritance_map = {} | ||
class_definitions = {} | ||
|
||
for node in parsed.body: | ||
if isinstance(node, ast.ClassDef): | ||
if node.name in ["ABC", "ABCMeta"]: # Ignore abstract base classes | ||
continue | ||
parent_classes = [base.id for base in node.bases if isinstance(base, ast.Name)] | ||
inheritance_map[node.name] = parent_classes | ||
class_definitions[node.name] = node | ||
|
||
logging.info(f"📌 Extracted Classes & Inheritance Map: {inheritance_map}") | ||
|
||
updated_files = [] | ||
for class_name, tsv_filename in CLASS_TO_TSV_MAP.items(): | ||
if class_name in class_definitions: | ||
logging.info(f"🔍 Processing class: {class_name}") | ||
|
||
# Retrieve all attributes including inherited ones | ||
all_attributes = get_all_attributes(class_name, class_definitions, inheritance_map) | ||
|
||
# Extract docstrings for descriptions | ||
doc = ast.get_docstring(class_definitions[class_name]) or "" | ||
param_docs = parse_docstring(doc) | ||
|
||
tsv_path = DOCS_DIR / tsv_filename | ||
logging.info(f"📂 Mapping {class_name} to TSV file: {tsv_path}") | ||
|
||
# Read existing TSV content | ||
existing_lines = tsv_path.read_text().strip().split("\n") if tsv_path.exists() else [] | ||
existing_params = {line.split("\t")[0]: line for line in existing_lines[1:]} # Skip header | ||
|
||
# Prepare new TSV content | ||
header = "Parameter\tDefault\tType\tDescription\n" | ||
lines = [] | ||
for name, (default, type_) in all_attributes.items(): | ||
description = param_docs.get(name, "") | ||
if name in existing_params: | ||
lines.append(existing_params[name]) # Preserve existing description | ||
else: | ||
lines.append(f"{name}\t{default}\t{type_}\t{description}") | ||
|
||
new_content = header + "\n".join(lines) | ||
|
||
# Write only if content has changed | ||
if new_content != header + "\n".join(existing_lines): | ||
logging.info(f"✅ Writing to {tsv_path}") | ||
with open(tsv_path, "w") as f: | ||
f.write(new_content) | ||
updated_files.append(tsv_path) | ||
|
||
if updated_files: | ||
logging.info(f"✅ Updated {len(updated_files)} TSV files: {', '.join(map(str, updated_files))}") | ||
|
||
except FileNotFoundError as e: | ||
logging.error(f"❌ File not found: {e.filename}") | ||
except Exception as e: | ||
logging.error(f"❌ Critical error: {str(e)}") | ||
|
||
if __name__ == "__main__": | ||
update_tsv_files() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,33 @@ | ||
Parameter Default Type Description | ||
x* str The column name for x-axis data | ||
y* str The column name for y-axis data | ||
kind* str 'The kind of plot to create. One of: [ “line”, “vline”, scatter”, “chromatogram”, “mobilogram”, “spectrum”, “peak_map”] | ||
by str The column name to group by | ||
backend str 'Backend to use. One of: [ “ms_matplotlib”, “ms_bokeh”, “ms_plotly” ]. Must be specified if not set globally | ||
relative_intensity False bool Convert y-axis values to relative intensity | ||
height int Height of plot, units dependent on backend. | ||
width int Width of plot in pixels, units dependent on backend. | ||
grid False bool Whether to show grid on the plot | ||
toolbar_location “above” Location of toolbar for interactive plots. One of: [“above”, “below”, “left”] | ||
fig None fig Existing Figure object to plot on | ||
xlabel None str Label for x axis | ||
ylabel None str Label for y axis | ||
show_plot True bool Whether to display the plot. If plot is not shown, will return the plot object corresponding with the backend. If plot is displayed the method returns None | ||
kind* "" str The kind of plot to create. One of: ["line", "vline", "scatter", "chromatogram", "mobilogram", "spectrum", "peakmap", "complex"]. | ||
x* "" str The column name for x-axis data. | ||
y* "" str The column name for y-axis data. | ||
z "" str The column name for z-axis data (if applicable). | ||
by "" str The column name to group by. | ||
canvas None Any Canvas for the plot. Default is None. | ||
height 500 int Height of plot, units dependent on backend. | ||
width 500 int Width of plot, units dependent on backend. | ||
grid True bool Whether to show grid on the plot. | ||
toolbar_location ["above", "below", "left", "right"] str Location of the toolbar. | ||
title "" str Title of the plot. | ||
xlabel "" str Label for x-axis. | ||
ylabel "" str Label for y-axis. | ||
zlabel "" str Label for z-axis. | ||
x_axis_location "below" str Location of the X-axis. | ||
y_axis_location "left" str Location of the Y-axis. | ||
title_font_size 18 int Font size of the title. | ||
xaxis_label_font_size 16 int Font size of the X-axis label. | ||
yaxis_label_font_size 16 int Font size of the Y-axis label. | ||
zaxis_label_font_size 16 int Font size of the Z-axis label. | ||
xaxis_labelpad 16 int Padding for the X-axis label. | ||
yaxis_labelpad 16 int Padding for the Y-axis label. | ||
zaxis_labelpad 9 int Padding for the Z-axis label. | ||
annotation_font_size 12 int Font size of annotations. | ||
color ColorGenerator str Color for the plot. | ||
plot_3d False bool Whether to plot in 3D. | ||
min_border 0 int Minimum border around the plot. | ||
show_plot True bool Whether to display the plot. | ||
relative_intensity False bool Convert y-axis values to relative intensity. | ||
aggregate_duplicates False bool Whether to aggregate duplicate values. | ||
legend_config LegendConfig | dict Configuration for the legend. | ||
opacity 1.0 float Opacity of the plot. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,15 @@ | ||
Parameter Default Type Description | ||
x* str The column name for x-axis data | ||
y* str The column name for y-axis data | ||
Comment on lines
-2
to
-3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These options should not be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay i am using this |
||
by str The column name to group by. Will result in separate line traces per group | ||
backend str 'Backend to use. One of: [ “ms_matplotlib”, “ms_bokeh”, “ms_plotly” ]. Must be specified if not set globally | ||
annotation_data DataFrame DataFrame of annotation data with columns [‘leftWidth’, ‘rightWidth’] | ||
relative_intensity False bool Convert y-axis values to relative intensity | ||
height int Height of plot, units dependent on backend. | ||
width int Width of plot in pixels, units dependent on backend. | ||
grid False bool Whether to show grid on the plot | ||
toolbar_location “above” Location of toolbar for interactive plots. One of: [“above”, “below”, “left”] | ||
fig None fig Existing figure object to plot on. Useful for matplotlib backend | ||
xlabel None str Label for x axis | ||
ylabel None str Label for y axis | ||
show_plot True bool Whether to display the plot. If plot is not shown, will return the plot object corresponding with the backend. If plot is displayed the method returns None | ||
x* "Retention Time" str X-axis data. | ||
y* "mass-to-charge" str Y-axis data. | ||
annotation_data None DataFrame Data for annotations. | ||
annotation_colormap "Dark2" str Colormap for annotations. | ||
annotation_line_width 3 float Width of the annotation lines. | ||
annotation_line_type "solid" str Type of the annotation lines. | ||
grid True bool Whether to display grid lines. | ||
height 500 int Height of the plot. | ||
width 500 int Width of the plot. | ||
toolbar_location ["above", "below", "left", "right"] str Location of the toolbar. | ||
title "Chromatogram" str Title of the plot. | ||
xlabel "Retention Time" str Label for the X-axis. | ||
ylabel "Intensity" str Label for the Y-axis. | ||
show_plot True bool Whether to display the plot. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,17 @@ | ||
Parameter Default Type Description | ||
x* str The column name for x-axis data | ||
y* str The column name for y-axis data | ||
by str The column name to group by. Will result in separate line traces per group | ||
backend str 'Backend to use. One of: [ “ms_matplotlib”, “ms_bokeh”, “ms_plotly” ]. Must be specified if not set globally | ||
annotation_data DataFrame DataFrame of annotation data with columns [‘leftWidth’, ‘rightWidth’] | ||
relative_intensity False bool Convert y-axis values to relative intensity | ||
height int Height of plot, units dependent on backend. | ||
width int Width of plot in pixels, units dependent on backend. | ||
grid False bool Whether to show grid on the plot | ||
toolbar_location “above” Location of toolbar for interactive plots. One of: [“above”, “below”, “left”] | ||
fig None fig Existing figure object to plot on. Useful for matplotlib backend | ||
xlabel None str Label for x axis | ||
ylabel None str Label for y axis | ||
show_plot True bool Whether to display the plot. If plot is not shown, will return the plot object corresponding with the backend. If plot is displayed the method returns None | ||
Comment on lines
-2
to
-15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These options should all be present. Your script might also have to take into account inheritance of data classes. |
||
x* "Retention Time" str X-axis data. | ||
y* "mass-to-charge" str Y-axis data. | ||
title "Mobilogram" str Title of the plot. | ||
xlabel "Ion Mobility" str Label for the X-axis. | ||
ylabel "Intensity" str Label for the Y-axis. | ||
grid True bool Whether to display grid lines. | ||
height 500 int Height of the plot. | ||
width 500 int Width of the plot. | ||
toolbar_location ["above", "below", "left", "right"] str Location of the toolbar. | ||
annotation_data None DataFrame Data for annotations. | ||
annotation_colormap "Dark2" str Colormap for annotations. | ||
annotation_line_width 3 float Width of the annotation lines. | ||
annotation_line_type "solid" str Type of the annotation lines. | ||
annotation_legend_config None Dict | LegendConfig Configuration for the annotation legend. | ||
legend_config None LegendConfig | dict Configuration for the legend. | ||
show_plot True bool Whether to display the plot. |
Uh oh!
There was an error while loading. Please reload this page.