From b5451edd862ed8841ecf19b113d73aae45e3cdc4 Mon Sep 17 00:00:00 2001 From: PCO Date: Mon, 3 Feb 2025 16:51:33 +0100 Subject: [PATCH 1/3] Model.export_to_stream() is only for LP --- docplex/mp/model.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/docplex/mp/model.py b/docplex/mp/model.py index 07391e2..af2bd96 100644 --- a/docplex/mp/model.py +++ b/docplex/mp/model.py @@ -5648,7 +5648,6 @@ def export_as_savgz(self, path=None, basename=None): """ return self._export_from_cplex(path, basename, format_spec="sav.gz") - def _export_from_cplex(self, path=None, basename=None, hide_user_names=False, format_spec="lp"): return self._export(path, basename, @@ -5713,7 +5712,7 @@ def _export_to_stream(self, stream, hide_user_names=False, format_spec="lp"): printer.set_mangle_names(hide_user_names) printer.printModel(self, stream) else: - self.__engine.export(stream, format_spec) + self.__engine.export(stream, format_) def export_to_stream(self, stream, hide_user_names=False, format_spec="lp"): """ Export the model to an output stream in LP format. @@ -5731,7 +5730,9 @@ def export_to_stream(self, stream, hide_user_names=False, format_spec="lp"): and `c1`, `c2`, ,... for constraints. Default is to keep user names. """ - self._export_to_stream(stream, hide_user_names, format_spec) + if format_spec != "lp": + self.fatal("Model.export_to_stream() is only available for LP format, \"{0}\" not supported", format_spec) + self._export_to_stream(stream, hide_user_names, format_spec="lp") def export_as_lp_string(self, hide_user_names=False): """ Exports the model to a string in LP format. @@ -5746,7 +5747,9 @@ def export_as_lp_string(self, hide_user_names=False): Returns: A string, containing the model exported in LP format. """ - return self.export_to_string(hide_user_names, "lp") + oss = StringIO() + self._export_to_stream(oss, hide_user_names) + return oss.getvalue() @property def lp_string(self): @@ -5796,11 +5799,6 @@ def _export_as_cplex_string(self, format_spec): else: return raw_res.decode(self.parameters.read.fileencoding.get()) - def export_to_string(self, hide_user_names=False, format_spec="lp"): - # INTERNAL - oss = StringIO() - self._export_to_stream(oss, hide_user_names, format_spec) - return oss.getvalue() def export_parameters_as_prm(self, path=None, basename=None): # path is either a nonempty path string or None From f0992c7185de6bf38fc615ec913c8db968cf8c22 Mon Sep 17 00:00:00 2001 From: PCO Date: Tue, 4 Feb 2025 11:16:37 +0100 Subject: [PATCH 2/3] simplify lp exports --- docplex/mp/cplex_engine.py | 6 +++++- docplex/mp/model.py | 20 +++++++++++++------- docplex/mp/tck.py | 3 ++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/docplex/mp/cplex_engine.py b/docplex/mp/cplex_engine.py index 1af3611..314fe74 100644 --- a/docplex/mp/cplex_engine.py +++ b/docplex/mp/cplex_engine.py @@ -21,6 +21,7 @@ from docplex.mp.constants import ConflictStatus from docplex.mp.constr import IndicatorConstraint, RangeConstraint, BinaryConstraint, \ EquivalenceConstraint +from docplex.mp.format import ExchangeFormat from docplex.mp.progress import ProgressData from docplex.mp.qprogress import QProgressData from docplex.mp.solution import SolveSolution, SolutionPool @@ -2547,6 +2548,9 @@ def var_by_index(idx): return ConflictRefinerResult(conflicts, refined_by=self.name) def export(self, out, exchange_format): + if exchange_format is not None and not isinstance(exchange_format, ExchangeFormat): + self._model.fatal("Not a valid exchange format: {0}", exchange_format) + self.sync_cplex() if is_string(out): path = out @@ -2563,7 +2567,7 @@ def export(self, out, exchange_format): else: raise DOcplexException("CPLEX error in SAV export: {0!s}", cpx_se) else: - # assume a file-like object + # delegate to cplex, assume write and close methods. filetype = exchange_format.filetype return self._cplex.write_to_stream(out, filetype) diff --git a/docplex/mp/model.py b/docplex/mp/model.py index af2bd96..d94b17b 100644 --- a/docplex/mp/model.py +++ b/docplex/mp/model.py @@ -5494,6 +5494,11 @@ def _resolve_path(self, path_arg, basename_arg, extension): def _make_output_path(self, extension, basename, path=None): return make_output_path2(self.name, extension, basename, path) + def _new_lp_printer(self): + printer_kwargs = {'full_obj': self._print_full_obj} + lp_printer = LPModelPrinter(**printer_kwargs) + return lp_printer + def _get_printer(self, format_spec, do_raise=False, silent=False): # INTERNAL printer_kwargs = {'full_obj': self._print_full_obj} @@ -5714,6 +5719,12 @@ def _export_to_stream(self, stream, hide_user_names=False, format_spec="lp"): else: self.__engine.export(stream, format_) + def _export_to_lp_stream(self, out_stream, hide_user_names=False): + lp_printer = self._new_lp_printer() + assert lp_printer + lp_printer.set_mangle_names(hide_user_names) + lp_printer.printModel(self, out_stream) + def export_to_stream(self, stream, hide_user_names=False, format_spec="lp"): """ Export the model to an output stream in LP format. @@ -5732,7 +5743,7 @@ def export_to_stream(self, stream, hide_user_names=False, format_spec="lp"): """ if format_spec != "lp": self.fatal("Model.export_to_stream() is only available for LP format, \"{0}\" not supported", format_spec) - self._export_to_stream(stream, hide_user_names, format_spec="lp") + self._export_to_lp_stream(stream, hide_user_names) def export_as_lp_string(self, hide_user_names=False): """ Exports the model to a string in LP format. @@ -5748,7 +5759,7 @@ def export_as_lp_string(self, hide_user_names=False): A string, containing the model exported in LP format. """ oss = StringIO() - self._export_to_stream(oss, hide_user_names) + self._export_to_lp_stream(oss, hide_user_names) return oss.getvalue() @property @@ -5791,15 +5802,10 @@ def _export_as_cplex_string(self, format_spec): self.__engine.export(bs, _format) raw_res = bs.getvalue() if _format.is_binary: - # for b, by in enumerate(raw_res): - # nl = (b % 21 == 20) - # print(f" {by}", end='\n' if nl else '') - # print() return raw_res else: return raw_res.decode(self.parameters.read.fileencoding.get()) - def export_parameters_as_prm(self, path=None, basename=None): # path is either a nonempty path string or None self._checker.typecheck_string(path, accept_none=True, accept_empty=False) diff --git a/docplex/mp/tck.py b/docplex/mp/tck.py index 769a13b..0805452 100644 --- a/docplex/mp/tck.py +++ b/docplex/mp/tck.py @@ -487,7 +487,8 @@ def typecheck_string(self, arg, accept_empty=False, accept_none=False, caller='' elif not (arg is None and accept_none): s_caller = resolve_caller_as_string(caller) qualifier = "non-empty " if not accept_empty else "" - self.fatal("{0}Expecting a {2}string, got: {1!r}", s_caller, arg, qualifier) + s_none = " or None" if accept_none else "" + self.fatal("{0}Expecting a {2}string{3}, got: {1!r}", s_caller, arg, qualifier, s_none) def typecheck_string_seq(self, arg, accept_empty=False, accept_none=False, caller=''): checked_strings = list(arg) From 111554468648240798704cdb214352f07d9a5595 Mon Sep 17 00:00:00 2001 From: PCO Date: Fri, 7 Feb 2025 15:53:51 +0100 Subject: [PATCH 3/3] refactor creation of lp printer --- docplex/mp/model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docplex/mp/model.py b/docplex/mp/model.py index d94b17b..709b9d7 100644 --- a/docplex/mp/model.py +++ b/docplex/mp/model.py @@ -5501,11 +5501,10 @@ def _new_lp_printer(self): def _get_printer(self, format_spec, do_raise=False, silent=False): # INTERNAL - printer_kwargs = {'full_obj': self._print_full_obj} format_ = parse_format(format_spec) printer = None if format_.name == 'LP': - printer = LPModelPrinter(**printer_kwargs) + printer = self._new_lp_printer() else: if do_raise: self.fatal("Unsupported output format: {0!s}", format_spec)