Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pip/_internal/exceptions/network.py: 37%

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

76 statements  

1"""Network-related pip exceptions.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Literal 

6 

7from pip._vendor.rich.markup import escape 

8from pip._vendor.rich.text import Text 

9 

10from pip._internal.exceptions._base import DiagnosticPipError, PipError 

11 

12if TYPE_CHECKING: 

13 from pip._vendor import urllib3 

14 from pip._vendor.requests.models import PreparedRequest, Request, Response 

15 

16 from pip._internal.network.download import _FileDownload 

17 

18 

19class NetworkConnectionError(PipError): 

20 """HTTP connection error""" 

21 

22 def __init__( 

23 self, 

24 error_msg: str, 

25 response: Response | None = None, 

26 request: Request | PreparedRequest | None = None, 

27 ) -> None: 

28 """ 

29 Initialize NetworkConnectionError with `request` and `response` 

30 objects. 

31 """ 

32 self.response = response 

33 self.request = request 

34 self.error_msg = error_msg 

35 if ( 

36 self.response is not None 

37 and not self.request 

38 and hasattr(response, "request") 

39 ): 

40 self.request = self.response.request 

41 super().__init__(error_msg, response, request) 

42 

43 def __str__(self) -> str: 

44 return str(self.error_msg) 

45 

46 

47class ConnectionFailedError(DiagnosticPipError): 

48 reference = "connection-failed" 

49 

50 def __init__(self, url: str, host: str, error: Exception) -> None: 

51 from http.client import RemoteDisconnected 

52 

53 from pip._vendor.urllib3.exceptions import ( 

54 NameResolutionError, 

55 NewConnectionError, 

56 ProtocolError, 

57 ) 

58 

59 details = str(error) 

60 if isinstance(error, NameResolutionError): 

61 parts = details.split("Failed to resolve ", maxsplit=1) 

62 if len(parts) == 2: 

63 details = "Failed to resolve IP address for " + parts[1] 

64 elif isinstance(error, NewConnectionError): 

65 parts = details.split("Failed to establish a new connection: ", maxsplit=1) 

66 if len(parts) == 2: 

67 _, details = parts 

68 elif isinstance(error, ProtocolError): 

69 try: 

70 reason = error.args[1] 

71 except IndexError: 

72 pass 

73 else: 

74 if isinstance(reason, (RemoteDisconnected, ConnectionResetError)): 

75 details = ( 

76 "the connection was closed without a reply from the server." 

77 ) 

78 

79 super().__init__( 

80 message=( 

81 f"Failed to connect to [magenta]{escape(host)}[/] while fetching " 

82 f"{escape(url)}" 

83 ), 

84 context=Text(details), 

85 hint_stmt=( 

86 "Are you connected to the Internet? If so, check whether your system " 

87 f"can connect to [magenta]{escape(host)}[/] before trying again. " 

88 "There may be a firewall or proxy that's preventing the connection." 

89 ), 

90 ) 

91 

92 

93class ConnectionTimeoutError(DiagnosticPipError): 

94 reference = "connection-timeout" 

95 

96 def __init__( 

97 self, 

98 url: str, 

99 host: str, 

100 *, 

101 kind: Literal["connect", "read"], 

102 timeout: float, 

103 ) -> None: 

104 context = Text.assemble( 

105 (host, "magenta"), f" didn't respond within {timeout} seconds" 

106 ) 

107 if kind == "connect": 

108 context.append(" (while establishing a connection)") 

109 super().__init__( 

110 message=f"Unable to fetch {escape(url)}", 

111 context=context, 

112 hint_stmt=( 

113 "This is probably a temporary issue with the remote server or the " 

114 "network connection. If this error persists, check the network " 

115 "configuration. There may be a firewall or proxy that's preventing " 

116 "the connection." 

117 ), 

118 ) 

119 

120 

121class SSLMissingError(DiagnosticPipError): 

122 reference = "ssl-missing" 

123 

124 def __init__(self, url: str) -> None: 

125 super().__init__( 

126 message=f"Failed to establish a secure connection for {escape(url)}", 

127 context="The 'ssl' module is unavailable but required for HTTPS URLs", 

128 hint_stmt=None, 

129 ) 

130 

131 

132class SSLVerificationError(DiagnosticPipError): 

133 reference = "ssl-verification-failed" 

134 

135 def __init__(self, url: str, host: str, error: urllib3.exceptions.SSLError) -> None: 

136 message = ( 

137 "Failed to establish a secure connection to " 

138 f"[magenta]{escape(host)}[/] while fetching {escape(url)}" 

139 ) 

140 hint = "You may need to use --cert or check your proxy/firewall configuration" 

141 super().__init__(message=message, context=Text(str(error)), hint_stmt=hint) 

142 

143 

144class ProxyConnectionError(DiagnosticPipError): 

145 reference = "proxy-connection-failed" 

146 

147 def __init__( 

148 self, url: str, proxy: str, error: urllib3.exceptions.ProxyError 

149 ) -> None: 

150 super().__init__( 

151 message=( 

152 "Failed to connect to proxy " 

153 f"[magenta]{escape(proxy)}[/] while fetching {escape(url)}" 

154 ), 

155 context=Text(str(error)), 

156 hint_stmt="This is likely a proxy configuration issue.", 

157 ) 

158 

159 

160class IncompleteDownloadError(DiagnosticPipError): 

161 """Raised when the downloader receives fewer bytes than advertised 

162 in the Content-Length header.""" 

163 

164 reference = "incomplete-download" 

165 

166 def __init__(self, download: _FileDownload) -> None: 

167 # Dodge circular import. 

168 from pip._internal.utils.misc import format_size 

169 

170 assert download.size is not None 

171 download_status = ( 

172 f"{format_size(download.bytes_received)}/{format_size(download.size)}" 

173 ) 

174 if download.reattempts: 

175 retry_status = f"after {download.reattempts + 1} attempts " 

176 hint = "Use --resume-retries to configure resume attempt limit." 

177 else: 

178 # Download retrying is not enabled. 

179 retry_status = "" 

180 hint = "Consider using --resume-retries to enable download resumption." 

181 message = Text( 

182 f"Download failed {retry_status}because not enough bytes " 

183 f"were received ({download_status})" 

184 ) 

185 

186 super().__init__( 

187 message=message, 

188 context=f"URL: {download.link.redacted_url}", 

189 hint_stmt=hint, 

190 note_stmt="This is an issue with network connectivity, not pip.", 

191 )