Skip to content

Lint tests/ with muff-check; fix the lint violations - #72

Merged
jsh9 merged 4 commits into
mainfrom
2026-10-08-lint-tests
Oct 10, 2026
Merged

jsh9 merged 4 commits into
mainfrom
2026-10-08-lint-tests

Conversation

@jsh9

@jsh9 jsh9 commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #71: muff-check now lints tests/ too, and all ~1,060 violations there are fixed.

Config (muff.toml)

  • Remove lint.exclude = ["tests/**"].
  • Add test-only ignores to the existing "tests/*" per-file ignores, next to PLC2701/PLR2004:
    • INP001: tests/ is not a package; pytest runs the files directly
    • PLR0904: a test class can group many tests
    • PLR6301: test methods in unittest.TestCase classes don't use self (221 hits after the assertion changes below)
    • SLF001: tests can check private members (75 hits)

Fixes in tests/*.py

  • PT009/PT027 (476 hits): self.assertTrue/Equal/... → plain assert, and self.assertRaises(Regex) → pytest.raises(match=...), mostly with muff's fixes. The auto-fixer re-spelled some number literals (e.g., 6.4e7 → 64000000.0), so I restored the original spellings. The 40 assertAlmostEqual calls became pytest.approx(b, abs=delta). Where no delta was given, I used abs=1e-7, close to its default of 7 decimal places. The test classes still inherit from unittest.TestCase, so the if __name__ == '__main__' runners still work.
  • PTH118/PTH120 (184 hits): f_dir = Path(__file__).resolve().parent / 'files'. Paths passed to PySeismoSoil are wrapped in str(...), because the library checks isinstance(data, str) to tell a file name from an array. np.genfromtxt takes the Path directly.
  • RUF043: literal match= strings that contain . etc. are wrapped in re.escape().
  • ANN*: -> None on test methods; annotated the nearly_identical() helper and the __init__ overrides.
  • The rest, by hand:
    • imports moved to the top of the file (PLC0415)
    • unused variables removed or renamed to _ (F841, RUF059)
    • long comments and strings wrapped (E501), and three over-long test names shortened
    • one statement per pytest.raises() block (PT012)
    • a list comprehension (PERF401)
    • return not r[1, 0] < thres (SIM103; same result as before, including when r is NaN)
    • in test_Vs_cap_is_user_defined, compare with a Vs_cap variable instead of the float literal 1234.5 (RUF069); still an exact comparison
  • NPY002: kept as inline # noqa in one SVM test. That test checks on purpose that get_randomized_profile() doesn't change numpy's legacy global random state, so it has to call np.random.seed() and np.random.random().

Docs

  • CONTRIBUTING.md and CHANGELOG.md are updated: tests/ is now linted, and tests use plain assert and pytest.raises().

Notebooks

  • examples/*.ipynb re-run, as every PR requires.

Test logic is unchanged

I compared every test function with main after parsing both versions. I mapped each self.assert*() call to its plain-assert form and os.path.join to pathlib, and ignored annotations and moved imports. The other differences fall into these groups:

  • Equivalent:
    • operand order (0 == x → x == 0)
    • unused variables dropped or renamed to _
    • the list comprehension
    • the Vs_cap variable
    • not r < thres
  • Slightly stricter:
    • two pytest.raises() blocks now hold only the call that should raise; the setup moved out (PT012)
    • 11 match= patterns are escaped, so . matches only a literal period
  • Slightly looser: the assertAlmostEqual calls without delta now allow an absolute difference of up to 1e-7. unittest's default (rounding to 7 decimal places) is about 5e-8.

Number literal values, comments (apart from line wrapping and the removed # noqa: F841), class bases and module-level code are all unchanged. Both versions collect the same 262 tests, apart from the 3 renamed ones.

Test plan

  • pytest tests: 262 passed (same tests as before)
  • pre-commit run -a: all hooks pass, including muff-check on tests/
  • tox -e run-notebooks: all notebooks ran without errors

🤖 Generated with Claude Code

https://claude.ai/code/session_01TaAeTVJL3sqwsptnDto2WD

claude added 4 commits October 8, 2026 02:56
Remove the `lint.exclude` for `tests/` in `muff.toml`, so `muff-check` also
lints the test files, and fix the violations:

- Use plain `assert` statements and `pytest.raises()` instead of the
  `unittest`-style assertion methods (PT009, PT027). `assertAlmostEqual()`
  becomes `pytest.approx()`, with `abs=` set to its `delta` (or to 1e-7,
  its default precision of 7 decimal places)
- Read the data files via `pathlib` instead of `os.path` (PTH118, PTH120).
  Paths passed to PySeismoSoil are converted with `str()`, since its
  functions check for `str` file names
- Escape the literal `match=` patterns with `re.escape()` (RUF043)
- Add return type annotations (ANN201 etc.), move imports to the top level,
  remove unused variables, wrap long lines, and keep one statement in each
  `pytest.raises()` block

Test-specific ignores (INP001, PLR0904, PLR6301, SLF001) are added to the
`tests/*` per-file ignores. The SVM test that checks numpy's legacy global
random state keeps its `np.random` calls, with inline `noqa: NPY002`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaAeTVJL3sqwsptnDto2WD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaAeTVJL3sqwsptnDto2WD
Three leftovers from the automatic conversion to plain `assert`:

- `test_Vs_cap_is_user_defined` compared with `pytest.approx(1234.5)`
  (about +/-0.001), instead of the original exact equality. Compare with
  the `Vs_cap` variable instead, which keeps the exact check and avoids the
  float literal that RUF069 flags
- `nearly_identical()` returned `r >= thres`, which is `False` for a NaN
  correlation, whereas the original returned `True`. Use
  `not r < thres`, which matches the original for every value
- The auto-fixer re-spelled number literals inside the asserts it rewrote
  (e.g., `6.4e7` -> `64000000.0`, `0.9980` -> `0.998`, `1e-5` -> `1e-05`).
  Restore the original spellings (same values)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaAeTVJL3sqwsptnDto2WD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaAeTVJL3sqwsptnDto2WD
@jsh9
jsh9 merged commit 9ef1b26 into main Oct 10, 2026
12 checks passed
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.

2 participants