Skip to content

Commit d05b049

Browse files
authored
Merge pull request #929 from scipopt/243-fix-write-methods-dont-work-after-redirectoutput
Correct output redirection
2 parents cfbd832 + a4a5f70 commit d05b049

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Added stage checks to presolve, freereoptsolve, freetransform
88
- Added primal_dual_evolution recipe and a plot recipe
99
### Fixed
10+
- Only redirect stdout and stderr in redirectOutput() so that file output still works afterwards
1011
### Changed
1112
- GitHub actions using Mac now use precompiled SCIP from latest release
1213
### Removed

src/pyscipopt/scip.pxi

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ cimport cython
1212
from cpython cimport Py_INCREF, Py_DECREF
1313
from cpython.pycapsule cimport PyCapsule_New, PyCapsule_IsValid, PyCapsule_GetPointer
1414
from libc.stdlib cimport malloc, free
15-
from libc.stdio cimport fdopen, fclose
15+
from libc.stdio cimport stdout, stderr, fdopen, fputs, fflush, fclose
1616
from posix.stdio cimport fileno
1717

1818
from collections.abc import Iterable
@@ -1851,10 +1851,22 @@ cdef class Constraint:
18511851

18521852

18531853
cdef void relayMessage(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *msg) noexcept:
1854-
sys.stdout.write(msg.decode('UTF-8'))
1854+
if file is stdout:
1855+
sys.stdout.write(msg.decode('UTF-8'))
1856+
elif file is stderr:
1857+
sys.stderr.write(msg.decode('UTF-8'))
1858+
else:
1859+
if msg is not NULL:
1860+
fputs(msg, file)
1861+
fflush(file)
18551862

18561863
cdef void relayErrorMessage(void *messagehdlr, FILE *file, const char *msg) noexcept:
1857-
sys.stderr.write(msg.decode('UTF-8'))
1864+
if file is NULL:
1865+
sys.stderr.write(msg.decode('UTF-8'))
1866+
else:
1867+
if msg is not NULL:
1868+
fputs(msg, file)
1869+
fflush(file)
18581870

18591871
# - remove create(), includeDefaultPlugins(), createProbBasic() methods
18601872
# - replace free() by "destructor"

tests/test_model.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import itertools
44

55
from pyscipopt import Model, SCIP_STAGE, SCIP_PARAMSETTING, quicksum
6+
from helpers.utils import random_mip_1
67

78
def test_model():
89
# create solver instance
@@ -477,4 +478,36 @@ def test_getObjVal():
477478
assert m.getVal(x) == 0
478479

479480
assert m.getObjVal() == 16
480-
assert m.getVal(x) == 0
481+
assert m.getVal(x) == 0
482+
483+
# tests writeProblem() after redirectOutput()
484+
def test_redirection():
485+
486+
# create problem instances
487+
original = random_mip_1(False, False, False, -1, True)
488+
redirect = Model()
489+
490+
# redirect console output
491+
original.redirectOutput()
492+
493+
# write problem instance
494+
original.writeProblem("redirection.lp")
495+
496+
# solve original instance
497+
original.optimize()
498+
499+
# read problem instance
500+
redirect.readProblem("redirection.lp")
501+
502+
# remove problem file
503+
os.remove("redirection.lp")
504+
505+
# compare problem dimensions
506+
assert redirect.getNVars(False) == original.getNVars(False)
507+
assert redirect.getNConss(False) == original.getNConss(False)
508+
509+
# solve redirect instance
510+
redirect.optimize()
511+
512+
# compare objective values
513+
assert original.isEQ(redirect.getObjVal(), original.getObjVal())

0 commit comments

Comments
 (0)