Skip to content

Commit 9c16201

Browse files
committed
ruff
1 parent c9b25f9 commit 9c16201

5 files changed

Lines changed: 95 additions & 79 deletions

File tree

‎.planning/codebase/ARCHITECTURE.md‎

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Architecture
22

3-
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @ `66adaf54`
3+
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @
4+
`66adaf54`
45

56
## Pattern Overview
67

@@ -27,8 +28,8 @@ is computed by pluggable engine wrappers (refnx, refl1d) behind
2728
- Inequality constraints are enforced by patching the BUMPS driver in
2829
the core's namespace, because the core offers no hook
2930
- Shared objects (one material in two layers, one assembly in two
30-
models) serialize once through `sample/references.py` (`file_format`
31-
3)
31+
models) serialize once through `sample/references.py`
32+
(`file_format` 3)
3233

3334
## Layers
3435

@@ -64,14 +65,16 @@ is computed by pluggable engine wrappers (refnx, refl1d) behind
6465
- Purpose: Post-hoc posterior analysis and chain persistence
6566
- Location: `src/easyreflectometry/analysis/bayesian.py`
6667
- Contains: `PosteriorResults` (summary, corner, trace, distribution,
67-
credible_interval, gelman_rubin, save), `posterior_predictive_*`,
68-
`save_posterior` / `load_posterior` with fingerprinted sidecar
68+
credible*interval, gelman_rubin, save),
69+
`posterior_predictive*\*`, `save_posterior`/`load_posterior` with
70+
fingerprinted sidecar
6971
- Depends on: plotly (required), arviz (optional), numpy
7072

7173
**Model / Sample Layer:**
7274

7375
- Purpose: Physical description of the sample and measurement
74-
- Location: `src/easyreflectometry/model/`, `src/easyreflectometry/sample/`
76+
- Location: `src/easyreflectometry/model/`,
77+
`src/easyreflectometry/sample/`
7578
- Contains: `Model` (scale, background, resolution, `total_thickness`
7679
derived parameter), `Sample` and assemblies/layers/materials,
7780
`LayerMagnetism`, `MaterialDensity.sld_coupled`, `volume_fraction`,
@@ -119,21 +122,22 @@ is computed by pluggable engine wrappers (refnx, refl1d) behind
119122

120123
**Classical Fit (project path):**
121124

122-
1. GUI/user calls `Project.prepare_fit(experiments=None, objective=None, skip_invalid=False)`
125+
1. GUI/user calls
126+
`Project.prepare_fit(experiments=None, objective=None, skip_invalid=False)`
123127
2. `_fit_scope` selects experiments with `include_in_fit` and a model;
124128
`_fitter_for` builds `MultiFitter.for_experiments(...)` with a deep
125129
copy of `fit_settings` and a weak `constraints_factory_provider`
126130
3. `MultiFitter.prepare` applies the objective (`hybrid` default:
127-
Mighell for zero-variance points, WLS otherwise), binds each dataset's
128-
fit function to its own resolution (`_resolution_for_fitted_points`
129-
for `legacy_mask`), collects `added_roots` (free parameters of
130-
left-out models that fitted parameters follow), builds the core
131-
fitter via `_core_fitter_for` + `FitSettings.configure`, checks
132-
preconditions (finite bounds for engines that need them, warns on
133-
starts at bounds)
131+
Mighell for zero-variance points, WLS otherwise), binds each
132+
dataset's fit function to its own resolution
133+
(`_resolution_for_fitted_points` for `legacy_mask`), collects
134+
`added_roots` (free parameters of left-out models that fitted
135+
parameters follow), builds the core fitter via `_core_fitter_for` +
136+
`FitSettings.configure`, checks preconditions (finite bounds for
137+
engines that need them, warns on starts at bounds)
134138
4. Caller runs `prepared.execute(**kwargs)` or `core_fitter.fit(...)` in
135-
a thread; the `_ConstrainedEasyScienceMultiFitter.fit` property
136-
wraps the call in `_bumps_constraints.applied(factory)`
139+
a thread; the `_ConstrainedEasyScienceMultiFitter.fit` property wraps
140+
the call in `_bumps_constraints.applied(factory)`
137141
5. `Project.record_fit(prepared, results, status)` computes classical
138142
metrics from the measured arrays (`prepared.finalize`), stores a
139143
`FitRun` on `last_fit` and pushes results to `project.fitter`
@@ -148,22 +152,23 @@ is computed by pluggable engine wrappers (refnx, refl1d) behind
148152

