Split ASE/thermo.py into a package, one module per concern - #172
Merged
Merged
Conversation
1895 lines became four modules under `Auto3D/ASE/thermo/`:
properties molecular inspection -- geometry class, symmetry number,
multiplicity, display name. No model, no calculator.
calculator the ASE calculator fronting an Auto3D model, and the
conversions into it.
vibrations Hessian, Eckart/Sayvetz projection, frequencies.
driver the per-record sequence and the run over a file.
Dependency order is properties, calculator <- vibrations <- driver, read off
the import graph rather than asserted. Each of the 33 top-level statements
was compared by `ast.dump` against its original: byte-identical, none lost,
none invented.
A PACKAGE, not four sibling modules, and the reason is not tidiness.
`get_logger(__name__)` now yields `Auto3D.ASE.thermo.properties` and
friends, which are *children* of `Auto3D.ASE.thermo`, so records propagate
and the fifteen-odd tests that capture on `logger="Auto3D.ASE.thermo"` keep
seeing warnings raised anywhere in the four. Siblings named
`thermo_properties` would have broken every one of them -- and broken them
silently, because a log-capture assertion that stops seeing records fails by
never firing. Demonstrated directly rather than argued: the child
propagates, the sibling does not.
`__init__.py` re-exports `calc_thermo` alone. That is permitted by the
package-barrel rule for exactly one reason, the same one `isomers` records:
api.rst documents `Auto3D.ASE.thermo.calc_thermo` at that package path.
`SUBPACKAGES_WITH_ALL` gains `thermo` accordingly.
THE BUG THIS SPLIT CREATES, and the test that did not exist:
`_symmetry_default_warned` de-duplicates `_symmetry_number`'s sigma=1
warning to once per run, and `calc_thermo` clears it at the top of each run.
The flag lives with `_symmetry_number` in `properties` now, so `global
_symmetry_default_warned` in `driver` would bind a name *in driver* that
`_symmetry_number` never reads: the reset silently stops working and the
warning fires once per process instead of once per run. The assignment goes
through the module object instead.
Mutation-testing that found the real gap. The naive `global` version passed
the entire suite, because every existing test of this warning sets the flag
itself and so passes either way -- the per-run reset was never covered at
all. `test_calc_thermo_resets_the_symmetry_warn_once_flag_in_properties` is
the missing guard; the mutation now fails it with a message naming the
consequence.
One more consequence worth knowing: `create_model` is now imported into two
modules, so `calc_thermo` reaches it twice -- via `_load_hessian_model`
(driver) and via `model_name2model_calculator` (calculator). A single
monkeypatch used to cover both. One test measuring the ASE relaxation was
silently loading a real model until both bindings were patched.
Test repointing was mechanical but not blind: every misrouted monkeypatch
located a name exactly where this split says it belongs -- `Atoms` and
`create_model` with the calculator that constructs them, `VibrationsData`
and `_ASE_HAS_VIB_SELECTION` with the Hessian code, `_electron_count` and
the warn-once flag with the molecular properties. The tests were an
independent check on the grouping and agreed with it.
`docs/source/migration-3.0.rst` names `projected_vibrations` by dotted path
in a live description of current behavior; updated to its new module. It is
the only doc reference to a moved name -- api.rst points at `calc_thermo`,
which did not move.
Verification:
- 1771 passed, 1 skipped, 74 deselected (+1 new guard), randomized order.
- mypy: 68 errors, unchanged; 23 files instead of 22 and 79 checked instead
of 75, because one file became four plus an __init__.
- All 33 moved statements AST-identical to their originals.
- Mutation-tested both hazards: the naive `global` reset fails the new test,
and the logger-hierarchy property the package decision rests on is
demonstrated rather than assumed.
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.
What
1895 lines became four modules under
Auto3D/ASE/thermo/:propertiescalculatorvibrationsdriverDependency order is
properties, calculator ← vibrations ← driver, read off the import graph rather than asserted. Each of the 33 top-level statements was compared byast.dumpagainst its original: byte-identical, none lost, none invented.A package, not four sibling modules — and not for tidiness
get_logger(__name__)now yieldsAuto3D.ASE.thermo.propertiesand friends, which are children ofAuto3D.ASE.thermo. Records propagate, so the fifteen-odd tests capturing onlogger="Auto3D.ASE.thermo"keep seeing warnings raised anywhere in the four.Siblings named
thermo_propertieswould have broken every one of them — and broken them silently, because a log-capture assertion that stops seeing records fails by never firing. Demonstrated directly rather than argued: the child propagates, the sibling does not.__init__.pyre-exportscalc_thermoalone, permitted by the package-barrel rule for exactly the reasonisomersalready records: api.rst documentsAuto3D.ASE.thermo.calc_thermoat that package path.The bug this split creates, and the test that didn't exist
_symmetry_default_warnedde-duplicates_symmetry_number's sigma=1 warning to once per run, andcalc_thermoclears it at the top of each run. The flag lives with_symmetry_numberinpropertiesnow — soglobal _symmetry_default_warnedindriverwould bind a name in driver that_symmetry_numbernever reads. The reset silently stops working and the warning fires once per process instead of once per run. The assignment goes through the module object instead.Mutation-testing is what found the real gap. The naive
globalversion passed the entire suite: every existing test of this warning sets the flag itself, so they pass either way, and the per-run reset was never covered at all.test_calc_thermo_resets_the_symmetry_warn_once_flag_in_propertiesis the missing guard, and the mutation now fails it with a message naming the consequence.One more consequence worth knowing
create_modelis now imported into two modules, socalc_thermoreaches it twice — via_load_hessian_model(driver) and viamodel_name2model_calculator(calculator). A single monkeypatch used to cover both. One test measuring the ASE relaxation was silently loading a real model until both bindings were patched.The test repointing was mechanical but not blind
Every misrouted monkeypatch located a name exactly where this split says it belongs —
Atomsandcreate_modelwith the calculator that constructs them,VibrationsDataand_ASE_HAS_VIB_SELECTIONwith the Hessian code,_electron_countand the warn-once flag with the molecular properties. The tests were an independent check on the grouping, and they agreed with it.Docs
docs/source/migration-3.0.rstnamesprojected_vibrationsby dotted path in a live description of current behavior; updated to its new module. It is the only doc reference to a moved name —api.rstpoints atcalc_thermo, which did not move.Verification
__init__.globalreset fails the new test, and the logger-hierarchy property the package decision rests on is demonstrated rather than assumed.