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

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# ------------------------------------------------------------------------------ 

18 

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

20 

21import functools 

22import warnings 

23 

24from .apidoc import api_end, api_start 

25from .formatting import doc_cat 

26 

27_API_START = api_start(globals()) 

28# ------------------------------- 

29 

30 

31def throw_deprecation_warning(reason, decoratorLevel=0): 

32 """Raise a deprecation warning.""" 

33 warnings.warn(reason, DeprecationWarning, stacklevel=3 + decoratorLevel) 

34 

35 

36def deprecated(since, reason=None, useInstead=None, decoratorLevel=0): 

37 """Decorate a deprecated function or method. 

38 

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." 

46 

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) 

53 

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) 

62 

63 # … and extend it. 

64 wrapper.__doc__ = doc_cat( 

65 wrapper.__doc__ if wrapper.__doc__ else "Deprecated name.", 

66 ".. deprecated:: {}\n {}".format(since, rest)) 

67 

68 return wrapper 

69 return decorator 

70 

71 

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} 

88 

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} 

94 

95 

96def map_legacy_options(options={}, **kwOptions): 

97 """Map deprecated solver options to those replacing them.""" 

98 kwOptions.update(options) 

99 

100 newOptions = {} 

101 for name, value in kwOptions.items(): 

102 if name in _option_name_old2new: 

103 newNames = _option_name_old2new[name] 

104 

105 if isinstance(newNames, str): 

106 newNames = (newNames,) 

107 

108 warnings.warn( 

109 "Option '{}' is deprecated, use '{}'.".format( 

110 name, ", ".join(newNames)), DeprecationWarning, stacklevel=3) 

111 

112 if name in _option_value_old2new: 

113 value = _option_value_old2new[name](value) 

114 

115 for newName in newNames: 

116 newOptions[newName] = value 

117 else: 

118 newOptions[name] = value 

119 

120 return newOptions 

121 

122 

123# -------------------------------------- 

124__all__ = api_end(_API_START, globals())