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

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

31 statements  

1""" 

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

3""" 

4 

5from __future__ import annotations 

6 

7import logging 

8import warnings 

9from typing import Any, TextIO 

10 

11from pip._vendor.packaging.version import parse 

12 

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

14 

15DEPRECATION_MSG_PREFIX = "DEPRECATION: " 

16 

17 

18class PipDeprecationWarning(Warning): 

19 pass 

20 

21 

22_original_showwarning: Any = None 

23 

24 

25# Warnings <-> Logging Integration 

26def _showwarning( 

27 message: Warning | str, 

28 category: type[Warning], 

29 filename: str, 

30 lineno: int, 

31 file: TextIO | None = None, 

32 line: str | None = None, 

33) -> None: 

34 if file is not None: 

35 if _original_showwarning is not None: 

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

37 elif issubclass(category, PipDeprecationWarning): 

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

39 # deprecation messages for pip. 

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

41 logger.warning(message) 

42 else: 

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

44 

45 

46def install_warning_logger() -> None: 

47 # Enable our Deprecation Warnings 

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

49 

50 global _original_showwarning 

51 

52 if _original_showwarning is None: 

53 _original_showwarning = warnings.showwarning 

54 warnings.showwarning = _showwarning 

55 

56 

57def deprecated( 

58 *, 

59 reason: str, 

60 replacement: str | None, 

61 gone_in: str | None, 

62 feature_flag: str | None = None, 

63 issue: int | None = None, 

64) -> None: 

65 """Helper to deprecate existing functionality. 

66 

67 reason: 

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

69 been deprecated. Should be a complete sentence. 

70 replacement: 

71 Textual suggestion shown to the user about what alternative 

72 functionality they can use. 

73 gone_in: 

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

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

76 this. 

77 feature_flag: 

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

79 upcoming functionality. 

80 issue: 

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

82 users to find related discussion and provide feedback. 

83 """ 

84 

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

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

87 

88 message_parts = [ 

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

90 ( 

91 gone_in, 

92 ( 

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

94 if not is_gone 

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

96 ), 

97 ), 

98 ( 

99 replacement, 

100 "A possible replacement is {}.", 

101 ), 

102 ( 

103 feature_flag, 

104 ( 

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

106 if not is_gone 

107 else None 

108 ), 

109 ), 

110 ( 

111 issue, 

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

113 ), 

114 ] 

115 

116 message = " ".join( 

117 format_str.format(value) 

118 for value, format_str in message_parts 

119 if format_str is not None and value is not None 

120 ) 

121 

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

123 if is_gone: 

124 raise PipDeprecationWarning(message) 

125 

126 warnings.warn(message, category=PipDeprecationWarning, stacklevel=2)