Skip to content
Merged
1 change: 1 addition & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:

- name: Run pyscipopt tests
run: |
sudo apt-get install tzdata locales -y && sudo locale-gen pt_PT && sudo update-locale # add pt_PT locale that is used in tests
coverage run -m pytest
coverage report -m
coverage xml
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Add SCIP function SCIPgetTreesizeEstimation and wrapper getTreesizeEstimation
- Add recipes sub-package
### Fixed
- Fixed incorrect writing/printing when user had a non-default locale
### Changed
### Removed

Expand Down
104 changes: 86 additions & 18 deletions src/pyscipopt/scip.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ from os.path import splitext
import os
import sys
import warnings
import locale

cimport cython
from cpython cimport Py_INCREF, Py_DECREF
Expand Down Expand Up @@ -1128,8 +1129,13 @@ cdef class Model:

def printVersion(self):
"""Print version, copyright information and compile mode"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

SCIPprintVersion(self._scip, NULL)

locale.setlocale(locale.LC_ALL, user_locale)

def getProbName(self):
"""Retrieve problem name"""
return bytes(SCIPgetProbName(self._scip)).decode('UTF-8')
Expand Down Expand Up @@ -1455,6 +1461,9 @@ cdef class Model:
:param genericnames: indicates whether the problem should be written with generic variable and constraint names (Default value = False)

"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

str_absfile = abspath(filename)
absfile = str_conversion(str_absfile)
fn, ext = splitext(absfile)
Expand All @@ -1468,6 +1477,8 @@ cdef class Model:
PY_SCIP_CALL(SCIPwriteOrigProblem(self._scip, fn, ext, genericnames))
print('wrote problem to file ' + str_absfile)

locale.setlocale(locale.LC_ALL, user_locale)

# Variable Functions

def addVar(self, name='', vtype='C', lb=0.0, ub=None, obj=0.0, pricedVar=False, pricedVarScore=1.0):
Expand Down Expand Up @@ -4373,9 +4384,14 @@ cdef class Model:
"""writes current LP to a file
:param filename: file name (Default value = "LP.lp")
"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

absfile = str_conversion(abspath(filename))
PY_SCIP_CALL( SCIPwriteLP(self._scip, absfile) )

locale.setlocale(locale.LC_ALL, user_locale)

def createSol(self, Heur heur = None):
"""Create a new primal solution.

Expand Down Expand Up @@ -4413,19 +4429,30 @@ cdef class Model:

def printBestSol(self, write_zeros=False):
"""Prints the best feasible primal solution."""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

PY_SCIP_CALL(SCIPprintBestSol(self._scip, NULL, write_zeros))

locale.setlocale(locale.LC_ALL, user_locale)

def printSol(self, Solution solution=None, write_zeros=False):
"""Print the given primal solution.
"""Print the given primal solution.

Keyword arguments:
solution -- solution to print
write_zeros -- include variables that are set to zero
"""

user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

Keyword arguments:
solution -- solution to print
write_zeros -- include variables that are set to zero
"""
if solution is None:
PY_SCIP_CALL(SCIPprintSol(self._scip, NULL, NULL, write_zeros))
else:
PY_SCIP_CALL(SCIPprintSol(self._scip, solution.sol, NULL, write_zeros))
if solution is None:
PY_SCIP_CALL(SCIPprintSol(self._scip, NULL, NULL, write_zeros))
else:
PY_SCIP_CALL(SCIPprintSol(self._scip, solution.sol, NULL, write_zeros))

locale.setlocale(locale.LC_ALL, user_locale)

def writeBestSol(self, filename="origprob.sol", write_zeros=False):
"""Write the best feasible primal solution to a file.
Expand All @@ -4434,24 +4461,35 @@ cdef class Model:
filename -- name of the output file
write_zeros -- include variables that are set to zero
"""

user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

# use this doubled opening pattern to ensure that IOErrors are
# triggered early and in Python not in C,Cython or SCIP.
with open(filename, "w") as f:
cfile = fdopen(f.fileno(), "w")
PY_SCIP_CALL(SCIPprintBestSol(self._scip, cfile, write_zeros))

locale.setlocale(locale.LC_ALL, user_locale)

def writeBestTransSol(self, filename="transprob.sol", write_zeros=False):
"""Write the best feasible primal solution for the transformed problem to a file.

Keyword arguments:
filename -- name of the output file
write_zeros -- include variables that are set to zero
"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

