Problems with requests version 2.12

We're currently seeing problems with requests version 2.12.0 and 2.12.1, see obspy/obspy#1599.

I don't have much time to investigate right now, unfortunately, but wanted to quickly report this here.
This might be an interaction with `future` package, as we are using it for Python 2/3 compatibility.

Steps to reproduce with anaconda:

```bash
$ conda create -n requests_bug python=2.7 requests=2.12.1 obspy
$ source activate requests_bug
$ obspy-runtests core
```

```
Traceback (most recent call last):
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/obspy/core/tests/test_stream.py", line 1720, in test_read
tr = read('https://examples.obspy.org/test.sac', dtype=np.int32)[0]
File "<decorator-gen-31>", line 2, in read
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/obspy/core/util/decorator.py", line 294, in _map_example_filename
return func(*args, **kwargs)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/obspy/core/stream.py", line 225, in read
download_to_file(url=pathname_or_url, filename_or_buffer=fh)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/obspy/core/util/base.py", line 602, in download_to_file
r = requests.get(url, stream=True)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/api.py", line 70, in get
return request('get', url, params=params, **kwargs)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/api.py", line 56, in request
return session.request(method=method, url=url, **kwargs)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/sessions.py", line 369, in __exit__
self.close()
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/sessions.py", line 690, in close
v.close()
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/adapters.py", line 306, in close
self.poolmanager.clear()
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/packages/urllib3/poolmanager.py", line 156, in clear
self.pools.clear()
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/packages/urllib3/_collections.py", line 94, in clear
self.dispose_func(value)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/packages/urllib3/poolmanager.py", line 117, in <lambda>
dispose_func=lambda p: p.close())
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 423, in close
conn = old_pool.get(block=False)
File "/home/travis/miniconda/envs/test-environment/lib/python2.7/Queue.py", line 165, in get
raise Empty
Empty
```

Can you check #2935, and in particular the solution linked by the solver of that issue [here](https://github.com/kennethreitz/requests/issues/2935)?

