Skip to content

v2.9.16 — Parser fix: $-in-comment no longer truncates parameter blocks

Choose a tag to compare

@Robterheine Robterheine released this 11 May 07:30
· 15 commits to main since this release

Silent-correctness bug fix in inject_estimates

Four regex sites in parser.py captured $THETA / $OMEGA / $SIGMA / $TABLE record bodies using patterns that terminate at any literal $ — including $ characters that appear inside comments. When this happened, the captured block was truncated and subsequent parameter values were silently missed.

Real-world impact

You have this in your source .mod:

$THETA
 (0, 0.5)      ; 1 CL  — based on $5 paper Smith et al.
 (0, 2.0)      ; 2 V1
 (0, 0.1) FIX  ; 3 KA

You right-click → Duplicate → tick Inject final estimates from .lst.

  • Before v2.9.16: the parser hit the $ in $5 paper and thought the $THETA block ended there. Only CL got its new value; V1 and KA were silently left at the original initial estimates. No error message.
  • After v2.9.16: all three values are correctly replaced. The lookahead now requires the next $ to be followed by a letter (a real NM-TRAN record like $OMEGA), so $digit in a comment no longer terminates the block.

Sites changed

  • parser.py:1234 — inject_estimates $THETA block
  • parser.py:1286 — inject_estimates $OMEGA block
  • parser.py:1336 — inject_estimates $SIGMA block
  • parser.py:1540 — extract_table_files (cosmetic — incomplete table-file listings)

Pattern swap: [^\$]* → .*?(?=\$[A-Za-z]|\Z) with re.DOTALL.

Verification

16 inline checks, all pass:

  • 6 bug-case fires (would have failed before): $THETA values 1/2/3 correctly replaced, no leftover originals; both $TABLE files captured with $ in comments.
  • 5 regression checks: clean .mod files (no $ in comments) behave identically to v2.9.15; empty $THETA followed by $OMEGA reaches; $TABLE at end of file captured.
  • 5 end-to-end on run19.lst: 15 thetas, THETA(15)=1.36, THETA(12)=20.0, 54 cor_labels, 54 cor_matrix rows — identical to v2.9.15.

Residual edge case (deliberately not fixed)

A comment containing $letter (e.g. RCS keywords like $Id$, $Revision, or markers like $Patient) would still mis-scope the block. These are rare in hand-written NONMEM control streams. The bulletproof fix (enumerating all NM-TRAN keywords in the alternation, or stripping comments before scoping) is held back as a separate change if the residual case ever surfaces in practice.

Pre-existing FIX-counter bug (separate issue, not fixed)

While investigating the four sites above, three sibling regexes at parser.py:673,682,695 were inspected and found to have a different structural bug: they count "is there at least one FIX in this block before any comment", not "how many FIX'd parameters are in the block". The simple regex swap doesn't apply to these — they need a per-line state-machine count. Filed as a separate item for a future release.

Working agreement note

Following the CLAUDE.md working agreement adopted locally this session: surgical fix to exactly the 4 sites described in the code-review plan; pre-existing issues discovered in adjacent code flagged in the changelog but not silently bundled into the fix.