Skip to content

chore: update linopy requirement from <0.8,>=0.5.1 to >=0.5.1,<0.9#701

Open
dependabot[bot] wants to merge 2 commits into
mainfrom
dependabot/pip/linopy-gte-0.5.1-and-lt-0.9
Open

chore: update linopy requirement from <0.8,>=0.5.1 to >=0.5.1,<0.9#701
dependabot[bot] wants to merge 2 commits into
mainfrom
dependabot/pip/linopy-gte-0.5.1-and-lt-0.9

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jun 14, 2026

Copy link
Copy Markdown
Contributor

Updates the requirements on linopy to permit the latest version.

Release notes

Sourced from linopy's releases.

v0.8.0

What's Changed

New Contributors

Full Changelog: PyPSA/linopy@v0.7.0...v0.8.0

Changelog

Sourced from linopy's changelog.

Version 0.8.0

Features

Constraints — CSR-backed storage

  • Add CSRConstraint: a memory-efficient immutable constraint representation backed by scipy CSR sparse matrices. Up to 90% memory savings for constraints with many terms and 30–120× faster matrix generation for direct solver APIs.
  • Opt in globally via Model(freeze_constraints=True) or per-call via model.add_constraints(..., freeze=True).
  • Lossless conversion both ways with Constraint.freeze() / CSRConstraint.mutable().

Inspect the solver after solving

  • After model.solve(), the solver object stays available on model.solver. You can inspect it, reuse it, or release the underlying solver (and its license) by calling model.solver.close() or assigning model.solver = None. It is also released automatically when the model is garbage-collected.
  • New SolverReport on the result (result.report) reports runtime, MIP gap, dual (best) bound, and iteration counts. It is shown in repr(result) and currently populated by CBC, HiGHS, Gurobi, Knitro, and cuPDLPx.

