PyPSA / PyPSA/linopy

Audit CPLEX license-slot leaks

Open
#696 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug solver interface
Dominant language
Python
Stars
257
Forks
87
Avg merge
1d 3h
Merged PRs (30d)
29

Description

Follow-up from #695 (the broader audit triggered by #679).

After fixing the Mosek/COPT/MindOpt probe and _run_file leaks, two solvers remain unaudited because they have no explicit cleanup and rely on the wrapper's __del__:

CPLEX

In Cplex._run_file (linopy/solvers.py:1765):

m = cplex.Cplex()
...
return self._make_result(status, solution, solver_model=m)

m is stored as solver_model and is only ever cleared by Solver.close() setting it to None. The Cplex Python API recommends an explicit m.end() to release the model and the underlying license slot. Whether dropping the reference reliably calls end() via __del__ is library-internal — needs verification with a real CPLEX license.~

(xpress already covered, unfold to see original xpress section)

Xpress

In Xpress._run_file (linopy/solvers.py:2213) and Xpress._build_direct (linopy/solvers.py:2032):

m = xpress.problem()
m.read(...)
...
return self._solve(m, ...)

Same shape — m is the license-bearing object, stored as solver_model, no explicit m.reset() / equivalent.

Suggested approach
  • Register cleanup on _env_stack (e.g. self._env_stack.callback(m.end) for CPLEX) so close() releases the slot deterministically.
  • Verify with a real license that calling end() is idempotent and doesn't break the result accessors that other tests rely on.
Why this wasn't in #695

I don't have CPLEX or Xpress licensed locally and didn't want to ship a "fix" that only works in theory and might break working solver paths in CI. Tagging this so anyone with a CPLEX/Xpress license can pick it up.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in linopy/solvers.py at Cplex._run_file (around line 1765), Xpress._run_file (around line 2213), and Xpress._build_direct (around line 2032), then inspect Solver.close() and _env_stack handling. Verify explicit cleanup with real CPLEX or Xpress licenses, confirm it is idempotent, and ensure result accessors and existing solver paths still work.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.