From 13a6e02ccd0b932b9cf8b8eb88cdb47ee118bbd1 Mon Sep 17 00:00:00 2001 From: Matt Spitz Date: Thu, 10 Oct 2013 14:54:47 -0400 Subject: [PATCH] Increasing super_len compatibilty to include BytesIO and cStringIO objects. Added a check for 'getvalue' attr, calling it to retrieve the length if we can. We also try/except the fileno() call, which can throw io.UnsupportedOperation for BytesIO because, well, they're not files. --- requests/utils.py | 13 ++++++++++++- test_requests.py | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/requests/utils.py b/requests/utils.py index 3ec6131..5000105 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -12,6 +12,7 @@ that are also useful for external consumption. import cgi import codecs import collections +import io import os import platform import re @@ -46,11 +47,21 @@ def dict_to_sequence(d): def super_len(o): if hasattr(o, '__len__'): return len(o) + if hasattr(o, 'len'): return o.len + if hasattr(o, 'fileno'): - return os.fstat(o.fileno()).st_size + try: + fileno = o.fileno() + except io.UnsupportedOperation: + pass + else: + return os.fstat(fileno).st_size + if hasattr(o, 'getvalue'): + # e.g. BytesIO, cStringIO.StringI + return len(o.getvalue()) def get_netrc_auth(url): """Returns the Requests tuple auth for a given url from netrc.""" diff --git a/test_requests.py b/test_requests.py index 3d6665b..18fb10e 100755 --- a/test_requests.py +++ b/test_requests.py @@ -873,5 +873,26 @@ class TestCaseInsensitiveDict(unittest.TestCase): self.assertEqual(frozenset(cid), keyset) +class UtilsTestCase(unittest.TestCase): + + def test_super_len_io_streams(self): + """ Ensures that we properly deal with different kinds of IO streams. """ + # uses StringIO or io.StringIO (see import above) + from io import BytesIO + from requests.utils import super_len + + self.assertEqual(super_len(StringIO.StringIO()), 0) + self.assertEqual(super_len(StringIO.StringIO('with so much drama in the LBC')), 29) + + self.assertEqual(super_len(BytesIO()), 0) + self.assertEqual(super_len(BytesIO(b"it's kinda hard bein' snoop d-o-double-g")), 40) + + try: + import cStringIO + except ImportError: + pass + else: + self.assertEqual(super_len(cStringIO.StringIO('but some how, some way...')), 25) + if __name__ == '__main__': unittest.main() -- 2.34.1