diff --git a/docs/dev/adrs/accepted/analysis-cif-fit-state.md b/docs/dev/adrs/accepted/analysis-cif-fit-state.md index 9883a3b94..0cc5e658a 100644 --- a/docs/dev/adrs/accepted/analysis-cif-fit-state.md +++ b/docs/dev/adrs/accepted/analysis-cif-fit-state.md @@ -26,7 +26,7 @@ Analysis-owned fit state needs to persist: - pre-fit scalar snapshots for recovery workflows - compact status metadata for the latest saved fit projection - deterministic correlation summaries -- minimizer-specific fit outputs on the active `_minimizer.*` category +- minimizer-specific fit outputs on the paired `_fit_result.*` category - per-parameter posterior summaries on `_fit_parameter` - large posterior arrays and plot caches in `analysis/results.h5` @@ -47,8 +47,7 @@ Persist analysis-owned fit state as explicit analysis categories in Do not add a dedicated `_fit_state` category or `_fit_state.schema_version`. Persisted fit state is detected from -`_fit_result`, `_fit_parameter`, `_fit_parameter_correlation`, and -fit-output fields on `_minimizer.*`. +`_fit_result`, `_fit_parameter`, and `_fit_parameter_correlation`. ### Common fit-state categories @@ -77,7 +76,8 @@ pre-fit scalar snapshots: - `posterior_gelman_rubin` - `posterior_effective_sample_size_bulk` -`_fit_result` stores the latest saved fit header: +`_fit_result` stores the latest saved fit header and scalar +family-specific fit outputs: - `result_kind` - `success` @@ -92,9 +92,9 @@ pairs are stored. ### Minimizer fit projection -The active `_minimizer.*` category stores both user-selected solver -inputs and fit-filled outputs. Deterministic minimizer classes store -compact fit output counts: +The active `_minimizer.*` category stores user-selected solver inputs +only. Scalar outputs are written to the paired `_fit_result.*` category. +Deterministic fit-result classes add compact fit output counts: - `objective_name` - `objective_value` @@ -104,8 +104,6 @@ compact fit output counts: - `degrees_of_freedom` - `covariance_available` - `correlation_available` -- `runtime_seconds` -- `iterations_performed` - `exit_reason` Do not persist a `_deterministic_parameter_result` category. Final @@ -113,8 +111,7 @@ deterministic parameter values and uncertainties already persist in the model CIF files, and restored deterministic ordering comes from `_fit_parameter`. -Bayesian minimizer classes store sampler inputs and fit outputs under -`_minimizer.*`, including: +Bayesian minimizer classes store sampler inputs under `_minimizer.*`: - `sampling_steps` - `burn_in_steps` @@ -123,7 +120,9 @@ Bayesian minimizer classes store sampler inputs and fit outputs under - `parallel_workers` - `initialization_method` - `random_seed` -- `runtime_seconds` + +Bayesian fit-result classes store scalar outputs under `_fit_result.*`: + - `point_estimate_name` - `sampler_completed` - `credible_interval_inner` @@ -170,10 +169,10 @@ posterior displays. Load order is: 1. standard analysis configuration -2. common fit-state categories -3. `_minimizer.*` fit-output fields according to the active - `_minimizer.type` -4. posterior sidecar arrays when a Bayesian result is expected +2. `_minimizer.*` settings according to the active `_minimizer.type` +3. common and family-specific `_fit_result.*` fields on the paired class +4. `_fit_parameter` and `_fit_parameter_correlation` +5. posterior sidecar arrays when a Bayesian result is expected Persist backend runtime objects, optimizer instances, and raw driver payloads nowhere in this design. diff --git a/docs/dev/adrs/accepted/display-ux.md b/docs/dev/adrs/accepted/display-ux.md index 0b33b708e..379bdb8c8 100644 --- a/docs/dev/adrs/accepted/display-ux.md +++ b/docs/dev/adrs/accepted/display-ux.md @@ -200,6 +200,12 @@ Use these naming rules: path for `versus`. - `posterior.*` names are used only when posterior samples are required. +`project.display.fit.results()` also prints a "Settings used" block +above the result tables. The block is sourced from +`analysis.minimizer.*` so the minimizer inputs and paired +`analysis.fit_result.*` outputs are visible from the accepted display +facade without adding a new `Analysis`-level display method. + ## Rejected Alternatives Flat display facade: diff --git a/docs/dev/adrs/accepted/minimizer-category-consolidation.md b/docs/dev/adrs/accepted/minimizer-category-consolidation.md index f86b56a95..ed1e24f36 100644 --- a/docs/dev/adrs/accepted/minimizer-category-consolidation.md +++ b/docs/dev/adrs/accepted/minimizer-category-consolidation.md @@ -55,31 +55,34 @@ samplers. ## Decision -### 1. Unified `minimizer` category replaces all sampler-input and fit-result categories +### 1. Unified `minimizer` category replaces sampler-input categories Introduce a single switchable category `minimizer` on `Analysis`. Its concrete class is determined by `Analysis.minimizer_type`. The category -holds both user-writable inputs and fit-filled outputs in one place. +now holds user-writable minimizer inputs only. The later +[`minimizer-input-output-split.md`](minimizer-input-output-split.md) ADR +reverses the fit-output half of this rule: scalar fit outputs live on +the paired `fit_result` category instead of on `minimizer`. The following categories are removed: - `bayesian_sampler` — fields move into the Bayesian concrete classes of `minimizer`. - `bayesian_result`, `bayesian_convergence` — fields move into the - Bayesian concrete classes of `minimizer` (`runtime_seconds`, + Bayesian concrete classes of `fit_result` (`fitting_time`, `acceptance_rate_mean`, `gelman_rubin_max`, `effective_sample_size_min`, `best_log_posterior`, …). - `deterministic_result` — fields move into the deterministic concrete - classes of `minimizer` (`runtime_seconds`, `iterations_performed`, - `exit_reason`, …). + classes of `fit_result` (`fitting_time`, `iterations`, + `objective_value`, `exit_reason`, …). - `bayesian_parameter_posterior` — replaced by `Parameter.posterior` (see §3). - `bayesian_distribution_cache`, `bayesian_pair_cache`, `bayesian_predictive_dataset` — replaced by HDF5 sidecar (see §4). -`fit_result` and `fit_parameter` (analysis-owned bounds, success flag, -reduced chi-square, message, fit time, iterations) remain unchanged as -fit-mode-agnostic header categories. +`fit_parameter` (analysis-owned bounds) remains a fit-state category. +`fit_result` remains the common fit header category and is extended by +the input/output split ADR with family-specific scalar outputs. ### 2. Selectors move to the `Analysis` owner @@ -388,10 +391,11 @@ category's class-level `_engine_metadata` dict. ### Trade-offs -- `minimizer` is the first category that mixes writable user inputs and - writable fit-filled outputs in the same scope. This is a small new - convention but is the natural generalization of how `Parameter` - already holds both user input and refined value on the same object. +- `minimizer` no longer mixes writable user inputs and fit-filled + outputs in the same scope. That stricter boundary is recorded by + [`minimizer-input-output-split.md`](minimizer-input-output-split.md); + `Parameter` remains the refinement-in-place precedent for model values + rather than minimizer diagnostics. - The set of `_minimizer.*` tags present in CIF depends on the active `_fitting.minimizer_type`. Loading a CIF whose tags don't match the minimizer's allowed set raises (clear validation, not silent @@ -461,9 +465,10 @@ category count for each new sampler and entrenches the convention break. ### D. Strict input-only `minimizer` plus a separate `fit_result` -Keep the categories single-concept (inputs xor outputs) at the cost of -two-place lookup for related info. Rejected in favour of the -one-category-mixes-both shape (§1, §"Trade-offs") because the existing -`Parameter` model already mixes input and refined value on the same -object, and one-place discoverability is more valuable than strict -purity. +Originally rejected in favour of the one-category-mixes-both shape (§1, +§"Trade-offs"). Reversed by +[`minimizer-input-output-split.md`](minimizer-input-output-split.md) +after implementation showed the `Parameter` analogy does not hold for +minimizer settings versus fit diagnostics. The current design keeps +`minimizer` input-only and moves scalar fit outputs to the paired +`fit_result` category. diff --git a/docs/dev/adrs/accepted/minimizer-input-output-split.md b/docs/dev/adrs/accepted/minimizer-input-output-split.md new file mode 100644 index 000000000..13a33a5be --- /dev/null +++ b/docs/dev/adrs/accepted/minimizer-input-output-split.md @@ -0,0 +1,407 @@ +# ADR: Minimizer Input/Output Split + +**Status:** Accepted **Date:** 2026-05-24 + +## Status Note + +This proposal revisits and supersedes Alternative D in +[`minimizer-category-consolidation.md`](minimizer-category-consolidation.md) +("Strict input-only `minimizer` plus a separate `fit_result`"), which +was rejected during the consolidation work on the assumption that the +input/output mix on `analysis.minimizer` was symmetric with the +input/output mix on `Parameter`. Implementation experience shows that +analogy does not hold and the mix has produced measurable UX and +duplication problems documented below. + +## Context + +After +[`minimizer-category-consolidation.md`](minimizer-category-consolidation.md) +landed, `analysis.minimizer` holds both writable user inputs and +fit-filled outputs in a single namespace. A user typing +`analysis.minimizer.help()` before any fit sees roughly twenty +properties, the majority of which are `None`, `0`, or empty strings, +with no signal which they may write and which the fit fills in. + +The current shape on the live category surfaces: + +- **Writable inputs:** `max_iterations` (LSQ); `sampling_steps`, + `burn_in_steps`, `thinning_interval`, `population_size`, + `parallel_workers`, `initialization_method`, `random_seed` (Bayesian). +- **Fit-filled outputs (no public setter, only `_set_*` internals):** + `objective_name`, `objective_value`, `n_data_points`, `n_parameters`, + `n_free_parameters`, `degrees_of_freedom`, `covariance_available`, + `correlation_available`, `runtime_seconds`, `iterations_performed`, + `exit_reason` (LSQ); `runtime_seconds`, `point_estimate_name`, + `sampler_completed`, `credible_interval_inner`, + `credible_interval_outer`, `acceptance_rate_mean`, `gelman_rubin_max`, + `effective_sample_size_min`, `best_log_posterior` (Bayesian). + +Three current output fields straddle `analysis.minimizer` and +`analysis.fit_result`: + +| Output concept | Field on `analysis.minimizer` | Field on `analysis.fit_result` | Relationship | +| ----------------------- | ----------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| Wall time | `runtime_seconds` | `fitting_time` | Real duplication — same scalar in two places. | +| Iteration count | `iterations_performed` (LSQ) | `iterations` | Real duplication — same scalar in two places. | +| Objective vs reduced χ² | `objective_value` (raw χ²) | `reduced_chi_square` (χ² / dof) | Cross-category misplacement — two related but distinct scalars where the raw value sits on `minimizer` instead of with the rest of the fit outputs. | + +So a reader who wants "how long did the fit take" must already pick +between two places. The current layout has both **input/output mixed +inside `minimizer`** and **fit-output content split across `minimizer` +and `fit_result`** (whether the two scalars per row are the same value +or not). §2 resolves each row above explicitly. + +The consolidation ADR's two-line argument for keeping inputs and outputs +together was: + +1. **Symmetry with `Parameter`.** A `Parameter` holds both its user-set + initial value and its refined value plus uncertainty. +2. **One-place discoverability** > strict purity. + +The symmetry argument does not actually transfer. `Parameter.value` and +`Parameter.uncertainty` describe the _same scalar quantity_ before and +after refinement; they share a name, semantics, and lifecycle. +`minimizer.sampling_steps` (a user request) and +`minimizer.gelman_rubin_max` (a diagnostic the sampler reports) are +about completely different things and only share a namespace because the +consolidation ADR put them there. "One-place" is also already broken: +scalar fit outputs are split across `minimizer`, `fit_result`, +`fit_parameters`, and `fit_parameter_correlations` today. + +## Decision + +### 1. Split `analysis.minimizer` into inputs and outputs + +`analysis.minimizer` keeps only **writable user settings**. The +fit-filled output fields move to `analysis.fit_result`, which gets a +class hierarchy parallel to `minimizer` so each minimizer family can +declare its own output schema. + +After this ADR: + +| Category | Role | Writable | +| ------------------------------------- | -------------------------------------------------- | --------------------------- | +| `analysis.minimizer` | user-supplied settings | yes | +| `analysis.fit_result` | scalar fit outputs | no (internal `_set_*` only) | +| `analysis.fit_parameters` | per-parameter snapshots and posterior summary rows | no | +| `analysis.fit_parameter_correlations` | upper-triangle correlation rows | no | + +**`fit_result` is not a user-facing switchable category.** It is an +internal projection paired with the active `minimizer`. It does not +expose `fit_result.type` or `fit_result.show_supported()`; the only way +the user changes the active `fit_result` class is by setting +`analysis.minimizer.type`, which the owner's `_swap_minimizer` hook uses +to instantiate both `self._minimizer` and `self._fit_result` atomically. +This is an explicit, documented exception to the global selector +contract from +[`switchable-category-owned-selectors.md`](switchable-category-owned-selectors.md) +§1 because there is no user choice involved at the `fit_result` level — +the minimizer family fully determines the result schema. See the new +exception text added to that ADR (listed under §"ADRs amended"). + +**Family mapping is one-to-one between minimizer family and result +class.** Every minimizer registered under `MinimizerTypeEnum` maps to +exactly one `FitResult` concrete class according to its family: + +| `MinimizerTypeEnum` member | Minimizer family | Paired `FitResult` class | +| -------------------------- | ---------------- | ------------------------ | +| `LMFIT` | LSQ | `LeastSquaresFitResult` | +| `LMFIT_LEASTSQ` | LSQ | `LeastSquaresFitResult` | +| `LMFIT_LEAST_SQUARES` | LSQ | `LeastSquaresFitResult` | +| `DFOLS` | LSQ | `LeastSquaresFitResult` | +| `BUMPS` | LSQ | `LeastSquaresFitResult` | +| `BUMPS_LM` | LSQ | `LeastSquaresFitResult` | +| `BUMPS_AMOEBA` | LSQ | `LeastSquaresFitResult` | +| `BUMPS_DE` | LSQ | `LeastSquaresFitResult` | +| `BUMPS_DREAM` | Bayesian | `BayesianFitResult` | +| `EMCEE` _(when added)_ | Bayesian | `BayesianFitResult` | + +The pairing rule is encoded once on the minimizer base classes +(`LeastSquaresMinimizerBase._fit_result_class = LeastSquaresFitResult`, +`BayesianMinimizerBase._fit_result_class = BayesianFitResult`) so +`_swap_minimizer` reads the paired class off the new minimizer instance +and does not need a per-tag dispatch. + +This preserves the consolidation ADR's "no `_bayesian_*` mirror" +guarantee — there is exactly one output category, not seven — while +making the input/output boundary unambiguous. + +### 2. Field assignments + +**`analysis.minimizer` after the split** (writable settings only): + +- LSQ: `max_iterations`. +- Bayesian: `sampling_steps`, `burn_in_steps`, `thinning_interval`, + `population_size`, `parallel_workers`, `initialization_method`, + `random_seed`. + +`credible_interval_inner` and `credible_interval_outer` **stay on the +output side** in this ADR, attached to `BayesianFitResult` (see below). +They are persisted with the fixed values `0.68` and `0.95`, matching the +per-parameter interval columns (`posterior_interval_68_low/high`, +`posterior_interval_95_low/high`). Promoting the levels to user-writable +settings would let the user choose a 50% interval that then gets +persisted under a column named `posterior_interval_68_low` — a +data-integrity problem rather than a UX problem. A future suggestion ADR +can promote them to settings and generalise the column naming (e.g. +`posterior_interval_low_`) in one combined change; doing one +without the other is unsafe and out of scope here. + +**`analysis.fit_result` after the split** (outputs only). Common fields +live on `FitResultBase`; family-specific fields on the concrete classes: + +- `FitResultBase`: `success`, `message`, `iterations`, `fitting_time`, + `reduced_chi_square`, `result_kind`. +- `LeastSquaresFitResult` adds: `objective_name`, `objective_value`, + `n_data_points`, `n_parameters`, `n_free_parameters`, + `degrees_of_freedom`, `covariance_available`, `correlation_available`, + `exit_reason`. +- `BayesianFitResult` adds: `point_estimate_name`, `sampler_completed`, + `credible_interval_inner`, `credible_interval_outer`, + `acceptance_rate_mean`, `gelman_rubin_max`, + `effective_sample_size_min`, `best_log_posterior`. + +The three overlapping pairs from §"Context" are resolved by **dropping +the `minimizer` copy** and keeping the `fit_result` copy: + +- `minimizer.runtime_seconds` removed; `fit_result.fitting_time` is the + single source. +- `minimizer.iterations_performed` removed; `fit_result.iterations` is + the single source. +- `minimizer.objective_value` removed. `LeastSquaresFitResult` keeps + **two distinct fields**: `objective_value` (raw χ² returned by the + minimizer's objective function) and `reduced_chi_square` (= χ² / + `degrees_of_freedom`). They are not duplicates; the unreduced value is + what the solver actually optimises and is useful for diagnostics on + small-dof fits, while the reduced value is what every user-facing + table and plot displays. `BayesianFitResult` does not carry + `objective_value` because the Bayesian engine optimises the log + posterior rather than χ² directly. + +### 3. CIF layout follows the Python split + +The `_minimizer.*` block becomes settings-only. A new `_fit_result.*` +block (already present today for the common header fields) absorbs every +fit output. The set of `_fit_result.*` tags depends on the active +`_minimizer.type`, matching the same shape-shifting convention that +`_minimizer.*` itself already uses per +[`switchable-category-owned-selectors.md`](switchable-category-owned-selectors.md). + +Example deterministic fit: + +``` +_minimizer.type 'lmfit (leastsq)' +_minimizer.max_iterations 1000 + +_fit_result.result_kind deterministic +_fit_result.success true +_fit_result.message converged +_fit_result.iterations 87 +_fit_result.fitting_time 12.34 +_fit_result.reduced_chi_square 1.42 +_fit_result.objective_name chi_square +_fit_result.objective_value 1532.4 +_fit_result.n_data_points 1024 +_fit_result.n_parameters 12 +_fit_result.n_free_parameters 8 +_fit_result.degrees_of_freedom 1016 +_fit_result.covariance_available true +_fit_result.correlation_available true +_fit_result.exit_reason converged +``` + +Example Bayesian fit: + +``` +_minimizer.type 'bumps (dream)' +_minimizer.sampling_steps 3000 +_minimizer.burn_in_steps 600 +_minimizer.thinning_interval 1 +_minimizer.population_size 4 +_minimizer.parallel_workers 0 +_minimizer.initialization_method latin_hypercube +_minimizer.random_seed ? + +_fit_result.result_kind bayesian +_fit_result.success true +_fit_result.message 'sampler converged' +_fit_result.iterations 3000 +_fit_result.fitting_time 124.7 +_fit_result.reduced_chi_square 1.18 +_fit_result.point_estimate_name best_sample +_fit_result.sampler_completed true +_fit_result.credible_interval_inner 0.68 +_fit_result.credible_interval_outer 0.95 +_fit_result.acceptance_rate_mean 0.27 +_fit_result.gelman_rubin_max 1.03 +_fit_result.effective_sample_size_min 482 +_fit_result.best_log_posterior -1234.56 +``` + +### 4. The runtime `analysis.fit_results` object is the same data shaped differently + +`analysis.fit_results` (plural, runtime) is the rich `FitResults` / +`BayesianFitResults` Python object that holds posterior samples, +predictive summaries, raw engine results, and reporting helpers. This +ADR does **not** rename it. After the split it remains the +"give-me-everything" accessor; `analysis.fit_result.*` (singular, CIF +category) holds the persisted scalar projection of the same fit. The +naming pair stays as today. + +A small UX win is added under the accepted display facade +([`display-ux.md`](display-ux.md)): the existing +`project.display.fit.results()` entry point gains a "Settings used" +table above the existing results tables, populated from +`analysis.minimizer.*`. No new `Analysis`-level display method is added; +the user-facing surface stays exactly where the display ADR put it. +Internally the helper reads `self.minimizer.*` and `self.fit_result.*` +and renders one combined view. + +### 5. Help and discoverability + +`analysis.minimizer.help()` after the split lists ~7 properties for +Bayesian and 1 for LSQ — every one writable. The "is this writable" +question disappears. + +`analysis.fit_result.help()` lists 6 common output properties plus the +family-specific ones, all clearly read-only. + +### 6. No new selector wiring + +`analysis.minimizer.type` remains the single user-facing selector. The +swap hook updates **both** `analysis.minimizer` and +`analysis.fit_result` instances atomically (via +`Analysis._swap_minimizer`, which reads the paired `_fit_result_class` +off the new minimizer base). The paired `fit_result` is not a +user-facing switchable: there is no `fit_result.type` and no +`fit_result.show_supported()`, per the documented exception added to +[`switchable-category-owned-selectors.md`](switchable-category-owned-selectors.md) +(see §"ADRs amended"). This keeps "one minimizer concept, one +user-facing type" intact and removes the temptation to swap the result +class independently of the minimizer. + +## Consequences + +### Positive + +- **Clear writable surface.** `analysis.minimizer.help()` shows only + settings. Inputs and outputs no longer mix in one namespace. +- **Single source for every output field.** The two current real + duplications (`runtime_seconds`/`fitting_time` and + `iterations_performed`/`iterations`) collapse to one location each. + The `objective_value`/`reduced_chi_square` pair is **not** a + duplication and both stay (see §2 for the distinction). +- **Family-specific outputs have a natural home.** Currently + `minimizer.gelman_rubin_max` lives on the Bayesian minimizer class; + after the split it lives on the paired `BayesianFitResult` class. The + two categories pair symmetrically and emcee inherits the pattern for + free. +- **CIF stays compact.** No new CIF blocks beyond `_fit_result.*` which + is already present. The settings/outputs split is reflected in the CIF + tag prefix. +- **The "are we done with a fit?" check becomes simple.** + `bool(analysis.fit_result.success.value)` answers it directly without + scanning a mixed input/output namespace. + +### Trade-offs + +- **Settings and matching outputs are two-place reads.** Mitigation: + `project.display.fit.results()` presents both. The current layout + already requires multi-place reads; this just makes the rule + consistent. +- **`fit_result` becomes an internally-paired category.** The pairing + cost is small (one paired-instance assignment in the existing + `_swap_minimizer` hook) and is invisible to the user — there is no + second `fit_result.type` selector. The exception to the global + selector contract is documented explicitly in §"ADRs amended" + alongside the selector ADR. +- **Saved CIF files from the post-consolidation layout cannot load + unchanged.** Beta posture (no legacy shims) applies. Tutorial fixtures + regenerate via `pixi run script-tests`. Tutorial `ed-24` already + carries a narrow archive normaliser; the new layout would extend it + once. +- **Reopens a decision from a recently accepted ADR.** Documented + explicitly above in §"Status Note". + +### ADRs amended by this ADR + +- [`minimizer-category-consolidation.md`](minimizer-category-consolidation.md) + — §1 ("Unified `minimizer` category replaces all sampler-input and + fit-result categories") becomes a partial rule: the unified + `minimizer` holds inputs; outputs move to the paired `fit_result`. + §"Alternatives Considered → D" updated to record the reversal and the + implementation evidence that prompted it. +- [`analysis-cif-fit-state.md`](analysis-cif-fit-state.md) — §"Minimizer + fit projection" rewritten to describe the split (`_minimizer.*` + settings-only, `_fit_result.*` outputs including family-specific + fields). +- [`runtime-fit-results.md`](runtime-fit-results.md) — closing paragraph + references this ADR alongside the existing two. +- [`switchable-category-owned-selectors.md`](switchable-category-owned-selectors.md) + — §1 ("The category owns its selector") gains a paragraph carving out + one documented exception: a category that is fully determined by + another category's `type` (today only `fit_result`, derived from + `minimizer.type`) is allowed to omit `category.type` and + `category.show_supported()`. The mechanism is described in §1 of this + ADR. The user-facing selector convention is otherwise unchanged. +- [`display-ux.md`](display-ux.md) — §"Fit results display" expanded to + mention that `project.display.fit.results()` now prints a "Settings + used" block above the result tables, sourced from + `analysis.minimizer.*`. No new public entry point is added. + +## Deferred Work + +- **Renaming `analysis.fit_results` (plural runtime object).** The + plural/singular pair is mildly confusing but the rename has wide blast + radius (tests, tutorials, every BayesianFitResults reference). Track + separately if the confusion remains after the combined display lands. +- **Paired internal categories beyond `minimizer` / `fit_result`.** This + ADR introduces the paired pattern for the minimizer only. If future + categories grow the same input/output asymmetry (e.g. extinction, + peak), apply the same pattern then; do not generalise pre-emptively. +- **User-configurable credible-interval levels.** The two interval + levels currently stay at the hardcoded `0.68` / `0.95`, matching the + fixed per-parameter column names (`posterior_interval_68_low` etc.). + Promoting the levels to user settings requires generalising the column + naming at the same time to avoid the data-integrity hole where a + `0.50` level lands in a column called `posterior_interval_68_low`. + Both pieces belong in a follow-on ADR so this proposal stays focused + on the input/output split. +- **CIF compatibility helper for ID 35 archive.** The + `_normalize_id35_archive_for_tutorial` helper in `ed-24.py` already + has a roadmap to deletion; the new CIF layout extends the rename map + one more line. No new architecture decision needed. + +## Alternatives Considered + +### A. Keep current mixed-category layout, fix only the duplications + +Drop `minimizer.runtime_seconds`, `.iterations_performed`, +`.objective_value` and route every reader to `fit_result.*`. Rejected +because it leaves the input/output mix on `minimizer` intact and +therefore does not fix the `minimizer.help()` discoverability problem. + +### B. Mark fields with metadata, keep one category + +Add an `is_input: bool` marker to each descriptor and have +`minimizer.help()` group inputs vs outputs in display. Rejected because +it ships the structural problem unchanged — the CIF still mixes both +under `_minimizer.*`, the duplications with `fit_result` remain, and the +`_set_*` vs writable-setter split is still ad-hoc. + +### C. Move outputs into the runtime `fit_results` object, not a CIF category + +Persist only settings in CIF; outputs live in `analysis.fit_results` at +runtime and `analysis/results.h5` on disk. Rejected because the small +scalar outputs (success, χ², runtime, R̂) are exactly what users want to +read from CIF without unpacking HDF5, and the consolidation ADR +explicitly puts them in CIF (`_minimizer.*` today). + +### D. Rename `fit_result` to mirror minimizer (`minimizer_result`) + +Make the pairing rule explicit in the name (`` and `_result`). +Rejected because the recently-accepted +[`switchable-category-owned-selectors.md`](switchable-category-owned-selectors.md) +ADR deliberately drops `_type` and other suffixes from category names; +adding `_result` walks the convention back. diff --git a/docs/dev/adrs/accepted/runtime-fit-results.md b/docs/dev/adrs/accepted/runtime-fit-results.md index 282b9841d..c0cbf7b29 100644 --- a/docs/dev/adrs/accepted/runtime-fit-results.md +++ b/docs/dev/adrs/accepted/runtime-fit-results.md @@ -30,9 +30,11 @@ raw driver payloads remain runtime-only unless a narrower ADR defines a persisted projection. The accepted [`analysis-cif-fit-state.md`](analysis-cif-fit-state.md) and [`minimizer-category-consolidation.md`](minimizer-category-consolidation.md) -ADRs define the current compact projection for fit headers, -minimizer-owned outputs, parameter posterior summaries, and the -`analysis/results.h5` sidecar. +ADRs, as amended by +[`minimizer-input-output-split.md`](minimizer-input-output-split.md), +define the current compact projection for fit headers, paired fit-result +outputs, parameter posterior summaries, and the `analysis/results.h5` +sidecar. ## Consequences diff --git a/docs/dev/adrs/accepted/switchable-category-owned-selectors.md b/docs/dev/adrs/accepted/switchable-category-owned-selectors.md index 19fb491bb..f74fdf849 100644 --- a/docs/dev/adrs/accepted/switchable-category-owned-selectors.md +++ b/docs/dev/adrs/accepted/switchable-category-owned-selectors.md @@ -101,6 +101,14 @@ Owner-level shims are removed (no `._type`, no `show_supported__types()`, no `show_current__type()`). The owner exposes only the category itself, e.g. `analysis.minimizer`. +Exception: an internally paired category whose concrete class is fully +determined by another category's `type` may omit its own public +selector. Today this applies only to `analysis.fit_result`, whose class +is derived from `analysis.minimizer.type` by the +[`minimizer-input-output-split.md`](minimizer-input-output-split.md) +ADR. It has no `fit_result.type`, no `fit_result.show_supported()`, and +no `_fit_result.type` CIF tag. + The owner still owns the swap mechanism (it holds the slot) but the swap is _initiated_ from the category through a back-reference. diff --git a/docs/dev/adrs/index.md b/docs/dev/adrs/index.md index 28859e145..fcdf7bbfa 100644 --- a/docs/dev/adrs/index.md +++ b/docs/dev/adrs/index.md @@ -21,6 +21,7 @@ folders. | Analysis and fitting | Accepted | Parameter Correlation Persistence | Persists deterministic and posterior correlation summaries in `_fit_parameter_correlation` | [`parameter-correlation-persistence.md`](accepted/parameter-correlation-persistence.md) | | Analysis and fitting | Suggestion | Fit Output Files and Data Exports | Narrows remaining archive/export questions after adopting `results.csv` and `results.h5`. | [`fit-output-files-and-data-exports.md`](suggestions/fit-output-files-and-data-exports.md) | | Analysis and fitting | Accepted | Minimizer Category Consolidation | Collapses the seven Bayesian categories into one owner-level switchable `minimizer` category with HDF5 sidecar. | [`minimizer-category-consolidation.md`](accepted/minimizer-category-consolidation.md) | +| Analysis and fitting | Accepted | Minimizer Input/Output Split | Keeps `analysis.minimizer` input-only and moves scalar fit outputs to paired `analysis.fit_result` classes. | [`minimizer-input-output-split.md`](accepted/minimizer-input-output-split.md) | | Analysis and fitting | Superseded | Parameter-Level Posterior Projection | Superseded by minimizer-category consolidation; kept as historical context for `parameter.posterior`. | [`parameter-posterior-summary.md`](suggestions/parameter-posterior-summary.md) | | Analysis and fitting | Suggestion | Undo Fit | Builds rollback semantics and CLI behavior on already-persisted pre-fit scalar snapshots. | [`undo-fit.md`](suggestions/undo-fit.md) | | Core model | Accepted | Category Owners and Real Datablocks | Introduces `CategoryOwner` so singleton sections do not pretend to be real CIF datablocks. | [`category-owner-sections.md`](accepted/category-owner-sections.md) | diff --git a/docs/dev/adrs/suggestions/iucr-cif-tag-alignment.md b/docs/dev/adrs/suggestions/iucr-cif-tag-alignment.md new file mode 100644 index 000000000..052412cbd --- /dev/null +++ b/docs/dev/adrs/suggestions/iucr-cif-tag-alignment.md @@ -0,0 +1,184 @@ +# ADR: IUCr CIF Tag Alignment for Fit Outputs + +**Status:** Proposed **Date:** 2026-05-24 + +## Status Note + +This suggestion captures research done during the +[`minimizer-input-output-split`](accepted/minimizer-input-output-split.md) +work. That ADR's `_fit_result.*` CIF prefix is functional but diverges +from the IUCr core and powder dictionaries. This proposal records the +divergence and a plausible alignment path so it is not lost; the work is +**not** in scope for the input/output-split PR. + +## Context + +After the input/output split, fit outputs persist under `_fit_result.*`. +The IUCr maintains two relevant dictionaries that already cover much of +the same ground: + +- [`COMCIFS/cif_core`](https://github.com/COMCIFS/cif_core) — core CIF + dictionary, refinement parameters under `_refine_ls.*` (51 items) and + aggregate reflection statistics under `_reflns.*`. +- [`COMCIFS/Powder_Dictionary`](https://github.com/COMCIFS/Powder_Dictionary) + (`cif_pow.dic`) — powder-specific refinement under `_pd_proc_ls.*` (9 + items). + +Cross-reference today: + +| Concept | Our `_fit_result.*` | IUCr core (`_refine_ls.*`) | IUCr powder (`_pd_proc_ls.*`) | +| ----------------------- | -------------------- | ------------------------------------------------ | ------------------------------------------------ | +| Reduced χ² / GoF | `reduced_chi_square` | `goodness_of_fit_all` (S, plus `_su`) | derived from `prof_wR_factor`/`prof_wR_expected` | +| R-factor unweighted | — | `r_factor_all`, `r_factor_gt` | `prof_R_factor` | +| R-factor weighted | — | `wr_factor_all`, `wr_factor_gt`, `wr_factor_ref` | `prof_wR_factor` | +| R-expected | — | (derived from S and counts) | `prof_wR_expected` | +| Number of data points | `n_data_points` | `number_reflns`, `number_reflns_gt` | derive from `_pd_proc.number_of_points` | +| Number of parameters | `n_parameters` | `number_parameters` | (in `_refine_ls.*`) | +| Number of restraints | — | `number_restraints` | same | +| Number of constraints | — | `number_constraints` | same | +| Shift / σ | — | `shift_over_su_max`, `shift_over_su_mean` | same | +| Profile function | — | — | `profile_function` | +| Background function | — | — | `background_function` | +| Wall time | `fitting_time` | (none) | (none) | +| Iteration count | `iterations` | (none) | (none) | +| Success flag, message | `success`, `message` | (none) | (none) | +| Bayesian R̂, ESS, accept | various | (none) | (none) | + +Two consequences: + +1. **Real gaps.** Our serialization omits R-factors, + restraint/constraint counts, shift/σ diagnostics, and powder + profile/background function names. These are fields that + crystallographers expect in a saved CIF. +2. **Naming divergence.** Where IUCr does have a tag, we use a different + prefix (`_fit_result.*` vs `_refine_ls.*` / `_pd_proc_ls.*`). Our + CIFs are valid but cannot be consumed by external tools that expect + IUCr-standard names. + +## Decision + +### 1. Use IUCr tag names where they exist + +For every `_fit_result.*` field that has a one-to-one IUCr counterpart, +emit the IUCr tag instead. The Python attribute name stays +(`analysis.fit_result.reduced_chi_square`); only the `cif_handler` +`names` tuple changes. Examples: + +- `fit_result.reduced_chi_square` → emits + `_refine_ls.goodness_of_fit_all` for single-crystal, + `_pd_proc_ls.prof_wR_factor` + `_pd_proc_ls.prof_wR_expected` for + powder (or both, with the GoF derived on the powder side). +- `fit_result.n_data_points` → `_refine_ls.number_reflns` + (single-crystal), `_pd_proc.number_of_points` (powder). +- `fit_result.n_parameters` → `_refine_ls.number_parameters`. + +The emitted prefix becomes shape-shifting based on +`experiment.type.scattering_type` and `experiment.type.sample_form` — +the same convention powder packages use today. The Python API remains +uniform. + +### 2. Add the missing IUCr fields to `fit_result` + +Promote the following from "gap" to "available" on the existing +`LeastSquaresFitResult`: + +- `r_factor_all`, `wr_factor_all` — emitted as the standard tags; + computed by the LSQ projection writer from residuals. +- `prof_r_factor`, `prof_wr_factor`, `prof_wr_expected` — + powder-specific variants, computed the same way against the profile + data. +- `number_restraints`, `number_constraints` — current count from the + analysis model. +- `shift_over_su_max`, `shift_over_su_mean` — last-iteration convergence + diagnostic. +- `profile_function`, `background_function` (powder) — string-form + descriptions of the active peak and background categories. + +### 3. Keep our own prefix for fields IUCr does not cover + +`fitting_time`, `iterations`, `success`, `message`, every Bayesian +diagnostic (`gelman_rubin_max`, `acceptance_rate_mean`, etc.), and the +`result_kind`/`point_estimate_name` markers have no IUCr home today. +They stay under a project-specific prefix. Two options for that prefix: + +- Keep `_fit_result.*` for the non-IUCr fields only. The CIF then mixes + prefixes (`_refine_ls.*` + `_fit_result.*`) which is unusual but + legal. +- Use a clearly-namespaced extension like `_easydiffraction.*` or + `_eddict_fit.*` so external tools recognise the fields as non-IUCr. + +Decide during implementation; the second option is friendlier to +external CIF readers. + +### 4. Bayesian Rietveld output has no IUCr precedent today + +There is no IUCr convention for sampler convergence (R̂, ESS, acceptance) +or posterior diagnostics. This proposal does not invent one. The +Bayesian-specific fields stay under the project prefix chosen in §3. If +a community standard emerges, a follow-on ADR can absorb it. + +## Consequences + +### Positive + +- Saved CIFs become consumable by standard IUCr tools (publCIF, + checkCIF, journal submission pipelines). +- The "what is the R-factor of this fit?" question has an answer in the + saved file — currently we only record reduced χ². +- Powder users get the conventional Rp / Rwp / Rexp triplet. +- We pick up restraint/constraint accounting that the structure side of + the project already tracks but does not currently emit. + +### Trade-offs + +- Shape-shifting CIF prefix per experiment family is more work to + implement than a single `_fit_result.*` prefix. Roughly: one + `cif_handler` per descriptor that maps to a different IUCr tag + depending on context; the Python API stays uniform. +- Bayesian fields remain non-standard. There is no way around that until + IUCr defines tags for Bayesian Rietveld. +- Existing saved projects from the post-split layout cannot load + unchanged. Beta posture applies; one more legacy-rename pass in + tutorial `ed-24` covers it. + +### ADRs amended by this ADR + +- [`analysis-cif-fit-state.md`](../accepted/analysis-cif-fit-state.md) — + replace the `_fit_result.*` projection description with the + IUCr-aligned tag set; document the per-experiment-family + shape-shifting. +- [`minimizer-input-output-split.md`](../accepted/minimizer-input-output-split.md) + — the `_fit_result.*` examples in §3 are updated to use IUCr tags for + the covered fields; the non-IUCr fields keep the project-prefix + examples. + +## Deferred Work + +- The exact prefix for non-IUCr fields (§3 option choice). +- IUCr-Bayesian alignment if a community standard appears. +- Single-crystal `r_factor_gt` / `wr_factor_gt` (greater-than-σ subsets) + need a "threshold expression" decision. The + `_reflns.threshold_expression` field already covers it on the + reflection side; the LSQ projection writer needs to know the threshold + to compute the `_gt` variants. +- Whether to also emit `_refine.special_details` for human-readable fit + notes. + +## Alternatives Considered + +### A. Keep `_fit_result.*` as-is + +Simplest. Saved CIFs stay self-contained but are not IUCr-portable. +Defensible if the project never targets external CIF interop. + +### B. Emit both prefixes for the covered fields + +`_fit_result.reduced_chi_square` and `_refine_ls.goodness_of_fit_all` +both present, holding the same value. Belt-and-braces, doubles the +surface area of every saved file, and the two values can drift. + +### C. Adopt IUCr tags only for tags we already need + +Add the R-factor fields (§2) under our own `_fit_result.*` prefix. +Smaller diff, fixes the missing-field gap but not the naming divergence. +Pick if IUCr interop is genuinely not a goal. diff --git a/docs/dev/issues/open.md b/docs/dev/issues/open.md index 46e85a912..1e0bfe340 100644 --- a/docs/dev/issues/open.md +++ b/docs/dev/issues/open.md @@ -1782,6 +1782,49 @@ optional-diagnostics components. --- +## 105. 🟢 Remove Orphaned Fit-Result Reset Helper + +**Type:** Cleanup **Source:** `minimizer-input-output-split` review 6. + +`Analysis._clear_fit_result_projection` is a private method with no +callers after `_clear_persisted_fit_state` switched to replacing +`self._fit_result` with a fresh paired result instance. + +**TODOs:** + +- [analysis.py](src/easydiffraction/analysis/analysis.py#L1217) + +**Fix:** delete the unused helper, or reintroduce a caller only if a +future fit-result reset path genuinely needs to preserve the active +instance. + +**Depends on:** nothing. + +--- + +## 106. 🟢 Document `FitResultBase.result_kind` Default Rationale + +**Type:** Code readability **Source:** `minimizer-input-output-split` +review 6. + +Most `FitResultBase` descriptors use `default=None, allow_none=True` so +pre-fit CIF output serializes unknown values as `?`. `result_kind` +intentionally keeps a valid enum default because it drives deterministic +versus Bayesian projection handling, but that exception is not +documented in code. + +**TODOs:** + +- [base.py](src/easydiffraction/analysis/categories/fit_result/base.py#L44) + +**Fix:** add a short code comment near the `result_kind` descriptor +explaining why it keeps a concrete default while unknown result values +use `None`. + +**Depends on:** nothing. + +--- + ## Summary | # | Issue | Severity | Type | @@ -1869,3 +1912,5 @@ optional-diagnostics components. | 91 | Disable TODO checks in CodeFactor PRs | 🟢 Low | CI / Tooling | | 92 | Make `save()` respect verbosity | 🟢 Low | UX | | 93 | Eliminate flicker in live progress tables | 🟡 Med | UX | +| 105 | Remove orphaned fit-result reset helper | 🟢 Low | Cleanup | +| 106 | Document `FitResultBase.result_kind` default | 🟢 Low | Code readability | diff --git a/docs/dev/package-structure/full.md b/docs/dev/package-structure/full.md index a29064bdb..1f0663352 100644 --- a/docs/dev/package-structure/full.md +++ b/docs/dev/package-structure/full.md @@ -47,10 +47,15 @@ │ │ │ └── 🏷️ class FitParametersFactory │ │ ├── 📁 fit_result │ │ │ ├── 📄 __init__.py +│ │ │ ├── 📄 base.py +│ │ │ │ └── 🏷️ class FitResultBase +│ │ │ ├── 📄 bayesian.py +│ │ │ │ └── 🏷️ class BayesianFitResult │ │ │ ├── 📄 default.py -│ │ │ │ └── 🏷️ class FitResult -│ │ │ └── 📄 factory.py -│ │ │ └── 🏷️ class FitResultFactory +│ │ │ ├── 📄 factory.py +│ │ │ │ └── 🏷️ class FitResultFactory +│ │ │ └── 📄 lsq.py +│ │ │ └── 🏷️ class LeastSquaresFitResult │ │ ├── 📁 fitting_mode │ │ │ ├── 📄 __init__.py │ │ │ ├── 📄 default.py diff --git a/docs/dev/package-structure/short.md b/docs/dev/package-structure/short.md index dbe4e8f6d..e0a529800 100644 --- a/docs/dev/package-structure/short.md +++ b/docs/dev/package-structure/short.md @@ -29,8 +29,11 @@ │ │ │ └── 📄 factory.py │ │ ├── 📁 fit_result │ │ │ ├── 📄 __init__.py +│ │ │ ├── 📄 base.py +│ │ │ ├── 📄 bayesian.py │ │ │ ├── 📄 default.py -│ │ │ └── 📄 factory.py +│ │ │ ├── 📄 factory.py +│ │ │ └── 📄 lsq.py │ │ ├── 📁 fitting_mode │ │ │ ├── 📄 __init__.py │ │ │ ├── 📄 default.py diff --git a/docs/dev/plans/minimizer-input-output-split.md b/docs/dev/plans/minimizer-input-output-split.md new file mode 100644 index 000000000..0d9361a8a --- /dev/null +++ b/docs/dev/plans/minimizer-input-output-split.md @@ -0,0 +1,674 @@ +# Plan: Minimizer Input/Output Split + +> This plan follows +> [`.github/copilot-instructions.md`](../../../.github/copilot-instructions.md). +> No deliberate exceptions. + +## ADR + +Implements +[`docs/dev/adrs/suggestions/minimizer-input-output-split.md`](../adrs/suggestions/minimizer-input-output-split.md). +This plan promotes that ADR from Suggestion → Accepted during +implementation (step P1.16). + +Affected ADRs that this plan amends (per the ADR's §"ADRs amended"): + +- [`accepted/minimizer-category-consolidation.md`](../adrs/accepted/minimizer-category-consolidation.md) + — §1 becomes a partial rule; §"Alternatives Considered → D" records + the reversal. +- [`accepted/analysis-cif-fit-state.md`](../adrs/accepted/analysis-cif-fit-state.md) + — §"Minimizer fit projection" rewritten for the settings-only + `_minimizer.*` / outputs-on-`_fit_result.*` shape. +- [`accepted/runtime-fit-results.md`](../adrs/accepted/runtime-fit-results.md) + — closing paragraph references this ADR alongside the existing two. +- [`accepted/switchable-category-owned-selectors.md`](../adrs/accepted/switchable-category-owned-selectors.md) + — §1 gains the documented "fully-determined paired category" + exception. +- [`accepted/display-ux.md`](../adrs/accepted/display-ux.md) — + `project.display.fit.results()` prints a "Settings used" block. + +## Branch and PR + +- Branch: `minimizer-input-output-split` (continued from the branch the + ADR was drafted on). Do not push unless asked. +- Each step in §"Implementation steps (Phase 1)" must be staged with + explicit paths and committed locally **before** moving to the next + step. See `.github/copilot-instructions.md` → **Commits**. +- After P1.17, stop and wait for the user review gate before starting + Phase 2. + +## Decisions already made (from the ADR) + +1. `analysis.minimizer` holds **writable user settings only**. +2. `analysis.fit_result` becomes a class hierarchy paired with + `analysis.minimizer`. `FitResultBase` carries common fields; + `LeastSquaresFitResult` and `BayesianFitResult` add family-specific + ones. +3. `fit_result` is **not a user-facing switchable category**. No + `fit_result.type`, no `fit_result.show_supported()`. The owner's + `_swap_minimizer` hook installs both the minimizer and the paired + `fit_result` atomically. +4. Pairing rule is encoded on the minimizer base classes: + `LeastSquaresMinimizerBase._fit_result_class = LeastSquaresFitResult`, + `BayesianMinimizerBase._fit_result_class = BayesianFitResult`. +5. `objective_value` (raw χ²) and `reduced_chi_square` are distinct + fields, both kept on `LeastSquaresFitResult`. +6. `credible_interval_inner` / `credible_interval_outer` stay on the + output side (`BayesianFitResult`) at the fixed `0.68` / `0.95` + values. User-configurable levels deferred to a follow-on ADR. +7. The display extension lives under `project.display.fit.results()`; no + new `Analysis`-level display method is added. +8. Beta posture: hard cutover, no shims, no deprecation warnings. + Tutorials and saved fixtures regenerate. + +## Open questions + +- **Existing `analysis.fit_result.from_cif` parameter ordering.** After + this split, the CIF restore for `_fit_result.*` must run **after** + `_minimizer.*` is read so the paired class is known before the result + descriptors load. The current `_restore_*` order in + [`serialize.py`](../../../src/easydiffraction/io/cif/serialize.py) + reads `_minimizer.*` first via `_swap_minimizer`, then iterates the + rest. P1.6 must ensure `_fit_result` is included in the iteration only + after the swap has installed the paired class. Confirm during P1.6 + implementation. +- **Posterior-summary code path that currently writes + `_set_credible_interval_*` on `minimizer`.** After P1.11, the setters + move to `BayesianFitResult`. The `_store_posterior_fit_projection` + method in + [`analysis.py`](../../../src/easydiffraction/analysis/analysis.py) + must be updated to call + `self._fit_result._set_credible_interval_inner(...)` instead of + `self.minimizer._set_*`. Verify the order of operations against the + test in + [`test_results_sidecar.py`](../../../tests/unit/easydiffraction/io/test_results_sidecar.py). + +## Concrete files likely to change + +### Created + +- `src/easydiffraction/analysis/categories/fit_result/base.py` — rename + existing `FitResult` class to `FitResultBase` (or extract a base). + Common output descriptors live here. +- `src/easydiffraction/analysis/categories/fit_result/lsq.py` — + `LeastSquaresFitResult` with LSQ-specific output descriptors. +- `src/easydiffraction/analysis/categories/fit_result/bayesian.py` — + `BayesianFitResult` with Bayesian-specific output descriptors, + including `credible_interval_inner` / `credible_interval_outer`. +- _(`src/easydiffraction/analysis/categories/fit_result/factory.py` + already exists; this plan extends it rather than creating it. See P1.4 + — the factory becomes a registration helper for the two new family + classes; the authoritative swap mechanism is the `_fit_result_class` + attribute on the paired minimizer base, not a factory lookup. The + factory is still useful for introspection / testing.)_ +- `tests/unit/easydiffraction/analysis/categories/fit_result/test_base.py` +- `tests/unit/easydiffraction/analysis/categories/fit_result/test_lsq.py` +- `tests/unit/easydiffraction/analysis/categories/fit_result/test_bayesian.py` +- `tests/unit/easydiffraction/analysis/categories/fit_result/test_factory.py` + +### Modified + +- `src/easydiffraction/analysis/categories/fit_result/__init__.py` — add + explicit imports for every new concrete class to trigger factory + registration. +- `src/easydiffraction/analysis/categories/fit_result/default.py` — + rewritten to import from the new family modules; the existing + `FitResult` is renamed to `FitResultBase` and absorbed. +- `src/easydiffraction/analysis/categories/minimizer/base.py` — add + `_fit_result_class: ClassVar[type]` declaration. +- `src/easydiffraction/analysis/categories/minimizer/lsq_base.py` — set + `_fit_result_class = LeastSquaresFitResult`; **remove** + `objective_name`, `objective_value`, `n_data_points`, `n_parameters`, + `n_free_parameters`, `degrees_of_freedom`, `covariance_available`, + `correlation_available`, `runtime_seconds`, `iterations_performed`, + `exit_reason` from descriptor declarations and from + `_result_descriptor_names`. `_setting_descriptor_names` stays + `('max_iterations',)`. +- `src/easydiffraction/analysis/categories/minimizer/bayesian_base.py` — + set `_fit_result_class = BayesianFitResult`; remove `runtime_seconds`, + `point_estimate_name`, `sampler_completed`, `credible_interval_inner`, + `credible_interval_outer`, `acceptance_rate_mean`, `gelman_rubin_max`, + `effective_sample_size_min`, `best_log_posterior` from descriptor + declarations and from `_result_descriptor_names`. + `_setting_descriptor_names` keeps the seven Bayesian inputs. +- `src/easydiffraction/analysis/analysis.py` — extend `_swap_minimizer` + to also instantiate the paired `fit_result` via the minimizer's + `_fit_result_class`; add `analysis.fit_result` property; route every + `self._minimizer._set_*` result-writer call in + `_store_least_squares_result_projection` / + `_store_posterior_fit_projection` / + `_restore_fit_results_from_projection` to `self._fit_result._set_*` + instead. +- `src/easydiffraction/io/cif/serialize.py` — emit/read `_fit_result.*` + from the paired class; remove the removed `_minimizer.*` output tags + from the serialise/deserialise paths. Update the legacy-tag rejection + message. +- `src/easydiffraction/project/display.py` — extend + `project.display.fit.results()` to print a "Settings used" block + populated from `analysis.minimizer.*` above the existing result + tables. +- All tutorials referencing `analysis.minimizer.` (e.g. + `runtime_seconds`, `gelman_rubin_max`, `objective_value`) → + `analysis.fit_result.`. List enumerated at P1.15 start + via `git grep`. +- Tests reading `analysis.minimizer.` → migrate to + `analysis.fit_result.`. P2.1 enumerates. + +### Deleted + +- None. The existing `fit_result/default.py` is rewritten in place; the + existing `FitResult` class becomes `FitResultBase`. + +## Implementation steps (Phase 1) + +Mark `[x]` as each step lands. + +- [x] **P1.1 — Rename `FitResult` to `FitResultBase`; add reset hooks; + update every import site.** In + `src/easydiffraction/analysis/categories/fit_result/default.py`, + rename the class. The factory `@register` decorator stays on the + renamed class so the default-tag lookup keeps working until P1.4 + extends the factory. + + Add two class-level hooks to `FitResultBase` matching the + `MinimizerCategoryBase` shape introduced by the consolidation + work + ([`minimizer/base.py:69-74`](../../../src/easydiffraction/analysis/categories/minimizer/base.py)): + + ```python + _result_descriptor_names: ClassVar[tuple[str, ...]] = ( + 'success', 'message', 'iterations', + 'fitting_time', 'reduced_chi_square', 'result_kind', + ) + + def _reset_result_descriptors(self) -> None: + """Reset fit-result descriptors to declared defaults.""" + for name in self._result_descriptor_names: + descriptor = getattr(self, name) + if isinstance(descriptor, GenericDescriptorBase): + descriptor.value = descriptor._value_spec.default_value() + ``` + + `LeastSquaresFitResult` (P1.2) and `BayesianFitResult` (P1.3) + then add their own field names to `_result_descriptor_names` + so the inherited helper resets every relevant descriptor. + + This must land in P1.1 because P1.6 retargets + `_clear_minimizer_result_projection` (renamed + `_clear_fit_result_projection`) to call + `self.fit_result._reset_result_descriptors()`, and that method + must exist on `FitResultBase` before the swap is wired. + + Update every package-level import that referenced the old + name. `git grep -nP '\bFitResult\b' src/ tests/` lists the + sites at plan time: + + - `src/easydiffraction/analysis/__init__.py` (line 14 today) + - `src/easydiffraction/analysis/categories/__init__.py` + (line 14 today) + - `src/easydiffraction/analysis/categories/fit_result/__init__.py` + - `src/easydiffraction/analysis/analysis.py` (import line 18; + type annotation on the `fit_result` property at line 432; + `self._fit_result = FitResult()` at line 483; same + construction at line 1208) + + All four `FitResult` import/annotation/construction sites in + `analysis.py` become `FitResultBase` after this step. The two + `self._fit_result = FitResult()` construction sites (init and + `_clear_persisted_fit_state`) become + `FitResultBase()` temporarily; P1.6 retargets them to the + paired class. + + Re-run `git grep -nP '\bFitResult\b' src/` at the end of this + step — every remaining hit must be the renamed class name or a + module path, not the old bare class. Tests are migrated by + P2.1. + + Commit: `Rename FitResult to FitResultBase, add reset hooks` + +- [x] **P1.2 — Add `LeastSquaresFitResult` class.** New file + `src/easydiffraction/analysis/categories/fit_result/lsq.py`. + `LeastSquaresFitResult(FitResultBase)` declares: `objective_name`, + `objective_value`, `n_data_points`, `n_parameters`, + `n_free_parameters`, `degrees_of_freedom`, `covariance_available`, + `correlation_available`, `exit_reason`. **All defaults are `None` + with `allow_none=True`**, matching the consolidation cleanup that + previously moved LSQ outputs off `0` / `false` / `''` so a pre-fit + CIF emits `?` rather than a value that looks like a degenerate + result. This applies to numeric, integer-like, string, and bool + fields alike; the descriptor helpers in + `LeastSquaresMinimizerBase` + ([`lsq_base.py`](../../../src/easydiffraction/analysis/categories/minimizer/lsq_base.py)) + that currently produce these descriptors are the model — they can + be lifted into `LeastSquaresFitResult` verbatim before being + removed from `lsq_base.py` at P1.9. Declare + `_expected_descriptor_names`, `_result_descriptor_names` for + parity with the minimizer hierarchy. Tests deferred to Phase 2. + Commit: `Add LeastSquaresFitResult class` + +- [x] **P1.3 — Add `BayesianFitResult` class.** New file + `src/easydiffraction/analysis/categories/fit_result/bayesian.py`. + `BayesianFitResult(FitResultBase)` declares: + `point_estimate_name`, `sampler_completed`, + `credible_interval_inner` (default `0.68`), + `credible_interval_outer` (default `0.95`), + `acceptance_rate_mean`, `gelman_rubin_max`, + `effective_sample_size_min`, `best_log_posterior`. Declare + `_expected_descriptor_names`, `_result_descriptor_names`. Tests + deferred to Phase 2. Commit: `Add BayesianFitResult class` + +- [x] **P1.4 — Register fit-result classes with the existing + `FitResultFactory`.** The factory already exists at + [`src/easydiffraction/analysis/categories/fit_result/factory.py`](../../../src/easydiffraction/analysis/categories/fit_result/factory.py) + and currently registers only the default common class. Update it + to also register `LeastSquaresFitResult` and `BayesianFitResult` + with their family tags. Update + `src/easydiffraction/analysis/categories/fit_result/__init__.py` + to explicitly import every concrete class (so registration fires + on package import, per the repo's standard pattern). + + **Authoritative mechanism:** `Analysis._swap_minimizer` + constructs the paired fit-result via the minimizer's + `_fit_result_class` attribute (P1.5), not via a factory + lookup. The factory is kept as a registration helper for + introspection and testing; do not add a public selector surface + (`type`, `show_supported`) since `fit_result` is internally + paired, per ADR §1. Commit: + `Register fit-result family classes with factory` + +- [x] **P1.5 — Declare `_fit_result_class` on minimizer bases.** In + `src/easydiffraction/analysis/categories/minimizer/lsq_base.py`, + add `_fit_result_class: ClassVar[type] = LeastSquaresFitResult`. + In + `src/easydiffraction/analysis/categories/minimizer/bayesian_base.py`, + add `_fit_result_class: ClassVar[type] = BayesianFitResult`. Add + the matching declaration to + `src/easydiffraction/analysis/categories/minimizer/base.py` with + `_fit_result_class: ClassVar[type] = FitResultBase` as a safety + fallback (no concrete minimizer instantiates the bare base, but + `_swap_minimizer` reads through this attribute). Commit: + `Declare paired _fit_result_class on minimizer bases` + +- [x] **P1.6 — Wire `Analysis._swap_minimizer` to install both + instances, and update every `_fit_result` reset path.** In + `src/easydiffraction/analysis/analysis.py`: + - `__init__` constructs the initial `_fit_result` from the default + minimizer's `_fit_result_class`: + `self._fit_result = self._minimizer._fit_result_class()`. The line + 483 `self._fit_result = FitResultBase()` (after P1.1) is replaced. + - `_replace_minimizer` constructs + `self._fit_result = new_minimizer._fit_result_class()` after the new + minimizer is created. The old `fit_result` is detached + (`_parent = None`) before being replaced. + - `_clear_persisted_fit_state` (line 1204 today) currently calls + `self._clear_minimizer_result_projection()` and then + `self._fit_result = FitResult()`. After P1.1 + the split, both lines + must change: + - `self._fit_result = self.minimizer._fit_result_class()` replaces + the bare `FitResultBase()` construction. This keeps the paired + class invariant whenever the persisted state is reset. + - `self._clear_minimizer_result_projection()` currently calls + `self.minimizer._reset_result_descriptors()`. After P1.9/P1.10 + remove the result descriptors from the minimizer, this method + becomes a no-op. **Retarget it to + `self.fit_result._reset_result_descriptors()`** and rename it to + `_clear_fit_result_projection`. Update the call sites (line 1204; + potentially others — `git grep` confirms). + - Add `analysis.fit_result` read-only property + (`return self._fit_result`). Type annotation: `FitResultBase` (the + family classes inherit from it). + - Wire `self._fit_result._parent = self` in + `_attach_category_parents`. Every `_fit_result` reassignment in the + methods above must also set `_parent` on the new instance. + + Verification at the end of this step: + + ``` + git grep -nE 'self\._fit_result\s*=' src/easydiffraction/analysis/analysis.py + ``` + + Every match must construct via `self.minimizer._fit_result_class()` + (or `new_minimizer._fit_result_class()` in `_replace_minimizer`), not + a bare class name. There must be no remaining + `self._fit_result = FitResultBase()` after this step. + + Commit: `Wire fit_result swap and reset paths to paired class` + +- [x] **P1.7 — Route LSQ result writers to `fit_result`.** In + `src/easydiffraction/analysis/analysis.py`, + `_store_least_squares_result_projection` currently writes to + `self.minimizer._set_objective_name(...)` etc. Reroute every such + call to `self.fit_result._set_*`. Same for + `_restore_fit_results_from_projection`'s LSQ branch (it reads + `self.minimizer.objective_name.value` etc. — change to + `self.fit_result..value`). Commit: + `Route LSQ result writers to fit_result` + +- [x] **P1.8 — Route Bayesian result writers to `fit_result`.** Same + treatment for `_store_posterior_fit_projection` and the Bayesian + branch of `_restore_fit_results_from_projection`. Includes the + `_set_credible_interval_*` calls — they now target + `self.fit_result._set_credible_interval_*`. Commit: + `Route Bayesian result writers to fit_result` + +- [x] **P1.9 — Remove output fields from LSQ minimizer base.** In + `src/easydiffraction/analysis/categories/minimizer/lsq_base.py`, + delete the descriptor declarations and properties for + `objective_name`, `objective_value`, `n_data_points`, + `n_parameters`, `n_free_parameters`, `degrees_of_freedom`, + `covariance_available`, `correlation_available`, + `runtime_seconds`, `iterations_performed`, `exit_reason`. Remove + these names from `_expected_descriptor_names` and + `_result_descriptor_names`. `_setting_descriptor_names` stays + `('max_iterations',)`. After this step, `_result_descriptor_names` + on `LeastSquaresMinimizerBase` is `()` and + `_reset_result_descriptors()` is a no-op on every LSQ minimizer — + confirming the P1.6 retarget of + `_clear_minimizer_result_projection` to operate on + `self.fit_result` is the correct call site. + + Note: `optimizer_name` and `method_name` were already removed + by the consolidation work (`_engine_metadata` dict replaces + them); this step is the bulk removal of the remaining LSQ + outputs. + + Commit: `Remove LSQ output descriptors from minimizer base` + +- [x] **P1.10 — Remove duplicate fields from Bayesian minimizer base.** + In + `src/easydiffraction/analysis/categories/minimizer/bayesian_base.py`, + delete the descriptor declarations and properties for + `runtime_seconds`, `point_estimate_name`, `sampler_completed`, + `credible_interval_inner`, `credible_interval_outer`, + `acceptance_rate_mean`, `gelman_rubin_max`, + `effective_sample_size_min`, `best_log_posterior`. Remove these + names from `_expected_descriptor_names` and + `_result_descriptor_names`. The `_setting_descriptor_names` tuple + keeps the seven Bayesian inputs. + + Commit: `Remove Bayesian output descriptors from minimizer base` + +- [x] **P1.11 — Update CIF emit/read for the split.** In + `src/easydiffraction/io/cif/serialize.py`: + + **No category-list reordering is performed in this step.** Neither + `Analysis._serializable_categories()` nor + `Analysis._fit_state_categories()` is restructured. `fit_result` stays + conditionally included by `_fit_state_categories()` only when + `self._has_persisted_fit_state()` is true — exactly as today. Pre-fit + projects continue to emit no `_fit_result.*` block. + + The only changes in this step are content updates inside the existing + emit/read flow: + - `_minimizer.*` emit/read continues to handle settings only (the + minimizer category's `from_cif` walks its remaining descriptors + after P1.9 / P1.10 removed the output descriptors). + - `_fit_result.*` emit/read picks up the new family-specific + descriptors automatically because P1.6 wires the paired class + (`LeastSquaresFitResult` or `BayesianFitResult`) onto + `self._fit_result`. The existing + `analysis.fit_result.from_cif(block)` call inside + `_restore_common_fit_state` + ([`serialize.py:590`](../../../src/easydiffraction/io/cif/serialize.py)) + reads `_fit_result.*` tags into the already-paired class — no + reordering, no new call. + - The read-side already restores `minimizer.type` first + ([`serialize.py:553-555`](../../../src/easydiffraction/io/cif/serialize.py)), + so the paired-class swap fires before `fit_result.from_cif` runs. No + code change is required here. + - Update the legacy-tag rejection message in + `_raise_for_legacy_analysis_tags` to include the now-removed + `_minimizer.` tags (e.g. `_minimizer.runtime_seconds`, + `_minimizer.gelman_rubin_max`) as legacy markers that should raise a + clear error rather than load silently. + + Commit: `Serialize fit outputs to _fit_result.* tags` + +- [x] **P1.12 — Confirm `_fit_state_categories` returns the paired + `fit_result`.** In `src/easydiffraction/analysis/analysis.py`, + `_fit_state_categories()` already returns + `[self.fit_parameters, self.fit_result, self.fit_parameter_correlations]` + when persisted fit state exists. After P1.6 wires the paired-class + construction, `self.fit_result` is automatically the paired + `LeastSquaresFitResult` / `BayesianFitResult` instance — no method + body change is needed. The dead branch in `_fit_state_categories` + (review-9 finding F4, open issue #101) can be cleaned up here + since this step is already reading the function. The plan does not + require the cleanup; if taken, mention "closes #101" in the commit + message. + + Commit: `Confirm fit_result paired instance flows through serializer` + +- [x] **P1.13 — Update `project.display.fit.results()` to add a + "Settings used" block.** In + `src/easydiffraction/project/display.py`, extend the existing + results-display method to print, above the current tables, a + one-section table titled "Settings used" populated from + `analysis.minimizer.*`. Use the same `render_table` machinery the + rest of the display facade uses. Commit: + `Add settings-used block to fit.results display` + +- [x] **P1.14 — Amend the five accepted ADRs listed in §"ADR".** For + each, apply the matching paragraph from the ADR's §"ADRs amended" + section: + - `minimizer-category-consolidation.md` — §1 partial-rule + qualification; §"Alternatives Considered → D" reversal record. + - `analysis-cif-fit-state.md` — §"Minimizer fit projection" rewrite. + - `runtime-fit-results.md` — closing-paragraph reference. + - `switchable-category-owned-selectors.md` — §1 paired-category + exception paragraph. + - `display-ux.md` — `project.display.fit.results()` settings-block + note. + - Update `docs/dev/adrs/index.md` to add the new ADR row under + "Accepted" (per P1.16 promotion). + + Commit: `Amend affected ADRs for minimizer input/output split` + +- [x] **P1.15 — Update tutorials.** `git grep` `docs/docs/tutorials/` + for `analysis.minimizer.` references and rewrite + each per the migration table below. The two **collapsed** rows + target existing common fields on `FitResultBase` (already written + by the existing common projection writer); they are not 1:1 + renames of the old setter/getter name. The other rows are + moved-but-keep-the-name relocations. + + | Old (removed at P1.9 / P1.10) | New | Notes | + | --- | --- | --- | + | `analysis.minimizer.runtime_seconds` | `analysis.fit_result.fitting_time` | Collapsed onto existing common field; setter remains `fit_result._set_fitting_time(...)` (already in `FitResultBase`). | + | `analysis.minimizer.iterations_performed` | `analysis.fit_result.iterations` | Collapsed onto existing common field; setter remains `fit_result._set_iterations(...)`. | + | `analysis.minimizer.objective_name` | `analysis.fit_result.objective_name` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.objective_value` | `analysis.fit_result.objective_value` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.n_data_points` | `analysis.fit_result.n_data_points` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.n_parameters` | `analysis.fit_result.n_parameters` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.n_free_parameters` | `analysis.fit_result.n_free_parameters` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.degrees_of_freedom` | `analysis.fit_result.degrees_of_freedom` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.covariance_available` | `analysis.fit_result.covariance_available` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.correlation_available` | `analysis.fit_result.correlation_available` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.exit_reason` | `analysis.fit_result.exit_reason` | Moved to `LeastSquaresFitResult`. | + | `analysis.minimizer.point_estimate_name` | `analysis.fit_result.point_estimate_name` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.sampler_completed` | `analysis.fit_result.sampler_completed` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.credible_interval_inner` | `analysis.fit_result.credible_interval_inner` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.credible_interval_outer` | `analysis.fit_result.credible_interval_outer` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.acceptance_rate_mean` | `analysis.fit_result.acceptance_rate_mean` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.gelman_rubin_max` | `analysis.fit_result.gelman_rubin_max` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.effective_sample_size_min` | `analysis.fit_result.effective_sample_size_min` | Moved to `BayesianFitResult`. | + | `analysis.minimizer.best_log_posterior` | `analysis.fit_result.best_log_posterior` | Moved to `BayesianFitResult`. | + + Run `pixi run notebook-prepare` to regenerate the `.ipynb` + files. + + Verification grep (must return empty against + `docs/docs/tutorials/`): + + ``` + git grep -nE 'analysis\.minimizer\.(runtime_seconds|iterations_performed|objective_value|objective_name|n_data_points|n_parameters|n_free_parameters|degrees_of_freedom|covariance_available|correlation_available|exit_reason|point_estimate_name|sampler_completed|credible_interval_inner|credible_interval_outer|acceptance_rate_mean|gelman_rubin_max|effective_sample_size_min|best_log_posterior)' docs/docs/tutorials/ + ``` + + Commit: `Update tutorials to read outputs from fit_result` + +- [x] **P1.16 — Promote ADR + update index.** + - `git mv docs/dev/adrs/suggestions/minimizer-input-output-split.md docs/dev/adrs/accepted/minimizer-input-output-split.md`. + Flip the Status header to `Accepted`. + - Move the seven `_reply-N.md` and seven `_review-N.md` siblings: keep + them next to the ADR if the project convention preserves history + under `accepted/`; delete them if the convention is to drop the + deliberation artefacts on promotion (the + `switchable-category-owned-selectors` precedent deleted them). Per + the precedent, delete on promotion. + - Update `docs/dev/adrs/index.md` — move the row for this ADR from + Suggestion → Accepted. + + Commit: `Promote minimizer-input-output-split ADR` + +- [x] **P1.17 — Phase 1 review gate.** No code change. Re-run the P1.15 + tutorial grep against `src/`, `docs/docs/tutorials/`, and + `tests/`. The `src/` and `docs/docs/tutorials/` scopes must return + empty. The `tests/` sweep is deferred to P2.1, which migrates the + tests. Then stop and request user review. After approval, proceed + to Phase 2. + +## Verification (Phase 2) + +Each command captures its log with a zsh-safe exit-code variable as +required by `.github/copilot-instructions.md` → **Workflow**. + +- [x] **P2.1 — Migrate existing tests off the removed minimizer output + fields.** `git grep` `tests/` for the same patterns as P1.15. + Apply the same migration table from P1.15 — including the two + collapsed rows (`runtime_seconds` → `fitting_time`, + `iterations_performed` → `iterations`) where the setter name also + changes. Examples: + + - Reader rewrite: + `analysis.minimizer.gelman_rubin_max` → + `analysis.fit_result.gelman_rubin_max`. + - Reader rewrite with collapse: + `analysis.minimizer.runtime_seconds` → + `analysis.fit_result.fitting_time`. + - Setter rewrite (moved-but-kept name): + `analysis.minimizer._set_gelman_rubin_max(...)` → + `analysis.fit_result._set_gelman_rubin_max(...)`. + - Setter rewrite (collapsed name): + `analysis.minimizer._set_runtime_seconds(...)` → + `analysis.fit_result._set_fitting_time(...)`. + + Layout check: + + ``` + pixi run test-structure-check > /tmp/easydiffraction-test-structure-check.log 2>&1; \ + test_structure_check_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-test-structure-check.log; \ + exit $test_structure_check_exit_code + ``` + + Final stale-reference grep (all four must return empty): + + ``` + git grep -nE 'analysis\.minimizer\.(runtime_seconds|iterations_performed|objective_value|objective_name|n_data_points|n_parameters|n_free_parameters|degrees_of_freedom|covariance_available|correlation_available|exit_reason|point_estimate_name|sampler_completed|credible_interval_inner|credible_interval_outer|acceptance_rate_mean|gelman_rubin_max|effective_sample_size_min|best_log_posterior)' src/ docs/docs/tutorials/ tests/ + git grep -nE '_minimizer\.(runtime_seconds|iterations_performed|objective_value|point_estimate_name|sampler_completed|credible_interval_inner|credible_interval_outer|acceptance_rate_mean|gelman_rubin_max|effective_sample_size_min|best_log_posterior)' src/ docs/docs/tutorials/ tests/ + ``` + +- [x] **P2.2 — Add unit tests for new modules.** New tests under + `tests/unit/easydiffraction/analysis/categories/fit_result/`: + - `test_base.py` — `FitResultBase` defaults, + `_reset_result_descriptors`. + - `test_lsq.py` — `LeastSquaresFitResult` defaults; CIF round-trip of + LSQ outputs. + - `test_bayesian.py` — `BayesianFitResult` defaults including the + fixed credible interval levels; CIF round-trip. + - `test_factory.py` — pairing rule via + `LeastSquaresMinimizerBase._fit_result_class` and + `BayesianMinimizerBase._fit_result_class`. + + Layout check: + + ``` + pixi run test-structure-check > /tmp/easydiffraction-test-structure-check.log 2>&1; \ + test_structure_check_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-test-structure-check.log; \ + exit $test_structure_check_exit_code + ``` + +- [x] **P2.3 — Auto-fixes and static checks.** + + ``` + pixi run fix > /tmp/easydiffraction-fix.log 2>&1; \ + fix_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-fix.log; \ + exit $fix_exit_code + ``` + + Then: + + ``` + pixi run check > /tmp/easydiffraction-check.log 2>&1; \ + check_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-check.log; \ + exit $check_exit_code + ``` + + Iterate `pixi run check` until clean. Do not raise lint + thresholds — refactor instead. + +- [x] **P2.4 — Unit tests.** + + ``` + pixi run unit-tests > /tmp/easydiffraction-unit-tests.log 2>&1; \ + unit_tests_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-unit-tests.log; \ + exit $unit_tests_exit_code + ``` + +- [x] **P2.5 — Integration tests.** + + ``` + pixi run integration-tests > /tmp/easydiffraction-integration-tests.log 2>&1; \ + integration_tests_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-integration-tests.log; \ + exit $integration_tests_exit_code + ``` + +- [x] **P2.6 — Script tests.** + + ``` + pixi run script-tests > /tmp/easydiffraction-script-tests.log 2>&1; \ + script_tests_exit_code=$?; \ + tail -n 200 /tmp/easydiffraction-script-tests.log; \ + exit $script_tests_exit_code + ``` + + This regenerates `tmp/tutorials/projects/*` fixtures with the + new CIF layout (`_minimizer.*` settings-only, + `_fit_result.*` outputs). + +## Suggested Pull Request + +**Title:** Split minimizer settings from fit-result outputs + +**Description (user-facing):** + +`analysis.minimizer` now holds only the settings you can change — +`sampling_steps`, `max_iterations`, and the other input knobs. Once a +fit completes, every output the project records (wall time, χ², the +Bayesian diagnostics, the LSQ counters) lives on a paired +`analysis.fit_result`. The pairing happens automatically when you change +minimizer type, so users never see a separate result selector. + +`project.display.fit.results()` now prints a "Settings used" block above +the existing result tables, so the settings that produced the fit and +the outputs the fit produced are visible side-by-side without having to +open two namespaces. + +The CIF layout follows the same split: `_minimizer.*` holds settings +only, `_fit_result.*` holds outputs. Saved projects from the previous +layout do not load unchanged (the project is in beta; no legacy shims). +Tutorials and saved-fixture regeneration land in this PR. + +Incidental cleanup also bundled in this branch: the unused +`essdiffraction` development dependency is removed, and a handful of +unrelated functions are split into helpers to satisfy the project's +complexity thresholds during Phase 2 verification: +`singleton.ConstraintsHandler.apply_constraints`, +`analysis.sequential._fit_worker`, +`display.plotting._posterior_predictive_*`, and +`calculators.{crysfml,pdffit}._calculate_pattern`. diff --git a/docs/docs/tutorials/ed-24.ipynb b/docs/docs/tutorials/ed-24.ipynb index 869a30919..4e77ed733 100644 --- a/docs/docs/tutorials/ed-24.ipynb +++ b/docs/docs/tutorials/ed-24.ipynb @@ -46,9 +46,7 @@ "cell_type": "code", "execution_count": null, "id": "3", - "metadata": { - "lines_to_next_cell": 1 - }, + "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", diff --git a/pixi.lock b/pixi.lock index c421cdaaa..e17dcaa8c 100644 --- a/pixi.lock +++ b/pixi.lock @@ -184,7 +184,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl @@ -218,31 +217,22 @@ environments: - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/43/fe/ad0ecbe2393cb690a4b3100a8fea47ecfdb49f6e06f40cf2f626635adc0c/scipp-26.3.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/46/b4/0887c88ddfaba1d7140ea335144eb904af97550786ee58bdb295ff10d255/crysfml-0.6.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/3b/1cdec6772bdbaf7b25dab360c59f03cadf05492dd724c6540af905389b07/pandas-3.0.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/58/e0/f1871f520c359e4e3a2eb7437c9e7e792bb6c356414e8617937561167caf/pycifrw-5.0.1.tar.gz - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -260,14 +250,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -276,7 +263,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl @@ -288,8 +274,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a8/4e/c09876f08fa9faaa5e1178f3d77b7af3f343258689bd6f3b72593b2f74e3/mkdocs_markdownextradata_plugin-0.2.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl @@ -298,15 +282,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c2/20/193faab46a68ea550587331a698c3dca8099f8901d10937c4443135c7ed9/chardet-7.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/c2/53/d81269aaafccea0d33396c03035de997b743f11e648e6e27a0df99c72980/yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl @@ -317,38 +298,27 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/51/ec641c26e6dca1b25a7d2035ba6ecb7c884ef1a100a9e42fbe4ce4405139/coverage-7.14.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/04/c5bb20d64417d20cba0105277235c51969444fa873000fbc26ac0a3fc5a8/gemmi-0.7.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/16/d905e7f53e661ce2c24686c38048d8e2b750ffc4350009d41c4e6c6c9826/h5py-3.16.0-cp314-cp314-manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f1/2c/3850985d4c64048dec7b826f8a803e135b52b11b4c81c9cd4326b1ca15ab/ncrystal_core-4.4.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -520,11 +490,9 @@ environments: - pypi: https://files.pythonhosted.org/packages/0d/12/bbce9472f489cb5c4c23b0d13e5c59c37c1aab11b7ac637dfe6bbdccebe7/copier-9.15.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/1f/d398de1612f7a611e22d743280339c9af4903675635e41be3370091c704b/arviz_stats-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/fe/6bea5c9162869c5beba5d9c8abbed835ec85bf1ec1fba05a3822325c45f3/build-1.5.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0f/0e/0eb94e64f5badef67f11fe1e448dde2a44f00940d8949f4adf71d560552e/scipp-26.3.1-cp314-cp314-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl @@ -554,37 +522,29 @@ environments: - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/41/86/86231232fff41c9f8e4a1a7d7a597d349a02527109c3af7d618366122139/matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/51/ac/b9d68ebddfe1b02c77af5bf81120e12b036b4432dc6af7a303d90e2bc38b/chardet-7.4.3-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/33/bf28f618c0a9597d14e0b9ee7d1e0622faff738d44fe986ee287cdf1b8d0/sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/58/e0/f1871f520c359e4e3a2eb7437c9e7e792bb6c356414e8617937561167caf/pycifrw-5.0.1.tar.gz - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/68/10/bf2d6738d72748b961a3751ab89522d58c54efc36a8e1a12161216cd45cf/pandas-3.0.3-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6a/b7/9366ed44ced9b7ef357ab48c94205280276db9d7f064aa3012a97227e966/h5py-3.16.0-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -600,14 +560,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -617,7 +574,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl @@ -629,9 +585,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/a8/4e/c09876f08fa9faaa5e1178f3d77b7af3f343258689bd6f3b72593b2f74e3/mkdocs_markdownextradata_plugin-0.2.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl @@ -639,18 +593,14 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/ba/b1/5297bb6a7df4782f7605bffc43b31f5044070935fbbcaa6c705a07e6ac65/yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/ea/7988934c8e3e3418aa043f70421817df28d06aef50bfd85f5ad3ec6e70f1/ncrystal_core-4.4.2-py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl @@ -658,36 +608,26 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/9b/4165a1d56ddc302a0e2d518fd9d412a4fd0b57562618c78c5f21c57194f5/coverage-7.14.0-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl @@ -855,7 +795,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl @@ -863,7 +802,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/1d/77/928ea2e70641ca177a11140062cc5840d421795f2e82749d408d0cce900a/narwhals-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1f/28/3f8aa247d29d010547d52207395cb057ebd0a40b88f64bc1dbac9e17a729/scipp-26.3.1-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/20/16/e777eadfa0c0305878c36fae1d5e6db474fbb15dae202b9ec378809dfb4d/nbstripout-0.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/7a/1c6e3562dfd8950adbb11ffbc65d21e7c89d01a6e4f137fa981056de25c5/gitpython-3.1.50-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl @@ -886,32 +824,24 @@ environments: - pypi: https://files.pythonhosted.org/packages/3e/14/615a450205e1b56d16c6783f5ccd116cde05550faad70ae077c955654a75/h5py-3.16.0-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/e0/f1871f520c359e4e3a2eb7437c9e7e792bb6c356414e8617937561167caf/pycifrw-5.0.1.tar.gz - pypi: https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/d2/45c9defbaa1ea297035d9d4cce9e8f80daafbf19319c6007f157c6256ea9/propcache-0.5.2-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -929,15 +859,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -946,7 +873,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl @@ -959,8 +885,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/1a/5a4f747a8b271cbb024946d2dd3c913ab5032ba430626f8c3528ada96b4b/matplotlib-3.10.9-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/2c/cad8b5e3623a987f3c930b68e2bdd06cfc388cd91cd42ed05f1227701b73/chardet-7.4.3-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl @@ -969,16 +893,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/6b/6c02f55c2ce2f137ccca0986be7dd89bea31d5bee4346b4377fa3b8586df/ncrystal_core-4.4.2-py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl @@ -989,37 +909,27 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f9/58/6e1b8f52fdc3184b47dc5037f5070d83a3d11042db1594b02d2a44d786c8/coverage-7.14.0-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/d9/5582d57e2b2db9b85eb6663a22efdd78e08805f3f5389566e9fcad254d1b/yarl-1.24.2-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl @@ -1203,7 +1113,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/14/15/5574111ae50dd6e879456888c0eadd4c5a869959775854e18e18a6b345f3/propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -1213,7 +1122,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/c0/56472c251d09858a53e51efbd485b09e1995d8731668b76d52e5dd6ee0f1/ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1e/e7/cd78635d0ece7e4d3393f2c1d2ebabf6ff4bd615da142891b1d42ad58abf/scipp-26.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/20/16/e777eadfa0c0305878c36fae1d5e6db474fbb15dae202b9ec378809dfb4d/nbstripout-0.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/7a/1c6e3562dfd8950adbb11ffbc65d21e7c89d01a6e4f137fa981056de25c5/gitpython-3.1.50-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl @@ -1227,7 +1135,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/32/28/79f0f8de97cce916d5ae88a7bee1ad724855e83e6019c0b4d5b3fabc80f3/mkdocstrings_python-2.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/91/d024616abdba99e83120e07a20658976f6a343646710760c4a51df126029/matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/33/75/98a7eb100dc5cfd20b019046452f08d5e67dfbacc71d8f28763d32426fd3/spglib-2.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/eb/f9f1ded8e4db9638f9530c3782eb01f5ab04945f4cb9e597a51c203fa4c5/diffpy_pdffit2-1.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/33/f0/3fe8c6e69135a845f4106f2ff8b6805638d4e85c264e70114e8126689587/tokenize_rt-6.2.0-py2.py3-none-any.whl @@ -1237,35 +1144,27 @@ environments: - pypi: https://files.pythonhosted.org/packages/3a/eb/fea4d1d51c49832120f7f285d07306db3960f423a2612c6057caf3e8196f/pip-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/40/69/b91cda0647df839483201545913514c2827ebea5e5ccdf931842763bc127/greenlet-3.5.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/57/d8/8d44036d7eb7b6a8ec4c5494ea0c8c8b94fbc0ed3991c1a7adf230df03bf/aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/65/92/a5100f7185a800a5d29f8d14041f61475b9de465ffcc0f3b9fba606e4505/msgpack-1.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/65/b6/09b01cdbc15224e2850365192d17b7bdebb8bdbd8780ed221fcdf0d9a515/pandas-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/ff/6699e7b71e60d3049eb2bdcbc95ee3f35707b2b0e48f32e9e63d3ce30c08/coverage-7.14.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -1283,14 +1182,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -1301,7 +1197,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/e9/1a19e42cd43cc1365e127db6aae85e1c671da1d9a5d746f4d34a50edb577/h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl @@ -1313,9 +1208,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/a8/4e/c09876f08fa9faaa5e1178f3d77b7af3f343258689bd6f3b72593b2f74e3/mkdocs_markdownextradata_plugin-0.2.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ae/61/3c1ea8c10bf4f6bf83c33a7f5b4a3143f4cc1f979859dec5498b6cc31900/pycifrw-5.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl @@ -1324,12 +1217,10 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl @@ -1341,36 +1232,25 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/59/a32a241d861cf180853a11c8e5a67641cb1b2af13c3a5ccce83ec07e2c9f/chardet-7.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e8/88/5a431cd1ea7587408a66947384b39beb2ab2bcc1c87b7c4082f05036719f/gemmi-0.7.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f1/2c/3850985d4c64048dec7b826f8a803e135b52b11b4c81c9cd4326b1ca15ab/ncrystal_core-4.4.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl osx-arm64: @@ -1543,7 +1423,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/15/1d/9f9e30d76300b0150afaa8b37fab9a0194d44fd4f6b1e5038aca4a1440ed/crysfml-0.6.2-cp312-cp312-macosx_14_0_arm64.whl @@ -1579,32 +1458,23 @@ environments: - pypi: https://files.pythonhosted.org/packages/3a/eb/fea4d1d51c49832120f7f285d07306db3960f423a2612c6057caf3e8196f/pip-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/44/7b/537a61906eac58d94131273084d21d4eb219f5453f0ed30de3aca580a2b4/scipp-26.3.1-cp312-cp312-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/49/b3/2de412451330756aaaa72d27131db6dde23995efe62c941184e15242a5fa/sqlalchemy-2.0.49-cp312-cp312-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -1620,14 +1490,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -1638,7 +1505,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/9c/2f/4c5af01fd1a7506a1d5375403d68925eac70289229492db5aa68b58103d8/chardet-7.4.3-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl @@ -1650,9 +1516,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b0/3e/a6497e1c2c9bc6ed2b79e0f2d31a4ce509fd2a9eed4e4f7ac63eda8113cb/gemmi-0.7.5-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/b0/42/c84efcc1d4caebafb1ecd8be4643f39c85c47a80fe254d92b8b43b1eadaf/h5py-3.16.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl @@ -1663,16 +1527,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bd/8c/d4907ad4f6bdc5bf79462d8767728713a7b316918a7444df372958a0e417/spglib-2.6.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/ea/7988934c8e3e3418aa043f70421817df28d06aef50bfd85f5ad3ec6e70f1/ncrystal_core-4.4.2-py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl @@ -1682,33 +1542,23 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl win-64: @@ -1875,12 +1725,10 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1a/1f/86b4d15221096cb5500bcd73bf350745749e3ba056cdd7a7f75f126f154e/scipp-26.3.1-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/1a/c7/78200c18404ded028758b28b588aa1f4f3acd851271a74156a2a3db9eadf/crysfml-0.6.2-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/1c/59/964ecb8008722d27d8a835baea81f56a91cea8e097b3be992bc6ccde6367/versioningit-3.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1d/77/928ea2e70641ca177a11140062cc5840d421795f2e82749d408d0cce900a/narwhals-2.21.2-py3-none-any.whl @@ -1908,32 +1756,24 @@ environments: - pypi: https://files.pythonhosted.org/packages/3a/eb/fea4d1d51c49832120f7f285d07306db3960f423a2612c6057caf3e8196f/pip-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/9e/fd90114059175cac64e4fafa9bf3ac20584384d66de40793ae2e2f26f3bb/sqlalchemy-2.0.49-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/7c/5c0d34aa3024694d6dcb9271cdbdd08c4e47c1c0ad95ec7e7bc74cdea145/propcache-0.5.2-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6f/0c/8297c8d978c919ad6318011631a6123082d5da940da5f8612e75a247d739/diffpy_pdffit2-1.6.0-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -1952,16 +1792,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8c/ec/d431eb7941fb55a31dd6ca3404d41fbb52d99172df2e7707754488390910/msgpack-1.1.2-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8f/82/b54e646be7b938fcbdda10030c6533bd2bb1a59930a1381cc83d6050a49c/spglib-2.6.0-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -1970,7 +1806,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl @@ -1984,10 +1819,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl @@ -1997,14 +1830,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/b9/c5/fc1b368f303087d20e8c9bf3d6ceb186263cfac0ade735cd938538bea839/pandas-3.0.3-cp312-cp312-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/6b/6c02f55c2ce2f137ccca0986be7dd89bea31d5bee4346b4377fa3b8586df/ncrystal_core-4.4.2-py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl @@ -2013,34 +1843,24 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/f2/53be7a4ba5816e13c39be0f728facac4bcb39cf4903ceeec54b006511c8f/gemmi-0.7.5-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl py-314-env: @@ -2223,7 +2043,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl @@ -2257,31 +2076,22 @@ environments: - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/43/fe/ad0ecbe2393cb690a4b3100a8fea47ecfdb49f6e06f40cf2f626635adc0c/scipp-26.3.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/46/b4/0887c88ddfaba1d7140ea335144eb904af97550786ee58bdb295ff10d255/crysfml-0.6.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/3b/1cdec6772bdbaf7b25dab360c59f03cadf05492dd724c6540af905389b07/pandas-3.0.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/58/e0/f1871f520c359e4e3a2eb7437c9e7e792bb6c356414e8617937561167caf/pycifrw-5.0.1.tar.gz - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -2299,14 +2109,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -2315,7 +2122,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a3/58/35da89ee790598a0700ea49b2a66594140f44dec458c07e8e3d4979137fc/ply-3.11-py2.py3-none-any.whl @@ -2327,8 +2133,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a8/4e/c09876f08fa9faaa5e1178f3d77b7af3f343258689bd6f3b72593b2f74e3/mkdocs_markdownextradata_plugin-0.2.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl @@ -2337,15 +2141,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c2/20/193faab46a68ea550587331a698c3dca8099f8901d10937c4443135c7ed9/chardet-7.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/c2/53/d81269aaafccea0d33396c03035de997b743f11e648e6e27a0df99c72980/yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl @@ -2356,38 +2157,27 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/51/ec641c26e6dca1b25a7d2035ba6ecb7c884ef1a100a9e42fbe4ce4405139/coverage-7.14.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/04/c5bb20d64417d20cba0105277235c51969444fa873000fbc26ac0a3fc5a8/gemmi-0.7.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/16/d905e7f53e661ce2c24686c38048d8e2b750ffc4350009d41c4e6c6c9826/h5py-3.16.0-cp314-cp314-manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f1/2c/3850985d4c64048dec7b826f8a803e135b52b11b4c81c9cd4326b1ca15ab/ncrystal_core-4.4.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -2559,11 +2349,9 @@ environments: - pypi: https://files.pythonhosted.org/packages/0d/12/bbce9472f489cb5c4c23b0d13e5c59c37c1aab11b7ac637dfe6bbdccebe7/copier-9.15.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/1f/d398de1612f7a611e22d743280339c9af4903675635e41be3370091c704b/arviz_stats-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/fe/6bea5c9162869c5beba5d9c8abbed835ec85bf1ec1fba05a3822325c45f3/build-1.5.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0f/0e/0eb94e64f5badef67f11fe1e448dde2a44f00940d8949f4adf71d560552e/scipp-26.3.1-cp314-cp314-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl @@ -2593,37 +2381,29 @@ environments: - pypi: https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/41/86/86231232fff41c9f8e4a1a7d7a597d349a02527109c3af7d618366122139/matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/51/ac/b9d68ebddfe1b02c77af5bf81120e12b036b4432dc6af7a303d90e2bc38b/chardet-7.4.3-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/33/bf28f618c0a9597d14e0b9ee7d1e0622faff738d44fe986ee287cdf1b8d0/sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/58/e0/f1871f520c359e4e3a2eb7437c9e7e792bb6c356414e8617937561167caf/pycifrw-5.0.1.tar.gz - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/68/10/bf2d6738d72748b961a3751ab89522d58c54efc36a8e1a12161216cd45cf/pandas-3.0.3-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6a/b7/9366ed44ced9b7ef357ab48c94205280276db9d7f064aa3012a97227e966/h5py-3.16.0-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -2639,14 +2419,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -2656,7 +2433,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl @@ -2668,9 +2444,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/a8/4e/c09876f08fa9faaa5e1178f3d77b7af3f343258689bd6f3b72593b2f74e3/mkdocs_markdownextradata_plugin-0.2.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl @@ -2678,18 +2452,14 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/ba/b1/5297bb6a7df4782f7605bffc43b31f5044070935fbbcaa6c705a07e6ac65/yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/ea/7988934c8e3e3418aa043f70421817df28d06aef50bfd85f5ad3ec6e70f1/ncrystal_core-4.4.2-py3-none-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl @@ -2697,36 +2467,26 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/9b/4165a1d56ddc302a0e2d518fd9d412a4fd0b57562618c78c5f21c57194f5/coverage-7.14.0-cp314-cp314-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl @@ -2894,7 +2654,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/95/cf3f7fe4910cf0365fa8ea0c731f4b8a624d97cd76ea777913ac8d0868e2/mkdocs_jupyter-0.26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl @@ -2902,7 +2661,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/1d/77/928ea2e70641ca177a11140062cc5840d421795f2e82749d408d0cce900a/narwhals-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1f/28/3f8aa247d29d010547d52207395cb057ebd0a40b88f64bc1dbac9e17a729/scipp-26.3.1-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/20/16/e777eadfa0c0305878c36fae1d5e6db474fbb15dae202b9ec378809dfb4d/nbstripout-0.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/7a/1c6e3562dfd8950adbb11ffbc65d21e7c89d01a6e4f137fa981056de25c5/gitpython-3.1.50-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl @@ -2925,32 +2683,24 @@ environments: - pypi: https://files.pythonhosted.org/packages/3e/14/615a450205e1b56d16c6783f5ccd116cde05550faad70ae077c955654a75/h5py-3.16.0-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/3e/17/1f31d8562e6f970d64911f1abc330d233bc0c0601411cf7e19c1292be6da/spdx_headers-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3e/5c/fb93d3092640a24dfb7bd7727a24016d7c01774ca013e60efd3f683c8002/backrefs-7.0-py314-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/e0/f1871f520c359e4e3a2eb7437c9e7e792bb6c356414e8617937561167caf/pycifrw-5.0.1.tar.gz - pypi: https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/2b/e260d50e64690d2a9e405d52ccd18a63c286c5088937dd0107cb23eb3195/diffpy_utils-3.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/61/d2/45c9defbaa1ea297035d9d4cce9e8f80daafbf19319c6007f157c6256ea9/propcache-0.5.2-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/f1/abd09c2ae91228c5f3998dbd7f41353def9eac64253de3c8105efa2082f7/msgpack-1.1.2-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/72/dc/0decaf5da92a7a969374474025787102d811d42aed1d32191fa338620e15/python_socketio-5.16.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/8e/56ccb09c7232a55403a7637caa21922f3b65901a37f5e8bdb405d0de0946/mike-2.2.0-py3-none-any.whl @@ -2968,15 +2718,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/f7/d00d9b4a0313a6be3a3e0818e6375e15da6d7076f4ae47d1324e7ca986a1/radon-6.0.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/5d/0c59079aa7ef34980a5925a06a90ad2b7c94e486c194b3527d557cabb042/cryspy-0.11.0-py3-none-any.whl @@ -2985,7 +2732,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl @@ -2998,8 +2744,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/aa/ec/d9be3bd1db141e76b2f525c265f70e66edd30a51a3307d8edf0ef1909c54/jupytext-1.19.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/1a/5a4f747a8b271cbb024946d2dd3c913ab5032ba430626f8c3528ada96b4b/matplotlib-3.10.9-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/2c/cad8b5e3623a987f3c930b68e2bdd06cfc388cd91cd42ed05f1227701b73/chardet-7.4.3-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl @@ -3008,16 +2752,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/b7/28/180bfc5c95e83d40cb2abce512684ccad44e4819ec899fc36cb404a19061/python_engineio-4.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/6b/6c02f55c2ce2f137ccca0986be7dd89bea31d5bee4346b4377fa3b8586df/ncrystal_core-4.4.2-py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl @@ -3028,37 +2768,27 @@ environments: - pypi: https://files.pythonhosted.org/packages/d2/f0/834e479e47e499b6478e807fb57b31cc2db696c4db30557bb6f5aea4a90b/mando-0.7.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/eb/be/b257e12f9710819fde40adc972578bee6b72c5992da1bc8369bef2597756/nbmake-1.5.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f2/f2/728f041460f1b9739b85ee23b45fa5a505962ea11fd85bdbe2a02b021373/darkdetect-0.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f9/58/6e1b8f52fdc3184b47dc5037f5070d83a3d11042db1594b02d2a44d786c8/coverage-7.14.0-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/fa/bc/8b8ec5a4bfc5b9cf3ce27a118339e994f88410be5677c96493e0ea28e76d/dunamai-1.26.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/d9/5582d57e2b2db9b85eb6663a22efdd78e08805f3f5389566e9fcad254d1b/yarl-1.24.2-cp314-cp314-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl @@ -8066,7 +7796,6 @@ packages: - build ; extra == 'dev' - copier ; extra == 'dev' - docstripy ; extra == 'dev' - - essdiffraction ; extra == 'dev' - format-docstring ; extra == 'dev' - gitpython ; extra == 'dev' - interrogate ; extra == 'dev' @@ -8375,32 +8104,6 @@ packages: - virtualenv>=20.17 ; python_full_version >= '3.10' and python_full_version < '3.14' and extra == 'virtualenv' - virtualenv>=20.31 ; python_full_version >= '3.14' and extra == 'virtualenv' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/0f/0e/0eb94e64f5badef67f11fe1e448dde2a44f00940d8949f4adf71d560552e/scipp-26.3.1-cp314-cp314-macosx_14_0_arm64.whl - name: scipp - version: 26.3.1 - sha256: 1f103f6c5a33b08773206c613fe2dd9c02585f5c4e44b77311c54b7828a758ed - requires_dist: - - numpy>=2 - - pytest ; extra == 'test' - - matplotlib ; extra == 'test' - - beautifulsoup4 ; extra == 'test' - - ipython ; extra == 'test' - - h5py ; extra == 'extra' - - scipy>=1.7.0 ; extra == 'extra' - - graphviz ; extra == 'extra' - - pooch ; extra == 'extra' - - plopp ; extra == 'extra' - - matplotlib ; extra == 'extra' - - scipp[extra] ; extra == 'all' - - ipympl ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets ; extra == 'all' - - jupyterlab ; extra == 'all' - - jupyterlab-widgets ; extra == 'all' - - jupyter-nbextensions-configurator ; extra == 'all' - - nodejs ; extra == 'all' - - pythreejs ; extra == 'all' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl name: pyparsing version: 3.3.2 @@ -8455,15 +8158,6 @@ packages: - trove-classifiers>=2024.10.12 ; extra == 'tests' - defusedxml ; extra == 'xmp' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/12/aa/fb2a0649fdeef5ab7072d221e8f4df164098792c813af6c87e2581cfa860/mpltoolbox-26.2.0-py3-none-any.whl - name: mpltoolbox - version: 26.2.0 - sha256: cd2668db4216fc4d7c2ba37974961aa61445f1517527b645b6082930e35ba7f0 - requires_dist: - - matplotlib - - ipympl ; extra == 'test' - - pytest>=8.0 ; extra == 'test' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl name: interrogate version: 1.7.0 @@ -8576,32 +8270,6 @@ packages: - pytest-xdist ; extra == 'test-no-images' - wurlitzer ; extra == 'test-no-images' requires_python: '>=3.11' -- pypi: https://files.pythonhosted.org/packages/1a/1f/86b4d15221096cb5500bcd73bf350745749e3ba056cdd7a7f75f126f154e/scipp-26.3.1-cp312-cp312-win_amd64.whl - name: scipp - version: 26.3.1 - sha256: 8b036876edf7895d17644f59711037d2d7d9ad048b1a503200646d8229fb1ad7 - requires_dist: - - numpy>=2 - - pytest ; extra == 'test' - - matplotlib ; extra == 'test' - - beautifulsoup4 ; extra == 'test' - - ipython ; extra == 'test' - - h5py ; extra == 'extra' - - scipy>=1.7.0 ; extra == 'extra' - - graphviz ; extra == 'extra' - - pooch ; extra == 'extra' - - plopp ; extra == 'extra' - - matplotlib ; extra == 'extra' - - scipp[extra] ; extra == 'all' - - ipympl ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets ; extra == 'all' - - jupyterlab ; extra == 'all' - - jupyterlab-widgets ; extra == 'all' - - jupyter-nbextensions-configurator ; extra == 'all' - - nodejs ; extra == 'all' - - pythreejs ; extra == 'all' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/1a/c7/78200c18404ded028758b28b588aa1f4f3acd851271a74156a2a3db9eadf/crysfml-0.6.2-cp312-cp312-win_amd64.whl name: crysfml version: 0.6.2 @@ -8663,58 +8331,6 @@ packages: version: 0.0.4 sha256: 571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320 requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/1e/e7/cd78635d0ece7e4d3393f2c1d2ebabf6ff4bd615da142891b1d42ad58abf/scipp-26.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - name: scipp - version: 26.3.1 - sha256: 7525c843f673ef5461d229095054a701aeb3233db29af137fdf4bbf0884ad9d4 - requires_dist: - - numpy>=2 - - pytest ; extra == 'test' - - matplotlib ; extra == 'test' - - beautifulsoup4 ; extra == 'test' - - ipython ; extra == 'test' - - h5py ; extra == 'extra' - - scipy>=1.7.0 ; extra == 'extra' - - graphviz ; extra == 'extra' - - pooch ; extra == 'extra' - - plopp ; extra == 'extra' - - matplotlib ; extra == 'extra' - - scipp[extra] ; extra == 'all' - - ipympl ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets ; extra == 'all' - - jupyterlab ; extra == 'all' - - jupyterlab-widgets ; extra == 'all' - - jupyter-nbextensions-configurator ; extra == 'all' - - nodejs ; extra == 'all' - - pythreejs ; extra == 'all' - requires_python: '>=3.11' -- pypi: https://files.pythonhosted.org/packages/1f/28/3f8aa247d29d010547d52207395cb057ebd0a40b88f64bc1dbac9e17a729/scipp-26.3.1-cp314-cp314-win_amd64.whl - name: scipp - version: 26.3.1 - sha256: 26291c0a882b9d5aac868c6d6f2508b79baa821ed30060a22c50620dbcce9e75 - requires_dist: - - numpy>=2 - - pytest ; extra == 'test' - - matplotlib ; extra == 'test' - - beautifulsoup4 ; extra == 'test' - - ipython ; extra == 'test' - - h5py ; extra == 'extra' - - scipy>=1.7.0 ; extra == 'extra' - - graphviz ; extra == 'extra' - - pooch ; extra == 'extra' - - plopp ; extra == 'extra' - - matplotlib ; extra == 'extra' - - scipp[extra] ; extra == 'all' - - ipympl ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets ; extra == 'all' - - jupyterlab ; extra == 'all' - - jupyterlab-widgets ; extra == 'all' - - jupyter-nbextensions-configurator ; extra == 'all' - - nodejs ; extra == 'all' - - pythreejs ; extra == 'all' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/1f/7e/c2cfe0bdbec1f5ce2bd92e03311038e1c491dfd54824606f38a61167a3f0/crysfml-0.6.2-cp314-cp314-macosx_14_0_arm64.whl name: crysfml version: 0.6.2 @@ -9144,32 +8760,6 @@ packages: name: distlib version: 0.4.0 sha256: 9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 -- pypi: https://files.pythonhosted.org/packages/33/75/98a7eb100dc5cfd20b019046452f08d5e67dfbacc71d8f28763d32426fd3/spglib-2.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - name: spglib - version: 2.6.0 - sha256: a8e9c34da1e2428c3a8bd4e209e5356d12d454d8ac54120d5ba4a437d3abe7ba - requires_dist: - - numpy>=1.20,<3 - - importlib-resources ; python_full_version < '3.10' - - typing-extensions>=4.9.0 ; python_full_version < '3.13' - - pytest ; extra == 'test' - - pyyaml ; extra == 'test' - - sphinx>=7.0 ; extra == 'docs' - - sphinxcontrib-bibtex>=2.5 ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - myst-parser>=2.0 ; extra == 'docs' - - linkify-it-py ; extra == 'docs' - - sphinx-tippy ; extra == 'docs' - - spglib[test] ; extra == 'test-cov' - - pytest-cov ; extra == 'test-cov' - - spglib[test] ; extra == 'test-benchmark' - - pytest-benchmark ; extra == 'test-benchmark' - - spglib[test] ; extra == 'dev' - - pre-commit ; extra == 'dev' - - spglib[docs] ; extra == 'doc' - - spglib[test] ; extra == 'testing' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl name: format-docstring version: 0.2.7 @@ -9434,11 +9024,6 @@ packages: requires_dist: - regex ; extra == 'extras' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - name: widgetsnbextension - version: 4.0.15 - sha256: 8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366 - requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/3f/d0/7b958df957e4827837b590944008f0b28078f552b451f7407b4b3d54f574/asciichartpy-1.5.25-py2.py3-none-any.whl name: asciichartpy version: 1.5.25 @@ -9493,13 +9078,6 @@ packages: - setuptools-scm>=7,<10 ; extra == 'dev' - setuptools>=64 ; extra == 'dev' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/42/d9/27b13bc9419bf5dae02905b348f16ca827646cd76244ddd326f1a8139a6a/cyclebane-24.10.0-py3-none-any.whl - name: cyclebane - version: 24.10.0 - sha256: 902dd318667e4a222afc270cc5bc72c67d5d6047d2e0e1c36018885fb80f5e5d - requires_dist: - - networkx - requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl name: mpmath version: 1.3.0 @@ -9545,58 +9123,6 @@ packages: - trove-classifiers>=2024.10.12 ; extra == 'tests' - defusedxml ; extra == 'xmp' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/43/fe/ad0ecbe2393cb690a4b3100a8fea47ecfdb49f6e06f40cf2f626635adc0c/scipp-26.3.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - name: scipp - version: 26.3.1 - sha256: 2ef08ba8d83542807f9f9833ba8f01583215c1629693bfadb1d6508cbdeb335c - requires_dist: - - numpy>=2 - - pytest ; extra == 'test' - - matplotlib ; extra == 'test' - - beautifulsoup4 ; extra == 'test' - - ipython ; extra == 'test' - - h5py ; extra == 'extra' - - scipy>=1.7.0 ; extra == 'extra' - - graphviz ; extra == 'extra' - - pooch ; extra == 'extra' - - plopp ; extra == 'extra' - - matplotlib ; extra == 'extra' - - scipp[extra] ; extra == 'all' - - ipympl ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets ; extra == 'all' - - jupyterlab ; extra == 'all' - - jupyterlab-widgets ; extra == 'all' - - jupyter-nbextensions-configurator ; extra == 'all' - - nodejs ; extra == 'all' - - pythreejs ; extra == 'all' - requires_python: '>=3.11' -- pypi: https://files.pythonhosted.org/packages/44/7b/537a61906eac58d94131273084d21d4eb219f5453f0ed30de3aca580a2b4/scipp-26.3.1-cp312-cp312-macosx_14_0_arm64.whl - name: scipp - version: 26.3.1 - sha256: 2608ba21e2c550abe864598e8cfffe22d7e7be70ff9f9b03d44868e353b241c9 - requires_dist: - - numpy>=2 - - pytest ; extra == 'test' - - matplotlib ; extra == 'test' - - beautifulsoup4 ; extra == 'test' - - ipython ; extra == 'test' - - h5py ; extra == 'extra' - - scipy>=1.7.0 ; extra == 'extra' - - graphviz ; extra == 'extra' - - pooch ; extra == 'extra' - - plopp ; extra == 'extra' - - matplotlib ; extra == 'extra' - - scipp[extra] ; extra == 'all' - - ipympl ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets ; extra == 'all' - - jupyterlab ; extra == 'all' - - jupyterlab-widgets ; extra == 'all' - - jupyter-nbextensions-configurator ; extra == 'all' - - nodejs ; extra == 'all' - - pythreejs ; extra == 'all' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/46/b4/0887c88ddfaba1d7140ea335144eb904af97550786ee58bdb295ff10d255/crysfml-0.6.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl name: crysfml version: 0.6.2 @@ -9685,38 +9211,6 @@ packages: - typing-extensions!=3.10.0.1 ; extra == 'aiosqlite' - sqlcipher3-binary ; extra == 'sqlcipher' requires_python: '>=3.7' -- pypi: https://files.pythonhosted.org/packages/4a/f3/00bb1e867fba351e2d784170955713bee200c43ea306c59f30bd7e748192/dask-2026.3.0-py3-none-any.whl - name: dask - version: 2026.3.0 - sha256: be614b9242b0b38288060fb2d7696125946469c98a1c30e174883fd199e0428d - requires_dist: - - click>=8.1 - - cloudpickle>=3.0.0 - - fsspec>=2021.9.0 - - packaging>=20.0 - - partd>=1.4.0 - - pyyaml>=5.3.1 - - toolz>=0.12.0 - - importlib-metadata>=4.13.0 ; python_full_version < '3.12' - - numpy>=1.24 ; extra == 'array' - - dask[array] ; extra == 'dataframe' - - pandas>=2.0 ; extra == 'dataframe' - - pyarrow>=16.0 ; extra == 'dataframe' - - distributed>=2026.3.0,<2026.3.1 ; extra == 'distributed' - - bokeh>=3.1.0 ; extra == 'diagnostics' - - jinja2>=2.10.3 ; extra == 'diagnostics' - - dask[array,dataframe,diagnostics,distributed] ; extra == 'complete' - - pyarrow>=16.0 ; extra == 'complete' - - lz4>=4.3.2 ; extra == 'complete' - - pandas[test] ; extra == 'test' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-mock ; extra == 'test' - - pytest-rerunfailures ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest-xdist ; extra == 'test' - - pre-commit ; extra == 'test' - requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl name: scipy version: 1.17.1 @@ -9852,22 +9346,6 @@ packages: - typing-extensions!=3.10.0.1 ; extra == 'aiosqlite' - sqlcipher3-binary ; extra == 'sqlcipher' requires_python: '>=3.7' -- pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - name: ipywidgets - version: 8.1.8 - sha256: ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e - requires_dist: - - comm>=0.1.3 - - ipython>=6.1.0 - - traitlets>=4.3.1 - - widgetsnbextension~=4.0.14 - - jupyterlab-widgets~=3.0.15 - - jsonschema ; extra == 'test' - - ipykernel ; extra == 'test' - - pytest>=3.6.0 ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytz ; extra == 'test' - requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl name: ruff version: 0.15.14 @@ -10021,16 +9499,6 @@ packages: requires_dist: - pyyaml>=3.10 ; extra == 'watchmedo' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/5c/01/6cb4d63c6b6933be4b7945b2f64638336420f04ea71ca5b9a7539c008bc5/scippnexus-26.1.1-py3-none-any.whl - name: scippnexus - version: 26.1.1 - sha256: 899a0a5e71291b7809d902c17b6c74addf5a805397eabcec557491ff74eead12 - requires_dist: - - scipp>=24.2.0 - - scipy>=1.10.0 - - h5py>=3.12 - - pytest>=7.0 ; extra == 'test' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl name: pillow version: 12.2.0 @@ -10099,35 +9567,6 @@ packages: version: 0.5.2 sha256: 81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/63/9f/724f66a48309dd97a2ff58f491d6ffd925f35d1278a5e55dc9a5ac6a156b/scippneutron-26.5.0-py3-none-any.whl - name: scippneutron - version: 26.5.0 - sha256: e9cfad09b974867c6dc2a175cd2e575e06eaa951b2409e9ef863db237853bf99 - requires_dist: - - python-dateutil>=2.8 - - email-validator>=2 - - h5py>=3.12 - - lazy-loader>=0.4 - - mpltoolbox>=24.6.0 - - numpy>=1.20 - - plopp>=26.4.1 - - pydantic>=2 - - scipp>=25.8.0 - - scippnexus>=23.11.0 - - scipy>=1.7.0 - - scipp[all]>=25.8.0 ; extra == 'all' - - pooch>=1.5 ; extra == 'all' - - hypothesis>=6.100 ; extra == 'test' - - ipympl>0.9.0 ; extra == 'test' - - ipykernel>6.30 ; extra == 'test' - - pace-neutrons>=0.3 ; extra == 'test' - - pooch>=1.5 ; extra == 'test' - - psutil>=5.0 ; extra == 'test' - - pytest>=7.0 ; extra == 'test' - - pytest-xdist>=3.0 ; extra == 'test' - - pythreejs>=2.4.1 ; extra == 'test' - - sciline>=25.1.0 ; extra == 'test' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl name: propcache version: 0.5.2 @@ -10401,27 +9840,6 @@ packages: version: 1.8.0 sha256: 494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383 requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/6c/25/4f103d1bedb3593718713b3f743df7b3ff3fc68d36d6666c30265ef59c8a/ase-3.28.0-py3-none-any.whl - name: ase - version: 3.28.0 - sha256: 0e24056302d7307b7247f90de281de15e3031c14cf400bedb1116c3b0d0e50b8 - requires_dist: - - numpy>=1.21.6 - - scipy>=1.8.1 - - matplotlib>=3.5.2 - - sphinx ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinxcontrib-video ; extra == 'docs' - - sphinx-gallery ; extra == 'docs' - - pillow ; extra == 'docs' - - pytest>=7.4.0 ; extra == 'test' - - pytest-xdist>=3.2.0 ; extra == 'test' - - spglib>=1.9 ; extra == 'spglib' - - mypy ; extra == 'lint' - - ruff ; extra == 'lint' - - types-docutils ; extra == 'lint' - - types-pymysql ; extra == 'lint' - requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/6e/94/be70f8ee9c45f2f62b39a1f0e9303bc20e138a8f3b8e50ffd89498e177e1/mkdocstrings-1.0.4-py3-none-any.whl name: mkdocstrings version: 1.0.4 @@ -10449,18 +9867,6 @@ packages: requires_dist: - diffpy-structure requires_python: '>=3.12,<3.15' -- pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - name: partd - version: 1.4.2 - sha256: 978e4ac767ec4ba5b86c6eaa52e5a2a3bc748a2ca839e8cc798f1cc6ce6efb0f - requires_dist: - - locket - - toolz - - numpy>=1.20.0 ; extra == 'complete' - - pandas>=1.3 ; extra == 'complete' - - pyzmq ; extra == 'complete' - - blosc ; extra == 'complete' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/72/b9/313e8f2f2e9517ae050a692ae7b3e4b3f17cc5e6dfea0db51fe14e586580/jinja2_ansible_filters-1.3.2-py3-none-any.whl name: jinja2-ansible-filters version: 1.3.2 @@ -10754,39 +10160,6 @@ packages: requires_dist: - typing-extensions>=4.14.1 requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/8a/06/2c1bd1ee9eee3e65b0b6395dcf960e71b11576995eae3b4ab9ec63d89bea/essreduce-26.4.1-py3-none-any.whl - name: essreduce - version: 26.4.1 - sha256: 1758a18fffca9c7c2a6fa9547cf87bf45f9d52fc3ccbdffcf7524f71bc060424 - requires_dist: - - sciline>=25.11.0 - - scipp>=26.3.1 - - scippneutron>=25.11.1 - - scippnexus>=25.6.0 - - graphviz>=0.20 ; extra == 'test' - - ipywidgets>=8.1 ; extra == 'test' - - matplotlib>=3.10.7 ; extra == 'test' - - numba>=0.63 ; extra == 'test' - - pooch>=1.9.0 ; extra == 'test' - - pytest>=7.0 ; extra == 'test' - - scipy>=1.14 ; extra == 'test' - - tof>=25.12.0 ; extra == 'test' - - autodoc-pydantic ; extra == 'docs' - - graphviz>=0.20 ; extra == 'docs' - - ipykernel ; extra == 'docs' - - ipython!=8.7.0 ; extra == 'docs' - - ipywidgets>=8.1 ; extra == 'docs' - - myst-parser ; extra == 'docs' - - nbsphinx ; extra == 'docs' - - numba>=0.63 ; extra == 'docs' - - plopp ; extra == 'docs' - - pydata-sphinx-theme>=0.14 ; extra == 'docs' - - sphinx>=7 ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx-design ; extra == 'docs' - - tof>=25.12.0 ; extra == 'docs' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl name: lazy-loader version: '0.5' @@ -10816,16 +10189,6 @@ packages: version: 1.1.2 sha256: 1de460f0403172cff81169a30b9a92b260cb809c4cb7e2fc79ae8d0510c78b6b requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - name: traittypes - version: 0.2.3 - sha256: 49016082ce740d6556d9bb4672ee2d899cd14f9365f17cbb79d5d96b47096d4e - requires_dist: - - traitlets>=4.2.2 - - numpy ; extra == 'test' - - pandas ; extra == 'test' - - xarray ; extra == 'test' - - pytest ; extra == 'test' - pypi: https://files.pythonhosted.org/packages/8e/5a/7fd1b784a87e96e0078f49a0a13a98b4c5f644ba5597a4a3b70a2ba3e613/py3dmol-2.5.5-py2.py3-none-any.whl name: py3dmol version: 2.5.5 @@ -10847,32 +10210,6 @@ packages: - python-docs-theme ; extra == 'doc' - uncertainties[arrays,doc,test] ; extra == 'all' requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/8f/82/b54e646be7b938fcbdda10030c6533bd2bb1a59930a1381cc83d6050a49c/spglib-2.6.0-cp312-cp312-win_amd64.whl - name: spglib - version: 2.6.0 - sha256: 86d0fd355689e58becd2cda609b03c3a0d9ad9d6f761cefd08b970db6f314eae - requires_dist: - - numpy>=1.20,<3 - - importlib-resources ; python_full_version < '3.10' - - typing-extensions>=4.9.0 ; python_full_version < '3.13' - - pytest ; extra == 'test' - - pyyaml ; extra == 'test' - - sphinx>=7.0 ; extra == 'docs' - - sphinxcontrib-bibtex>=2.5 ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - myst-parser>=2.0 ; extra == 'docs' - - linkify-it-py ; extra == 'docs' - - sphinx-tippy ; extra == 'docs' - - spglib[test] ; extra == 'test-cov' - - pytest-cov ; extra == 'test-cov' - - spglib[test] ; extra == 'test-benchmark' - - pytest-benchmark ; extra == 'test-benchmark' - - spglib[test] ; extra == 'dev' - - pre-commit ; extra == 'dev' - - spglib[docs] ; extra == 'doc' - - spglib[test] ; extra == 'testing' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl name: paginate version: 0.5.7 @@ -10953,26 +10290,6 @@ packages: - numpy>=1.22 ; extra == 'express' - kaleido>=1.1.0 ; extra == 'kaleido' requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl - name: graphviz - version: '0.21' - sha256: 54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42 - requires_dist: - - build ; extra == 'dev' - - wheel ; extra == 'dev' - - twine ; extra == 'dev' - - flake8 ; extra == 'dev' - - flake8-pyproject ; extra == 'dev' - - pep8-naming ; extra == 'dev' - - tox>=3 ; extra == 'dev' - - pytest>=7,<8.1 ; extra == 'test' - - pytest-mock>=3 ; extra == 'test' - - pytest-cov ; extra == 'test' - - coverage ; extra == 'test' - - sphinx>=5,<7 ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinx-rtd-theme>=0.2.5 ; extra == 'docs' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/91/6d/c00cb0d69d2e240c233c65b7f76d10522731156b28a2135bb97a05abc32c/easydiffraction-0.17.0-py3-none-any.whl name: easydiffraction version: 0.17.0 @@ -11146,49 +10463,6 @@ packages: - pycodestyle>=2.12.0 - tomli ; python_full_version < '3.11' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - name: networkx - version: 3.6.1 - sha256: d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762 - requires_dist: - - asv ; extra == 'benchmarking' - - virtualenv ; extra == 'benchmarking' - - numpy>=1.25 ; extra == 'default' - - scipy>=1.11.2 ; extra == 'default' - - matplotlib>=3.8 ; extra == 'default' - - pandas>=2.0 ; extra == 'default' - - pre-commit>=4.1 ; extra == 'developer' - - mypy>=1.15 ; extra == 'developer' - - sphinx>=8.0 ; extra == 'doc' - - pydata-sphinx-theme>=0.16 ; extra == 'doc' - - sphinx-gallery>=0.18 ; extra == 'doc' - - numpydoc>=1.8.0 ; extra == 'doc' - - pillow>=10 ; extra == 'doc' - - texext>=0.6.7 ; extra == 'doc' - - myst-nb>=1.1 ; extra == 'doc' - - intersphinx-registry ; extra == 'doc' - - osmnx>=2.0.0 ; extra == 'example' - - momepy>=0.7.2 ; extra == 'example' - - contextily>=1.6 ; extra == 'example' - - seaborn>=0.13 ; extra == 'example' - - cairocffi>=1.7 ; extra == 'example' - - igraph>=0.11 ; extra == 'example' - - scikit-learn>=1.5 ; extra == 'example' - - iplotx>=0.9.0 ; extra == 'example' - - lxml>=4.6 ; extra == 'extra' - - pygraphviz>=1.14 ; extra == 'extra' - - pydot>=3.0.1 ; extra == 'extra' - - sympy>=1.10 ; extra == 'extra' - - build>=0.10 ; extra == 'release' - - twine>=4.0 ; extra == 'release' - - wheel>=0.40 ; extra == 'release' - - changelist==0.5 ; extra == 'release' - - pytest>=7.2 ; extra == 'test' - - pytest-cov>=4.0 ; extra == 'test' - - pytest-xdist>=3.0 ; extra == 'test' - - pytest-mpl ; extra == 'test-extras' - - pytest-randomly ; extra == 'test-extras' - requires_python: '>=3.11,!=3.14.1' - pypi: https://files.pythonhosted.org/packages/9e/e9/1a19e42cd43cc1365e127db6aae85e1c671da1d9a5d746f4d34a50edb577/h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl name: h5py version: 3.16.0 @@ -11466,11 +10740,6 @@ packages: - pytest ; extra == 'testing' - tox ; extra == 'testing' requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - name: jupyterlab-widgets - version: 3.0.16 - sha256: 45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8 - requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl name: numpy version: 2.4.6 @@ -11501,23 +10770,6 @@ packages: - prettytable - ply - numpy -- pypi: https://files.pythonhosted.org/packages/af/46/661159ad844034ba8b3f4e0516215c41e4ee17db4213d13a82227670764f/sciline-25.11.1-py3-none-any.whl - name: sciline - version: 25.11.1 - sha256: 13c378287b8157e819b9b67d7e973c65bc6bdc545a3602d18204c365b0c336f9 - requires_dist: - - cyclebane>=24.6.0 - - pytest ; extra == 'test' - - pytest-randomly>=3 ; extra == 'test' - - dask ; extra == 'test' - - graphviz ; extra == 'test' - - jsonschema ; extra == 'test' - - numpy ; extra == 'test' - - pandas ; extra == 'test' - - pydantic ; extra == 'test' - - rich ; extra == 'test' - - rich ; extra == 'progress' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/b0/3e/a6497e1c2c9bc6ed2b79e0f2d31a4ce509fd2a9eed4e4f7ac63eda8113cb/gemmi-0.7.5-cp312-cp312-macosx_11_0_arm64.whl name: gemmi version: 0.7.5 @@ -11751,33 +11003,6 @@ packages: - xlsxwriter>=3.2.0 ; extra == 'all' - zstandard>=0.23.0 ; extra == 'all' requires_python: '>=3.11' -- pypi: https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl - name: dnspython - version: 2.8.0 - sha256: 01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af - requires_dist: - - black>=25.1.0 ; extra == 'dev' - - coverage>=7.0 ; extra == 'dev' - - flake8>=7 ; extra == 'dev' - - hypercorn>=0.17.0 ; extra == 'dev' - - mypy>=1.17 ; extra == 'dev' - - pylint>=3 ; extra == 'dev' - - pytest-cov>=6.2.0 ; extra == 'dev' - - pytest>=8.4 ; extra == 'dev' - - quart-trio>=0.12.0 ; extra == 'dev' - - sphinx-rtd-theme>=3.0.0 ; extra == 'dev' - - sphinx>=8.2.0 ; extra == 'dev' - - twine>=6.1.0 ; extra == 'dev' - - wheel>=0.45.0 ; extra == 'dev' - - cryptography>=45 ; extra == 'dnssec' - - h2>=4.2.0 ; extra == 'doh' - - httpcore>=1.0.0 ; extra == 'doh' - - httpx>=0.28.0 ; extra == 'doh' - - aioquic>=1.2.0 ; extra == 'doq' - - idna>=3.10 ; extra == 'idna' - - trio>=0.30 ; extra == 'trio' - - wmi>=1.5.1 ; sys_platform == 'win32' and extra == 'wmi' - requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl name: pillow version: 12.2.0 @@ -11824,32 +11049,6 @@ packages: version: 1.2.0 sha256: 9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913 requires_python: '>=3.7' -- pypi: https://files.pythonhosted.org/packages/bd/8c/d4907ad4f6bdc5bf79462d8767728713a7b316918a7444df372958a0e417/spglib-2.6.0-cp312-cp312-macosx_11_0_arm64.whl - name: spglib - version: 2.6.0 - sha256: 83ea2e90addc7232017c793a32d94b47bc68040c595671d1cbb836ede4349510 - requires_dist: - - numpy>=1.20,<3 - - importlib-resources ; python_full_version < '3.10' - - typing-extensions>=4.9.0 ; python_full_version < '3.13' - - pytest ; extra == 'test' - - pyyaml ; extra == 'test' - - sphinx>=7.0 ; extra == 'docs' - - sphinxcontrib-bibtex>=2.5 ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - myst-parser>=2.0 ; extra == 'docs' - - linkify-it-py ; extra == 'docs' - - sphinx-tippy ; extra == 'docs' - - spglib[test] ; extra == 'test-cov' - - pytest-cov ; extra == 'test-cov' - - spglib[test] ; extra == 'test-benchmark' - - pytest-benchmark ; extra == 'test-benchmark' - - spglib[test] ; extra == 'dev' - - pre-commit ; extra == 'dev' - - spglib[docs] ; extra == 'doc' - - spglib[test] ; extra == 'testing' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: aiohttp version: 3.13.5 @@ -11868,32 +11067,6 @@ packages: - brotlicffi>=1.2 ; platform_python_implementation != 'CPython' and extra == 'speedups' - backports-zstd ; python_full_version < '3.14' and platform_python_implementation == 'CPython' and extra == 'speedups' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/bf/34/1fe99124be59579ebd24316522e1da780979c856977b142c0dcd878b0a2d/spglib-2.6.0.tar.gz - name: spglib - version: 2.6.0 - sha256: d66eda2ba00a1e14fd96ec9c3b4dbf8ab0fb3f124643e35785c71ee455b408eb - requires_dist: - - numpy>=1.20,<3 - - importlib-resources ; python_full_version < '3.10' - - typing-extensions>=4.9.0 ; python_full_version < '3.13' - - pytest ; extra == 'test' - - pyyaml ; extra == 'test' - - sphinx>=7.0 ; extra == 'docs' - - sphinxcontrib-bibtex>=2.5 ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - myst-parser>=2.0 ; extra == 'docs' - - linkify-it-py ; extra == 'docs' - - sphinx-tippy ; extra == 'docs' - - spglib[test] ; extra == 'test-cov' - - pytest-cov ; extra == 'test-cov' - - spglib[test] ; extra == 'test-benchmark' - - pytest-benchmark ; extra == 'test-benchmark' - - spglib[test] ; extra == 'dev' - - pre-commit ; extra == 'dev' - - spglib[docs] ; extra == 'doc' - - spglib[test] ; extra == 'testing' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl name: docstring-parser-fork version: 0.0.14 @@ -11963,44 +11136,6 @@ packages: version: 1.5.0 sha256: bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/c4/6d/82e65254354ba651dc966775270a9bbc02414a3eb3f1704e6c87dab2ea83/essdiffraction-26.5.1-py3-none-any.whl - name: essdiffraction - version: 26.5.1 - sha256: 8a6c779078c71be250714619214069221ab7968a69580d4e4d3f4b3e9a1a53ad - requires_dist: - - dask>=2022.1.0 - - essreduce>=26.4.0 - - graphviz - - numpy>=2 - - plopp>=26.2.0 - - pythreejs>=2.4.1 - - sciline>=25.4.1 - - scipp>=25.11.0 - - scippneutron>=26.3.0 - - scippnexus>=23.12.0 - - tof>=25.12.0 - - ncrystal[cif]>=4.1.0 - - spglib!=2.7 - - pandas>=2.1.2 ; extra == 'test' - - pooch>=1.5 ; extra == 'test' - - pytest>=7.0 ; extra == 'test' - - ipywidgets>=8.1.7 ; extra == 'test' - - autodoc-pydantic ; extra == 'docs' - - ipykernel ; extra == 'docs' - - ipympl ; extra == 'docs' - - ipython!=8.7.0 ; extra == 'docs' - - myst-parser ; extra == 'docs' - - nbsphinx ; extra == 'docs' - - pandas ; extra == 'docs' - - pooch ; extra == 'docs' - - pydata-sphinx-theme>=0.14 ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx-design ; extra == 'docs' - - sphinxcontrib-bibtex ; extra == 'docs' - - pyarrow ; extra == 'docs' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/c6/3d/020a6b6248c3d4a37797db068256f0b3f15b01bc481327ba888c50309aa8/mkdocs_plugin_inline_svg-0.1.0-py3-none-any.whl name: mkdocs-plugin-inline-svg version: 0.1.0 @@ -12015,11 +11150,6 @@ packages: requires_dist: - colorama ; sys_platform == 'win32' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/c7/6b/6c02f55c2ce2f137ccca0986be7dd89bea31d5bee4346b4377fa3b8586df/ncrystal_core-4.4.2-py3-none-win_amd64.whl - name: ncrystal-core - version: 4.4.2 - sha256: 9b28a90b63849e6a3a807a0a59f7c2ee57e4c64f5643b2dcb6a798ac8ccf666a - requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl name: dfo-ls version: 1.6.5 @@ -12034,11 +11164,6 @@ packages: - sphinx-rtd-theme ; extra == 'dev' - trustregion>=1.1 ; extra == 'trustregion' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/c7/ea/7988934c8e3e3418aa043f70421817df28d06aef50bfd85f5ad3ec6e70f1/ncrystal_core-4.4.2-py3-none-macosx_11_0_arm64.whl - name: ncrystal-core - version: 4.4.2 - sha256: b7e6101a6850aa18cf441825214381614db444ffcba648de8266fe1c4d1024ce - requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/c9/02/9a14d3048ffa4f45b7c60956a9b22688dd925d6de50f6baf7e55f3664942/trove_classifiers-2026.5.22.10-py3-none-any.whl name: trove-classifiers version: 2026.5.22.10 @@ -12331,114 +11456,6 @@ packages: name: funcy version: '2.0' sha256: 53df23c8bb1651b12f095df764bfb057935d49537a56de211b098f4c79614bb0 -- pypi: https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl - name: fsspec - version: 2026.4.0 - sha256: 11ef7bb35dab8a394fde6e608221d5cf3e8499401c249bebaeaad760a1a8dec2 - requires_dist: - - adlfs ; extra == 'abfs' - - adlfs ; extra == 'adl' - - pyarrow>=1 ; extra == 'arrow' - - dask ; extra == 'dask' - - distributed ; extra == 'dask' - - pre-commit ; extra == 'dev' - - ruff>=0.5 ; extra == 'dev' - - numpydoc ; extra == 'doc' - - sphinx ; extra == 'doc' - - sphinx-design ; extra == 'doc' - - sphinx-rtd-theme ; extra == 'doc' - - yarl ; extra == 'doc' - - dropbox ; extra == 'dropbox' - - dropboxdrivefs ; extra == 'dropbox' - - requests ; extra == 'dropbox' - - adlfs ; extra == 'full' - - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'full' - - dask ; extra == 'full' - - distributed ; extra == 'full' - - dropbox ; extra == 'full' - - dropboxdrivefs ; extra == 'full' - - fusepy ; extra == 'full' - - gcsfs>2024.2.0 ; extra == 'full' - - libarchive-c ; extra == 'full' - - ocifs ; extra == 'full' - - panel ; extra == 'full' - - paramiko ; extra == 'full' - - pyarrow>=1 ; extra == 'full' - - pygit2 ; extra == 'full' - - requests ; extra == 'full' - - s3fs>2024.2.0 ; extra == 'full' - - smbprotocol ; extra == 'full' - - tqdm ; extra == 'full' - - fusepy ; extra == 'fuse' - - gcsfs>2024.2.0 ; extra == 'gcs' - - pygit2 ; extra == 'git' - - requests ; extra == 'github' - - gcsfs ; extra == 'gs' - - panel ; extra == 'gui' - - pyarrow>=1 ; extra == 'hdfs' - - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'http' - - libarchive-c ; extra == 'libarchive' - - ocifs ; extra == 'oci' - - s3fs>2024.2.0 ; extra == 's3' - - paramiko ; extra == 'sftp' - - smbprotocol ; extra == 'smb' - - paramiko ; extra == 'ssh' - - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'test' - - numpy ; extra == 'test' - - pytest ; extra == 'test' - - pytest-asyncio!=0.22.0 ; extra == 'test' - - pytest-benchmark ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-mock ; extra == 'test' - - pytest-recording ; extra == 'test' - - pytest-rerunfailures ; extra == 'test' - - requests ; extra == 'test' - - aiobotocore>=2.5.4,<3.0.0 ; extra == 'test-downstream' - - dask[dataframe,test] ; extra == 'test-downstream' - - moto[server]>4,<5 ; extra == 'test-downstream' - - pytest-timeout ; extra == 'test-downstream' - - xarray ; extra == 'test-downstream' - - adlfs ; extra == 'test-full' - - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'test-full' - - backports-zstd ; python_full_version < '3.14' and extra == 'test-full' - - cloudpickle ; extra == 'test-full' - - dask ; extra == 'test-full' - - distributed ; extra == 'test-full' - - dropbox ; extra == 'test-full' - - dropboxdrivefs ; extra == 'test-full' - - fastparquet ; extra == 'test-full' - - fusepy ; extra == 'test-full' - - gcsfs ; extra == 'test-full' - - jinja2 ; extra == 'test-full' - - kerchunk ; extra == 'test-full' - - libarchive-c ; extra == 'test-full' - - lz4 ; extra == 'test-full' - - notebook ; extra == 'test-full' - - numpy ; extra == 'test-full' - - ocifs ; extra == 'test-full' - - pandas<3.0.0 ; extra == 'test-full' - - panel ; extra == 'test-full' - - paramiko ; extra == 'test-full' - - pyarrow ; extra == 'test-full' - - pyarrow>=1 ; extra == 'test-full' - - pyftpdlib ; extra == 'test-full' - - pygit2 ; extra == 'test-full' - - pytest ; extra == 'test-full' - - pytest-asyncio!=0.22.0 ; extra == 'test-full' - - pytest-benchmark ; extra == 'test-full' - - pytest-cov ; extra == 'test-full' - - pytest-mock ; extra == 'test-full' - - pytest-recording ; extra == 'test-full' - - pytest-rerunfailures ; extra == 'test-full' - - python-snappy ; extra == 'test-full' - - requests ; extra == 'test-full' - - smbprotocol ; extra == 'test-full' - - tqdm ; extra == 'test-full' - - urllib3 ; extra == 'test-full' - - zarr ; extra == 'test-full' - - zstandard ; python_full_version < '3.14' and extra == 'test-full' - - tqdm ; extra == 'tqdm' - requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl name: pycodestyle version: 2.14.0 @@ -12451,27 +11468,6 @@ packages: requires_dist: - tomli ; python_full_version <= '3.11' and extra == 'toml' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/d8/8b/e2bbeb42068f0c48899e8eddd34902afc0f7429d4d2a152d2dc2670dc661/pythreejs-2.4.2-py3-none-any.whl - name: pythreejs - version: 2.4.2 - sha256: 8418807163ad91f4df53b58c4e991b26214852a1236f28f1afeaadf99d095818 - requires_dist: - - ipywidgets>=7.2.1 - - ipydatawidgets>=1.1.1 - - numpy - - traitlets - - sphinx>=1.5 ; extra == 'docs' - - nbsphinx>=0.2.13 ; extra == 'docs' - - nbsphinx-link ; extra == 'docs' - - sphinx-rtd-theme ; extra == 'docs' - - scipy ; extra == 'examples' - - matplotlib ; extra == 'examples' - - scikit-image ; extra == 'examples' - - ipywebrtc ; extra == 'examples' - - nbval ; extra == 'test' - - pytest-check-links ; extra == 'test' - - numpy>=1.14 ; extra == 'test' - requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl name: pillow version: 12.2.0 @@ -12560,11 +11556,6 @@ packages: requires_dist: - pyyaml>=3.10 ; extra == 'watchmedo' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - name: locket - version: 1.0.0 - sha256: b6c819a722f7b6bd955b80781788e4a66a55628b858d347536b7e81325a3a5e3 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl name: watchdog version: 6.0.0 @@ -12627,21 +11618,6 @@ packages: requires_dist: - typing-extensions>=4.12.0 requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/dc/b7/901d837999a9350a7773289f7760cb473d4ba01fdc6ebae0ff2553d269ac/ncrystal_python-4.4.2-py3-none-any.whl - name: ncrystal-python - version: 4.4.2 - sha256: f419318d088fade6bcff1e39e15baf6fe69fcf5306dd681fca1106d1f63a89ce - requires_dist: - - numpy>=1.22 - requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl - name: email-validator - version: 2.3.0 - sha256: 80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4 - requires_dist: - - dnspython>=2.0.0 - - idna>=2.0.0 - requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl name: markdown version: 3.10.2 @@ -12674,37 +11650,6 @@ packages: version: 1.5.4 sha256: 7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 requires_python: '>=3.7' -- pypi: https://files.pythonhosted.org/packages/e4/bc/daa30c02069eeac5b9198985ba42f5d65ca71bed6705b18329e51d352b7c/plopp-26.4.2-py3-none-any.whl - name: plopp - version: 26.4.2 - sha256: 5cab99bb0905ce08a1d1d7d82f0f64cee7d594269ec1bd01a8a361bd14ab7bff - requires_dist: - - lazy-loader>=0.4 - - matplotlib>=3.8 - - scipp>=25.8.0 ; extra == 'scipp' - - plopp[scipp] ; extra == 'all' - - ipympl>0.8.4 ; extra == 'all' - - pythreejs>=2.4.1 ; extra == 'all' - - mpltoolbox>=24.6.0 ; extra == 'all' - - ipywidgets>=8.1.0 ; extra == 'all' - - graphviz>=0.20.3 ; extra == 'all' - - plopp[scipp] ; extra == 'test' - - graphviz>=0.20.3 ; extra == 'test' - - h5py>=3.12 ; extra == 'test' - - ipympl>=0.8.4 ; extra == 'test' - - ipywidgets>=8.1.0 ; extra == 'test' - - ipykernel>=6.26,<7 ; extra == 'test' - - mpltoolbox>=24.6.0 ; extra == 'test' - - pandas>=2.2.2 ; extra == 'test' - - plotly>=5.15.0 ; extra == 'test' - - pooch>=1.5 ; extra == 'test' - - pyarrow>=13.0.0 ; extra == 'test' - - pytest>=8.0 ; extra == 'test' - - pythreejs>=2.4.1 ; extra == 'test' - - scipy>=1.10.0 ; extra == 'test' - - xarray>=2024.5.0 ; extra == 'test' - - anywidget>=0.9.0 ; extra == 'test' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/e5/04/c5bb20d64417d20cba0105277235c51969444fa873000fbc26ac0a3fc5a8/gemmi-0.7.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl name: gemmi version: 0.7.5 @@ -12771,11 +11716,6 @@ packages: requires_dist: - numpy>=1.21.2 requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/f1/2c/3850985d4c64048dec7b826f8a803e135b52b11b4c81c9cd4326b1ca15ab/ncrystal_core-4.4.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - name: ncrystal-core - version: 4.4.2 - sha256: d0d9c47cd017b7cefc52dde50546d7c151bfdd75d345e42e2b3e74ab5fe83c62 - requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl name: multidict version: 6.7.1 @@ -12783,21 +11723,6 @@ packages: requires_dist: - typing-extensions>=4.1.0 ; python_full_version < '3.11' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/f1/5b/e63c877c4c94382b66de5045e08ec8cd960e8a4d22f0d62a4dfb1f9e5ac6/ipydatawidgets-4.3.5-py2.py3-none-any.whl - name: ipydatawidgets - version: 4.3.5 - sha256: d590cdb7c364f2f6ab346f20b9d2dd661d27a834ef7845bc9d7113118f05ec87 - requires_dist: - - ipywidgets>=7.0.0 - - numpy - - traittypes>=0.2.0 - - sphinx ; extra == 'docs' - - recommonmark ; extra == 'docs' - - sphinx-rtd-theme ; extra == 'docs' - - pytest>=4 ; extra == 'test' - - pytest-cov ; extra == 'test' - - nbval>=0.9.2 ; extra == 'test' - requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl name: pathspec version: 1.1.1 @@ -12851,55 +11776,11 @@ packages: version: 0.1.4 sha256: 27b3b67cf898684e646d569f017cb27046774ad23866cb0bdf51d5f76a46476b requires_python: '>=3.7' -- pypi: https://files.pythonhosted.org/packages/f5/57/2a154a69d6642860300bf8eb205d13131104991f2b1065bbb9075ac5c32e/tof-26.3.0-py3-none-any.whl - name: tof - version: 26.3.0 - sha256: e89783a072b05fdb53d9e76fbf919dc8935e75e118fdaf17ca5cc33727ef002b - requires_dist: - - plopp>=23.10.0 - - pooch>=1.5.0 - - scipp>=25.1.0 - - lazy-loader>=0.3 - - pytest>=8.0 ; extra == 'test' - - scippneutron>=24.12.0 ; extra == 'test' - requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl name: py version: 1.11.0 sha256: 607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- pypi: https://files.pythonhosted.org/packages/f7/00/bbca25f8a2372465cdf93138c1e1e38dff045fb0afef1488f395d0afcb3b/ncrystal-4.4.2-py3-none-any.whl - name: ncrystal - version: 4.4.2 - sha256: e02fa7d743addc3fbea23287737a88b8d01192450fdca51554d3f9032fe4617c - requires_dist: - - ncrystal-core==4.4.2 - - ncrystal-python==4.4.2 - - spglib>=2.1.0 ; extra == 'composer' - - ase>=3.23.0 ; extra == 'cif' - - gemmi>=0.6.1 ; extra == 'cif' - - spglib>=2.1.0 ; extra == 'cif' - - endf-parserpy>=0.14.3 ; extra == 'endf' - - matplotlib>=3.6.0 ; extra == 'plot' - - ase>=3.23.0 ; extra == 'all' - - endf-parserpy>=0.14.3 ; extra == 'all' - - gemmi>=0.6.1 ; extra == 'all' - - matplotlib>=3.6.0 ; extra == 'all' - - spglib>=2.1.0 ; extra == 'all' - - pyyaml>=6.0.0 ; extra == 'devel' - - ase>=3.23.0 ; extra == 'devel' - - cppcheck ; extra == 'devel' - - endf-parserpy>=0.14.3 ; extra == 'devel' - - gemmi>=0.6.1 ; extra == 'devel' - - matplotlib>=3.6.0 ; extra == 'devel' - - mpmath>=1.3.0 ; extra == 'devel' - - numpy>=1.22 ; extra == 'devel' - - pybind11>=2.11.0 ; extra == 'devel' - - ruff>=0.8.1 ; extra == 'devel' - - simple-build-system>=1.6.0 ; extra == 'devel' - - spglib>=2.1.0 ; extra == 'devel' - - tomli>=2.0.0 ; python_full_version < '3.11' and extra == 'devel' - requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl name: ghp-import version: 2.1.0 @@ -12934,11 +11815,6 @@ packages: - multidict>=4.0 - propcache>=0.2.1 requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - name: toolz - version: 1.1.0 - sha256: 15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8 - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl name: aiosignal version: 1.4.0 diff --git a/pyproject.toml b/pyproject.toml index 507a069d1..d953cfa19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,6 @@ dependencies = [ [project.optional-dependencies] dev = [ - 'essdiffraction', # ESS-specific diffraction library 'GitPython', # Interact with Git repositories 'build', # Building the package 'pre-commit', # Pre-commit hooks diff --git a/src/easydiffraction/analysis/__init__.py b/src/easydiffraction/analysis/__init__.py index 186c375c8..325c9882a 100644 --- a/src/easydiffraction/analysis/__init__.py +++ b/src/easydiffraction/analysis/__init__.py @@ -11,7 +11,7 @@ from easydiffraction.analysis.categories.fit_parameters import FitParameterItem from easydiffraction.analysis.categories.fit_parameters import FitParameters from easydiffraction.analysis.categories.fit_parameters import FitParametersFactory -from easydiffraction.analysis.categories.fit_result import FitResult +from easydiffraction.analysis.categories.fit_result import FitResultBase from easydiffraction.analysis.categories.fit_result import FitResultFactory from easydiffraction.analysis.categories.joint_fit import JointFitCollection from easydiffraction.analysis.categories.joint_fit import JointFitFactory diff --git a/src/easydiffraction/analysis/analysis.py b/src/easydiffraction/analysis/analysis.py index 87676646e..9a01d8385 100644 --- a/src/easydiffraction/analysis/analysis.py +++ b/src/easydiffraction/analysis/analysis.py @@ -15,7 +15,6 @@ from easydiffraction.analysis.categories.constraints.factory import ConstraintsFactory from easydiffraction.analysis.categories.fit_parameter_correlations import FitParameterCorrelations from easydiffraction.analysis.categories.fit_parameters import FitParameters -from easydiffraction.analysis.categories.fit_result import FitResult from easydiffraction.analysis.categories.fitting_mode import FittingMode from easydiffraction.analysis.categories.fitting_mode import FittingModeFactory from easydiffraction.analysis.categories.joint_fit import JointFitCollection @@ -56,6 +55,7 @@ from easydiffraction.utils.utils import render_table if TYPE_CHECKING: + from easydiffraction.analysis.categories.fit_result import FitResultBase from easydiffraction.analysis.categories.minimizer.base import MinimizerCategoryBase from easydiffraction.core.posterior import PosteriorParameterSummary @@ -429,7 +429,7 @@ def fit_parameters(self) -> FitParameters: return self._fit_parameters @property - def fit_result(self) -> FitResult: + def fit_result(self) -> FitResultBase: """Persisted common fit-result status metadata.""" return self._fit_result @@ -480,7 +480,7 @@ def __init__(self, project: object) -> None: ) self._sequential_fit_extract = SequentialFitExtractCollection() self._fit_parameters = FitParameters() - self._fit_result = FitResult() + self._fit_result = self._minimizer._fit_result_class() self._fit_parameter_correlations = FitParameterCorrelations() self._has_persisted_fit_state_data = False self._persisted_fit_state_sidecar: dict[str, object] = {} @@ -736,13 +736,13 @@ def _restore_fit_results_from_projection(self) -> object | None: starting_parameters=list(restored_parameters), fitting_time=fitting_time, sampler_name=sampler_name, - point_estimate_name=self.minimizer.point_estimate_name.value, + point_estimate_name=self.fit_result.point_estimate_name.value or 'best_sample', posterior_samples=posterior_samples, posterior_parameter_summaries=self._restored_posterior_summaries(), posterior_predictive=self._restored_predictive_summaries(), credible_interval_levels=( - float(self.minimizer.credible_interval_inner.value), - float(self.minimizer.credible_interval_outer.value), + float(self.fit_result.credible_interval_inner.value), + float(self.fit_result.credible_interval_outer.value), ), sampler_settings={ 'steps': int(sampler_settings.get('steps', 0)), @@ -755,17 +755,17 @@ def _restore_fit_results_from_projection(self) -> object | None: }, convergence_diagnostics={ 'converged': False, - 'max_r_hat': self.minimizer.gelman_rubin_max.value, - 'min_ess_bulk': self.minimizer.effective_sample_size_min.value, + 'max_r_hat': self.fit_result.gelman_rubin_max.value, + 'min_ess_bulk': self.fit_result.effective_sample_size_min.value, 'n_draws': int(sample_shape[0]), 'n_chains': int(sample_shape[1]), 'n_parameters': int(sample_shape[2]), }, - sampler_completed=bool(self.minimizer.sampler_completed.value), - best_log_posterior=self.minimizer.best_log_posterior.value, + sampler_completed=bool(self.fit_result.sampler_completed.value), + best_log_posterior=self.fit_result.best_log_posterior.value, ) - restored_results.message = self.fit_result.message.value - restored_results.iterations = int(self.fit_result.iterations.value) + restored_results.message = self.fit_result.message.value or '' + restored_results.iterations = _int_or_none(self.fit_result.iterations.value) or 0 self.fit_results = restored_results return restored_results @@ -778,21 +778,21 @@ def _restore_fit_results_from_projection(self) -> object | None: fitting_time=fitting_time, optimizer_name=engine_metadata['optimizer_name'], method_name=engine_metadata['method_name'], - objective_name=self.minimizer.objective_name.value, - objective_value=self.minimizer.objective_value.value, - n_data_points=_int_or_none(self.minimizer.n_data_points.value), - n_parameters=_int_or_none(self.minimizer.n_parameters.value), - n_free_parameters=_int_or_none(self.minimizer.n_free_parameters.value), - degrees_of_freedom=_int_or_none(self.minimizer.degrees_of_freedom.value), - covariance_available=self.minimizer.covariance_available.value, - correlation_available=self.minimizer.correlation_available.value, - runtime_seconds=self.minimizer.runtime_seconds.value, - iterations_performed=_int_or_none(self.minimizer.iterations_performed.value), - exit_reason=self.minimizer.exit_reason.value, + objective_name=self.fit_result.objective_name.value, + objective_value=self.fit_result.objective_value.value, + n_data_points=_int_or_none(self.fit_result.n_data_points.value), + n_parameters=_int_or_none(self.fit_result.n_parameters.value), + n_free_parameters=_int_or_none(self.fit_result.n_free_parameters.value), + degrees_of_freedom=_int_or_none(self.fit_result.degrees_of_freedom.value), + covariance_available=self.fit_result.covariance_available.value, + correlation_available=self.fit_result.correlation_available.value, + runtime_seconds=fitting_time, + iterations_performed=_int_or_none(self.fit_result.iterations.value), + exit_reason=self.fit_result.exit_reason.value, ) - restored_results.message = self.fit_result.message.value - restored_results.iterations = int(self.fit_result.iterations.value) - restored_results.chi_square = self.minimizer.objective_value.value + restored_results.message = self.fit_result.message.value or '' + restored_results.iterations = _int_or_none(self.fit_result.iterations.value) or 0 + restored_results.chi_square = self.fit_result.objective_value.value self.fit_results = restored_results return restored_results @@ -1062,8 +1062,11 @@ def _replace_minimizer( self._warn_about_minimizer_swap_defaults(old_defaults, new_minimizer) old_minimizer._parent = None + self._fit_result._parent = None self._minimizer = new_minimizer + self._fit_result = new_minimizer._fit_result_class() self._minimizer._parent = self + self._fit_result._parent = self self._fitter = Fitter(value) if announce: console.paragraph('Current minimizer changed to') @@ -1203,16 +1206,19 @@ def _fit_state_categories(self) -> list[object]: def _clear_persisted_fit_state(self) -> None: """Reset all persisted fit-state categories before a new fit.""" - self._clear_minimizer_result_projection() self._fit_parameters = FitParameters() - self._fit_result = FitResult() + self._fit_result._parent = None + self._fit_result = self.minimizer._fit_result_class() + self._fit_result._parent = self self._fit_parameter_correlations = FitParameterCorrelations() self._set_has_persisted_fit_state(value=False) self._persisted_fit_state_sidecar = {} - def _clear_minimizer_result_projection(self) -> None: - """Reset result-only fields on the active minimizer category.""" - self.minimizer._reset_result_descriptors() + def _clear_fit_result_projection(self) -> None: + """ + Reset result-only fields on the active fit-result category. + """ + self.fit_result._reset_result_descriptors() def _capture_fit_parameter_state(self, parameters: list[Parameter]) -> None: """Capture pre-fit parameter state.""" @@ -1372,17 +1378,15 @@ def _store_least_squares_result_projection( else None ) - self.minimizer._set_objective_name('chi_square') - self.minimizer._set_objective_value(self._resolve_objective_value(results)) - self.minimizer._set_n_data_points(n_data_points) - self.minimizer._set_n_parameters(n_parameters) - self.minimizer._set_n_free_parameters(n_free_parameters) - self.minimizer._set_degrees_of_freedom(degrees_of_freedom) - self.minimizer._set_covariance_available(value=covariance is not None) - self.minimizer._set_correlation_available(value=correlation_matrix is not None) - self.minimizer._set_runtime_seconds(results.fitting_time) - self.minimizer._set_iterations_performed(results.iterations) - self.minimizer._set_exit_reason(results.message) + self.fit_result._set_objective_name('chi_square') + self.fit_result._set_objective_value(self._resolve_objective_value(results)) + self.fit_result._set_n_data_points(n_data_points) + self.fit_result._set_n_parameters(n_parameters) + self.fit_result._set_n_free_parameters(n_free_parameters) + self.fit_result._set_degrees_of_freedom(degrees_of_freedom) + self.fit_result._set_covariance_available(value=covariance is not None) + self.fit_result._set_correlation_available(value=correlation_matrix is not None) + self.fit_result._set_exit_reason(results.message) if correlation_matrix is not None: self._store_correlation_projection( @@ -1679,15 +1683,14 @@ def _store_posterior_fit_projection(self, results: BayesianFitResults) -> None: point_estimate_name = results.point_estimate_name or 'best_sample' convergence = results.convergence_diagnostics - self.minimizer._set_runtime_seconds(results.fitting_time) - self.minimizer._set_point_estimate_name(point_estimate_name) - self.minimizer._set_sampler_completed(value=results.sampler_completed) - self.minimizer._set_best_log_posterior(results.best_log_posterior) - self.minimizer._set_credible_interval_inner(credible_interval_inner) - self.minimizer._set_credible_interval_outer(credible_interval_outer) - self.minimizer._set_gelman_rubin_max(convergence.get('max_r_hat')) - self.minimizer._set_effective_sample_size_min(convergence.get('min_ess_bulk')) - self.minimizer._set_acceptance_rate_mean(convergence.get('acceptance_rate_mean')) + self.fit_result._set_point_estimate_name(point_estimate_name) + self.fit_result._set_sampler_completed(value=results.sampler_completed) + self.fit_result._set_best_log_posterior(results.best_log_posterior) + self.fit_result._set_credible_interval_inner(credible_interval_inner) + self.fit_result._set_credible_interval_outer(credible_interval_outer) + self.fit_result._set_gelman_rubin_max(convergence.get('max_r_hat')) + self.fit_result._set_effective_sample_size_min(convergence.get('min_ess_bulk')) + self.fit_result._set_acceptance_rate_mean(convergence.get('acceptance_rate_mean')) self._store_posterior_samples_sidecar_projection(results) live_parameters = { @@ -1945,33 +1948,14 @@ def _fit_single( self.fitter.minimizer.tracker._set_shared_display_handle(short_display_handle) try: - for expt_name in expt_names: - if verb is VerbosityEnum.FULL: - console.print( - f"📋 Using experiment 🔬 '{expt_name}' for '{mode.value}' fitting" - ) - - experiment = experiments[expt_name] - self.fitter.fit( - structures, - [experiment], - analysis=self, - verbosity=verb, - use_physical_limits=use_physical_limits, - random_seed=self._resolved_fit_random_seed(random_seed), - ) - - # After fitting, snapshot parameter values before - # they get overwritten by the next experiment's fit - results = self.fitter.results - self._snapshot_params(expt_name, results) - self.fit_results = results - - # Short mode: append one summary row and update in-place - if verb is VerbosityEnum.SHORT: - self._fit_single_update_short_table( - short_rows, expt_name, results, short_display_handle - ) + self._fit_single_experiments( + verb, + structures, + experiments, + use_physical_limits=use_physical_limits, + random_seed=random_seed, + short_state=(short_rows, short_display_handle), + ) finally: self.fitter.minimizer.tracker._set_shared_display_handle(None) @@ -1980,6 +1964,47 @@ def _fit_single( with suppress(Exception): short_display_handle.close() + def _fit_single_experiments( + self, + verb: VerbosityEnum, + structures: object, + experiments: object, + *, + use_physical_limits: bool, + random_seed: int | None, + short_state: tuple[list[list[str]], object], + ) -> None: + """Run the per-experiment loop for single-fit mode.""" + short_rows, short_display_handle = short_state + for expt_name in experiments.names: + if verb is VerbosityEnum.FULL: + console.print( + f"📋 Using experiment 🔬 '{expt_name}' for " + f"'{FitModeEnum.SINGLE.value}' fitting" + ) + + experiment = experiments[expt_name] + self.fitter.fit( + structures, + [experiment], + analysis=self, + verbosity=verb, + use_physical_limits=use_physical_limits, + random_seed=self._resolved_fit_random_seed(random_seed), + ) + + results = self.fitter.results + self._snapshot_params(expt_name, results) + self.fit_results = results + + if verb is VerbosityEnum.SHORT: + self._fit_single_update_short_table( + short_rows, + expt_name, + results, + short_display_handle, + ) + @staticmethod def _fit_single_print_header( verb: VerbosityEnum, diff --git a/src/easydiffraction/analysis/calculators/crysfml.py b/src/easydiffraction/analysis/calculators/crysfml.py index 85ff5779f..70231b02f 100644 --- a/src/easydiffraction/analysis/calculators/crysfml.py +++ b/src/easydiffraction/analysis/calculators/crysfml.py @@ -129,22 +129,40 @@ def calculate_pattern( crysfml_dict = self._crysfml_dict(structure, experiment) try: - if experiment.type.beam_mode.value == BeamModeEnum.CONSTANT_WAVELENGTH: - _, y = cfml_py_utilities.cw_powder_pattern_from_dict(crysfml_dict) - elif experiment.type.beam_mode.value == BeamModeEnum.TIME_OF_FLIGHT: - _, y = cfml_py_utilities.tof_powder_pattern_from_dict(crysfml_dict) - else: - print( - f'[CrysfmlCalculator] Error: ' - f'Unsupported beam mode {experiment.type.beam_mode.value}' - ) - return np.array([]) - y = self._adjust_pattern_length(y, len(experiment.data.x)) + y = self._calculate_adjusted_pattern(crysfml_dict, experiment) except KeyError: print('[CrysfmlCalculator] Error: No calculated data') y = [] return np.asarray(y) + def _calculate_adjusted_pattern( + self, + crysfml_dict: dict[str, object], + experiment: ExperimentBase, + ) -> list[float]: + """Calculate a Crysfml pattern and match experiment length.""" + y = self._calculate_raw_pattern(crysfml_dict, experiment) + if y is None: + return [] + return self._adjust_pattern_length(y, len(experiment.data.x)) + + @staticmethod + def _calculate_raw_pattern( + crysfml_dict: dict[str, object], + experiment: ExperimentBase, + ) -> list[float] | None: + """Calculate a Crysfml pattern without length adjustment.""" + if experiment.type.beam_mode.value == BeamModeEnum.CONSTANT_WAVELENGTH: + _, y = cfml_py_utilities.cw_powder_pattern_from_dict(crysfml_dict) + return y + if experiment.type.beam_mode.value == BeamModeEnum.TIME_OF_FLIGHT: + _, y = cfml_py_utilities.tof_powder_pattern_from_dict(crysfml_dict) + return y + print( + f'[CrysfmlCalculator] Error: Unsupported beam mode {experiment.type.beam_mode.value}' + ) + return None + def _adjust_pattern_length( # noqa: PLR6301 self, pattern: list[float], diff --git a/src/easydiffraction/analysis/calculators/pdffit.py b/src/easydiffraction/analysis/calculators/pdffit.py index ed0717536..a9c3b3697 100644 --- a/src/easydiffraction/analysis/calculators/pdffit.py +++ b/src/easydiffraction/analysis/calculators/pdffit.py @@ -19,17 +19,19 @@ from easydiffraction.datablocks.experiment.item.base import ExperimentBase from easydiffraction.datablocks.structure.item.base import Structure + +def _open_pdffit_devnull() -> object: + """Open a durable devnull handle for PDFfit stdout redirection.""" + with Path(os.devnull).open('w', encoding='utf-8') as tmp_devnull: + return os.fdopen(os.dup(tmp_devnull.fileno()), 'w') + + try: from diffpy.pdffit2 import PdfFit from diffpy.pdffit2 import redirect_stdout from diffpy.structure.parsers.p_cif import P_cif as pdffit_cif_parser - # Silence the C++ engine output while keeping the handle open - _pdffit_devnull: object | None - with Path(os.devnull).open('w', encoding='utf-8') as _tmp_devnull: - # Duplicate file descriptor so the handle remains - # valid after the context - _pdffit_devnull = os.fdopen(os.dup(_tmp_devnull.fileno()), 'w') + _pdffit_devnull = _open_pdffit_devnull() redirect_stdout(_pdffit_devnull) # TODO: Add the following print to debug mode # print("✅ 'pdffit' calculation engine is successfully imported.") diff --git a/src/easydiffraction/analysis/categories/__init__.py b/src/easydiffraction/analysis/categories/__init__.py index d6dcda46b..54fea54e5 100644 --- a/src/easydiffraction/analysis/categories/__init__.py +++ b/src/easydiffraction/analysis/categories/__init__.py @@ -11,7 +11,7 @@ from easydiffraction.analysis.categories.fit_parameter_correlations import FitParameterCorrelations from easydiffraction.analysis.categories.fit_parameters import FitParameterItem from easydiffraction.analysis.categories.fit_parameters import FitParameters -from easydiffraction.analysis.categories.fit_result import FitResult +from easydiffraction.analysis.categories.fit_result import FitResultBase from easydiffraction.analysis.categories.fitting_mode import FittingMode from easydiffraction.analysis.categories.fitting_mode import FittingModeFactory from easydiffraction.analysis.categories.joint_fit import JointFitCollection diff --git a/src/easydiffraction/analysis/categories/fit_result/__init__.py b/src/easydiffraction/analysis/categories/fit_result/__init__.py index 8578ab47b..6bc137ee8 100644 --- a/src/easydiffraction/analysis/categories/fit_result/__init__.py +++ b/src/easydiffraction/analysis/categories/fit_result/__init__.py @@ -1,5 +1,7 @@ # SPDX-FileCopyrightText: 2026 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause -from easydiffraction.analysis.categories.fit_result.default import FitResult +from easydiffraction.analysis.categories.fit_result.base import FitResultBase +from easydiffraction.analysis.categories.fit_result.bayesian import BayesianFitResult from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory +from easydiffraction.analysis.categories.fit_result.lsq import LeastSquaresFitResult diff --git a/src/easydiffraction/analysis/categories/fit_result/base.py b/src/easydiffraction/analysis/categories/fit_result/base.py new file mode 100644 index 000000000..c94a35b09 --- /dev/null +++ b/src/easydiffraction/analysis/categories/fit_result/base.py @@ -0,0 +1,153 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Common fit-result status category.""" + +from __future__ import annotations + +from typing import ClassVar + +from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory +from easydiffraction.analysis.enums import FitResultKindEnum +from easydiffraction.core.category import CategoryItem +from easydiffraction.core.metadata import TypeInfo +from easydiffraction.core.validation import AttributeSpec +from easydiffraction.core.validation import MembershipValidator +from easydiffraction.core.variable import BoolDescriptor +from easydiffraction.core.variable import GenericDescriptorBase +from easydiffraction.core.variable import IntegerDescriptor +from easydiffraction.core.variable import NumericDescriptor +from easydiffraction.core.variable import StringDescriptor +from easydiffraction.io.cif.handler import CifHandler + + +@FitResultFactory.register +class FitResultBase(CategoryItem): + """Common persisted fit-result status metadata.""" + + _category_code = 'fit_result' + _result_descriptor_names: ClassVar[tuple[str, ...]] = ( + 'success', + 'message', + 'iterations', + 'fitting_time', + 'reduced_chi_square', + 'result_kind', + ) + + type_info = TypeInfo( + tag='default', + description='Common persisted fit-result status metadata', + ) + + def __init__(self) -> None: + super().__init__() + self._result_kind = StringDescriptor( + name='result_kind', + description='Kind of the latest persisted fit-result projection.', + value_spec=AttributeSpec( + default=FitResultKindEnum.default().value, + validator=MembershipValidator( + allowed=[member.value for member in FitResultKindEnum] + ), + ), + cif_handler=CifHandler(names=['_fit_result.result_kind']), + ) + self._success = BoolDescriptor( + name='success', + description='Whether the latest persisted fit-result projection succeeded.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.success']), + ) + self._message = StringDescriptor( + name='message', + description='Status message for the latest persisted fit-result projection.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.message']), + ) + self._iterations = IntegerDescriptor( + name='iterations', + description='Iteration count for the latest persisted fit-result projection.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.iterations']), + ) + self._fitting_time = NumericDescriptor( + name='fitting_time', + description='Fitting time in seconds for the latest persisted projection.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.fitting_time']), + ) + self._reduced_chi_square = NumericDescriptor( + name='reduced_chi_square', + description='Reduced chi-square for the latest persisted projection.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.reduced_chi_square']), + ) + + @property + def result_kind(self) -> StringDescriptor: + """Kind of the latest persisted fit-result projection.""" + return self._result_kind + + def _set_result_kind(self, value: str) -> None: + """Set the result kind for internal callers.""" + self._result_kind.value = value + + @property + def success(self) -> BoolDescriptor: + """ + Whether the latest persisted fit-result projection succeeded. + """ + return self._success + + def _set_success(self, *, value: bool | None) -> None: + """Set the success flag for internal callers.""" + self._success.value = value + + @property + def message(self) -> StringDescriptor: + """ + Status message for the latest persisted fit-result projection. + """ + return self._message + + def _set_message(self, value: str | None) -> None: + """Set the fit-result message for internal callers.""" + self._message.value = value + + @property + def iterations(self) -> IntegerDescriptor: + """ + Iteration count for the latest persisted fit-result projection. + """ + return self._iterations + + def _set_iterations(self, value: int | None) -> None: + """Set the iteration count for internal callers.""" + self._iterations.value = value + + @property + def fitting_time(self) -> NumericDescriptor: + """ + Fitting time in seconds for the latest persisted projection. + """ + return self._fitting_time + + def _set_fitting_time(self, value: float | None) -> None: + """Set the fitting time for internal callers.""" + self._fitting_time.value = value + + @property + def reduced_chi_square(self) -> NumericDescriptor: + """Reduced chi-square for the latest persisted projection.""" + return self._reduced_chi_square + + def _set_reduced_chi_square(self, value: float | None) -> None: + """Set the reduced chi-square for internal callers.""" + self._reduced_chi_square.value = value + + def _reset_result_descriptors(self) -> None: + """Reset fit-result descriptors to declared defaults.""" + for name in self._result_descriptor_names: + descriptor = getattr(self, name) + if isinstance(descriptor, GenericDescriptorBase): + descriptor.value = descriptor._value_spec.default_value() diff --git a/src/easydiffraction/analysis/categories/fit_result/bayesian.py b/src/easydiffraction/analysis/categories/fit_result/bayesian.py new file mode 100644 index 000000000..91e1310f1 --- /dev/null +++ b/src/easydiffraction/analysis/categories/fit_result/bayesian.py @@ -0,0 +1,207 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Bayesian fit-result category.""" + +from __future__ import annotations + +from typing import ClassVar + +from easydiffraction.analysis.categories.fit_result.base import FitResultBase +from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory +from easydiffraction.core.metadata import TypeInfo +from easydiffraction.core.validation import AttributeSpec +from easydiffraction.core.variable import BoolDescriptor +from easydiffraction.core.variable import NumericDescriptor +from easydiffraction.core.variable import StringDescriptor +from easydiffraction.io.cif.handler import CifHandler + + +@FitResultFactory.register +class BayesianFitResult(FitResultBase): + """Persisted Bayesian fit-result metadata.""" + + type_info = TypeInfo( + tag='bayesian', + description='Persisted Bayesian fit-result metadata', + ) + _result_descriptor_names: ClassVar[tuple[str, ...]] = ( + *FitResultBase._result_descriptor_names, + 'point_estimate_name', + 'sampler_completed', + 'credible_interval_inner', + 'credible_interval_outer', + 'acceptance_rate_mean', + 'gelman_rubin_max', + 'effective_sample_size_min', + 'best_log_posterior', + ) + _expected_descriptor_names: ClassVar[tuple[str, ...]] = _result_descriptor_names + + def __init__(self) -> None: + super().__init__() + self._point_estimate_name = self._point_estimate_name_descriptor() + self._sampler_completed = self._sampler_completed_descriptor() + self._credible_interval_inner = self._credible_interval_inner_descriptor() + self._credible_interval_outer = self._credible_interval_outer_descriptor() + self._acceptance_rate_mean = self._acceptance_rate_mean_descriptor() + self._gelman_rubin_max = self._gelman_rubin_max_descriptor() + self._effective_sample_size_min = self._effective_sample_size_min_descriptor() + self._best_log_posterior = self._best_log_posterior_descriptor() + + @staticmethod + def _point_estimate_name_descriptor() -> StringDescriptor: + """Create a point-estimate-name descriptor.""" + return StringDescriptor( + name='point_estimate_name', + description='Committed sampled point estimate name.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.point_estimate_name']), + ) + + @staticmethod + def _sampler_completed_descriptor() -> BoolDescriptor: + """Create a sampler-completed descriptor.""" + return BoolDescriptor( + name='sampler_completed', + description='Whether the sampler completed and returned posterior data.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.sampler_completed']), + ) + + @staticmethod + def _credible_interval_inner_descriptor() -> NumericDescriptor: + """Create an inner credible-interval descriptor.""" + return NumericDescriptor( + name='credible_interval_inner', + description='Inner credible-interval level used in summaries.', + value_spec=AttributeSpec(default=0.68), + cif_handler=CifHandler(names=['_fit_result.credible_interval_inner']), + ) + + @staticmethod + def _credible_interval_outer_descriptor() -> NumericDescriptor: + """Create an outer credible-interval descriptor.""" + return NumericDescriptor( + name='credible_interval_outer', + description='Outer credible-interval level used in summaries.', + value_spec=AttributeSpec(default=0.95), + cif_handler=CifHandler(names=['_fit_result.credible_interval_outer']), + ) + + @staticmethod + def _acceptance_rate_mean_descriptor() -> NumericDescriptor: + """Create an acceptance-rate descriptor.""" + return NumericDescriptor( + name='acceptance_rate_mean', + description='Mean sampler acceptance rate.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.acceptance_rate_mean']), + ) + + @staticmethod + def _gelman_rubin_max_descriptor() -> NumericDescriptor: + """Create a Gelman-Rubin descriptor.""" + return NumericDescriptor( + name='gelman_rubin_max', + description='Maximum rank-normalized split R-hat.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.gelman_rubin_max']), + ) + + @staticmethod + def _effective_sample_size_min_descriptor() -> NumericDescriptor: + """Create an effective-sample-size descriptor.""" + return NumericDescriptor( + name='effective_sample_size_min', + description='Minimum bulk effective sample size.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.effective_sample_size_min']), + ) + + @staticmethod + def _best_log_posterior_descriptor() -> NumericDescriptor: + """Create a best-log-posterior descriptor.""" + return NumericDescriptor( + name='best_log_posterior', + description='Best log-posterior value found.', + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=['_fit_result.best_log_posterior']), + ) + + @property + def point_estimate_name(self) -> StringDescriptor: + """Committed sampled point estimate name.""" + return self._point_estimate_name + + def _set_point_estimate_name(self, value: str | None) -> None: + """Set the point-estimate name for internal callers.""" + self._point_estimate_name.value = value + + @property + def sampler_completed(self) -> BoolDescriptor: + """Whether the sampler completed and returned posterior data.""" + return self._sampler_completed + + def _set_sampler_completed(self, *, value: bool | None) -> None: + """Set the sampler-completed flag for internal callers.""" + self._sampler_completed.value = value + + @property + def credible_interval_inner(self) -> NumericDescriptor: + """Inner credible-interval level used in summaries.""" + return self._credible_interval_inner + + def _set_credible_interval_inner(self, value: float) -> None: + """ + Set the inner credible-interval level for internal callers. + """ + self._credible_interval_inner.value = value + + @property + def credible_interval_outer(self) -> NumericDescriptor: + """Outer credible-interval level used in summaries.""" + return self._credible_interval_outer + + def _set_credible_interval_outer(self, value: float) -> None: + """ + Set the outer credible-interval level for internal callers. + """ + self._credible_interval_outer.value = value + + @property + def acceptance_rate_mean(self) -> NumericDescriptor: + """Mean sampler acceptance rate.""" + return self._acceptance_rate_mean + + def _set_acceptance_rate_mean(self, value: float | None) -> None: + """Set the acceptance-rate mean for internal callers.""" + self._acceptance_rate_mean.value = value + + @property + def gelman_rubin_max(self) -> NumericDescriptor: + """Maximum rank-normalized split R-hat.""" + return self._gelman_rubin_max + + def _set_gelman_rubin_max(self, value: float | None) -> None: + """Set the maximum R-hat for internal callers.""" + self._gelman_rubin_max.value = value + + @property + def effective_sample_size_min(self) -> NumericDescriptor: + """Minimum bulk effective sample size.""" + return self._effective_sample_size_min + + def _set_effective_sample_size_min(self, value: float | None) -> None: + """ + Set the minimum effective sample size for internal callers. + """ + self._effective_sample_size_min.value = value + + @property + def best_log_posterior(self) -> NumericDescriptor: + """Best log-posterior value found.""" + return self._best_log_posterior + + def _set_best_log_posterior(self, value: float | None) -> None: + """Set the best log-posterior for internal callers.""" + self._best_log_posterior.value = value diff --git a/src/easydiffraction/analysis/categories/fit_result/default.py b/src/easydiffraction/analysis/categories/fit_result/default.py index 564df008e..38c500e1e 100644 --- a/src/easydiffraction/analysis/categories/fit_result/default.py +++ b/src/easydiffraction/analysis/categories/fit_result/default.py @@ -1,135 +1,9 @@ # SPDX-FileCopyrightText: 2026 EasyScience contributors # SPDX-License-Identifier: BSD-3-Clause -"""Common fit-result status category.""" +"""Default fit-result category import.""" from __future__ import annotations -from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory -from easydiffraction.analysis.enums import FitResultKindEnum -from easydiffraction.core.category import CategoryItem -from easydiffraction.core.metadata import TypeInfo -from easydiffraction.core.validation import AttributeSpec -from easydiffraction.core.validation import MembershipValidator -from easydiffraction.core.variable import BoolDescriptor -from easydiffraction.core.variable import IntegerDescriptor -from easydiffraction.core.variable import NumericDescriptor -from easydiffraction.core.variable import StringDescriptor -from easydiffraction.io.cif.handler import CifHandler +from easydiffraction.analysis.categories.fit_result.base import FitResultBase - -@FitResultFactory.register -class FitResult(CategoryItem): - """Common persisted fit-result status metadata.""" - - _category_code = 'fit_result' - - type_info = TypeInfo( - tag='default', - description='Common persisted fit-result status metadata', - ) - - def __init__(self) -> None: - super().__init__() - self._result_kind = StringDescriptor( - name='result_kind', - description='Kind of the latest persisted fit-result projection.', - value_spec=AttributeSpec( - default=FitResultKindEnum.default().value, - validator=MembershipValidator( - allowed=[member.value for member in FitResultKindEnum] - ), - ), - cif_handler=CifHandler(names=['_fit_result.result_kind']), - ) - self._success = BoolDescriptor( - name='success', - description='Whether the latest persisted fit-result projection succeeded.', - value_spec=AttributeSpec(default=False), - cif_handler=CifHandler(names=['_fit_result.success']), - ) - self._message = StringDescriptor( - name='message', - description='Status message for the latest persisted fit-result projection.', - value_spec=AttributeSpec(default=''), - cif_handler=CifHandler(names=['_fit_result.message']), - ) - self._iterations = IntegerDescriptor( - name='iterations', - description='Iteration count for the latest persisted fit-result projection.', - value_spec=AttributeSpec(default=0), - cif_handler=CifHandler(names=['_fit_result.iterations']), - ) - self._fitting_time = NumericDescriptor( - name='fitting_time', - description='Fitting time in seconds for the latest persisted projection.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_fit_result.fitting_time']), - ) - self._reduced_chi_square = NumericDescriptor( - name='reduced_chi_square', - description='Reduced chi-square for the latest persisted projection.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_fit_result.reduced_chi_square']), - ) - - @property - def result_kind(self) -> StringDescriptor: - """Kind of the latest persisted fit-result projection.""" - return self._result_kind - - def _set_result_kind(self, value: str) -> None: - """Set the result kind for internal callers.""" - self._result_kind.value = value - - @property - def success(self) -> BoolDescriptor: - """ - Whether the latest persisted fit-result projection succeeded. - """ - return self._success - - def _set_success(self, *, value: bool) -> None: - """Set the success flag for internal callers.""" - self._success.value = value - - @property - def message(self) -> StringDescriptor: - """ - Status message for the latest persisted fit-result projection. - """ - return self._message - - def _set_message(self, value: str) -> None: - """Set the fit-result message for internal callers.""" - self._message.value = value - - @property - def iterations(self) -> IntegerDescriptor: - """ - Iteration count for the latest persisted fit-result projection. - """ - return self._iterations - - def _set_iterations(self, value: int) -> None: - """Set the iteration count for internal callers.""" - self._iterations.value = value - - @property - def fitting_time(self) -> NumericDescriptor: - """ - Fitting time in seconds for the latest persisted projection. - """ - return self._fitting_time - - def _set_fitting_time(self, value: float | None) -> None: - """Set the fitting time for internal callers.""" - self._fitting_time.value = value - - @property - def reduced_chi_square(self) -> NumericDescriptor: - """Reduced chi-square for the latest persisted projection.""" - return self._reduced_chi_square - - def _set_reduced_chi_square(self, value: float | None) -> None: - """Set the reduced chi-square for internal callers.""" - self._reduced_chi_square.value = value +DEFAULT_FIT_RESULT_CLASS: type[FitResultBase] = FitResultBase diff --git a/src/easydiffraction/analysis/categories/fit_result/lsq.py b/src/easydiffraction/analysis/categories/fit_result/lsq.py new file mode 100644 index 000000000..9e8e31ec9 --- /dev/null +++ b/src/easydiffraction/analysis/categories/fit_result/lsq.py @@ -0,0 +1,220 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Least-squares fit-result category.""" + +from __future__ import annotations + +from typing import ClassVar + +from easydiffraction.analysis.categories.fit_result.base import FitResultBase +from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory +from easydiffraction.core.metadata import TypeInfo +from easydiffraction.core.validation import AttributeSpec +from easydiffraction.core.variable import BoolDescriptor +from easydiffraction.core.variable import NumericDescriptor +from easydiffraction.core.variable import StringDescriptor +from easydiffraction.io.cif.handler import CifHandler + + +@FitResultFactory.register +class LeastSquaresFitResult(FitResultBase): + """Persisted least-squares fit-result metadata.""" + + type_info = TypeInfo( + tag='least_squares', + description='Persisted least-squares fit-result metadata', + ) + _result_descriptor_names: ClassVar[tuple[str, ...]] = ( + *FitResultBase._result_descriptor_names, + 'objective_name', + 'objective_value', + 'n_data_points', + 'n_parameters', + 'n_free_parameters', + 'degrees_of_freedom', + 'covariance_available', + 'correlation_available', + 'exit_reason', + ) + _expected_descriptor_names: ClassVar[tuple[str, ...]] = _result_descriptor_names + + def __init__(self) -> None: + super().__init__() + self._objective_name = self._string_result_descriptor( + 'objective_name', + 'Objective function name for the persisted deterministic fit.', + ) + self._objective_value = self._numeric_result_descriptor( + 'objective_value', + 'Objective value for the persisted deterministic fit.', + ) + self._n_data_points = self._integer_result_descriptor( + 'n_data_points', + 'Number of data points used in the persisted deterministic fit.', + ) + self._n_parameters = self._integer_result_descriptor( + 'n_parameters', + 'Number of parameters considered in the persisted deterministic fit.', + ) + self._n_free_parameters = self._integer_result_descriptor( + 'n_free_parameters', + 'Number of free parameters in the persisted deterministic fit.', + ) + self._degrees_of_freedom = self._integer_result_descriptor( + 'degrees_of_freedom', + 'Degrees of freedom for the persisted deterministic fit.', + ) + self._covariance_available = self._bool_result_descriptor( + 'covariance_available', + 'Whether covariance was available for the persisted deterministic fit.', + ) + self._correlation_available = self._bool_result_descriptor( + 'correlation_available', + 'Whether correlations were available for the persisted deterministic fit.', + ) + self._exit_reason = self._string_result_descriptor( + 'exit_reason', + 'Backend exit reason for the persisted deterministic fit.', + ) + + @staticmethod + def _string_result_descriptor(name: str, description: str) -> StringDescriptor: + """ + Create a string-valued result descriptor. + + Defaults to ``None`` so a CIF written before any fit emits ``?`` + rather than an empty string, matching the shared "no fit" + semantics of numeric, integer-like, and bool result fields. + """ + return StringDescriptor( + name=name, + description=description, + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=[f'_fit_result.{name}']), + ) + + @staticmethod + def _numeric_result_descriptor( + name: str, + description: str, + *, + default: float | None = None, + allow_none: bool = True, + ) -> NumericDescriptor: + """Create a numeric result descriptor.""" + return NumericDescriptor( + name=name, + description=description, + value_spec=AttributeSpec(default=default, allow_none=allow_none), + cif_handler=CifHandler(names=[f'_fit_result.{name}']), + ) + + @staticmethod + def _integer_result_descriptor(name: str, description: str) -> NumericDescriptor: + """ + Create an integer-like numeric result descriptor. + + Defaults to ``None`` so a CIF written before any fit emits ``?`` + rather than ``0``; the scientist audience reads ``0`` as a + degenerate result, not as "no fit yet". + """ + return NumericDescriptor( + name=name, + description=description, + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=[f'_fit_result.{name}']), + ) + + @staticmethod + def _bool_result_descriptor(name: str, description: str) -> BoolDescriptor: + """ + Create a boolean result descriptor. + + Defaults to ``None`` so a CIF written before any fit emits ``?`` + rather than ``false``; ``false`` would otherwise read as an + active result instead of "no fit happened yet". + """ + return BoolDescriptor( + name=name, + description=description, + value_spec=AttributeSpec(default=None, allow_none=True), + cif_handler=CifHandler(names=[f'_fit_result.{name}']), + ) + + @property + def objective_name(self) -> StringDescriptor: + """ + Objective function name for the persisted deterministic fit. + """ + return self._objective_name + + def _set_objective_name(self, value: str | None) -> None: + self._objective_name.value = value + + @property + def objective_value(self) -> NumericDescriptor: + """Objective value for the persisted deterministic fit.""" + return self._objective_value + + def _set_objective_value(self, value: float | None) -> None: + self._objective_value.value = value + + @property + def n_data_points(self) -> NumericDescriptor: + """ + Number of data points used in the persisted deterministic fit. + """ + return self._n_data_points + + def _set_n_data_points(self, value: float | None) -> None: + self._n_data_points.value = value + + @property + def n_parameters(self) -> NumericDescriptor: + """Number of parameters in the persisted deterministic fit.""" + return self._n_parameters + + def _set_n_parameters(self, value: float | None) -> None: + self._n_parameters.value = value + + @property + def n_free_parameters(self) -> NumericDescriptor: + """ + Number of free parameters in the persisted deterministic fit. + """ + return self._n_free_parameters + + def _set_n_free_parameters(self, value: float | None) -> None: + self._n_free_parameters.value = value + + @property + def degrees_of_freedom(self) -> NumericDescriptor: + """Degrees of freedom for the persisted deterministic fit.""" + return self._degrees_of_freedom + + def _set_degrees_of_freedom(self, value: float | None) -> None: + self._degrees_of_freedom.value = value + + @property + def covariance_available(self) -> BoolDescriptor: + """Whether deterministic covariance was available.""" + return self._covariance_available + + def _set_covariance_available(self, *, value: bool | None) -> None: + self._covariance_available.value = value + + @property + def correlation_available(self) -> BoolDescriptor: + """Whether deterministic correlations were available.""" + return self._correlation_available + + def _set_correlation_available(self, *, value: bool | None) -> None: + self._correlation_available.value = value + + @property + def exit_reason(self) -> StringDescriptor: + """Backend exit reason for the persisted deterministic fit.""" + return self._exit_reason + + def _set_exit_reason(self, value: str | None) -> None: + self._exit_reason.value = value diff --git a/src/easydiffraction/analysis/categories/minimizer/base.py b/src/easydiffraction/analysis/categories/minimizer/base.py index 1e0a6c672..fb583964d 100644 --- a/src/easydiffraction/analysis/categories/minimizer/base.py +++ b/src/easydiffraction/analysis/categories/minimizer/base.py @@ -6,6 +6,7 @@ from typing import ClassVar +from easydiffraction.analysis.categories.fit_result.base import FitResultBase from easydiffraction.analysis.minimizers.enums import MinimizerTypeEnum from easydiffraction.core.category import CategoryItem from easydiffraction.core.switchable import SwitchableCategoryBase @@ -25,6 +26,7 @@ class MinimizerCategoryBase(CategoryItem, SwitchableCategoryBase): _native_key_map: ClassVar[dict[str, str]] = {} _setting_descriptor_names: ClassVar[tuple[str, ...]] = () _result_descriptor_names: ClassVar[tuple[str, ...]] = () + _fit_result_class: ClassVar[type[FitResultBase]] = FitResultBase def __init__(self) -> None: super().__init__() diff --git a/src/easydiffraction/analysis/categories/minimizer/bayesian_base.py b/src/easydiffraction/analysis/categories/minimizer/bayesian_base.py index 7e999b859..30ceafa50 100644 --- a/src/easydiffraction/analysis/categories/minimizer/bayesian_base.py +++ b/src/easydiffraction/analysis/categories/minimizer/bayesian_base.py @@ -6,14 +6,13 @@ from typing import ClassVar +from easydiffraction.analysis.categories.fit_result.bayesian import BayesianFitResult from easydiffraction.analysis.categories.minimizer.base import MinimizerCategoryBase from easydiffraction.analysis.minimizers.enums import InitializationMethodEnum from easydiffraction.core.validation import AttributeSpec from easydiffraction.core.validation import MembershipValidator from easydiffraction.core.validation import RangeValidator -from easydiffraction.core.variable import BoolDescriptor from easydiffraction.core.variable import IntegerDescriptor -from easydiffraction.core.variable import NumericDescriptor from easydiffraction.core.variable import StringDescriptor from easydiffraction.io.cif.handler import CifHandler @@ -21,6 +20,7 @@ class BayesianMinimizerBase(MinimizerCategoryBase): """Shared behavior for Bayesian minimizer categories.""" + _fit_result_class: ClassVar[type] = BayesianFitResult _expected_descriptor_names: ClassVar[tuple[str, ...]] = ( 'sampling_steps', 'burn_in_steps', @@ -29,15 +29,6 @@ class BayesianMinimizerBase(MinimizerCategoryBase): 'parallel_workers', 'initialization_method', 'random_seed', - 'runtime_seconds', - 'point_estimate_name', - 'sampler_completed', - 'credible_interval_inner', - 'credible_interval_outer', - 'acceptance_rate_mean', - 'gelman_rubin_max', - 'effective_sample_size_min', - 'best_log_posterior', ) _native_key_map: ClassVar[dict[str, str]] = { 'sampling_steps': 'steps', @@ -57,17 +48,7 @@ class BayesianMinimizerBase(MinimizerCategoryBase): 'initialization_method', 'random_seed', ) - _result_descriptor_names: ClassVar[tuple[str, ...]] = ( - 'runtime_seconds', - 'point_estimate_name', - 'sampler_completed', - 'credible_interval_inner', - 'credible_interval_outer', - 'acceptance_rate_mean', - 'gelman_rubin_max', - 'effective_sample_size_min', - 'best_log_posterior', - ) + _result_descriptor_names: ClassVar[tuple[str, ...]] = () _supported_initialization_methods: ClassVar[tuple[InitializationMethodEnum, ...]] = ( InitializationMethodEnum.LATIN_HYPERCUBE, ) @@ -158,96 +139,6 @@ def _random_seed_descriptor() -> IntegerDescriptor: cif_handler=CifHandler(names=['_minimizer.random_seed']), ) - @staticmethod - def _runtime_seconds_descriptor() -> NumericDescriptor: - """Create a runtime-seconds descriptor.""" - return NumericDescriptor( - name='runtime_seconds', - description='Wall time of the fit in seconds.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_minimizer.runtime_seconds']), - ) - - @staticmethod - def _point_estimate_name_descriptor() -> StringDescriptor: - """Create a point-estimate-name descriptor.""" - return StringDescriptor( - name='point_estimate_name', - description='Committed sampled point estimate name.', - value_spec=AttributeSpec(default='best_sample'), - cif_handler=CifHandler(names=['_minimizer.point_estimate_name']), - ) - - @staticmethod - def _sampler_completed_descriptor() -> BoolDescriptor: - """Create a sampler-completed descriptor.""" - return BoolDescriptor( - name='sampler_completed', - description='Whether the sampler completed and returned posterior data.', - value_spec=AttributeSpec(default=False), - cif_handler=CifHandler(names=['_minimizer.sampler_completed']), - ) - - @staticmethod - def _credible_interval_inner_descriptor() -> NumericDescriptor: - """Create an inner credible-interval descriptor.""" - return NumericDescriptor( - name='credible_interval_inner', - description='Inner credible-interval level used in summaries.', - value_spec=AttributeSpec(default=0.68), - cif_handler=CifHandler(names=['_minimizer.credible_interval_inner']), - ) - - @staticmethod - def _credible_interval_outer_descriptor() -> NumericDescriptor: - """Create an outer credible-interval descriptor.""" - return NumericDescriptor( - name='credible_interval_outer', - description='Outer credible-interval level used in summaries.', - value_spec=AttributeSpec(default=0.95), - cif_handler=CifHandler(names=['_minimizer.credible_interval_outer']), - ) - - @staticmethod - def _acceptance_rate_mean_descriptor() -> NumericDescriptor: - """Create an acceptance-rate descriptor.""" - return NumericDescriptor( - name='acceptance_rate_mean', - description='Mean sampler acceptance rate.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_minimizer.acceptance_rate_mean']), - ) - - @staticmethod - def _gelman_rubin_max_descriptor() -> NumericDescriptor: - """Create a Gelman-Rubin descriptor.""" - return NumericDescriptor( - name='gelman_rubin_max', - description='Maximum rank-normalized split R-hat.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_minimizer.gelman_rubin_max']), - ) - - @staticmethod - def _effective_sample_size_min_descriptor() -> NumericDescriptor: - """Create an effective-sample-size descriptor.""" - return NumericDescriptor( - name='effective_sample_size_min', - description='Minimum bulk effective sample size.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_minimizer.effective_sample_size_min']), - ) - - @staticmethod - def _best_log_posterior_descriptor() -> NumericDescriptor: - """Create a best-log-posterior descriptor.""" - return NumericDescriptor( - name='best_log_posterior', - description='Best log-posterior value found.', - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=['_minimizer.best_log_posterior']), - ) - @property def sampling_steps(self) -> IntegerDescriptor: """Total sampler iterations per chain.""" @@ -315,90 +206,3 @@ def random_seed(self) -> IntegerDescriptor: @random_seed.setter def random_seed(self, value: int | None) -> None: self._random_seed.value = value - - @property - def runtime_seconds(self) -> NumericDescriptor: - """Wall time of the fit in seconds.""" - return self._runtime_seconds - - def _set_runtime_seconds(self, value: float | None) -> None: - """Set the fit runtime for internal callers.""" - self._runtime_seconds.value = value - - @property - def point_estimate_name(self) -> StringDescriptor: - """Committed sampled point estimate name.""" - return self._point_estimate_name - - def _set_point_estimate_name(self, value: str) -> None: - """Set the point-estimate name for internal callers.""" - self._point_estimate_name.value = value - - @property - def sampler_completed(self) -> BoolDescriptor: - """Whether the sampler completed and returned posterior data.""" - return self._sampler_completed - - def _set_sampler_completed(self, *, value: bool) -> None: - """Set the sampler-completed flag for internal callers.""" - self._sampler_completed.value = value - - @property - def credible_interval_inner(self) -> NumericDescriptor: - """Inner credible-interval level used in summaries.""" - return self._credible_interval_inner - - def _set_credible_interval_inner(self, value: float) -> None: - """ - Set the inner credible-interval level for internal callers. - """ - self._credible_interval_inner.value = value - - @property - def credible_interval_outer(self) -> NumericDescriptor: - """Outer credible-interval level used in summaries.""" - return self._credible_interval_outer - - def _set_credible_interval_outer(self, value: float) -> None: - """ - Set the outer credible-interval level for internal callers. - """ - self._credible_interval_outer.value = value - - @property - def acceptance_rate_mean(self) -> NumericDescriptor: - """Mean sampler acceptance rate.""" - return self._acceptance_rate_mean - - def _set_acceptance_rate_mean(self, value: float | None) -> None: - """Set the acceptance-rate mean for internal callers.""" - self._acceptance_rate_mean.value = value - - @property - def gelman_rubin_max(self) -> NumericDescriptor: - """Maximum rank-normalized split R-hat.""" - return self._gelman_rubin_max - - def _set_gelman_rubin_max(self, value: float | None) -> None: - """Set the maximum R-hat for internal callers.""" - self._gelman_rubin_max.value = value - - @property - def effective_sample_size_min(self) -> NumericDescriptor: - """Minimum bulk effective sample size.""" - return self._effective_sample_size_min - - def _set_effective_sample_size_min(self, value: float | None) -> None: - """ - Set the minimum effective sample size for internal callers. - """ - self._effective_sample_size_min.value = value - - @property - def best_log_posterior(self) -> NumericDescriptor: - """Best log-posterior value found.""" - return self._best_log_posterior - - def _set_best_log_posterior(self, value: float | None) -> None: - """Set the best log-posterior for internal callers.""" - self._best_log_posterior.value = value diff --git a/src/easydiffraction/analysis/categories/minimizer/bumps_dream.py b/src/easydiffraction/analysis/categories/minimizer/bumps_dream.py index 2fb8caebd..13b844e86 100644 --- a/src/easydiffraction/analysis/categories/minimizer/bumps_dream.py +++ b/src/easydiffraction/analysis/categories/minimizer/bumps_dream.py @@ -20,7 +20,7 @@ @MinimizerCategoryFactory.register class BumpsDreamMinimizer(BayesianMinimizerBase): - """Persisted settings and results for the BUMPS DREAM minimizer.""" + """Persisted settings for the BUMPS DREAM minimizer.""" _engine_metadata: ClassVar[dict[str, str]] = { 'optimizer_name': 'bumps (dream)', @@ -41,12 +41,3 @@ def __init__(self) -> None: self._parallel_workers = self._parallel_workers_descriptor(DEFAULT_PARALLEL_WORKERS) self._initialization_method = self._initialization_method_descriptor() self._random_seed = self._random_seed_descriptor() - self._runtime_seconds = self._runtime_seconds_descriptor() - self._point_estimate_name = self._point_estimate_name_descriptor() - self._sampler_completed = self._sampler_completed_descriptor() - self._credible_interval_inner = self._credible_interval_inner_descriptor() - self._credible_interval_outer = self._credible_interval_outer_descriptor() - self._acceptance_rate_mean = self._acceptance_rate_mean_descriptor() - self._gelman_rubin_max = self._gelman_rubin_max_descriptor() - self._effective_sample_size_min = self._effective_sample_size_min_descriptor() - self._best_log_posterior = self._best_log_posterior_descriptor() diff --git a/src/easydiffraction/analysis/categories/minimizer/lsq_base.py b/src/easydiffraction/analysis/categories/minimizer/lsq_base.py index bbe72b0fa..60e2bc751 100644 --- a/src/easydiffraction/analysis/categories/minimizer/lsq_base.py +++ b/src/easydiffraction/analysis/categories/minimizer/lsq_base.py @@ -6,13 +6,11 @@ from typing import ClassVar +from easydiffraction.analysis.categories.fit_result.lsq import LeastSquaresFitResult from easydiffraction.analysis.categories.minimizer.base import MinimizerCategoryBase from easydiffraction.core.validation import AttributeSpec from easydiffraction.core.validation import RangeValidator -from easydiffraction.core.variable import BoolDescriptor from easydiffraction.core.variable import IntegerDescriptor -from easydiffraction.core.variable import NumericDescriptor -from easydiffraction.core.variable import StringDescriptor from easydiffraction.io.cif.handler import CifHandler @@ -20,85 +18,17 @@ class LeastSquaresMinimizerBase(MinimizerCategoryBase): """Shared behavior for least-squares minimizer categories.""" _default_max_iterations: ClassVar[int] = 1000 - _expected_descriptor_names: ClassVar[tuple[str, ...]] = ( - 'max_iterations', - 'objective_name', - 'objective_value', - 'n_data_points', - 'n_parameters', - 'n_free_parameters', - 'degrees_of_freedom', - 'covariance_available', - 'correlation_available', - 'runtime_seconds', - 'iterations_performed', - 'exit_reason', - ) + _fit_result_class: ClassVar[type] = LeastSquaresFitResult + _expected_descriptor_names: ClassVar[tuple[str, ...]] = ('max_iterations',) _native_key_map: ClassVar[dict[str, str]] = { 'max_iterations': 'max_iterations', } _setting_descriptor_names: ClassVar[tuple[str, ...]] = ('max_iterations',) - _result_descriptor_names: ClassVar[tuple[str, ...]] = ( - 'objective_name', - 'objective_value', - 'n_data_points', - 'n_parameters', - 'n_free_parameters', - 'degrees_of_freedom', - 'covariance_available', - 'correlation_available', - 'runtime_seconds', - 'iterations_performed', - 'exit_reason', - ) + _result_descriptor_names: ClassVar[tuple[str, ...]] = () def __init__(self) -> None: super().__init__() self._max_iterations = self._max_iterations_descriptor(self._default_max_iterations) - self._objective_name = self._string_result_descriptor( - 'objective_name', - 'Objective function name for the persisted deterministic fit.', - ) - self._objective_value = self._numeric_result_descriptor( - 'objective_value', - 'Objective value for the persisted deterministic fit.', - ) - self._n_data_points = self._integer_result_descriptor( - 'n_data_points', - 'Number of data points used in the persisted deterministic fit.', - ) - self._n_parameters = self._integer_result_descriptor( - 'n_parameters', - 'Number of parameters considered in the persisted deterministic fit.', - ) - self._n_free_parameters = self._integer_result_descriptor( - 'n_free_parameters', - 'Number of free parameters in the persisted deterministic fit.', - ) - self._degrees_of_freedom = self._integer_result_descriptor( - 'degrees_of_freedom', - 'Degrees of freedom for the persisted deterministic fit.', - ) - self._covariance_available = self._bool_result_descriptor( - 'covariance_available', - 'Whether covariance was available for the persisted deterministic fit.', - ) - self._correlation_available = self._bool_result_descriptor( - 'correlation_available', - 'Whether correlations were available for the persisted deterministic fit.', - ) - self._runtime_seconds = self._numeric_result_descriptor( - 'runtime_seconds', - 'Runtime in seconds for the persisted deterministic fit.', - ) - self._iterations_performed = self._integer_result_descriptor( - 'iterations_performed', - 'Number of iterations performed by the persisted deterministic fit.', - ) - self._exit_reason = self._string_result_descriptor( - 'exit_reason', - 'Backend exit reason for the persisted deterministic fit.', - ) @staticmethod def _max_iterations_descriptor(default: int) -> IntegerDescriptor: @@ -110,71 +40,6 @@ def _max_iterations_descriptor(default: int) -> IntegerDescriptor: cif_handler=CifHandler(names=['_minimizer.max_iterations']), ) - @staticmethod - def _string_result_descriptor(name: str, description: str) -> StringDescriptor: - """ - Create a string-valued result descriptor. - - Defaults to ``None`` so a CIF written before any fit emits ``?`` - rather than an empty string, matching the "no fit happened yet" - semantics shared with the numeric/integer/bool variants. - """ - return StringDescriptor( - name=name, - description=description, - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=[f'_minimizer.{name}']), - ) - - @staticmethod - def _numeric_result_descriptor( - name: str, - description: str, - *, - default: float | None = None, - allow_none: bool = True, - ) -> NumericDescriptor: - """Create a numeric result descriptor.""" - return NumericDescriptor( - name=name, - description=description, - value_spec=AttributeSpec(default=default, allow_none=allow_none), - cif_handler=CifHandler(names=[f'_minimizer.{name}']), - ) - - @staticmethod - def _integer_result_descriptor(name: str, description: str) -> NumericDescriptor: - """ - Create an integer-like numeric result descriptor. - - Defaults to ``None`` so a CIF written before any fit emits ``?`` - rather than ``0``; the scientist audience reads ``0`` as a - degenerate result, not as "no fit yet". - """ - return NumericDescriptor( - name=name, - description=description, - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=[f'_minimizer.{name}']), - ) - - @staticmethod - def _bool_result_descriptor(name: str, description: str) -> BoolDescriptor: - """ - Create a boolean result descriptor. - - Defaults to ``None`` so a CIF written before any fit emits ``?`` - rather than ``false``; ``false`` would otherwise read as - "covariance/correlation was actively unavailable" instead of "no - fit happened yet". - """ - return BoolDescriptor( - name=name, - description=description, - value_spec=AttributeSpec(default=None, allow_none=True), - cif_handler=CifHandler(names=[f'_minimizer.{name}']), - ) - @property def max_iterations(self) -> IntegerDescriptor: """Maximum solver iterations.""" @@ -183,97 +48,3 @@ def max_iterations(self) -> IntegerDescriptor: @max_iterations.setter def max_iterations(self, value: int) -> None: self._max_iterations.value = value - - @property - def objective_name(self) -> StringDescriptor: - """ - Objective function name for the persisted deterministic fit. - """ - return self._objective_name - - def _set_objective_name(self, value: str | None) -> None: - self._objective_name.value = value - - @property - def objective_value(self) -> NumericDescriptor: - """Objective value for the persisted deterministic fit.""" - return self._objective_value - - def _set_objective_value(self, value: float | None) -> None: - self._objective_value.value = value - - @property - def n_data_points(self) -> NumericDescriptor: - """ - Number of data points used in the persisted deterministic fit. - """ - return self._n_data_points - - def _set_n_data_points(self, value: float | None) -> None: - self._n_data_points.value = value - - @property - def n_parameters(self) -> NumericDescriptor: - """Number of parameters in the persisted deterministic fit.""" - return self._n_parameters - - def _set_n_parameters(self, value: float | None) -> None: - self._n_parameters.value = value - - @property - def n_free_parameters(self) -> NumericDescriptor: - """ - Number of free parameters in the persisted deterministic fit. - """ - return self._n_free_parameters - - def _set_n_free_parameters(self, value: float | None) -> None: - self._n_free_parameters.value = value - - @property - def degrees_of_freedom(self) -> NumericDescriptor: - """Degrees of freedom for the persisted deterministic fit.""" - return self._degrees_of_freedom - - def _set_degrees_of_freedom(self, value: float | None) -> None: - self._degrees_of_freedom.value = value - - @property - def covariance_available(self) -> BoolDescriptor: - """Whether deterministic covariance was available.""" - return self._covariance_available - - def _set_covariance_available(self, *, value: bool | None) -> None: - self._covariance_available.value = value - - @property - def correlation_available(self) -> BoolDescriptor: - """Whether deterministic correlations were available.""" - return self._correlation_available - - def _set_correlation_available(self, *, value: bool | None) -> None: - self._correlation_available.value = value - - @property - def runtime_seconds(self) -> NumericDescriptor: - """Runtime in seconds for the persisted deterministic fit.""" - return self._runtime_seconds - - def _set_runtime_seconds(self, value: float | None) -> None: - self._runtime_seconds.value = value - - @property - def iterations_performed(self) -> NumericDescriptor: - """Number of iterations performed by the deterministic fit.""" - return self._iterations_performed - - def _set_iterations_performed(self, value: float | None) -> None: - self._iterations_performed.value = value - - @property - def exit_reason(self) -> StringDescriptor: - """Backend exit reason for the persisted deterministic fit.""" - return self._exit_reason - - def _set_exit_reason(self, value: str | None) -> None: - self._exit_reason.value = value diff --git a/src/easydiffraction/analysis/sequential.py b/src/easydiffraction/analysis/sequential.py index 2c48f40fc..ce9fe54b2 100644 --- a/src/easydiffraction/analysis/sequential.py +++ b/src/easydiffraction/analysis/sequential.py @@ -94,83 +94,80 @@ def _fit_worker( ``reduced_chi_square``, ``iterations``, and per-parameter ``{unique_name}`` / ``{unique_name}.uncertainty``. """ + try: + return _fit_worker_success(template, data_path) + except ( + RuntimeError, + ValueError, + TypeError, + ArithmeticError, + KeyError, + IndexError, + OSError, + ) as exc: + return _fit_worker_error(data_path, exc) + + +def _fit_worker_success( + template: SequentialFitTemplate, + data_path: str, +) -> dict[str, Any]: + """Run one sequential-fit worker and return collected results.""" # Lazy import to avoid circular dependencies and keep the module # importable without heavy imports at top level. from easydiffraction.project.project import Project # noqa: PLC0415 result: dict[str, Any] = {'file_path': data_path} + Project._loading = True try: - # 1. Create a fresh, isolated project - Project._loading = True - try: - project = Project(name='_worker') - finally: - Project._loading = False - - # 2. Load structure from template CIF - project.structures.add_from_cif_str(template.structure_cif) - - # 3. Load experiment from template CIF - # (full config + template data) - project.experiments.add_from_cif_str(template.experiment_cif) - expt = next(iter(project.experiments.values())) - - # 4. Replace data from the new data path - expt._load_ascii_data_to_experiment(data_path) - - # 5. Extract diffrn metadata from the data file - result.update(_extract_diffrn_values(expt, data_path, template.diffrn_extract_rules)) - - # 6. Override parameter values from propagated starting values - _apply_param_overrides(project, template.initial_params) - - # 7. Set free flags - _set_free_params(project, template.free_param_unique_names) - - # 8. Apply constraints - if template.constraints_enabled and template.alias_defs: - _apply_constraints( - project, - template.alias_defs, - template.constraint_defs, - ) - - # 9. Set calculator and minimizer - # (internal, no console output) - from easydiffraction.analysis.fitting import Fitter # noqa: PLC0415 + project = Project(name='_worker') + finally: + Project._loading = False + + project.structures.add_from_cif_str(template.structure_cif) + project.experiments.add_from_cif_str(template.experiment_cif) + expt = next(iter(project.experiments.values())) + expt._load_ascii_data_to_experiment(data_path) + result.update(_extract_diffrn_values(expt, data_path, template.diffrn_extract_rules)) + + _apply_param_overrides(project, template.initial_params) + _set_free_params(project, template.free_param_unique_names) + if template.constraints_enabled and template.alias_defs: + _apply_constraints( + project, + template.alias_defs, + template.constraint_defs, + ) - expt._swap_calculator(template.calculator_tag, announce=False) - project.analysis.fitter = Fitter(template.minimizer_tag) + from easydiffraction.analysis.fitting import Fitter # noqa: PLC0415 - # 10. Fit - original_verbosity = project.verbosity.fit.value - project.verbosity.fit = 'silent' - try: - project.analysis.fit() - finally: - project.verbosity.fit = original_verbosity + expt._swap_calculator(template.calculator_tag, announce=False) + project.analysis.fitter = Fitter(template.minimizer_tag) - # 11. Collect results - result.update(_collect_results(project, template)) + original_verbosity = project.verbosity.fit.value + project.verbosity.fit = 'silent' + try: + project.analysis.fit() + finally: + project.verbosity.fit = original_verbosity - except ( - RuntimeError, - ValueError, - TypeError, - ArithmeticError, - KeyError, - IndexError, - OSError, - ) as exc: - result['success'] = False - result['reduced_chi_square'] = None - result['iterations'] = 0 - result['error'] = str(exc) + result.update(_collect_results(project, template)) return result +def _fit_worker_error(data_path: str, exc: Exception) -> dict[str, Any]: + """Return the standard failed worker result payload.""" + return { + 'file_path': data_path, + 'success': False, + 'reduced_chi_square': None, + 'iterations': 0, + 'error': str(exc), + } + + # ------------------------------------------------------------------ # Helper functions # ------------------------------------------------------------------ diff --git a/src/easydiffraction/core/singleton.py b/src/easydiffraction/core/singleton.py index 9f997e535..95295a9ed 100644 --- a/src/easydiffraction/core/singleton.py +++ b/src/easydiffraction/core/singleton.py @@ -112,28 +112,27 @@ def apply(self) -> None: for lhs_alias, rhs_expr in self._parsed_constraints: try: - # Evaluate the RHS expression using the current values - rhs_value = ae(rhs_expr) - - # asteval silently returns None for undefined names - # instead of raising an exception; errors are stored in - # ae.error. - if ae.error: - error_msgs = '; '.join(str(e.get_error()) for e in ae.error) - ae.error.clear() - log.error( - f"Constraint '{lhs_alias} = {rhs_expr}' could not be " - f'evaluated: {error_msgs}. ' - f'Make sure every name in the expression is registered ' - f'as an alias via analysis.aliases.create().', - exc_type=ValueError, - ) - - # Get the actual parameter object we want to update - param = self._alias_to_param[lhs_alias].param - - # Update its value and mark it as user constrained - param._set_value_user_constrained(rhs_value) - + self._apply_one_constraint(ae, lhs_alias, rhs_expr) except (ValueError, TypeError, ArithmeticError, KeyError, AttributeError) as error: print(f"Failed to apply constraint '{lhs_alias} = {rhs_expr}': {error}") + + def _apply_one_constraint( + self, + ae: Interpreter, + lhs_alias: str, + rhs_expr: str, + ) -> None: + """Evaluate and apply one parsed constraint expression.""" + rhs_value = ae(rhs_expr) + if ae.error: + error_msgs = '; '.join(str(e.get_error()) for e in ae.error) + ae.error.clear() + log.error( + f"Constraint '{lhs_alias} = {rhs_expr}' could not be " + f'evaluated: {error_msgs}. ' + f'Make sure every name in the expression is registered ' + f'as an alias via analysis.aliases.create().', + exc_type=ValueError, + ) + param = self._alias_to_param[lhs_alias].param + param._set_value_user_constrained(rhs_value) diff --git a/src/easydiffraction/display/plotting.py b/src/easydiffraction/display/plotting.py index cae993fd0..f96c812a4 100644 --- a/src/easydiffraction/display/plotting.py +++ b/src/easydiffraction/display/plotting.py @@ -3684,37 +3684,18 @@ def _evaluate_posterior_predictive_draws( dtype=float, ) original_uncertainties = [parameter.uncertainty for parameter in sampled_parameters] - predictive_draws: list[np.ndarray] = [] draw_indices = self._posterior_predictive_draw_indices(flattened_samples.shape[0]) try: - best_sample_prediction, x_values = self._evaluate_posterior_predictive_state( + evaluated = self._evaluate_posterior_predictive_draw_values( + draw_indices=draw_indices, + flattened_samples=flattened_samples, sampled_parameters=sampled_parameters, - values=original_values, experiment=experiment, expt_name=expt_name, x_axis=x_axis, + original_values=original_values, ) - if best_sample_prediction is None or x_values is None: - return None - - for index in draw_indices: - prediction, current_x = self._evaluate_posterior_predictive_state( - sampled_parameters=sampled_parameters, - values=flattened_samples[index], - experiment=experiment, - expt_name=expt_name, - x_axis=x_axis, - ) - if prediction is None or current_x is None: - return None - if ( - prediction.shape != best_sample_prediction.shape - or current_x.shape != x_values.shape - ): - log.warning('Posterior predictive draws returned inconsistent array shapes.') - return None - predictive_draws.append(prediction) finally: self._restore_posterior_predictive_parameters( sampled_parameters=sampled_parameters, @@ -3723,12 +3704,58 @@ def _evaluate_posterior_predictive_draws( expt_name=expt_name, ) + if evaluated is None: + return None + best_sample_prediction, x_values, predictive_draws = evaluated return ( np.asarray(best_sample_prediction, dtype=float), np.asarray(x_values, dtype=float), np.asarray(predictive_draws, dtype=float), ) + def _evaluate_posterior_predictive_draw_values( + self, + *, + draw_indices: np.ndarray, + flattened_samples: np.ndarray, + sampled_parameters: list[object], + experiment: object, + expt_name: str, + x_axis: object, + original_values: np.ndarray, + ) -> tuple[np.ndarray, np.ndarray, list[np.ndarray]] | None: + """Evaluate posterior predictive best sample and draw curves.""" + best_sample_prediction, x_values = self._evaluate_posterior_predictive_state( + sampled_parameters=sampled_parameters, + values=original_values, + experiment=experiment, + expt_name=expt_name, + x_axis=x_axis, + ) + if best_sample_prediction is None or x_values is None: + return None + + predictive_draws: list[np.ndarray] = [] + for index in draw_indices: + prediction, current_x = self._evaluate_posterior_predictive_state( + sampled_parameters=sampled_parameters, + values=flattened_samples[index], + experiment=experiment, + expt_name=expt_name, + x_axis=x_axis, + ) + if prediction is None or current_x is None: + return None + if ( + prediction.shape != best_sample_prediction.shape + or current_x.shape != x_values.shape + ): + log.warning('Posterior predictive draws returned inconsistent array shapes.') + return None + predictive_draws.append(prediction) + + return best_sample_prediction, x_values, predictive_draws + def _restore_posterior_predictive_parameters( self, *, diff --git a/src/easydiffraction/io/cif/serialize.py b/src/easydiffraction/io/cif/serialize.py index 929b2217c..fcd209d08 100644 --- a/src/easydiffraction/io/cif/serialize.py +++ b/src/easydiffraction/io/cif/serialize.py @@ -569,11 +569,7 @@ def analysis_from_cif(analysis: object, cif_text: str) -> None: def _has_persisted_fit_state_sections(block: object) -> bool: """Return True when any persisted fit-state section is present.""" - scalar_tags = ( - '_fit_result.result_kind', - '_minimizer.runtime_seconds', - '_minimizer.best_log_posterior', - ) + scalar_tags = ('_fit_result.result_kind',) loop_tags = ( '_fit_parameter.param_unique_name', '_fit_parameter_correlation.param_unique_name_i', @@ -610,6 +606,29 @@ def _restore_persisted_fit_state(analysis: object, block: object) -> None: ) +_MINIMIZER_OUTPUT_LEGACY_TAGS = ( + '_minimizer.objective_name', + '_minimizer.objective_value', + '_minimizer.n_data_points', + '_minimizer.n_parameters', + '_minimizer.n_free_parameters', + '_minimizer.degrees_of_freedom', + '_minimizer.covariance_available', + '_minimizer.correlation_available', + '_minimizer.runtime_seconds', + '_minimizer.iterations_performed', + '_minimizer.exit_reason', + '_minimizer.point_estimate_name', + '_minimizer.sampler_completed', + '_minimizer.credible_interval_inner', + '_minimizer.credible_interval_outer', + '_minimizer.acceptance_rate_mean', + '_minimizer.gelman_rubin_max', + '_minimizer.effective_sample_size_min', + '_minimizer.best_log_posterior', +) + + def _collect_legacy_analysis_tags(block: object) -> list[str]: """Return deprecated analysis CIF tags present in a block.""" legacy_tags: list[str] = [] @@ -617,6 +636,7 @@ def _collect_legacy_analysis_tags(block: object) -> list[str]: legacy_tags.append('_joint_fit_experiment.id') if _has_cif_loop(block, '_joint_fit_experiment.weight'): legacy_tags.append('_joint_fit_experiment.weight') + legacy_tags.extend(tag for tag in _MINIMIZER_OUTPUT_LEGACY_TAGS if _has_cif_value(block, tag)) return legacy_tags @@ -629,7 +649,8 @@ def _raise_for_legacy_analysis_tags(block: object) -> None: msg = ( 'Legacy analysis CIF tags are no longer supported: ' f'{legacy_tags}. Use _minimizer.type, _fitting_mode.type, ' - '_minimizer.*, _joint_fit.experiment_id, and _joint_fit.weight.' + '_minimizer.* for settings, _fit_result.* for fit outputs, ' + '_joint_fit.experiment_id, and _joint_fit.weight.' ) raise ValueError(msg) diff --git a/src/easydiffraction/project/display.py b/src/easydiffraction/project/display.py index 168d16773..5067e40d3 100644 --- a/src/easydiffraction/project/display.py +++ b/src/easydiffraction/project/display.py @@ -17,6 +17,7 @@ from easydiffraction.display.progress import ACTIVITY_LABEL_PROCESSING from easydiffraction.display.progress import activity_indicator from easydiffraction.utils.enums import VerbosityEnum +from easydiffraction.utils.logging import console from easydiffraction.utils.logging import log from easydiffraction.utils.utils import render_object_help from easydiffraction.utils.utils import render_table @@ -87,7 +88,39 @@ def __init__(self, project: Project) -> None: def results(self) -> None: """Show the latest fit summary and fitted parameter table.""" - self._project.analysis.display.fit_results() + analysis = self._project.analysis + if analysis.fit_results is None: + analysis.display.fit_results() + return + + self._show_settings_used() + analysis.display.fit_results() + + def _show_settings_used(self) -> None: + """Show minimizer settings used for the latest fit.""" + rows = self._settings_used_rows() + if not rows: + return + + console.paragraph('Settings used') + render_table( + columns_headers=['Name', 'Value', 'Description'], + columns_alignment=['left', 'right', 'left'], + columns_data=rows, + ) + + def _settings_used_rows(self) -> list[list[str]]: + """Return minimizer setting rows for display.""" + minimizer = self._project.analysis.minimizer + rows: list[list[str]] = [] + for name in minimizer._setting_descriptor_names: + descriptor = getattr(minimizer, name) + rows.append([ + name, + str(descriptor.value), + descriptor.description or '', + ]) + return rows def correlations( self, diff --git a/tests/integration/scipp-analysis/dream/test_package_import.py b/tests/integration/scipp-analysis/dream/test_package_import.py index 45b5bc95b..d17da2007 100644 --- a/tests/integration/scipp-analysis/dream/test_package_import.py +++ b/tests/integration/scipp-analysis/dream/test_package_import.py @@ -3,17 +3,16 @@ """Tests for verifying package installation and version consistency. -These tests check that easydiffraction and essdiffraction packages are -installed and are not older than the latest PyPI release. +These tests check that easydiffraction is installed and can be found on +PyPI. """ import importlib.metadata import pytest import requests -from packaging.version import Version -PACKAGE_NAMES = ['easydiffraction', 'essdiffraction'] +PACKAGE_NAMES = ['easydiffraction'] PYPI_URL = 'https://pypi.org/pypi/{}/json' @@ -37,16 +36,6 @@ def get_latest_version( return None -def get_base_version( - version_str: str, -) -> str: - """Extract MAJOR.MINOR.PATCH from version string, ignoring local - identifiers. - """ - v = Version(version_str) - return v.base_version - - @pytest.mark.parametrize('package_name', PACKAGE_NAMES) def test_package_import( package_name: str, diff --git a/tests/unit/easydiffraction/analysis/categories/fit_result/test_base.py b/tests/unit/easydiffraction/analysis/categories/fit_result/test_base.py new file mode 100644 index 000000000..410754e1b --- /dev/null +++ b/tests/unit/easydiffraction/analysis/categories/fit_result/test_base.py @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for common fit-result status metadata.""" + +from __future__ import annotations + + +def test_fit_result_base_defaults_unknown_result_values_to_none(): + from easydiffraction.analysis.categories.fit_result.base import FitResultBase + from easydiffraction.analysis.enums import FitResultKindEnum + + fit_result = FitResultBase() + + assert fit_result.result_kind.value == FitResultKindEnum.DETERMINISTIC.value + assert fit_result.success.value is None + assert fit_result.message.value is None + assert fit_result.iterations.value is None + assert fit_result.fitting_time.value is None + assert fit_result.reduced_chi_square.value is None + + +def test_fit_result_base_reset_restores_declared_defaults(): + from easydiffraction.analysis.categories.fit_result.base import FitResultBase + + fit_result = FitResultBase() + fit_result._set_result_kind('bayesian') + fit_result._set_success(value=True) + fit_result._set_message('Fit converged') + fit_result._set_iterations(14) + fit_result._set_fitting_time(0.25) + fit_result._set_reduced_chi_square(1.2) + + fit_result._reset_result_descriptors() + + assert fit_result.result_kind.value == 'deterministic' + assert fit_result.success.value is None + assert fit_result.message.value is None + assert fit_result.iterations.value is None + assert fit_result.fitting_time.value is None + assert fit_result.reduced_chi_square.value is None + + +def test_fit_result_base_serializes_unknown_values_as_cif_unknowns(): + from easydiffraction.analysis.categories.fit_result.base import FitResultBase + + cif_text = FitResultBase().as_cif + + assert '_fit_result.success ?' in cif_text + assert '_fit_result.message ?' in cif_text + assert '_fit_result.iterations ?' in cif_text diff --git a/tests/unit/easydiffraction/analysis/categories/fit_result/test_bayesian.py b/tests/unit/easydiffraction/analysis/categories/fit_result/test_bayesian.py new file mode 100644 index 000000000..40c1a2657 --- /dev/null +++ b/tests/unit/easydiffraction/analysis/categories/fit_result/test_bayesian.py @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for Bayesian fit-result metadata.""" + +from __future__ import annotations + +import gemmi + + +def test_bayesian_fit_result_defaults_unknown_outputs_to_none(): + from easydiffraction.analysis.categories.fit_result.bayesian import ( + BayesianFitResult, + ) + + fit_result = BayesianFitResult() + + assert fit_result.point_estimate_name.value is None + assert fit_result.sampler_completed.value is None + assert fit_result.credible_interval_inner.value == 0.68 + assert fit_result.credible_interval_outer.value == 0.95 + assert fit_result.acceptance_rate_mean.value is None + assert fit_result.gelman_rubin_max.value is None + assert fit_result.effective_sample_size_min.value is None + assert fit_result.best_log_posterior.value is None + + +def test_bayesian_fit_result_round_trips_cif_outputs(): + from easydiffraction.analysis.categories.fit_result.bayesian import ( + BayesianFitResult, + ) + + fit_result = BayesianFitResult() + fit_result._set_point_estimate_name('posterior_median') + fit_result._set_sampler_completed(value=True) + fit_result._set_credible_interval_inner(0.5) + fit_result._set_credible_interval_outer(0.9) + fit_result._set_acceptance_rate_mean(0.42) + fit_result._set_gelman_rubin_max(1.01) + fit_result._set_effective_sample_size_min(80) + fit_result._set_best_log_posterior(-12.5) + + restored = BayesianFitResult() + restored.from_cif(gemmi.cif.read_string(f'data_fit_result\n{fit_result.as_cif}').sole_block()) + + assert restored.point_estimate_name.value == 'posterior_median' + assert restored.sampler_completed.value is True + assert restored.credible_interval_inner.value == 0.5 + assert restored.credible_interval_outer.value == 0.9 + assert restored.acceptance_rate_mean.value == 0.42 + assert restored.gelman_rubin_max.value == 1.01 + assert restored.effective_sample_size_min.value == 80 + assert restored.best_log_posterior.value == -12.5 diff --git a/tests/unit/easydiffraction/analysis/categories/fit_result/test_factory.py b/tests/unit/easydiffraction/analysis/categories/fit_result/test_factory.py new file mode 100644 index 000000000..7352301fb --- /dev/null +++ b/tests/unit/easydiffraction/analysis/categories/fit_result/test_factory.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for fit-result factory registration and pairing.""" + +from __future__ import annotations + + +def test_fit_result_factory_creates_registered_family_classes(): + import easydiffraction.analysis.categories.fit_result # noqa: F401 + from easydiffraction.analysis.categories.fit_result.bayesian import ( + BayesianFitResult, + ) + from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory + from easydiffraction.analysis.categories.fit_result.lsq import ( + LeastSquaresFitResult, + ) + + assert isinstance(FitResultFactory.create('least_squares'), LeastSquaresFitResult) + assert isinstance(FitResultFactory.create('bayesian'), BayesianFitResult) + + +def test_minimizer_bases_declare_paired_fit_result_classes(): + from easydiffraction.analysis.categories.fit_result.bayesian import ( + BayesianFitResult, + ) + from easydiffraction.analysis.categories.fit_result.lsq import ( + LeastSquaresFitResult, + ) + from easydiffraction.analysis.categories.minimizer.bayesian_base import ( + BayesianMinimizerBase, + ) + from easydiffraction.analysis.categories.minimizer.lsq_base import ( + LeastSquaresMinimizerBase, + ) + + assert LeastSquaresMinimizerBase._fit_result_class is LeastSquaresFitResult + assert BayesianMinimizerBase._fit_result_class is BayesianFitResult diff --git a/tests/unit/easydiffraction/analysis/categories/fit_result/test_lsq.py b/tests/unit/easydiffraction/analysis/categories/fit_result/test_lsq.py new file mode 100644 index 000000000..bce6e3670 --- /dev/null +++ b/tests/unit/easydiffraction/analysis/categories/fit_result/test_lsq.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for least-squares fit-result metadata.""" + +from __future__ import annotations + +import gemmi + + +def test_least_squares_fit_result_defaults_unknown_outputs_to_none(): + from easydiffraction.analysis.categories.fit_result.lsq import ( + LeastSquaresFitResult, + ) + + fit_result = LeastSquaresFitResult() + + assert fit_result.objective_name.value is None + assert fit_result.objective_value.value is None + assert fit_result.n_data_points.value is None + assert fit_result.n_parameters.value is None + assert fit_result.n_free_parameters.value is None + assert fit_result.degrees_of_freedom.value is None + assert fit_result.covariance_available.value is None + assert fit_result.correlation_available.value is None + assert fit_result.exit_reason.value is None + + +def test_least_squares_fit_result_round_trips_cif_outputs(): + from easydiffraction.analysis.categories.fit_result.lsq import ( + LeastSquaresFitResult, + ) + + fit_result = LeastSquaresFitResult() + fit_result._set_objective_name('chi-square') + fit_result._set_objective_value(1.25) + fit_result._set_n_data_points(120) + fit_result._set_n_parameters(4) + fit_result._set_n_free_parameters(3) + fit_result._set_degrees_of_freedom(117) + fit_result._set_covariance_available(value=True) + fit_result._set_correlation_available(value=False) + fit_result._set_exit_reason('converged') + + restored = LeastSquaresFitResult() + restored.from_cif(gemmi.cif.read_string(f'data_fit_result\n{fit_result.as_cif}').sole_block()) + + assert restored.objective_name.value == 'chi-square' + assert restored.objective_value.value == 1.25 + assert restored.n_data_points.value == 120 + assert restored.n_parameters.value == 4 + assert restored.n_free_parameters.value == 3 + assert restored.degrees_of_freedom.value == 117 + assert restored.covariance_available.value is True + assert restored.correlation_available.value is False + assert restored.exit_reason.value == 'converged' diff --git a/tests/unit/easydiffraction/analysis/categories/minimizer/test_lsq_base.py b/tests/unit/easydiffraction/analysis/categories/minimizer/test_lsq_base.py index 2dcf16563..011862282 100644 --- a/tests/unit/easydiffraction/analysis/categories/minimizer/test_lsq_base.py +++ b/tests/unit/easydiffraction/analysis/categories/minimizer/test_lsq_base.py @@ -7,32 +7,19 @@ import gemmi -def test_lsq_minimizer_defaults_and_result_reset(): +def test_lsq_minimizer_defaults_to_settings_only(): from easydiffraction.analysis.categories.minimizer.lmfit_leastsq import ( LmfitLeastsqMinimizer, ) minimizer = LmfitLeastsqMinimizer() - minimizer._set_objective_name('chi-square') - minimizer._set_objective_value(1.2) - minimizer._set_covariance_available(value=True) assert minimizer.max_iterations.value == 1000 - assert minimizer.objective_name.value == 'chi-square' + assert minimizer._setting_descriptor_names == ('max_iterations',) + assert minimizer._result_descriptor_names == () - minimizer._reset_result_descriptors() - # LSQ result descriptors default to None so a CIF written before - # any fit emits `?` rather than `''`, `0`, or `False`. See - # minimizer-category-consolidation_review-8 finding F6. - assert minimizer.objective_name.value is None - assert minimizer.objective_value.value is None - assert minimizer.covariance_available.value is None - assert minimizer.n_data_points.value is None - assert minimizer.iterations_performed.value is None - - -def test_lsq_minimizer_reads_cif_unknown_values_as_defaults(): +def test_lsq_minimizer_reads_cif_settings(): from easydiffraction.analysis.categories.minimizer.lmfit_leastsq import ( LmfitLeastsqMinimizer, ) @@ -40,13 +27,9 @@ def test_lsq_minimizer_reads_cif_unknown_values_as_defaults(): document = gemmi.cif.read_string( """data_minimizer _minimizer.max_iterations 42 -_minimizer.objective_name chi-square -_minimizer.objective_value ? """ ) minimizer = LmfitLeastsqMinimizer() minimizer.from_cif(document.sole_block()) assert minimizer.max_iterations.value == 42 - assert minimizer.objective_name.value == 'chi-square' - assert minimizer.objective_value.value is None diff --git a/tests/unit/easydiffraction/analysis/categories/test_fit_result.py b/tests/unit/easydiffraction/analysis/categories/test_fit_result.py index 4c9d869dc..580635c8c 100644 --- a/tests/unit/easydiffraction/analysis/categories/test_fit_result.py +++ b/tests/unit/easydiffraction/analysis/categories/test_fit_result.py @@ -4,10 +4,10 @@ def test_fit_result_factory_create(): - from easydiffraction.analysis.categories.fit_result.default import FitResult + from easydiffraction.analysis.categories.fit_result.base import FitResultBase from easydiffraction.analysis.categories.fit_result.factory import FitResultFactory fit_result = FitResultFactory.create('default') assert FitResultFactory.default_tag() == 'default' - assert isinstance(fit_result, FitResult) + assert isinstance(fit_result, FitResultBase) diff --git a/tests/unit/easydiffraction/analysis/categories/test_fit_state.py b/tests/unit/easydiffraction/analysis/categories/test_fit_state.py index a26d4435b..a3b4fd7cc 100644 --- a/tests/unit/easydiffraction/analysis/categories/test_fit_state.py +++ b/tests/unit/easydiffraction/analysis/categories/test_fit_state.py @@ -36,9 +36,9 @@ def test_fit_parameter_collection_serializes_expected_tags_and_values(): def test_fit_result_serializes_expected_tags_and_enum_value(): - from easydiffraction.analysis.categories.fit_result.default import FitResult + from easydiffraction.analysis.categories.fit_result.base import FitResultBase - fit_result = FitResult() + fit_result = FitResultBase() fit_result._set_result_kind('bayesian') fit_result._set_success(value=True) fit_result._set_message('Sampler completed') @@ -138,7 +138,10 @@ def test_fit_parameter_posterior_summary_serializes_expected_tags(): assert summary.ess_bulk == 120 -def test_dream_minimizer_sampler_and_diagnostics_use_cif_fields(): +def test_dream_sampler_settings_and_diagnostics_use_split_cif_fields(): + from easydiffraction.analysis.categories.fit_result.bayesian import ( + BayesianFitResult, + ) from easydiffraction.analysis.categories.minimizer.bumps_dream import ( BumpsDreamMinimizer, ) @@ -148,15 +151,17 @@ def test_dream_minimizer_sampler_and_diagnostics_use_cif_fields(): minimizer.burn_in_steps = 20 minimizer.parallel_workers = 0 minimizer.random_seed = 123 - minimizer._set_gelman_rubin_max(1.01) - minimizer._set_effective_sample_size_min(80) + fit_result = BayesianFitResult() + fit_result._set_gelman_rubin_max(1.01) + fit_result._set_effective_sample_size_min(80) - cif_text = minimizer.as_cif + minimizer_cif_text = minimizer.as_cif + fit_result_cif_text = fit_result.as_cif - assert '_minimizer.sampling_steps 100' in cif_text - assert '_minimizer.parallel_workers 0' in cif_text - assert '_minimizer.random_seed 123' in cif_text - assert '_minimizer.effective_sample_size_min' in cif_text + assert '_minimizer.sampling_steps 100' in minimizer_cif_text + assert '_minimizer.parallel_workers 0' in minimizer_cif_text + assert '_minimizer.random_seed 123' in minimizer_cif_text + assert '_fit_result.effective_sample_size_min' in fit_result_cif_text def test_fit_parameter_posteriors_preserve_row_order_from_cif(): diff --git a/tests/unit/easydiffraction/io/test_results_sidecar.py b/tests/unit/easydiffraction/io/test_results_sidecar.py index 70dbef7d6..75dbe571e 100644 --- a/tests/unit/easydiffraction/io/test_results_sidecar.py +++ b/tests/unit/easydiffraction/io/test_results_sidecar.py @@ -17,9 +17,11 @@ def _analysis_with_sidecar_payload( include_pair: bool = True, include_predictive: bool = True, ) -> object: - from easydiffraction.analysis.categories.fit_result.default import FitResult + from easydiffraction.analysis.categories.fit_result.bayesian import ( + BayesianFitResult, + ) - fit_result = FitResult() + fit_result = BayesianFitResult() fit_result._set_result_kind('bayesian') posterior_samples = None diff --git a/tests/unit/easydiffraction/project/test_display.py b/tests/unit/easydiffraction/project/test_display.py index 23de62edb..f80d243e4 100644 --- a/tests/unit/easydiffraction/project/test_display.py +++ b/tests/unit/easydiffraction/project/test_display.py @@ -54,6 +54,7 @@ def _recorder(*args, **kwargs): analysis=SimpleNamespace( display=analysis_display, fit_results=SimpleNamespace(posterior_predictive={}), + minimizer=SimpleNamespace(_setting_descriptor_names=()), bayesian_result=SimpleNamespace( has_pair_cache=SimpleNamespace(value=False), has_posterior_predictive=SimpleNamespace(value=False), diff --git a/tests/unit/easydiffraction/project/test_project_load.py b/tests/unit/easydiffraction/project/test_project_load.py index c726172f4..cfbd7652d 100644 --- a/tests/unit/easydiffraction/project/test_project_load.py +++ b/tests/unit/easydiffraction/project/test_project_load.py @@ -211,14 +211,14 @@ def test_round_trips_persisted_deterministic_correlation_summary_for_reloaded_di original.analysis.fit_result._set_iterations(21) original.analysis.fit_result._set_fitting_time(0.74) original.analysis.fit_result._set_reduced_chi_square(1.031) - original.analysis.minimizer._set_objective_name('chi-square') - original.analysis.minimizer._set_objective_value(1.031) - original.analysis.minimizer._set_n_data_points(120) - original.analysis.minimizer._set_n_parameters(2) - original.analysis.minimizer._set_n_free_parameters(2) - original.analysis.minimizer._set_degrees_of_freedom(118) - original.analysis.minimizer._set_covariance_available(value=False) - original.analysis.minimizer._set_correlation_available(value=True) + original.analysis.fit_result._set_objective_name('chi-square') + original.analysis.fit_result._set_objective_value(1.031) + original.analysis.fit_result._set_n_data_points(120) + original.analysis.fit_result._set_n_parameters(2) + original.analysis.fit_result._set_n_free_parameters(2) + original.analysis.fit_result._set_degrees_of_freedom(118) + original.analysis.fit_result._set_covariance_available(value=False) + original.analysis.fit_result._set_correlation_available(value=True) original.analysis.fit_parameter_correlations.create( source_kind='deterministic', param_unique_name_i=parameter_b.unique_name,