Source code for picos.legacy

# ------------------------------------------------------------------------------
# Copyright (C) 2019 Maximilian Stahlberg
#
# This file is part of PICOS.
#
# PICOS is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# PICOS is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------------------

"""Backwards-compatibility and deprecation helpers."""

import functools
import warnings

from .apidoc import api_end, api_start
from .formatting import doc_cat

_API_START = api_start(globals())
# -------------------------------


[docs]def throw_deprecation_warning(reason, decoratorLevel=0): """Raise a deprecation warning.""" warnings.warn(reason, DeprecationWarning, stacklevel=3 + decoratorLevel)
[docs]def deprecated(since, reason=None, useInstead=None, decoratorLevel=0): """Decorate a deprecated function or method. :param str reason: Textual deprecation reason. :param str useInstead: Alternative to the deprecated object. :param int decoratorLevel: If not the only decorator, number of decorators above this one that add to the stack level of a warning thrown. """ assert len([x for x in (reason, useInstead) if x is not None]) == 1, \ "Need to supply exactly one reason or reference to @deprecated." if reason is not None: rest, text = reason, reason if useInstead is not None: rest = "Use :py:obj:`{0}` instead.".format(useInstead) text = "Use {} instead.".format(useInstead.split(".")[-1] if useInstead.startswith("~") else useInstead) def decorator(wrapped): # Make the wrapper copy the wrapped object's documentation … @functools.wraps(wrapped) def wrapper(*args, **kwargs): warnings.warn( "{} is deprecated: {}".format(wrapped.__qualname__, text), DeprecationWarning, stacklevel=2 + decoratorLevel) return wrapped(*args, **kwargs) # … and extend it. wrapper.__doc__ = doc_cat( wrapper.__doc__ if wrapper.__doc__ else "Deprecated name.", ".. deprecated:: {}\n {}".format(since, rest)) return wrapper return decorator
_option_name_old2new = { "allow_license_warnings": "license_warnings", "verbose": "verbosity", "noprimals": "primals", "noduals": "duals", "tol": ("*_fsb_tol", "*_ipm_opt_tol"), "gaplim": "rel_bnb_opt_tol", "maxit": "max_iterations", "nbsol": "max_fsb_nodes", "pool_relgap": "pool_rel_gap", "pool_absgap": "pool_abs_gap", "lboundlimit": "cplex_lwr_bnd_limit", "uboundlimit": "cplex_upr_bnd_limit", "boundMonitor": "cplex_bnd_monitor", "solve_via_dual": "dualize" } _option_value_old2new = { "noprimals": lambda x: not x, "noduals": lambda x: not x, "solve_via_dual": lambda x: bool(x) # Map None to False. }
[docs]def map_legacy_options(options={}, **kwOptions): """Map deprecated solver options to those replacing them.""" kwOptions.update(options) newOptions = {} for name, value in kwOptions.items(): if name in _option_name_old2new: newNames = _option_name_old2new[name] if isinstance(newNames, str): newNames = (newNames,) warnings.warn( "Option '{}' is deprecated, use '{}'.".format( name, ", ".join(newNames)), DeprecationWarning, stacklevel=3) if name in _option_value_old2new: value = _option_value_old2new[name](value) for newName in newNames: newOptions[newName] = value else: newOptions[name] = value return newOptions
# -------------------------------------- __all__ = api_end(_API_START, globals())