149153
**Polarized Fit:**
150154

151-
- `fit_polarized(polarized_dataset)` or `for_experiments([...])`: one fit
152-
function per spin channel, all against one model, each bound to its
153-
channel via `CalculatorFactory.fit_func_for(channel, resolution)`.
155+
- `fit_polarized(polarized_dataset)` or `for_experiments([...])`: one
156+
fit function per spin channel, all against one model, each bound to
157+
its channel via `CalculatorFactory.fit_func_for(channel, resolution)`.
154158
Structural parameters shared, magnetic parameters constrained by all
155159
channels.
156160

157161
**Bayesian MCMC:**
158162

159163
1. `Project.prepare_sample()` → `for_experiments` fitter with settings
160164
snapshot; or `fitter.mcmc_sample(data)` directly
161-
2. `mcmc_sample` requires a BUMPS minimizer (`minimizer.package ==
162-
'bumps'`), refuses all-zero variances unless `objective='mighell'`,
163-
calls `prepare(action='sampling')`
165+
2. `mcmc_sample` requires a BUMPS minimizer
166+
(`minimizer.package == 'bumps'`), refuses all-zero variances unless
167+
`objective='mighell'`, calls `prepare(action='sampling')`
164168
3. Builds `Sampler(core_fitter, x, y, weights)` inside the constraints
165-
context, patches `sampler.extend` to re-enter it, keeps the sampler on
166-
`fitter.sampler`, runs `sampler.sample(samples, burn, thin, population, sampler_kwargs, progress_callback, abort_test)`
169+
context, patches `sampler.extend` to re-enter it, keeps the sampler
170+
on `fitter.sampler`, runs
171+
`sampler.sample(samples, burn, thin, population, sampler_kwargs, progress_callback, abort_test)`
167172
4. Returns `{'draws', 'param_names', 'state', 'logp'}`; user wraps in
168173
`PosteriorResults` or calls `save_posterior`
169174

@@ -191,10 +196,10 @@ is computed by pluggable engine wrappers (refnx, refl1d) behind
191196

192197
## Key Abstractions
193198

194-
**`PreparedFit` (fitting.py):** Snapshot pattern. Everything a run needs,
195-
fixed at prepare time; owns copies of measured arrays, the configured
196-
core fitter and both full-resolution (`curve_funcs`) and fitted-point
197-
(`fit_funcs`) evaluators.
199+
**`PreparedFit` (fitting.py):** Snapshot pattern. Everything a run
200+
needs, fixed at prepare time; owns copies of measured arrays, the
201+
configured core fitter and both full-resolution (`curve_funcs`) and
202+
fitted-point (`fit_funcs`) evaluators.
198203

199204
**`FitRun` (fitting.py):** Frozen record of a run (status, minimizer,
200205
objective, inputs by experiment key, pooled and per-dataset statistics).
@@ -205,10 +210,10 @@ Outlives model changes; `remapped()` follows experiment re-keying.
205210
validated by `MinimizerOption` schemas). `configure(fitter)` and
206211
`engine_kwargs()` are the two consumers.
207212

208-
**`_ConstrainedEasyScienceMultiFitter` / `_bumps_constraints`:** Property
209-
override plus monkeypatch. The subclass overrides the core's read-only
210-
`fit` property so the raw `easy_science_multi_fitter.fit(...)` path
211-
resolves the owner's constraints provider in the calling thread and
213+
**`_ConstrainedEasyScienceMultiFitter` / `_bumps_constraints`:**
214+
Property override plus monkeypatch. The subclass overrides the core's
215+
read-only `fit` property so the raw `easy_science_multi_fitter.fit(...)`
216+
path resolves the owner's constraints provider in the calling thread and
212217
consumes an explicit `constraints_factory` keyword (the core would
213218
swallow it via `**kwargs`). `install()`, run at import of
214219
`_bumps_constraints`, wraps `minimizer_bumps.FitDriver` so each
@@ -220,15 +225,16 @@ Non-BUMPS engines raise `NON_BUMPS_ERROR`.
220225
restricted symbol table; `build_constraints_factory` returns BUMPS
221226
penalty callables.
222227

223-
**Contrasts (`contrasts.py`):** A contrast is an ordinary `Model` sharing
224-
structure with a reference by identity or by `constrain_equal`.
228+
**Contrasts (`contrasts.py`):** A contrast is an ordinary `Model`
229+
sharing structure with a reference by identity or by `constrain_equal`.
225230
`derive_contrast` copies touched assemblies, shares the rest and ties
226231
parameters; `plan_link` / `apply_link` / `unlink` manage equalities
227232
between two models of one layout with full state snapshots.
228233

