diff --git a/pyomo/solvers/plugins/solvers/KNITROAMPL.py b/pyomo/solvers/plugins/solvers/KNITROAMPL.py index 930876d7ac6..0d01418b4c2 100644 --- a/pyomo/solvers/plugins/solvers/KNITROAMPL.py +++ b/pyomo/solvers/plugins/solvers/KNITROAMPL.py @@ -7,6 +7,7 @@ # software. This software is distributed under the 3-clause BSD License. # ____________________________________________________________________________________ import logging +import os from pyomo.common import Executable from pyomo.common.collections import Bunch @@ -64,17 +65,25 @@ def __init__(self, **kwds): self._capabilities.sos2 = False def _default_executable(self): - try: - # If knitro Python package is available, use the executable it contains - import knitro + executable = None + knitrodir = os.environ.get('KNITRODIR') + if knitrodir: + knitroampl_path = pathlib.Path(knitrodir) / 'knitroampl' / 'knitroampl' + executable = Executable(str(knitroampl_path)) + if not executable: + try: + # If knitro Python package is available, use the executable it contains + import knitro - package_knitroampl_path = ( - pathlib.Path(knitro.__file__).resolve().parent - / 'knitroampl' - / 'knitroampl' - ) - executable = Executable(str(package_knitroampl_path)) - except ModuleNotFoundError: + package_knitroampl_path = ( + pathlib.Path(knitro.__file__).resolve().parent + / 'knitroampl' + / 'knitroampl' + ) + executable = Executable(str(package_knitroampl_path)) + except ModuleNotFoundError: + pass + if not executable: # Otherwise, search usual path list executable = Executable('knitroampl') if not executable: diff --git a/pyomo/solvers/tests/checks/test_KNITROAMPL.py b/pyomo/solvers/tests/checks/test_KNITROAMPL.py index d9ab6f0cdb5..c762bdb88a8 100644 --- a/pyomo/solvers/tests/checks/test_KNITROAMPL.py +++ b/pyomo/solvers/tests/checks/test_KNITROAMPL.py @@ -7,7 +7,10 @@ # software. This software is distributed under the 3-clause BSD License. # ____________________________________________________________________________________ +import os + from pyomo.common import unittest +from pyomo.common.tempfiles import TempfileManager from pyomo.environ import ( ConcreteModel, Var, @@ -23,6 +26,32 @@ knitroampl_available = SolverFactory('knitroampl').available(False) +class TestKNITROAMPLDefaultExecutable(unittest.TestCase): + def test_default_executable_from_KNITRODIR(self): + with TempfileManager.new_context() as tempfile: + knitrodir = tempfile.create_tempdir() + exe = os.path.join(knitrodir, 'knitroampl', 'knitroampl') + # This makes a fake executable with the correct permissions + # so KNITRO actually recognizes it + os.mkdir(os.path.dirname(exe)) + with open(exe, 'w'): + pass + os.chmod(exe, 0o755) + + orig = os.environ.get('KNITRODIR') + os.environ['KNITRODIR'] = knitrodir + try: + opt = SolverFactory('knitroampl') + self.assertEqual( + os.path.realpath(opt._default_executable()), os.path.realpath(exe) + ) + finally: + if orig is None: + del os.environ['KNITRODIR'] + else: + os.environ['KNITRODIR'] = orig + + @unittest.skipIf(not knitroampl_available, "The 'knitroampl' command is not available") @unittest.pytest.mark.solver("knitroampl") class TestKNITROAMPLInterface(unittest.TestCase):