Coverage for picos/legacy.py: 80.49%
41 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-26 07:46 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-26 07:46 +0000
1# ------------------------------------------------------------------------------
2# Copyright (C) 2019 Maximilian Stahlberg
3#
4# This file is part of PICOS.
5#
6# PICOS is free software: you can redistribute it and/or modify it under the
7# terms of the GNU General Public License as published by the Free Software
8# Foundation, either version 3 of the License, or (at your option) any later
9# version.
10#
11# PICOS is distributed in the hope that it will be useful, but WITHOUT ANY
12# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along with
16# this program. If not, see <http://www.gnu.org/licenses/>.
17# ------------------------------------------------------------------------------
19"""Backwards-compatibility and deprecation helpers."""
21import functools
22import warnings
24from .apidoc import api_end, api_start
25from .formatting import doc_cat
27_API_START = api_start(globals())
28# -------------------------------
31def throw_deprecation_warning(reason, decoratorLevel=0):
32 """Raise a deprecation warning."""
33 warnings.warn(reason, DeprecationWarning, stacklevel=3 + decoratorLevel)
36def deprecated(since, reason=None, useInstead=None, decoratorLevel=0):
37 """Decorate a deprecated function or method.
39 :param str reason: Textual deprecation reason.
40 :param str useInstead: Alternative to the deprecated object.
41 :param int decoratorLevel: If not the only decorator, number of decorators
42 above this one that add to the stack level of a warning thrown.
43 """
44 assert len([x for x in (reason, useInstead) if x is not None]) == 1, \
45 "Need to supply exactly one reason or reference to @deprecated."
47 if reason is not None:
48 rest, text = reason, reason
49 if useInstead is not None:
50 rest = "Use :py:obj:`{0}` instead.".format(useInstead)
51 text = "Use {} instead.".format(useInstead.split(".")[-1]
52 if useInstead.startswith("~") else useInstead)
54 def decorator(wrapped):
55 # Make the wrapper copy the wrapped object's documentation …
56 @functools.wraps(wrapped)
57 def wrapper(*args, **kwargs):
58 warnings.warn(
59 "{} is deprecated: {}".format(wrapped.__qualname__, text),
60 DeprecationWarning, stacklevel=2 + decoratorLevel)
61 return wrapped(*args, **kwargs)
63 # … and extend it.
64 wrapper.__doc__ = doc_cat(
65 wrapper.__doc__ if wrapper.__doc__ else "Deprecated name.",
66 ".. deprecated:: {}\n {}".format(since, rest))
68 return wrapper
69 return decorator
72_option_name_old2new = {
73 "allow_license_warnings": "license_warnings",
74 "verbose": "verbosity",
75 "noprimals": "primals",
76 "noduals": "duals",
77 "tol": ("*_fsb_tol", "*_ipm_opt_tol"),
78 "gaplim": "rel_bnb_opt_tol",
79 "maxit": "max_iterations",
80 "nbsol": "max_fsb_nodes",
81 "pool_relgap": "pool_rel_gap",
82 "pool_absgap": "pool_abs_gap",
83 "lboundlimit": "cplex_lwr_bnd_limit",
84 "uboundlimit": "cplex_upr_bnd_limit",
85 "boundMonitor": "cplex_bnd_monitor",
86 "solve_via_dual": "dualize"
87}
89_option_value_old2new = {
90 "noprimals": lambda x: not x,
91 "noduals": lambda x: not x,
92 "solve_via_dual": lambda x: bool(x) # Map None to False.
93}
96def map_legacy_options(options={}, **kwOptions):
97 """Map deprecated solver options to those replacing them."""
98 kwOptions.update(options)
100 newOptions = {}
101 for name, value in kwOptions.items():
102 if name in _option_name_old2new:
103 newNames = _option_name_old2new[name]
105 if isinstance(newNames, str):
106 newNames = (newNames,)
108 warnings.warn(
109 "Option '{}' is deprecated, use '{}'.".format(
110 name, ", ".join(newNames)), DeprecationWarning, stacklevel=3)
112 if name in _option_value_old2new:
113 value = _option_value_old2new[name](value)
115 for newName in newNames:
116 newOptions[newName] = value
117 else:
118 newOptions[name] = value
120 return newOptions
123# --------------------------------------
124__all__ = api_end(_API_START, globals())