From 26b8578319f808817c8ab28cba8b57beac19c1c5 Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Thu, 14 Nov 2024 19:40:29 +0100 Subject: [PATCH 1/6] add check for solver installation when initializing solver class instance --- linopy/solvers.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/linopy/solvers.py b/linopy/solvers.py index d478c5ac..565274cf 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -6,6 +6,7 @@ from __future__ import annotations import contextlib +import importlib.util import enum import io import logging @@ -301,6 +302,15 @@ def solve_problem( msg = "No problem file or model specified." raise ValueError(msg) + def check_solver_installation(self, package_name: str): + """ + Check for the solver to be initialized whether the package is installed or not. + Gives an ImportError if that is not the case. + """ + if importlib.util.find_spec(package_name) is None: + msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." + raise ImportError(msg) + class CBC(Solver): """ @@ -312,12 +322,20 @@ class CBC(Solver): options for the given solver """ + package_name = "coin-or-cbc" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) + def check_solver_installation(self, package_name): + if sub.run([which, "cbc"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode != 0: + msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." + raise ImportError(msg) + def solve_problem_from_model( self, model: Model, @@ -469,12 +487,20 @@ class GLPK(Solver): options for the given solver """ + package_name = "glpk" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) + def check_solver_installation(self, package_name): + if sub.run([which, "glpsol"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode != 0: + msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." + raise ImportError(msg) + def solve_problem_from_model( self, model: Model, @@ -651,10 +677,13 @@ class Highs(Solver): options for the given solver """ + package_name = "highspy" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -868,10 +897,13 @@ class Gurobi(Solver): options for the given solver """ + package_name = "gurobipy" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1100,10 +1132,13 @@ class Cplex(Solver): options for the given solver """ + package_name = "cplex" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1242,10 +1277,13 @@ class SCIP(Solver): options for the given solver """ + package_name = "pyscipopt" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1383,10 +1421,13 @@ class Xpress(Solver): options for the given solver """ + package_name = "xpress" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1528,10 +1569,13 @@ class Mosek(Solver): options for the given solver """ + package_name = "mosek" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1850,10 +1894,13 @@ class COPT(Solver): options for the given solver """ + package_name = "coptpy" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1992,10 +2039,13 @@ class MindOpt(Solver): options for the given solver """ + package_name = "mindoptpy" + def __init__( self, **solver_options, ): + self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( From acac41476814f12e59b964c5d2cfcb03785dac27 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:02:05 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- linopy/solvers.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/linopy/solvers.py b/linopy/solvers.py index 565274cf..b0a383f7 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -6,8 +6,8 @@ from __future__ import annotations import contextlib -import importlib.util import enum +import importlib.util import io import logging import os @@ -332,7 +332,10 @@ def __init__( super().__init__(**solver_options) def check_solver_installation(self, package_name): - if sub.run([which, "cbc"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode != 0: + if ( + sub.run([which, "cbc"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode + != 0 + ): msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." raise ImportError(msg) @@ -497,7 +500,10 @@ def __init__( super().__init__(**solver_options) def check_solver_installation(self, package_name): - if sub.run([which, "glpsol"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode != 0: + if ( + sub.run([which, "glpsol"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode + != 0 + ): msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." raise ImportError(msg) From e1dd620f180cff65183780e7f6e065622f7e8f8f Mon Sep 17 00:00:00 2001 From: daniel-rdt Date: Fri, 15 Nov 2024 10:43:53 +0100 Subject: [PATCH 3/6] refactor check for solver installation using available_solvers and enum --- linopy/solvers.py | 61 ++++++----------------------------------------- 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/linopy/solvers.py b/linopy/solvers.py index b0a383f7..e581e022 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -210,6 +210,11 @@ def __init__( ): self.solver_options = solver_options + # Check for the solver to be initialized whether the package is installed or not. + if self.get_name_str() not in available_solvers: + msg = f"Solver package for '{self.get_name_str()}' is not installed. Please install first to initialize solver instance." + raise ImportError(msg) + def safe_get_solution(self, status: Status, func: Callable) -> Solution: """ Get solution from function call, if status is unknown still try to run it. @@ -302,14 +307,8 @@ def solve_problem( msg = "No problem file or model specified." raise ValueError(msg) - def check_solver_installation(self, package_name: str): - """ - Check for the solver to be initialized whether the package is installed or not. - Gives an ImportError if that is not the case. - """ - if importlib.util.find_spec(package_name) is None: - msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." - raise ImportError(msg) + def get_name_str(self): + return SolverName[self.__class__.__name__].value class CBC(Solver): @@ -322,23 +321,12 @@ class CBC(Solver): options for the given solver """ - package_name = "coin-or-cbc" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) - def check_solver_installation(self, package_name): - if ( - sub.run([which, "cbc"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode - != 0 - ): - msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." - raise ImportError(msg) - def solve_problem_from_model( self, model: Model, @@ -490,23 +478,12 @@ class GLPK(Solver): options for the given solver """ - package_name = "glpk" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) - def check_solver_installation(self, package_name): - if ( - sub.run([which, "glpsol"], stdout=sub.DEVNULL, stderr=sub.STDOUT).returncode - != 0 - ): - msg = f"Solver package '{package_name}' is not installed. Please install first to initialize solver instance." - raise ImportError(msg) - def solve_problem_from_model( self, model: Model, @@ -683,13 +660,10 @@ class Highs(Solver): options for the given solver """ - package_name = "highspy" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -903,13 +877,10 @@ class Gurobi(Solver): options for the given solver """ - package_name = "gurobipy" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1138,13 +1109,10 @@ class Cplex(Solver): options for the given solver """ - package_name = "cplex" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1283,13 +1251,10 @@ class SCIP(Solver): options for the given solver """ - package_name = "pyscipopt" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1427,13 +1392,10 @@ class Xpress(Solver): options for the given solver """ - package_name = "xpress" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1575,13 +1537,10 @@ class Mosek(Solver): options for the given solver """ - package_name = "mosek" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -1900,13 +1859,10 @@ class COPT(Solver): options for the given solver """ - package_name = "coptpy" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( @@ -2045,13 +2001,10 @@ class MindOpt(Solver): options for the given solver """ - package_name = "mindoptpy" - def __init__( self, **solver_options, ): - self.check_solver_installation(self.package_name) super().__init__(**solver_options) def solve_problem_from_model( From 74a3431b9132750c1d5acf56a1bb3b72d4ebf27d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:44:17 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- linopy/solvers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/linopy/solvers.py b/linopy/solvers.py index e581e022..f073912c 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -7,7 +7,6 @@ import contextlib import enum -import importlib.util import io import logging import os From 30868c3f45a9ee7ae56b1be0c471059312c3f227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20R=C3=BCdt?= <117752024+daniel-rdt@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:20:40 +0100 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Lukas Trippe --- linopy/solvers.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linopy/solvers.py b/linopy/solvers.py index f073912c..cae49177 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -210,7 +210,7 @@ def __init__( self.solver_options = solver_options # Check for the solver to be initialized whether the package is installed or not. - if self.get_name_str() not in available_solvers: + if self.solver_name.value not in available_solvers: msg = f"Solver package for '{self.get_name_str()}' is not installed. Please install first to initialize solver instance." raise ImportError(msg) @@ -306,8 +306,9 @@ def solve_problem( msg = "No problem file or model specified." raise ValueError(msg) - def get_name_str(self): - return SolverName[self.__class__.__name__].value + @property + def solver_name(self) -> SolverName: + return SolverName[self.__class__.__name__] class CBC(Solver): From f7565619c1aab2040616f33eab5ef8fa9bffb2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20R=C3=BCdt?= <117752024+daniel-rdt@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:22:40 +0100 Subject: [PATCH 6/6] Apply suggestions from code review --- linopy/solvers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linopy/solvers.py b/linopy/solvers.py index cae49177..bad0e29a 100644 --- a/linopy/solvers.py +++ b/linopy/solvers.py @@ -211,7 +211,7 @@ def __init__( # Check for the solver to be initialized whether the package is installed or not. if self.solver_name.value not in available_solvers: - msg = f"Solver package for '{self.get_name_str()}' is not installed. Please install first to initialize solver instance." + msg = f"Solver package for '{self.solver_name.value}' is not installed. Please install first to initialize solver instance." raise ImportError(msg) def safe_get_solution(self, status: Status, func: Callable) -> Solution: