Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pip/_internal/utils/deprecation.py: 39%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

38 statements  

1""" 

2A module that implements tooling to enable easy warnings about deprecations. 

3""" 

4 

5from __future__ import annotations 

6 

7import logging 

8import os 

9import warnings 

10from typing import Any, TextIO 

11 

12from pip._vendor.packaging.version import parse 

13 

14from pip import __version__ as current_version # NOTE: tests patch this name. 

15 

16DEPRECATION_MSG_PREFIX = "DEPRECATION: " 

17 

18 

19class PipDeprecationWarning(Warning): 

20 include_source: bool = False 

21 

22 

23_original_showwarning: Any = None 

24 

25 

26# Warnings <-> Logging Integration 

27def _showwarning( 

28 message: Warning | str, 

29 category: type[Warning], 

30 filename: str, 

31 lineno: int, 

32 file: TextIO | None = None, 

33 line: str | None = None, 

34) -> None: 

35 if file is not None: 

36 if _original_showwarning is not None: 

37 _original_showwarning(message, category, filename, lineno, file, line) 

38 elif issubclass(category, PipDeprecationWarning): 

39 # We use a specially named logger which will handle all of the 

40 # deprecation messages for pip. 

41 logger = logging.getLogger("pip._internal.deprecations") 

42 if isinstance(message, PipDeprecationWarning) and message.include_source: 

43 logger.warning("%s (%s:%s)", message, filename, lineno) 

44 else: 

45 logger.warning(message) 

46 else: 

47 _original_showwarning(message, category, filename, lineno, file, line) 

48 

49 

50def install_warning_logger() -> None: 

51 # Enable our Deprecation Warnings 

52 # If we're running pip test suite, promote the PipDeprecationWarning into errors. 

53 if os.environ.get("_PIP_TEST_ENV", None): 

54 warnings.simplefilter("error", PipDeprecationWarning) 

55 else: 

56 warnings.simplefilter("default", PipDeprecationWarning, append=True) 

57 

58 global _original_showwarning 

59 

60 if _original_showwarning is None: 

61 _original_showwarning = warnings.showwarning 

62 warnings.showwarning = _showwarning 

63 

64 

65def deprecated( 

66 *, 

67 reason: str, 

68 replacement: str | None, 

69 gone_in: str | None, 

70 feature_flag: str | None = None, 

71 issue: int | None = None, 

72 stacklevel: int = 2, 

73 include_source: bool = False, 

74) -> None: 

75 """Helper to deprecate existing functionality. 

76 

77 reason: 

78 Textual reason shown to the user about why this functionality has 

79 been deprecated. Should be a complete sentence. 

80 replacement: 

81 Textual suggestion shown to the user about what alternative 

82 functionality they can use. 

83 gone_in: 

84 The version of pip does this functionality should get removed in. 

85 Raises an error if pip's current version is greater than or equal to 

86 this. 

87 feature_flag: 

88 Command-line flag of the form --use-feature={feature_flag} for testing 

89 upcoming functionality. 

90 issue: 

91 Issue number on the tracker that would serve as a useful place for 

92 users to find related discussion and provide feedback. 

93 stacklevel: 

94 How many frames up the call stack to attribute the warning to. 

95 Defaults to 2 (the caller of deprecated()). 

96 include_source: 

97 If True, include the source filename and line number in the warning 

98 output. Useful when the warning originates from external code. 

99 """ 

100 

101 # Determine whether or not the feature is already gone in this version. 

102 is_gone = gone_in is not None and parse(current_version) >= parse(gone_in) 

103 

104 message_parts = [ 

105 (reason, f"{DEPRECATION_MSG_PREFIX}{{}}"), 

106 ( 

107 gone_in, 

108 ( 

109 "pip {} will enforce this behaviour change." 

110 if not is_gone 

111 else "Since pip {}, this is no longer supported." 

112 ), 

113 ), 

114 ( 

115 replacement, 

116 "A possible replacement is {}.", 

117 ), 

118 ( 

119 feature_flag, 

120 ( 

121 "You can use the flag --use-feature={} to test the upcoming behaviour." 

122 if not is_gone 

123 else None 

124 ), 

125 ), 

126 ( 

127 issue, 

128 "Discussion can be found at https://github.com/pypa/pip/issues/{}", 

129 ), 

130 ] 

131 

132 message = " ".join( 

133 format_str.format(value) 

134 for value, format_str in message_parts 

135 if format_str is not None and value is not None 

136 ) 

137 

138 # Raise as an error if this behaviour is deprecated. 

139 if is_gone: 

140 raise PipDeprecationWarning(message) 

141 

142 warning = PipDeprecationWarning(message) 

143 warning.include_source = include_source 

144 warnings.warn(warning, stacklevel=stacklevel)