Issue 1:
When adding an adapter with a retry object to a session, read timeout errors are converted to connection errors.

>>> s = requests.Session()
>>> s.get("http://whatever.com", timeout=(3.05, 0.001))
Timeout: HTTPConnectionPool(host='whatever.com', port=80): Read timed out. (read timeout=0.001)
>>> a = HTTPAdapter(max_retries=Retry(total=3))
>>> s.mount("http://", a)
>>> s.get("http://whatever.com", timeout=(3.05, 0.001))
ConnectionError: HTTPConnectionPool(host='whatever.com', port=80): Max retries exceeded with url: / (Caused by ReadTimeoutError("HTTPConnectionPool(host='whatever.com', port=80): Read timed out. (read timeout=0.001)"))

Is this intentional? If so, what's the reasoning behind it? I'd like to catch these errors, but handle connection errors differently (e.g. warn the user to check his internet connection) from timeout errors (e.g. inform the user that the requested resource is possibly overloaded). Wouldn't it make more sense to raise the original error type once the max number of retries is exceeded?

Issue 2:
Consider the code below (main.py). When a temporary network disconnect occurs without the timeout keyword argument to Session.get(), the client may hang indefinitely and no exception is raised.

However, if I use the timeout keyword argument, the application will raise a ConnectionError from models.py corresponding to the urllib3.exceptions.ReadTimeoutError:

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='confluence.danskenet.net', port=443): Read timed out.

Given that the exception is only raised, when using the timeout keyword argument, why isn't Requests raising ReadTimeout exception instead? In particular, the ConnectionError's exception message "Read timed out." suggests that it should be a ReadTimeout exception?

To mitigate the issue I'm currently performing a regular expression match on the exception message, which is a bad practice:

except ConnectionError as e:
if re.search('Read timed out', str(e), re.IGNORECASE):

main.py:

try:
with requests.Session() as rs:
rs.mount('https://', HTTPAdapter(max_retries=Retry(total=10, connect=10, read=10, backoff_factor=1)))
with rs.get(url, params={}, headers={}, auth=self.auth, verify=self.ssl_verify, timeout=(30, 30)) as r:
r.raise_for_status()
page_set = r.json()
except ReadTimeout as e:
logging.exception('Request for page set timed out: {}'.format(url))
continue
except ConnectionError as e:
if re.search('Read timed out', str(e), re.IGNORECASE):
logging.exception('Request for page set timed out (network problem): {}'.format(url))
continue
else:
raise

models.py:

https://github.com/psf/requests/blob/master/requests/models.py

def generate():
# Special case for urllib3.
if hasattr(self.raw, 'stream'):
try:
for chunk in self.raw.stream(chunk_size, decode_content=True):
yield chunk
except ProtocolError as e:
raise ChunkedEncodingError(e)
except DecodeError as e:
raise ContentDecodingError(e)
except ReadTimeoutError as e:
raise ConnectionError(e)

Exception:

ERROR -- 04/19/2020 04:51:32 PM -- root -- ThreadPoolExecutor-0_0 -- Request for page set timed out (network problem): https://confluence.danskenet.net/rest/api/content/search?expand=version,history,space,body.storage,children.attachment.version,children.attachment.history,children.attachment.space&limit=50&start=1900&cql=(type=page)
Traceback (most recent call last):
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/urllib3/response.py", line 425, in _error_catcher
yield
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/urllib3/response.py", line 755, in read_chunked
chunk = self._handle_chunk(amt)
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/urllib3/response.py", line 708, in _handle_chunk
returned_chunk = self._fp._safe_read(self.chunk_left)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/client.py", line 620, in _safe_read
chunk = self.fp.read(min(amt, MAXAMOUNT))
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/socket.py", line 589, in readinto
return self._sock.recv_into(b)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 1071, in recv_into
return self.read(nbytes, buffer)
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py", line 929, in read
return self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/requests/models.py", line 751, in generate
for chunk in self.raw.stream(chunk_size, decode_content=True):
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/urllib3/response.py", line 560, in stream
for line in self.read_chunked(amt, decode_content=decode_content):
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/urllib3/response.py", line 781, in read_chunked
self._original_response.close()
File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/contextlib.py", line 130, in __exit__
self.gen.throw(type, value, traceback)
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/urllib3/response.py", line 430, in _error_catcher
raise ReadTimeoutError(self._pool, None, "Read timed out.")
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='confluence.danskenet.net', port=443): Read timed out.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/nlykkei/projects/atlassian-watchdog/confluence/confluence.py", line 112, in __producer
with rs.get(url, params={}, headers={}, auth=self.auth, verify=self.ssl_verify, timeout=(30, 30)) as r:
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/requests/sessions.py", line 543, in get
return self.request('GET', url, **kwargs)
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/requests/sessions.py", line 530, in request
resp = self.send(prep, **send_kwargs)
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/requests/sessions.py", line 683, in send
r.content
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/requests/models.py", line 829, in content
self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
File "/Users/nlykkei/projects/atlassian-watchdog/lib/python3.7/site-packages/requests/models.py", line 758, in generate
raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='confluence.danskenet.net', port=443): Read timed out.

Expected Result

I would expect a requests.exceptions.ReadTimeout to be raised.

Actual Result

A requests.exceptions.ConnectError was raised instead, with the error message: Read timed out.

System Information

$ python -m requests.help

nlykkei:~$ python3 -m requests.help
{
"chardet": {
"version": "3.0.4"
},
"cryptography": {
"version": ""
},
"idna": {
"version": "2.7"
},
"implementation": {
"name": "CPython",
"version": "3.7.7"
},
"platform": {
"release": "19.4.0",
"system": "Darwin"
},
"pyOpenSSL": {
"openssl_version": "",
"version": null
},
"requests": {
"version": "2.23.0"
},
"system_ssl": {
"version": "1010106f"
},
"urllib3": {
"version": "1.24.3"
},
"using_pyopenssl": false
}

This command is only available on Requests v2.16.4 and greater. Otherwise,

please provide some basic information about your system (Python version,

operating system, &c).