# use this double opening pattern to ensure that IOErrors are
# triggered early and in python not in C, Cython or SCIP.
with open(filename, "w") as f:
cfile = fdopen(f.fileno(), "w")
PY_SCIP_CALL(SCIPprintBestTransSol(self._scip, cfile, write_zeros))

locale.setlocale(locale.LC_ALL, user_locale)

def writeSol(self, Solution solution, filename="origprob.sol", write_zeros=False):
"""Write the given primal solution to a file.
Expand All @@ -4461,11 +4499,16 @@ cdef class Model:
filename -- name of the output file
write_zeros -- include variables that are set to zero
"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

# use this doubled opening pattern to ensure that IOErrors are
# triggered early and in Python not in C,Cython or SCIP.
with open(filename, "w") as f:
cfile = fdopen(f.fileno(), "w")
PY_SCIP_CALL(SCIPprintSol(self._scip, solution.sol, cfile, write_zeros))

locale.setlocale(locale.LC_ALL, user_locale)

def writeTransSol(self, Solution solution, filename="transprob.sol", write_zeros=False):
"""Write the given transformed primal solution to a file.
Expand All @@ -4475,11 +4518,16 @@ cdef class Model:
filename -- name of the output file
write_zeros -- include variables that are set to zero
"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

# use this doubled opening pattern to ensure that IOErrors are
# triggered early and in Python not in C,Cython or SCIP.
with open(filename, "w") as f:
cfile = fdopen(f.fileno(), "w")
PY_SCIP_CALL(SCIPprintTransSol(self._scip, solution.sol, cfile, write_zeros))

locale.setlocale(locale.LC_ALL, user_locale)

# perhaps this should not be included as it implements duplicated functionality
# (as does it's namesake in SCIP)
Expand Down Expand Up @@ -4737,8 +4785,13 @@ cdef class Model:
:param Variable var: variable

"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

PY_SCIP_CALL(SCIPwriteVarName(self._scip, NULL, var.scip_var, False))

locale.setlocale(locale.LC_ALL, user_locale)

def getStage(self):
"""Retrieve current SCIP stage"""
return SCIPgetStage(self._scip)
Expand Down Expand Up @@ -4864,19 +4917,29 @@ cdef class Model:

def printStatistics(self):
"""Print statistics."""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

PY_SCIP_CALL(SCIPprintStatistics(self._scip, NULL))

locale.setlocale(locale.LC_ALL, user_locale)

def writeStatistics(self, filename="origprob.stats"):
"""Write statistics to a file.
"""Write statistics to a file.

Keyword arguments:
filename -- name of the output file
"""
# use this doubled opening pattern to ensure that IOErrors are
# triggered early and in Python not in C,Cython or SCIP.
with open(filename, "w") as f:
cfile = fdopen(f.fileno(), "w")
PY_SCIP_CALL(SCIPprintStatistics(self._scip, cfile))
Keyword arguments:
filename -- name of the output file
"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

# use this doubled opening pattern to ensure that IOErrors are
# triggered early and in Python not in C,Cython or SCIP.
with open(filename, "w") as f:
cfile = fdopen(f.fileno(), "w")
PY_SCIP_CALL(SCIPprintStatistics(self._scip, cfile))

locale.setlocale(locale.LC_ALL, user_locale)

def getNLPs(self):
"""gets total number of LPs solved so far"""
Expand Down Expand Up @@ -5070,11 +5133,16 @@ cdef class Model:
:param onlychanged: write only modified parameters (Default value = True)

"""
user_locale = locale.getlocale()
locale.setlocale(locale.LC_ALL, "C")

str_absfile = abspath(filename)
absfile = str_conversion(str_absfile)
PY_SCIP_CALL(SCIPwriteParams(self._scip, absfile, comments, onlychanged))
print('wrote parameter settings to file ' + str_absfile)

locale.setlocale(locale.LC_ALL, user_locale)

def resetParam(self, name):
"""Reset parameter setting to its default value

Expand Down
16 changes: 16 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,19 @@ def test_getTreesizeEstimation():
m.optimize()

assert m.getTreesizeEstimation() > 0

def test_locale():
import locale

m = Model()
x = m.addVar(lb=1.1)

locale.setlocale(locale.LC_NUMERIC, "pt_PT")

assert locale.str(1.1) == "1,1"

m.writeProblem("model.cip")

with open("model.cip") as file:
assert "1,1" not in file.read()