229234
**`CalculatorBase` / `WrapperBase` / `CalculatorFactory`:** Template +
230-
Adapter + Factory. Items are claimed per calculator (`_claim`), per-model
231-
resolution registry, magnetism toggles, channel-bound fit functions.
235+
Adapter + Factory. Items are claimed per calculator (`_claim`),
236+
per-model resolution registry, magnetism toggles, channel-bound fit
237+
functions.
232238

233239
**`references` (sample/references.py):** Context-managed shared-object
234240
serialization (`writing()`, `reading(report)`, `suspended()`), with
@@ -278,8 +284,8 @@ issues; refuse silent degradation.
278284
handler configured. `warnings` is the main user-facing channel.
279285

280286
**Validation:** `FitSettings.validate`, `MinimizerOption.validate`,
281-
`InequalitySpec.validate_syntax` + `check_units`, ORSO column validation,
282-
`_check_fit_preconditions`.
287+
`InequalitySpec.validate_syntax` + `check_units`, ORSO column
288+
validation, `_check_fit_preconditions`.
283289

284290
**Threading:** The constraints factory lives in a `contextvars`
285291
variable, resolved in the calling thread; `PreparedFit` owns array

‎.planning/codebase/CONCERNS.md‎

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Codebase Concerns
22

3-
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @ `66adaf54`
3+
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @
4+
`66adaf54`
45

56
## Summary
67

@@ -24,12 +25,13 @@ goes through the core `Sampler`. The concerns below are what remains.
2425
inside the core's `minimizer_bumps` namespace and inspects
2526
`problem.models[0].pars`. Any core refactor (importing `FitDriver`
2627
differently, building the problem elsewhere, renaming `.pars`) silently
27-
disables every inequality constraint; the shim passes untouched
28-
problems through without complaint.
28+
disables every inequality constraint; the shim passes untouched problems
29+
through without complaint.
2930

3031
**Files:** `src/easyreflectometry/_bumps_constraints.py`,
3132
`src/easyreflectometry/fitting.py` (`_constraints`,
32-
`_keep_constraints_on_extend`), `tests/unit/test_bumps_constraints_shim.py`
33+
`_keep_constraints_on_extend`),
34+
`tests/unit/test_bumps_constraints_shim.py`
3335

3436
**Impact:** High. Physics silently dropped on a core upgrade.
3537

@@ -53,8 +55,8 @@ against, and 3.0 is excluded by the pin.
5355
core release ships.
5456

5557
**Fix approach:** Add a CI job (allowed to fail) installing core from
56-
`release-3.0`; list the library's core API surface
57-
(`Sampler`, `MultiFitter._precompute_reshaping`, `MINIMIZER_PARAMETER_PREFIX`,
58+
`release-3.0`; list the library's core API surface (`Sampler`,
59+
`MultiFitter._precompute_reshaping`, `MINIMIZER_PARAMETER_PREFIX`,
5860
`InterfaceFactoryTemplate`, `minimizer_bumps.FitDriver`) and check it
5961
against the branch.
6062

@@ -66,7 +68,8 @@ against the branch.
6668
`ItemContainer` from `interface_factory` are not public core API.
6769

6870
**Files:** `analysis/bayesian.py`, `project.py`,
69-
`sample/collections/base_collection.py`, `calculators/calculator_base.py`
71+
`sample/collections/base_collection.py`,
72+
`calculators/calculator_base.py`
7073

7174
**Impact:** Medium.
7275

@@ -96,9 +99,9 @@ helpers). Keep `Project` as the facade.
9699
### `fitting.py` (1428 lines) and `analysis/bayesian.py` (1412 lines)
97100

98101
**Issue:** `bayesian.py` is mostly plotly styling constants and
99-
hand-rolled contour/density code for corner plots; `fitting.py`
100-
combines data preparation, settings, constraints wiring and five public
101-
fit paths.
102+
hand-rolled contour/density code for corner plots; `fitting.py` combines
103+
data preparation, settings, constraints wiring and five public fit
104+
paths.
102105

103106
**Impact:** Low-Medium.
104107

@@ -128,7 +131,8 @@ shared objects, an experiment left out of the fit, duplicate model
128131
names. A user may save a file in 1.9 that 1.8 refuses without an obvious
129132
reason.
130133

