Skip to content

Commit d5a82a2

Browse files
FBumannclaudeFabianHofmann
authored
refactor: move alignment code to linopy/alignment.py; restructure tests (#742)
* refactor: move conversion/broadcasting/alignment code to linopy/alignment.py Pure move, no behavior change. The new module owns the seam between user input and linopy's labelled arrays: - coords parsing: _coords_to_dict, _as_index, _as_multiindex - conversion: get_from_iterable, pandas_to_dataarray, numpy_to_dataarray, _named_pandas_to_dataarray, fill_missing_coords, as_dataarray - MultiIndex projection: _LevelProjection, _project_onto_multiindex_levels, _warn_implicit_projections - broadcasting: _broadcast_to_coords, broadcast_to_coords - validation: validate_alignment - symmetric alignment: align common.py keeps the general utilities (formatting, label indexes, polars helpers, decorators). Importers (model, expressions, variables, __init__, tests) updated; no re-exports. Follow-up requested by @FabianHofmann in #732. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: restructure alignment tests into test_alignment.py One class per concept in linopy.alignment, mirroring the module's public surface: - TestAsDataarrayFrom{Pandas,Numpy,Scalar,DataArray} + MultiIndexCoords - TestCoordsToDict (the coords-entry naming rules) - TestBroadcastToCoords (strict=False mechanics) - TestMultiIndexProjection (projection values, deprecation warnings, coverage gaps — the legacy/v1 fork point for #717) - TestStrictMode (strict=True contract) - TestValidateAlignment - TestAlign Shared fixtures (mi_index / mi_coords / by_level1) replace the repeated MultiIndex setup; the pandas dims-naming and numpy labeling tests are consolidated into parametrized tables. test_common.py keeps the utility tests. Full suite count unchanged (3202) — no coverage lost. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: close coverage gaps in alignment.py and the MI coords serialization alignment.py: 97% -> 99%. New edge-case tests: bare-string dims, 0-d arrays, fill_missing_coords type check, partially-named MI levels, gap detection with extra dims, gap-error truncation (>5 missing combinations). The two remaining uncovered lines are defensive branches for inputs outside the DimsLike contract (non-iterable dims). common.py: 88% -> 90%. The MultiIndex round-trip through coords_to_dataset_vars / coords_from_dataset (used by CSRConstraint) had zero coverage; now pinned. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Update test/test_alignment.py Co-authored-by: Fabian Hofmann <fab.hof@gmx.de> * Update test/test_alignment.py Co-authored-by: Fabian Hofmann <fab.hof@gmx.de> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Fabian Hofmann <fab.hof@gmx.de>
1 parent f4af3f1 commit d5a82a2

9 files changed

Lines changed: 1926 additions & 1823 deletions

File tree

doc/release_notes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Most users should keep calling ``model.solve(...)``. If you want more control, y
7474

7575
**Internal**
7676

77-
* ``linopy.common`` provides two DataArray conversion helpers: ``as_dataarray`` (convert only) and ``broadcast_to_coords`` (convert and broadcast against ``coords``). The latter takes ``strict`` (default ``True``): any mismatch with ``coords`` raises, naming ``label`` in the error; ``strict=False`` passes mismatches through for downstream xarray alignment.
77+
* New module ``linopy.alignment`` owns conversion, broadcasting, and alignment of user input against coordinates (moved out of ``linopy.common``): ``as_dataarray`` (convert only), ``broadcast_to_coords`` (convert and broadcast against ``coords``; ``strict=True`` by default raises on any mismatch, naming ``label`` in the error), ``validate_alignment``, and ``align``.
7878
* Each ``Solver`` subclass now overrides at most three hooks: ``_build_direct`` (build the native model), ``_run_direct`` (run it), and ``_run_file`` (run the solver on an LP/MPS file). File-only solvers (CBC, GLPK, CPLEX, SCIP, Knitro, COPT, MindOpt) only override ``_run_file``.
7979
* New ``ConstraintLabelIndex`` cached on ``Model.constraints`` (mirrors the existing ``Variables.label_index``); ``ConstraintBase`` gains ``active_labels()`` and a ``range`` property; ``CSRConstraint`` exposes ``coords``.
8080
* ``linopy.common`` gains ``values_to_lookup_array``; the legacy pandas-based helpers ``series_to_lookup_array`` and ``lookup_vals`` are removed.

linopy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# Note: For intercepting multiplications between xarray dataarrays, Variables and Expressions
1313
# we need to extend their __mul__ functions with a quick special case
1414
import linopy.monkey_patch_xarray # noqa: F401
15-
from linopy.common import align
15+
from linopy.alignment import align
1616
from linopy.config import options
1717
from linopy.constants import (
1818
EQUAL,

0 commit comments

Comments
 (0)