fix: support linopy 0.9.0 - #758
Conversation
…te() linopy 0.8 added Constraint.update() and 0.9 deprecates assignment to Constraint.lhs. flixopt escalates DeprecationWarning from its own package to an error, so every effect-bearing model failed to build on linopy 0.9. Add modeling._set_constraint_lhs(), which dispatches to Constraint.update() where it exists and to the .lhs setter on linopy < 0.8, and route the six in-place LHS mutations (share accumulators, bus imbalance, transmission absolute losses) through it. Term order is unchanged on every version. Widen the linopy pin to >=0.5.1,<0.10.
Both tests pinned one arbitrary vertex of a degenerate optimal face, so they flipped when linopy 0.9 changed internal ordering and HiGHS landed on the mirrored optimum. The objective and all flow rates were unchanged. test_storage_cyclic_charge_discharge_pattern: the two clusters carry identical data, so which one gets which absolute SOC offset is arbitrary (any level in [50, 100] is optimal). Assert the SOC deltas and the cyclic wrap instead. test_expanded_storage: gas price and boiler efficiency are flat, so storage earns nothing and every cycling depth -- including none -- is optimal. The old `nansum(charge_state) > 0` passed on linopy 0.7 only on ~1e-5 noise.
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Makes flixopt build and solve on linopy 0.9.0, and widens the pin to
>=0.5.1,<0.10.What broke
linopy 0.9 deprecates assignment to
Constraint.lhsin favour ofConstraint.update(lhs=...). flixopt escalatesDeprecationWarningfrom its own package to an error (error::DeprecationWarning:flixopt), so the accumulator inShareAllocationModeltook down every effect-bearing model at build time — 668 of 1261 tests failed, all from this single root cause.The fix
modeling._set_constraint_lhs()dispatches on whichever API the installed linopy provides:Constraint.update(lhs=...)(the.lhssetter is deprecated there).lhssetter (update()does not exist, and the setter is not deprecated)All six in-place LHS mutations route through it: the share accumulators in
features.py, the bus imbalance term inelements.py, and transmission absolute losses incomponents.py. Term order is unchanged on every version, so the existing white-box constraint tests still hold.Two tests were pinning degenerate optima
Both flipped under 0.9 because its internal reordering makes HiGHS land on a different vertex of the same optimal face. The objective and all flow rates are identical — only the arbitrary part of the solution moved. This is the degeneracy already diagnosed in #733, not a semantics change.
test_storage_cyclic_charge_discharge_pattern— the two clusters carry identical data, so which one gets which absolute SOC offset is arbitrary (any level in[50, 100]is optimal). Now asserts the SOC deltas and the cyclic wrap, which are uniquely determined.test_expanded_storage— gas price and boiler efficiency are flat, so storage earns nothing and every cycling depth (including none) is optimal. The oldnansum(charge_state) > 0passed on linopy 0.7 only on ~1e-5 numerical noise.Verification
Full suite minus
slow, 1261 tests:0.5.1 fails solely through the known incompatibility between old linopy and xarray >= 2026 —
TypeError: Passing a Dataset as data_varsraised insidelinopy/expressions.py, before any flixopt code runs. Paired with xarray 2025.7.1 it passes, so the>=0.5.1lower bound remains honest.Not run:
slowtests, notebooks, examples.Relationship to other PRs
_set_constraint_lhsof the same design; this PR deliberately reuses its name and shape to keep the conflict minimal. That PR's merge gate was "after linopy v0.9.0 is released" — 0.9.0 is now on PyPI, so if you'd rather merge fix: compatibility with linopy v1 arithmetic semantics #729 first, this PR reduces to the pin bump plus the two test changes.Pre-existing issue noticed, not addressed here
The expanded clustered
charge_statecan far exceed capacity (241 against a cap of 50 under gurobi), and the clusteredcharge_stategoes negative. Both behave identically on linopy 0.7.0, so they predate this work — plausibly the same root as #735 (initial_charge_stateignored in cycliccluster_mode).🤖 Generated with Claude Code