The debugging like described [here](http://kronuz.io/nasty-bugs-crawling-in-some-python-libraries.html) indeed works, however if I do it, I don't get any exception whatsoever anymore.. which is kind of puzzling for me right now..

@megies Interesting. However, you should check for that particular pattern of exception handling in your code and dependencies to see if you can find it.

I just `grep`ped through my complete python installation but didn't see any suspicious-looking patterns, most of these look like they are used as intended (I was only checking the naming of the second item, to see if anything might get overwritten accidently)..

```
$ cd ~/anaconda2/envs/requests_bug/lib/python2.7
$ ack-grep --python 'except [^()]*,[^()]*:'
```

output: [here](https://gist.github.com/megies/6e28df8c061669165c7d8c85f9d3ee42)

Hrm. Does any of your code do this? 

No, just checked. We have parantheses on all `except` lines that have a comma in it. Also checked for `future` package, that is sometimes behind confusing problems.

Ok, so you need to look to see if any third-or-first party code (yours or a dependency) is monkeypatching the queue module for any reason.

Just guessing right now, but maybe this has to do with it: https://github.com/PythonCharmers/python-future/blob/master/src/future/standard_library/__init__.py#L107

And when diffing for changes in `requests` (`git diff v2.10.0..v2.12.0`), I see the following:
```diff
--- a/requests/packages/urllib3/connectionpool.py
+++ b/requests/packages/urllib3/connectionpool.py
@@ -7,13 +7,6 @@ import warnings
 from socket import error as SocketError, timeout as SocketTimeout
 import socket
 
-try:  # Python 3
-    from queue import LifoQueue, Empty, Full
-except ImportError:
-    from Queue import LifoQueue, Empty, Full
-    # Queue is imported for side effects on MS Windows
-    import Queue as _unused_module_Queue  # noqa: unused
-
 
 from .exceptions import (
     ClosedPoolError,
@@ -32,6 +25,7 @@ from .exceptions import (
 )
 from .packages.ssl_match_hostname import CertificateError
 from .packages import six
+from .packages.six.moves.queue import LifoQueue, Empty, Full
 from .connection import (
     port_by_scheme,
     DummyConnection,
@@ -48,6 +42,10 @@ from .util.timeout import Timeout
 from .util.url import get_host, Url
 
 
+if six.PY2:
+    # Queue is imported for side effects on MS Windows
+    import Queue as _unused_module_Queue  # noqa: F401
+
 xrange = six.moves.xrange
 
 log = logging.getLogger(__name__)
```

So my best guess right now is that it might be a clash of `six` vs `future`..

There is always a risk of that.

I'm now 99% sure that this is an interaction of `six` and `future`.

With the following diff in `urllib3` the problem disappears:
```diff
--- connectionpool.py.orig	2016-12-01 16:04:38.473636714 +0100
+++ connectionpool.py.patched	2016-12-01 16:04:46.713677773 +0100
@@ -25,7 +25,7 @@
 )
 from .packages.ssl_match_hostname import CertificateError
 from .packages import six
-from .packages.six.moves.queue import LifoQueue, Empty, Full
+from .packages.six.moves import queue
 from .connection import (
     port_by_scheme,
     DummyConnection,
@@ -61,7 +61,7 @@
     """
 
     scheme = None
-    QueueCls = LifoQueue
+    QueueCls = queue.LifoQueue
 
     def __init__(self, host, port=None):
         if not host:
@@ -235,7 +235,7 @@
         except AttributeError:  # self.pool is None
             raise ClosedPoolError(self, "Pool is closed.")
 
-        except Empty:
+        except queue.Empty:
             if self.block:
                 raise EmptyPoolError(self,
                                      "Pool reached maximum size and no more "
@@ -274,7 +274,7 @@
         except AttributeError:
             # self.pool is None.
             pass
-        except Full:
+        except queue.Full:
             # This should never happen if self.block == True
             log.warning(
                 "Connection pool is full, discarding connection: %s",
@@ -424,7 +424,7 @@
                 if conn:
                     conn.close()
 
-        except Empty:
+        except queue.Empty:
             pass  # Done.
 
     def is_same_host(self, url):
@@ -612,7 +612,7 @@
             # Everything went great!
             clean_exit = True
 
-        except Empty:
+        except queue.Empty:
             # Timed out by queue.
             raise EmptyPoolError(self, "No pool connections are available.")
```

I'll propose that change to the urllib3 guys upstream.

Out of interest, why do you consider this to be urllib3's problem instead of future's problem?

Don't get me wrong, I'm not considering it to be urllib3's problem, I consider it a combined six/future problem. But since I could come up with a simple and non-intrusive solution in urllib, why not go with it?

Fact is that there are some version combinations of future and urllib3 that don't work well with each other, I'm not saying it is anybody's fault, just trying to fix it.

Sure thing. And we'll probably merge that fix in urllib3.

But ultimately, what urllib3 is doing is entirely reasonable. If a library is monkeypatching the standard library in any way, they need to be *extremely* cautious and ensure that their users import that library *before* anything else: otherwise, that monkeypatch can and will break other code.

For the sake of completeness, commenting out the following line in `future` (which is for Py2.6 compatibility) also makes the problem go away (on Python 2.7, not on Py2.6 obviously):

https://github.com/PythonCharmers/python-future/blob/v0.15.2/src/future/standard_library/__init__.py#L108

> But ultimately, what urllib3 is doing is entirely reasonable.

Yeah, sure. Like stated, I'm just being pragmatic here. There's a problem, found a fix that won't hurt anybody (or I'd be really surprised again), so it's fine for me.

@megies Out of interest, do you know what in your project or your dependencies imports future?

We use `future` all across `obspy` for Py2/3 compatibilty. We even have a test that checks that certain `future` imports are done at the very top of every Python file.
At some point we decided to go with `future` so we're stuck with for now.

>  At some point we decided to go with future so we're stuck with for now.

I'm so very sorry. That must be truly painful

> I'm so very sorry. That must be truly painful

It is.

FYI we can work around this within obspy (obspy/obspy#1612, obspy/obspy#1614), but it might still be good to solve this in requests/urllib3, mostly in case other packages use `future` and requests/urllib3.

Resolved in shazow/urllib3#1061