From 8d0889b91b7e9d487e69eea00baed666a25259af Mon Sep 17 00:00:00 2001 From: colin Date: Sun, 24 May 2015 09:59:35 -0400 Subject: [PATCH 1/2] fix contextlib.closing bug for sessions where content is not consumed (issue #2593) --- requests/models.py | 3 +++ test_requests.py | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/requests/models.py b/requests/models.py index ccaf5968..7ab21f78 100644 --- a/requests/models.py +++ b/requests/models.py @@ -842,4 +842,7 @@ class Response(object): *Note: Should not normally need to be called explicitly.* """ + if not self._content_consumed: + return self.raw.close() + return self.raw.release_conn() diff --git a/test_requests.py b/test_requests.py index cad8c055..92cdb154 100755 --- a/test_requests.py +++ b/test_requests.py @@ -9,6 +9,8 @@ import os import pickle import unittest import collections +import contextlib +import random import io import requests @@ -1252,6 +1254,27 @@ class TestCaseInsensitiveDict(unittest.TestCase): assert frozenset(cid) == keyset +class TestSessionContextClosing(unittest.TestCase): + + def _perform_session_without_consuming(self): + session = requests.Session() + + urls = [ + 'http://reddit.com', + 'http://github.com', + 'http://bitbucket.org', + ] + + for _ in range(25): + with contextlib.closing(session.get(random.choice(urls), stream=True)) as r: + pass + + return "OK" + + def test_stream_session_content_not_consumed(self): + self.assertEqual(self._perform_session_without_consuming(), "OK") + + class UtilsTestCase(unittest.TestCase): def test_super_len_io_streams(self): From 1da62a65d9b28306c3be7ad603b2721374ce7d13 Mon Sep 17 00:00:00 2001 From: colin Date: Sun, 24 May 2015 09:59:35 -0400 Subject: [PATCH 2/2] fix contextlib.closing bug for sessions where content is not consumed (issue #2593) --- AUTHORS.rst | 1 + requests/models.py | 3 +++ test_requests.py | 10 ++++++++++ 3 files changed, 14 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index b8191086..5ac39e4b 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -158,3 +158,4 @@ Patches and Suggestions - Ulrich Petri (`@ulope `_) - Muhammad Yasoob Ullah Khalid (`@yasoob `_) - Paul van der Linden (`@pvanderlinden `_) +- Colin Dickson (`@colindickson `_) diff --git a/requests/models.py b/requests/models.py index ccaf5968..7ab21f78 100644 --- a/requests/models.py +++ b/requests/models.py @@ -842,4 +842,7 @@ class Response(object): *Note: Should not normally need to be called explicitly.* """ + if not self._content_consumed: + return self.raw.close() + return self.raw.release_conn() diff --git a/test_requests.py b/test_requests.py index cad8c055..cf93c48a 100755 --- a/test_requests.py +++ b/test_requests.py @@ -9,6 +9,7 @@ import os import pickle import unittest import collections +import contextlib import io import requests @@ -1060,6 +1061,15 @@ class RequestsTestCase(unittest.TestCase): next(it) assert len(list(it)) == 3 + def test_unconsumed_session_response_closes_connection(self): + s = requests.session() + + with contextlib.closing(s.get(httpbin('stream/4'), stream=True)) as response: + pass + + self.assertEqual(response._content_consumed, False) + self.assertTrue(response.raw.closed, True) + @pytest.mark.xfail def test_response_iter_lines_reentrant(self): """Response.iter_lines() is not reentrant safe"""