131-
**Files:** `project.py` (`_needs_new_format`, `_as_dict_add_experiments`)
134+
**Files:** `project.py` (`_needs_new_format`,
135+
`_as_dict_add_experiments`)
132136

133137
**Impact:** Medium. Document in release notes; already in CHANGELOG.
134138

@@ -175,8 +179,9 @@ slow cases) under `integration/`.
175179

176180
**Issue:** `fitter.sampler.extend()` after constraints, and
177181
`save_posterior`/`load_posterior` fingerprint mismatch handling, have
178-
limited coverage (`TestMCMCSample*` in `test_fitting.py`, `test_bayesian.py`);
179-
all real DREAM runs are `slow` and only run on PRs/develop.
182+
limited coverage (`TestMCMCSample*` in `test_fitting.py`,
183+
`test_bayesian.py`); all real DREAM runs are `slow` and only run on
184+
PRs/develop.
180185

181186
**Impact:** Medium.
182187

@@ -230,9 +235,9 @@ and an accidental `git add .` would commit them.
230235

231236
**Impact:** Low.
232237

233-
**Fix approach:** Add `.planning/`, `.claude/`, `MD/` to `.gitignore` (or
234-
a global excludes file); decide whether `examples/` and `integration/`
235-
belong in the repo.
238+
**Fix approach:** Add `.planning/`, `.claude/`, `MD/` to `.gitignore`
239+
(or a global excludes file); decide whether `examples/` and
240+
`integration/` belong in the repo.
236241

237242
### Docstring tooling disabled
238243

‎.planning/codebase/INTEGRATIONS.md‎

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# External Integrations
22

3-
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @ `66adaf54`
3+
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @
4+
`66adaf54`
45

56
## APIs & External Services
67

@@ -14,8 +15,8 @@
1415
`fitter.sampler` for `extend()`, `save()`, `load_state()`
1516
- `easyscience.fitting.AvailableMinimizers`, `FitResults`
1617
- `easyscience.fitting.minimizers.minimizer_bumps` - Its module-level
17-
`FitDriver` name is wrapped by `_bumps_constraints.install()` to attach
18-
`FitProblem.constraints`
18+
`FitDriver` name is wrapped by `_bumps_constraints.install()` to
19+
attach `FitProblem.constraints`
1920
- `easyscience.fitting.minimizers.minimizer_base.MINIMIZER_PARAMETER_PREFIX` -
2021
Stripped from parameter names in `analysis/bayesian.py`
2122
- `easyscience.variable.Parameter` / `DescriptorNumber` and
@@ -25,8 +26,8 @@
2526
`easyscience.io.SerializerComponent` / `SerializerBase` - Base classes
2627
for `BaseCore`, `BaseCollection`, `DataSet1D`, `CalculatorBase`
2728
- `easyscience.global_object` - Unique-name registry and undo stack
28-
- `easyscience.fitting.calculators.interface_factory.InterfaceFactoryTemplate` /
29-
`ItemContainer` - `CalculatorFactory` base
29+
- `easyscience.fitting.calculators.interface_factory.InterfaceFactoryTemplate`
30+
/ `ItemContainer` - `CalculatorFactory` base
3031
- Auth: None (Python import)
3132

3233
**Reflectivity Calculators (pluggable via `CalculatorFactory`):**
@@ -69,8 +70,8 @@
6970

7071
**Plotting / Reports:**
7172

72-
- plotly - Corner, trace, distribution plots (`analysis/bayesian.py`) and
73-
interactive summary figures; plotly is a hard dependency
73+
- plotly - Corner, trace, distribution plots (`analysis/bayesian.py`)
74+
and interactive summary figures; plotly is a hard dependency
7475
- matplotlib - `plot.py`, static summary figures, `plot_volume_fraction`
7576
- xhtml2pdf (`pisa`) - `Summary.save_pdf_summary`; stderr silenced via
7677
`_silence_pdf_converter`
@@ -136,9 +137,10 @@
136137

137138
- PyPI (`pypi-publish.yml` on tag push, via `pixi run default-build`;
138139
legacy `python-publish.yml` also present)
139-
- GitHub Pages via mike (`docs.yml`): `dev` alias from develop, versioned
140-
+ `latest` on release; a quality dashboard is published by
141-
`dashboard.yml` (badgery + radon + interrogate)
140+
- GitHub Pages via mike (`docs.yml`): `dev` alias from develop,
141+
versioned
142+
- `latest` on release; a quality dashboard is published by
143+
`dashboard.yml` (badgery + radon + interrogate)
142144

143145
**CI Pipeline (`.github/workflows/`, 24 workflows):**
144146

@@ -157,8 +159,8 @@
157159
- `docs.yml`, `dashboard.yml` - site and metrics publishing
158160
- `security.yml` / `codeql-analysis.yml` / `ossar-analysis.yml` - CodeQL
159161
and OSSAR scans
160-
- `release-drafter.yml`, `release-notes.yml`, `release-pr.yml`
161-
(develop → master), `backmerge.yml` (master → develop),
162+
- `release-drafter.yml`, `release-notes.yml`, `release-pr.yml` (develop
163+
→ master), `backmerge.yml` (master → develop),
162164
`release-drafter-verify-pr-labels.yml`, `pr-labels.yml`,
163165
`issues-labels.yml`, `cleanup.yml`
164166
- `python-ci.yml`, `python-package.yml` - Older pip-based matrices that

‎.planning/codebase/STACK.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Technology Stack
22

3-
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @ `66adaf54`
4-
(tag `v1.7.0-51`; last release `v1.8.0` on 2026-09-18, develop carries
5-
the unreleased 1.9 work listed under "Unreleased" in `CHANGELOG.md`)
3+
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @
4+
`66adaf54` (tag `v1.7.0-51`; last release `v1.8.0` on 2026-09-18,
5+
develop carries the unreleased 1.9 work listed under "Unreleased" in
6+
`CHANGELOG.md`)
67

78
## Languages
89

@@ -80,7 +81,8 @@ the unreleased 1.9 work listed under "Unreleased" in `CHANGELOG.md`)
8081
`force-single-line`)
8182
- pre-commit, prettier (non-Python formatting), pydoclint /
8283
format-docstring (configured but disabled via `exclude = '\.'`),
83-
interrogate (`fail-under = 0`), radon, spdx-headers, validate-pyproject
84+
interrogate (`fail-under = 0`), radon, spdx-headers,
85+
validate-pyproject
8486
- copier (`.copier-answers.yml`) - repo scaffold synced from
8587
`gh:easyscience/templates` (`template_type=lib`)
8688
- MkDocs Material + mkdocstrings + mkdocs-jupyter + mike (versioned docs

‎.planning/codebase/STRUCTURE.md‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Codebase Structure
22

3-
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @ `66adaf54`
3+
**Analysis Date:** 2026-10-15 **Branch analysed:** `develop` @
4+
`66adaf54`
45

56
## Directory Layout
67

@@ -164,16 +165,15 @@ Untracked in the working copy (not on `develop`): `.planning/`,
164165

165166
## Naming Conventions
166167

167-
**Files:** snake_case modules; tests `test_<module>.py`; private module
168-
`_bumps_constraints.py`.
168+
**Files:** snake*case modules; tests
169+
`test*<module>.py`; private module `\_bumps_constraints.py`.
169170

170171
**Classes:** PascalCase (`MultiFitter`, `PreparedFit`, `FitRun`,
171172
`InequalitySpec`, `PolarizedDataSet`); core import aliased as
172173
`EasyScienceMultiFitter`; private subclasses prefixed `_`.
173174

174-
**Functions:** snake_case; private helpers `_`-prefixed; `Project`
175-
exposes `*_at_index` accessors for GUI use
176-
(`model_data_for_experiment_at_index`).
175+
**Functions:** snake*case; private helpers
176+
`*`-prefixed; `Project`exposes`\*\_at_index` accessors for GUI use (`model_data_for_experiment_at_index`).
177177

178178
**Constants:** UPPER_SNAKE (`DEFAULT_MINIMIZER`, `GUIDE_FIELD_ANGLE`,
179179
`DEFAULT_THETA_M`, `SIGMA_TO_FWHM`, `USER_CONSTRAINT_FLAG`).
@@ -192,9 +192,10 @@ records).
192192

193193
**New constraint kind:**
194194

195-
- Equality: `constraints.py` + persistence in `Project._user_constraints`
196-
/ `_restore_user_constraints`. Inequality: `inequality_constraints.py`
197-
+ `Project.add_inequality_constraint`. Tests under `tests/unit/`.
195+
- Equality: `constraints.py` + persistence in
196+
`Project._user_constraints` / `_restore_user_constraints`. Inequality:
197+
`inequality_constraints.py`
198+
- `Project.add_inequality_constraint`. Tests under `tests/unit/`.
198199

199200
**New calculator backend:**
200201

0 commit comments

Comments
 (0)