Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Commands:
convert-normalyzerde convert sdrf to NormalyzerDE design file
convert-openms convert sdrf to openms file output
download-cache Download ontology cache files from GitHub
list-templates List all available SDRF templates with their versions
split-sdrf Command to split the sdrf file
validate-sdrf Command to validate the sdrf file
validate-sdrf-simple Simple command to validate the sdrf file.
Expand Down
96 changes: 96 additions & 0 deletions src/sdrf_pipelines/parse_sdrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,8 +591,104 @@ def download_cache(ontology, cache_dir, show_info, force):
sys.exit(1)


@click.command("list-templates", short_help="List all available SDRF templates with their versions")
@click.option(
"--format",
"-f",
type=click.Choice(["table", "json", "yaml"], case_sensitive=False),
default="table",
help="Output format (table, json, or yaml)",
)
@click.option(
"--verbose",
"-v",
is_flag=True,
help="Include detailed information (description, extends, layer)",
)
def list_templates(format: str, verbose: bool):
"""
List all available SDRF templates with their versions.

Shows template names, latest versions, and optionally detailed information
like descriptions and inheritance relationships.

Examples:
parse_sdrf list-templates # Simple table view
parse_sdrf list-templates -v # Detailed table view
parse_sdrf list-templates -f json # JSON output
parse_sdrf list-templates -f yaml -v # Detailed YAML output
"""
registry = SchemaRegistry()

if not hasattr(registry, "manifest") or not registry.manifest:
click.secho("Error: Could not load templates manifest", fg="red")
sys.exit(1)

templates = registry.manifest.get("templates", {})

if not templates:
click.secho("No templates found", fg="yellow")
return

if format == "json":
if verbose:
output = templates
else:
output = {
name: {"latest": info["latest"], "versions": info["versions"]} for name, info in templates.items()
}
click.echo(json.dumps(output, indent=2))

elif format == "yaml":
if verbose:
output = templates
else:
output = {
name: {"latest": info["latest"], "versions": info["versions"]} for name, info in templates.items()
}
click.echo(yaml.dump(output, default_flow_style=False, sort_keys=False))

else: # table format
click.secho("\n=== Available SDRF Templates ===\n", fg="cyan", bold=True)

# Sort templates by name
sorted_templates = sorted(templates.items())

for name, info in sorted_templates:
latest = info.get("latest", "N/A")
versions = ", ".join(info.get("versions", []))
usable_alone = info.get("usable_alone", False)

# Color coding: green for usable standalone, yellow for must combine
name_color = "green" if usable_alone else "yellow"

click.secho(f"{name}", fg=name_color, bold=True, nl=False)
click.echo(f" (latest: {latest})")

if verbose:
click.echo(f" Versions: {versions}")
if info.get("extends"):
click.echo(f" Extends: {info['extends']}")
if info.get("layer"):
click.echo(f" Layer: {info['layer']}")
if info.get("description"):
# Wrap description at 80 characters
desc = info["description"]
click.echo(f" Description: {desc}")
click.echo(f" Usable alone: {'Yes' if usable_alone else 'No (must combine with other templates)'}")
click.echo()
else:
click.echo(f" All versions: {versions}")
click.echo()

click.secho(f"Total templates: {len(templates)}", fg="cyan")
click.echo("\nNote: Green = standalone templates, Yellow = must be combined with others")
click.echo("Use --verbose/-v for detailed information")


cli.add_command(download_cache)
cli.add_command(validate_sdrf_simple)
cli.add_command(list_templates)


def main():
Expand Down
12 changes: 7 additions & 5 deletions src/sdrf_pipelines/sdrf/sdrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,13 @@ def _parse_columns(self, df: pd.DataFrame):
if version_cols and pd.notna(first_row.get(version_cols[0])):
self.version = str(first_row[version_cols[0]])

# Parse comment[sdrf template] - can have multiple columns
template_cols = [c for c in df.columns if "comment[sdrf template]" in c.lower()]
for col in template_cols:
if pd.notna(first_row.get(col)):
template_val = str(first_row[col])
# Parse comment[sdrf template] - can have multiple columns (including duplicates)
# Use column indices to handle duplicate column names
template_col_indices = [i for i, c in enumerate(df.columns) if "comment[sdrf template]" in c.lower()]
for idx in template_col_indices:
value = df.iloc[0, idx]
if pd.notna(value):
template_val = str(value)
if template_val and template_val not in self.templates:
self.templates.append(template_val)

Expand Down
8 changes: 3 additions & 5 deletions tests/test_sdrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,10 @@ def test_template_format_parsing(self, template_value, expected_name, expected_v

def test_multiple_template_columns(self):
"""Test parsing multiple template columns."""
# Create DataFrame with duplicate column names using arrays
test_df = pd.DataFrame(
{
"source name": ["sample 1"],
"comment[sdrf template]": ["human v1.1.0"],
"comment[sdrf template].1": ["ms-proteomics v1.1.0"],
}
[["sample 1", "human v1.1.0", "ms-proteomics v1.1.0"]],
columns=["source name", "comment[sdrf template]", "comment[sdrf template]"],
)

metadata = SDRFMetadata(df=test_df)
Expand Down
Loading