Skip to content

allow full BIDS-acceptable chars as derivative names - #394

Open
asmacdo wants to merge 4 commits into
PennLINC:mainfrom
asmacdo:sanitize-zip-var
Open

allow full BIDS-acceptable chars as derivative names#394
asmacdo wants to merge 4 commits into
PennLINC:mainfrom
asmacdo:sanitize-zip-var

Conversation

@asmacdo

@asmacdo asmacdo commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

What / why

BIDS derivative naming produces <Tool>-<Version> names (fMRIPrep-25.2.5+anat, SimBIDS-0.0.3) full of characters — -, ., + — that break the generated job scripts in two places when such a derivative is used as a zipped input dataset. Both fail the running job (not babs init), and both make BIDS-normal names unusable as chained inputs. This fixes both so any BIDS-valid name works.

Changes

  • Shell variable name. The located zip path is held in a job variable <NAME>_ZIP, built by uppercasing the dataset name. SIMBIDS-0.0.3_ZIP is not a valid bash identifier, so the assignment crashes the job. New var_safe_name() (in utils.py) maps every non-word char to _ and uppercases (SIMBIDS_0_0_3_ZIP); it's registered as the shell_safe Jinja filter and applied everywhere the templates build <NAME>_ZIP. A plain name's variable is unchanged.
  • Zip lookup. find_single_zip_in_git_tree interpolated the name into a single grep -E, so +/. in the name were read as regex metacharacters and never matched the literal .zip filename — failing every chained job whose upstream derivative name carried a +. Each identifier (subid, sesid, name) is now matched as a fixed string with grep -F, keeping only \.zip$ as a genuine regex anchor.

Verification

  • New regression test (tests/test_generate_submit_script.py) renders the zip-locator template and runs the generated finder against a real git tree, parametrized over BIDS-plausible metachar names (single/double +, dots) × subject/session — the exact coverage gap that let the grep bug through.
  • Full pytest + e2e-slurm green on CI.
  • Exercised on-cluster: I hit both bugs doing real fMRIPrep+anatfMRIPrep+minimal chaining on the Unity cluster, and confirmed this branch fixes them.

The two bugs are independent but share a root cause (metachar-bearing names) and touch the same templates, so they land together.

@codecov-commenter

codecov-commenter commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.29%. Comparing base (0a2890c) to head (e53a172).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #394      +/-   ##
==========================================
+ Coverage   79.21%   79.29%   +0.07%     
==========================================
  Files          17       17              
  Lines        2170     2178       +8     
  Branches      385      385              
==========================================
+ Hits         1719     1727       +8     
  Misses        308      308              
  Partials      143      143              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@asmacdo asmacdo changed the title Sanitize shell safe variable names allow full BIDS-acceptable chars as derivative names Jul 20, 2026
@asmacdo
asmacdo marked this pull request as ready for review July 23, 2026 15:40

@tien-tong tien-tong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@asmacdo, once you test #385 and confirm that we don't need to revert main, we can resolve the conflicts in this PR and merge it.

asmacdo and others added 4 commits July 24, 2026 08:22
…P job var

A zipped input dataset's located zip path is held in a job shell variable named
<name>_ZIP, built by uppercasing the dataset name. A name with characters invalid
in a POSIX shell identifier (-, ., +, ...) yields an invalid variable name (e.g.
SIMBIDS-0.0.3_ZIP) that bash rejects, crashing the job — and BIDS derivative naming
(<Tool>-<Version>, e.g. fMRIPrep-24.1.1) makes such names the norm for a derivative
used as an input dataset.

Add var_safe_name() (non-word chars -> _, uppercased), exposed as the shell_safe_name
field on each input's as_dict; the job templates build <shell_safe_name>_ZIP from it.
Only the variable name changes; the zip is still located by the real dataset name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… field

The prior commit exposed the shell-safe name as an as_dict field, but babs's tests
(and any caller) build input-dataset dicts directly without it, so the templates
raised jinja2 UndefinedError('shell_safe_name'). Move var_safe_name to utils and
register it as the 'shell_safe' Jinja filter on the job-script environments;
templates now compute '<name | shell_safe>_ZIP' from 'name', which every dict has.
Verified: tests/test_generate_submit_script.py + tests/test_generate_bidsapp_runscript.py
pass in slurm-docker-ci (39 passed). No change to the generated scripts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Derivative names can contain regex metacharacters (the '+' and '.' in e.g.
'fMRIPrep-25.2.5+anat'). The previous single `grep -E` interpolated the name
raw into an extended-regex pattern, so '+' was read as a quantifier and never
matched the literal '+' in the zip filename — failing every chained job whose
upstream derivative name carried a '+'.

Match each identifier (subid, sesid, name) as a fixed string via `grep -F`,
keeping only the genuine `\.zip$` anchor as a regex.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renders the zip-locator template and runs the generated finder against a real
git tree, asserting the '+'/'.'/etc.-named zip is located. Parametrized over
BIDS-plausible metachar names (single '+', double '+', dots) x subject/session.
This exercises the coverage gap that let the grep bug through: the chained e2e
used producer names without a '+'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@asmacdo

asmacdo commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto current main (now includes #385). Verified the combined stack on a real cluster: a BABS fMRIPrep-25.2.5+anat+minimal chain on https://github.com/OpenNeuroDatasets/ds003097 (Unity), where the downstream stage consumes the +-bearing zipped input this PR fixes. All three chained minimal jobs located and consumed the fMRIPrep-25.2.5+anat zip and finished green — the grep -F fix holds end-to-end on real data, not just the regression test.

Note: the failing ruff check here is unrelated to this PR — a repo-wide ruff-version drift (unpinned CI ruff, latest release flags pre-existing errors), filed as #397. CircleCI pytest + e2e-slurm are green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants