Repository: coin-or/pulp

Issue:
Pulp is flashing empty log windows
### Details for the issue

#### What did you do?

I'm using `PULP_CBC_CMD` solver (`COIN_CMD` internally) for [my project (developing an scheduling app, it has GUI)](https://github.com/filtermap/pulp-scheduling/tree/a5688d8709ba59da37ad5cde69049871c66fbe69).

#### What did you expect to see?

Pulp shows no window on a GUI app when `msg=False` was passed to `PULP_CBC_CMD`.

```py
problem.solve(pulp.PULP_CBC_CMD(msg=False))
```

#### What did you see instead?

On Windows, Pulp is flashing empty log windows even when `msg=False` was passed to it.  
Such windows scared GUI app users.

According to [this discussion](https://groups.google.com/g/pulp-or-discuss/c/TKBBGF3vOo4/m/03tXAG-JAgAJ) and [a pull request](#116) below, just for `GLPK`, this problem was solved.

[Suppressing window popping up](https://groups.google.com/g/pulp-or-discuss/c/TKBBGF3vOo4/m/03tXAG-JAgAJ)

[Prevent flashing windows on Windows by oprypin · Pull Request #116 · coin-or/pulp](https://github.com/coin-or/pulp/pull/116)

But flashing windows problem still alives in `PULP_CBC_CMD` (and `COIN_CMD`).

### Useful extra information

I fixed the problem with this patch for my project.

[Comparing coin-or:master...filtermap:master · coin-or/pulp](https://github.com/coin-or/pulp/compare/master...filtermap:master)

I referred the pull request #116.

#### I'm opening this issue because:

- [x] PuLP has a bug
- [ ] PuLP needs a feature
- [ ] PuLP has another problem

#### I'm using PuLP on:

- [x] Windows: ( _version:_ 10 Pro )
- [ ] Linux: ( _distro:_ \_\_\_ )
- [ ] Mac OS: ( _version:_ \_\_\_ )
- [ ] Other: \_\_\_

#### I'm using python version:

- [ ] 2.7
- [ ] 3.4
- [ ] 3.5
- [ ] 3.6
- [x] Other: 3.9.9

#### I installed PuLP via:

- [x] pypi (pip install pulp)
- [ ] github (pip install -U git+https://github.com/coin-or/pulp)
- [ ] Other: \_\_\_

#### I have also:

- [x] Tried out the latest github version: https://github.com/coin-or/pulp
- [x] Searched for an existing similar issue: https://github.com/coin-or/pulp/issues?utf8=%E2%9C%93&q=is%3Aissue%20

[Suppressing window popping up](https://groups.google.com/g/pulp-or-discuss/c/TKBBGF3vOo4/m/03tXAG-JAgAJ)

I have found one discussion and one pull request #116.
But this pull request is just for GLPK, not for COIN.


Discussion:
CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/coin-or/pulp?pullRequest=534) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/coin-or/pulp?pullRequest=534) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/coin-or/pulp?pullRequest=534) it.</sub>

Patch:
diff --git a/pulp/apis/coin_api.py b/pulp/apis/coin_api.py
index da29f90..4622364 100644
--- a/pulp/apis/coin_api.py
+++ b/pulp/apis/coin_api.py
@@ -25,7 +25,7 @@
 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."""
 
 from .core import LpSolver_CMD, LpSolver, subprocess, PulpSolverError, clock, log
-from .core import cbc_path, pulp_cbc_path, coinMP_path, devnull
+from .core import cbc_path, pulp_cbc_path, coinMP_path, devnull, operating_system
 import os
 from .. import constants
 from tempfile import mktemp
@@ -191,7 +191,15 @@ class COIN_CMD(LpSolver_CMD):
         args = []
         args.append(self.path)
         args.extend(cmds[1:].split())
-        cbc = subprocess.Popen(args, stdout=pipe, stderr=pipe, stdin=devnull)
+        if not self.msg and operating_system == "win":
+            # Prevent flashing windows if used from a GUI application
+            startupinfo = subprocess.STARTUPINFO()
+            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+            cbc = subprocess.Popen(
+                args, stdout=pipe, stderr=pipe, stdin=devnull, startupinfo=startupinfo
+            )
+        else:
+            cbc = subprocess.Popen(args, stdout=pipe, stderr=pipe, stdin=devnull)
         if cbc.wait() != 0:
             if pipe:
                 pipe.close()
diff --git a/pulp/mps_lp.py b/pulp/mps_lp.py
index d9ddb11..e2fd055 100644
--- a/pulp/mps_lp.py
+++ b/pulp/mps_lp.py
@@ -63,7 +63,10 @@ def readMPS(path, sense, dropConsNames=False):
             if line[0] == "*":
                 continue
             if line[0] == "NAME":
-                parameters["name"] = line[1]
+                if len(line) > 1:
+                    parameters["name"] = line[1]
+                else:
+                    parameters["name"] = ""
                 continue
 
             # here we get the mode
@@ -183,6 +186,8 @@ def readMPSSetBounds(line, variable_dict):
 
 def readMPSSetRhs(line, constraintsDict):
     constraintsDict[line[1]]["constant"] = -float(line[2])
+    if len(line) == 5:  # read fields 5, 6
+        constraintsDict[line[3]]["constant"] = -float(line[4])
     return
 
 


Test patch:
diff --git a/pulp/tests/test_pulp.py b/pulp/tests/test_pulp.py
index 059de67..7404497 100644
--- a/pulp/tests/test_pulp.py
+++ b/pulp/tests/test_pulp.py
@@ -1,6 +1,9 @@
 """
 Tests for pulp
 """
+import os
+import tempfile
+
 from pulp.constants import PulpError
 from pulp.apis import *
 from pulp import LpVariable, LpProblem, lpSum, LpConstraintVar, LpFractionConstraint
@@ -9,6 +12,29 @@ from pulp.tests.bin_packing_problem import create_bin_packing_problem
 from pulp.utilities import makeDict
 import unittest
 
+# from: http://lpsolve.sourceforge.net/5.5/mps-format.htm
+EXAMPLE_MPS_RHS56 = """NAME          TESTPROB
+ROWS
+ N  COST
+ L  LIM1
+ G  LIM2
+ E  MYEQN
+COLUMNS
+    XONE      COST                 1   LIM1                 1
+    XONE      LIM2                 1
+    YTWO      COST                 4   LIM1                 1
+    YTWO      MYEQN               -1
+    ZTHREE    COST                 9   LIM2                 1
+    ZTHREE    MYEQN                1
+RHS
+    RHS1      LIM1                 5   LIM2                10
+    RHS1      MYEQN                7
+BOUNDS
+ UP BND1      XONE                 4
+ LO BND1      YTWO                -1
+ UP BND1      YTWO                 1
+ENDATA
+"""
 
 def dumpTestProblem(prob):
     try:
@@ -1042,6 +1068,26 @@ class BaseSolverTest:
             print("\t Testing reading MPS files - maximize")
             self.assertDictEqual(_dict1, _dict2)
 
+        def test_importMPS_noname(self):
+            name = self._testMethodName
+            prob = LpProblem("", const.LpMaximize)
+            x = LpVariable("x", 0, 4)
+            y = LpVariable("y", -1, 1)
+            z = LpVariable("z", 0)
+            w = LpVariable("w", 0)
+            prob += x + 4 * y + 9 * z, "obj"
+            prob += x + y <= 5, "c1"
+            prob += x + z >= 10, "c2"
+            prob += -y + z == 7, "c3"
+            prob += w >= 0, "c4"
+            filename = name + ".mps"
+            prob.writeMPS(filename)
+            _vars, prob2 = LpProblem.fromMPS(filename, sense=prob.sense)
+            _dict1 = getSortedDict(prob)
+            _dict2 = getSortedDict(prob2)
+            print("\t Testing reading MPS files - noname")
+            self.assertDictEqual(_dict1, _dict2)
+
         def test_importMPS_integer(self):
             name = self._testMethodName
             prob = LpProblem(name, const.LpMinimize)
@@ -1079,6 +1125,14 @@ class BaseSolverTest:
             print("\t Testing reading MPS files - binary variable, no constraint names")
             self.assertDictEqual(_dict1, _dict2)
 
+        def test_importMPS_RHS_fields56(self):
+            """Import MPS file with RHS definitions in fields 5 & 6."""
+            with tempfile.NamedTemporaryFile(delete=False) as h:
+                h.write(str.encode(EXAMPLE_MPS_RHS56))
+            _, problem = LpProblem.fromMPS(h.name)
+            os.unlink(h.name)
+            self.assertEqual(problem.constraints['LIM2'].constant, -10)
+
         # def test_importMPS_2(self):
         #     name = self._testMethodName
         #     # filename = name + ".mps"