Dualize LP models

  • New Model.dualize() constructs the LP dual as a standalone model, lifting finite variable bounds into explicit constraints so they are reflected in the dual. Dual variables are named after the primal constraints. Works for linear problems with linear objective and constraints. (PyPSA/linopy#626)

A new way to call a solver (advanced)

Most users should keep calling model.solve(...). If you want more control, you can now build the solver yourself and run it in two steps:

.. code-block:: python

solver = Solver.from_name("gurobi", model, io_api="direct", options=...)
result = solver.solve()
model.assign_result(result)  # write the solution back

Solver is now a dataclass, so writing a new solver backend is simpler — subclasses just override the hooks they need (_build_direct, _run_direct, _run_file).

Querying solver capabilities

  • Ask a solver class what it can do via Gurobi.supports(SolverFeature.MIP) (or any other SolverFeature). SolverFeature is importable from linopy.
  • linopy.solver_capabilities still works (re-exports SolverFeature and solver_supports), but the new SolverClass.supports(...) API is preferred.

Knowing which solvers you can actually use

  • linopy.available_solvers no longer tries to acquire licenses at import time, so importing linopy is faster and doesn't grab a license from solvers like Gurobi or Mosek. Note: membership now means "the package is installed", not "I have a working license" (see Breaking Changes). Call available_solvers.refresh() to re-scan. Same for quadratic_solvers.
  • New linopy.licensed_solvers: the subset of installed solvers that currently pass a license check. Handy in tests and for picking a solver at runtime.
  • New helpers for explicit license checks: linopy.solvers.check_solver_licenses("gurobi", "mosek"), Gurobi.license_status(), Gurobi.is_available(). They return a LicenseStatus dataclass (name, ok, message).

Constraints — indicator constraints

  • Add indicator constraints for solvers that support them. They are part of the unified constraints container: model.add_indicator_constraints returns a Constraint and the constraint is stored in model.constraints (filterable via model.constraints.indicator / model.constraints.regular), so it round-trips through netCDF and model.copy().

Compact multi-key grouping

  • LinearExpressionGroupby.sum gains a pandas-style observed parameter for grouping by a list of coordinate names: expr.groupby(["period", "season"]).sum(observed=True) keeps the result stacked over only the observed key combinations (a MultiIndex group dimension) instead of unstacking into one dimension per key, which materialises the dense cartesian grid. The default observed=False mirrors xarray. When the grid would be mostly fill values, a UserWarning points to observed=True.

... (truncated)

Commits
  • 0f62fd8 docs: cut release notes for v0.8.0 (#759)
  • 356fd45 feat: add m.dualize() (#626)
  • 6fb7bb7 feat: Add indicator constraints (#594)
  • 9eeb838 fix: Variable.fix() value alignment on named dimensions (#774)
  • 7eb8c9a fix(groupby): group by non-dimension coordinate names; fast multi-key groupin...
  • fdf613d test: use public API in assertions instead of internal .data (#760)
  • a539a6e fix: regression with tuple coords entries as xarray's (dim_name, values) (#766)
  • 076c16a fix(alignment): tolerate xarray without CoordinateValidationError (#762)
  • 6a5d748 docs: add AI-assisted contribution guide (#754)
  • a74724f refactor: return Self from SolverStatus.from_termination_condition (#746)
  • Additional commits viewable in compare view

@dependabot dependabot Bot added dependencies Updating or fixing dependencies python Pull requests that update python code labels Jun 14, 2026
@github-actions github-actions Bot enabled auto-merge (squash) June 14, 2026 12:43
Updates the requirements on [linopy](https://github.com/PyPSA/linopy) to permit the latest version.
- [Release notes](https://github.com/PyPSA/linopy/releases)
- [Changelog](https://github.com/PyPSA/linopy/blob/master/doc/release_notes.rst)
- [Commits](PyPSA/linopy@v0.5.1...v0.8.0)

---
updated-dependencies:
- dependency-name: linopy
  dependency-version: 0.8.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot force-pushed the dependabot/pip/linopy-gte-0.5.1-and-lt-0.9 branch from 216fc9b to 169d43e Compare June 14, 2026 13:16
FBumann added a commit that referenced this pull request Jun 14, 2026
linopy <0.8 stores the extra-timestep charge_state variable as
(time, cluster), because its 'time' coordinate (length n+1) conflicts
with the model's 'time' (length n), and 0.7 reorders the conflicting
dim to the front. Every other variable is (cluster, time). linopy >=0.8
makes coords the source of truth and is already consistent.

flixopt cannot control this from the bounds/coords it passes (0.7
reorders internally), so normalize in the solution property: transpose
'cluster' before 'time'. This is a no-op on linopy >=0.8 and for
non-clustered systems, and only touches the cluster/time axis ordering
(other dims and scalars are preserved via the ellipsis).

Also update the clustering test to access charge_state by label and
assert the now-deterministic (cluster, time) order. Unblocks the
linopy 0.8 bump in #701.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FBumann added a commit that referenced this pull request Jun 14, 2026
linopy <0.8 stores the extra-timestep charge_state variable as
(time, cluster), because its 'time' coordinate (length n+1) conflicts
with the model's 'time' (length n), and 0.7 reorders the conflicting
dim to the front. Every other variable is (cluster, time). linopy >=0.8
makes coords the source of truth and is already consistent.

flixopt cannot control this from the bounds/coords it passes (0.7
reorders internally), so normalize in the solution property: transpose
'cluster' before 'time'. This is a no-op on linopy >=0.8 and for
non-clustered systems, and only touches the cluster/time axis ordering
(other dims and scalars are preserved via the ellipsis).

Also update the clustering test to access charge_state by label and
assert the now-deterministic (cluster, time) order. Unblocks the
linopy 0.8 bump in #701.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FBumann added a commit that referenced this pull request Jun 14, 2026
linopy <0.8 stores the extra-timestep charge_state variable as
(time, cluster), because its 'time' coordinate (length n+1) conflicts
with the model's 'time' (length n), and 0.7 reorders the conflicting
dim to the front. Every other variable is (cluster, time). linopy >=0.8
makes coords the source of truth and is already consistent.

flixopt cannot control this from the bounds/coords it passes (0.7
reorders internally), so normalize in the solution property: transpose
'cluster' before 'time'. This is a no-op on linopy >=0.8 and for
non-clustered systems, and only touches the cluster/time axis ordering
(other dims and scalars are preserved via the ellipsis).

Also update the clustering test to access charge_state by label and
assert the now-deterministic (cluster, time) order. Unblocks the
linopy 0.8 bump in #701.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Updating or fixing dependencies python Pull requests that update python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant