Guard the rapidfuzz-dependent assertion in test_validate - #1705
Open
sbryngelson wants to merge 1 commit into
Open
Guard the rapidfuzz-dependent assertion in test_validate#1705sbryngelson wants to merge 1 commit into
sbryngelson wants to merge 1 commit into
Conversation
…s_targeted_error test_family_attr_typo_gives_targeted_error asserted that 'geometry' appears in the valid-attribute list for a patch_ib(1)%geometri typo. That only holds when rapidfuzz is installed: _family_attr_error orders candidates by similarity before truncating the list at 8 entries, and without rapidfuzz suggest_similar returns an empty list, so the ordering falls back to alphabetical and patch_ib's 26 attributes push 'geometry' past the cut. The test therefore failed rather than skipped in environments without the optional dependency, unlike the two neighbouring tests in the same class that already carry @unittest.skipUnless(RAPIDFUZZ_AVAILABLE, ...). Split the similarity-ordering assertion into its own guarded test and leave the rapidfuzz-independent assertions (targeted error, no 'Did you mean') running unconditionally, so coverage of the base path is not lost.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a unit-test robustness issue in the Python parameter-validation test suite by ensuring an assertion that depends on the optional rapidfuzz dependency is only evaluated when rapidfuzz is available, while keeping the rapidfuzz-independent coverage in place.
Changes:
- Removes the unguarded assertion that
"geometry"appears in the truncated “Valid attributes …” list for a family-attribute typo. - Adds a new
@unittest.skipUnless(RAPIDFUZZ_AVAILABLE, ...)test that asserts"geometry"is present when similarity ordering (viarapidfuzz) is available.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+91
to
+93
| def test_family_attr_typo_lists_intended_attr_first(self): | ||
| """The intended attribute must survive truncation of the valid-attribute list. | ||
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1705 +/- ##
=======================================
Coverage 60.77% 60.77%
=======================================
Files 83 83
Lines 20872 20872
Branches 3101 3101
=======================================
Hits 12685 12685
Misses 6121 6121
Partials 2066 2066 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This was referenced Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
test_family_attr_typo_gives_targeted_errorfails rather than skips whenrapidfuzzis not importable.Cause
The test feeds
patch_ib(1)%geometritocheck_unknown_paramsand asserts thatgeometryappears in the resulting "Valid attributes: ..." list._family_attr_error(toolchain/mfc/params/validate.py:78-90) orders candidates by similarity and then truncates at 8 entries:suggest.pydegrades gracefully when the import fails —RAPIDFUZZ_AVAILABLE = Falseandsuggest_similarreturns[]— so the ordering falls back to plain alphabetical.patch_ibnow has 26 attributes andgeometrysits past the 8-entry cut behindairfoil_id, angles(1..3), angular_vel(1..3), burn_rate_exp, so the assertion fails.rapidfuzzis a declared dependency intoolchain/pyproject.toml, so a properly provisioned environment always has it and CI is unaffected. Butsuggest.pysupports running without it, and the two neighbouring tests in the same class that depend on fuzzy matching already carry@unittest.skipUnless(RAPIDFUZZ_AVAILABLE, "rapidfuzz not installed"). This one was missed, so a partial environment gets a failure instead of a skip.Change
Split the similarity-ordering assertion into its own guarded test. The rapidfuzz-independent assertions — one error, "Valid attributes" present, no "Did you mean" — stay unguarded so the targeted-error path keeps its coverage either way.
Verification
Handover notes
Branch and commit
Single commit, one file:
toolchain/mfc/params_tests/test_validate.py. No Fortran, no goldens.Environment
cd toolchain python -m pytest mfc/params_tests/test_validate.py -qNo MFC build needed. To reproduce the original failure, run in an environment without
rapidfuzzinstalled:ruff check/ruff format --checkclean (ruff==0.6.5, config in.ruff.toml, line-length 200).Scope note
rapidfuzzis a declared dependency intoolchain/pyproject.toml, so a properly provisioned environment always has it and CI was never affected. What is real is narrower:toolchain/mfc/params/suggest.pydeliberately supports running without it (RAPIDFUZZ_AVAILABLE = False,suggest_similarreturns[]), and two neighbouring tests in the same class already carry@unittest.skipUnless(RAPIDFUZZ_AVAILABLE, ...). This one did not, so a partial environment got a failure instead of a skip.An earlier draft of this description overstated it as an "optional extra"; corrected.
Why the assertion depends on rapidfuzz
_family_attr_errorintoolchain/mfc/params/validate.pyorders candidates by similarity and then truncates at 8:Without rapidfuzz the ordering falls back to plain alphabetical.
patch_ibnow has 26 attributes andgeometrysits past the cut behindairfoil_id, angles(1..3), angular_vel(1..3), burn_rate_exp.The fix splits the similarity-ordering assertion into its own guarded test and leaves the rapidfuzz-independent assertions (one error, "Valid attributes" present, no "Did you mean") running unconditionally, so the targeted-error path keeps coverage either way.
CI note
This PR saw two rounds of Frontier failures that were not caused by it — a one-file Python test edit cannot affect Fortran GPU builds. Both rounds cleared on rerun. The first round died at a uniform ~15 minutes across heterogeneous jobs (AMD/CCE x cpu/gpu-omp/gpu-acc) while configured timeouts are 120/480 min, and other PRs' Frontier jobs succeeded an hour later taking 40-77 min on the same machine. If it recurs, rerun before investigating.
Note that
gh run rerun <id> --failedrefuses while the workflow is still running; the three residual failures on the second round needed a later retry.Purpose
Housekeeping, unrelated to the EOS series.
toolchain/mfc/params/suggest.pydeliberately supports running withoutrapidfuzz; one test intest_validate.pydid not honour that contract while its two siblings did. Restores the file's own convention so a partial environment gets a skip rather than a failure.Smallest and lowest-risk PR of the current set — one test file, no Fortran, no goldens.
Working conventions and hazards (shared across this series)
Collected from the work that produced #1705, #1709, #1712, #1713, #1714, #1716. Every one of these cost real time or produced a wrong result before being caught.
Testing
A regression test that cannot fail is worse than no test. Always verify the negative: revert the fix, rebuild, confirm the case fails, restore. Two ways this silently broke here:
git stash push -- <file>has nothing to stash once the fix is committed, so the "reverted" run tests the fixed binary and reports a pass identical to a real one. Usegit checkout master -- <file>, rebuild, test, thengit checkout HEAD -- <file>.model_eqns = 3cannot detect a sound-speed defect, because the six-equation branch ofs_compute_speed_of_soundtouches neitherHnorqv.The golden packer discards data.
toolchain/mfc/packer/pack.pytreated every.datunderD/as<x> [<y> <z>] <value>and kept only the last column of each row. Probe and integral output are multi-column time series, so most columns were never compared (#1711, fixed in #1712). Before asserting that a golden covers something, check it is actually ingolden.txt.Case labels are load-bearing. The golden UUID is
crc32(sha1(str(trace)))— the label chain determines the directory name. Renaming a label renames the golden. Avoid!in labels (history expansion in interactive bash).Local suite runs are flaky at high
-j. Non-reproducible failures appeared on several unrelated branches at-j 12–16(chemistry cases, probe cases) that passed individually and in clean reruns. Re-run before investigating.Removing parameters or features
Deregistering a parameter breaks things that are not the source tree. Removing
pref/rhoreffrom the registry broke the entire suite becauseBASE_CFGintoolchain/mfc/test/case.pyset them for every case. Also checkfp_stability.py,params_tests/mutation_tests.py, and lint fixtures that use real parameter names as examples.Grep the generated artifacts, not just the sources. A stale
TYPED_DECLSentry naming a deleted type survived removal and did not break the build only because the parameter had also left every target's namelist vars, so it was never emitted. Checkgenerated_decls.fpp,generated_constants.fpp,SIM_GPU_DECL_VARS, and the MPI broadcast generators.Dead-local tell: after removing a block, a local with exactly one remaining occurrence in its file is almost certainly its own declaration. Two occurrences often means declaration plus a
private()entry.Fortran is case-insensitive. A local
pRefshadowed the module globalprefin the hardcoded-IC files; the read site was spelledprefand looked like a reference to the global. It is not. Confirm scope before concluding a global is live.GPU
A CPU test run cannot catch a missing
private(). It is a silent device race. Audit by hand or by script when adding per-cell state.Do not match
GPU_PARALLEL_LOOPnaively —END_GPU_PARALLEL_LOOPcontains the same substring and will register as a loop start, producing false positives. Exclude it explicitly.Derived-type components cannot have runtime extents.
dimension(num_fluids)in a type fails to compile outside case-optimized builds, wherenum_fluidsis aparameter.Benchmarking
Run
./mfc.sh benchin the foreground on an idle machine. Running it in the background while a pre-commit precheck ran at-j 12produced a bogus +50% regression on a case that executes none of the changed code. Baseline noise here is ±3.5%; run the baseline twice before trusting any delta, and sanity-check that the regressing cases actually execute the modified code.GitHub mechanics
--force-with-leaseneeds an explicit SHA (--force-with-lease=<branch>:<sha>) when the ref has not been fetched in the current clone; the bare form fails with "stale info".gh run view --log-failedcan miss the real output entirely. On the Frontier jobs the failing step carried only a non-zero exit while the actual test output lived in a separatePrint Logsstep that succeeded. Fetch the full log.gh run rerun <id> --failedrefuses while the workflow is still running; retry later.file INSTALL cannot set modification time ... No such file or directory, exit 143). Check for a real error before assuming a code fault.