gevent - 'module' object has no attribute 'epoll' with Python2-7 and Gevent -1.0.1; with Requests-2.13.0


requests 2.13.0 fails

    >>> import sys
    >>> import gevent.monkey
    >>> gevent.monkey.patch_all()   # This must be called before any other modules calling socket/request
    >>> import requests
    >>>
    >>> print 'py version:', sys.version_info
    py version: sys.version_info(major=2, minor=7, micro=8, releaselevel='final', serial=0)
    >>> print 'requests version:', requests.__version__
    requests version: 2.13.0
    >>> print 'gevent version:', gevent.__version__
    gevent version: 1.0.1
    >>>
    >>> assert requests.get('http://www.python.org').content

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/api.py", line 70, in get
        return request('get', url, params=params, **kwargs)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/api.py", line 56, in request
        return session.request(method=method, url=url, **kwargs)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/sessions.py", line 488, in request
        resp = self.send(prep, **send_kwargs)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/sessions.py", line 630, in send
        history = [resp for resp in gen] if allow_redirects else []
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/sessions.py", line 190, in resolve_redirects
        **adapter_kwargs
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/sessions.py", line 609, in send
        r = adapter.send(request, **kwargs)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/adapters.py", line 423, in send
        timeout=timeout
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 600, in urlopen
        chunked=chunked)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 345, in _make_request
        self._validate_conn(conn)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 844, in _validate_conn
        conn.connect()
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/connection.py", line 326, in connect
        ssl_context=context)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/util/ssl_.py", line 324, in ssl_wrap_socket
        return context.wrap_socket(sock, server_hostname=server_hostname)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/contrib/pyopenssl.py", line 438, in wrap_socket
        rd = util.wait_for_read(sock, sock.gettimeout())
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/util/wait.py", line 33, in wait_for_read
        return _wait_for_io_events(socks, EVENT_READ, timeout)
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/util/wait.py", line 22, in _wait_for_io_events
        with DefaultSelector() as selector:
      File "/home/barikak/workplace/NetengCommonW/env/NetengCommon-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/util/selectors.py", line 364, in __init__
        self._epoll = select.epoll()
    AttributeError: 'module' object has no attribute 'epoll'
    >>>
    >>>

requests 2.9.1 works

    >>> import sys
    >>> import gevent.monkey
    >>> gevent.monkey.patch_all()   # This must be called before any other modules calling socket/request
    >>>
    >>> import requests
    >>>
    >>> print 'py version:', sys.version_info
    py version: sys.version_info(major=2, minor=7, micro=8, releaselevel='final', serial=0)
    >>> print 'requests version:', requests.__version__
    requests version: 2.9.1
    >>> print 'gevent version:', gevent.__version__
    gevent version: 1.0.1
    >>>
    >>> assert requests.get('http://www.python.org').content
    /home/barikak/workplace/NSDSwiftKanbanClientW/env/NSDSwiftKanbanClient-1.0/runtime/lib/python2.7/site-packages/requests/packages/urllib3/util/ssl_.py:120: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
      InsecurePlatformWarning
    >>>


Are you *absolutely certain* that nothing else imports requests before you get there? Because this seems to be a bug that only occurs if Requests is imported before gevent monkey patching.

In the meantime, please try 2.14.2.

I can't reproduce this on Python 2.7 with requests 2.13.0 and gevent 1.0.1 running the following:
```python
>>> import gevent.monkey
>>> gevent.monkey.patch_all()
>>> import requests
>>> requests.get('http://www.google.com')
<Response [200]>
```
This means that `select` is probably patching before the import of `requests` as @Lukasa suggested.

After upgrading to `2.14.2` you should be able to patch any time before `requests` is first used, including post-import.
```python
>>> import gevent.monkey
>>> import requests
>>> gevent.monkey.patch_all()
>>> requests.get('http://www.google.com')
<Response [200]>

```

Thanks a lot... Yes, I am absolutely sure requests is not being imported before patching.

Great. I am pushing for 2.14.2, but also found a workaround:

    import sys
    import gevent.monkey
    gevent.monkey.patch_all()   # This must be called before any other modules calling socket/request

    import requests

    print 'py version:', sys.version_info
    print 'requests version:', requests.__version__
    print 'gevent version:', gevent.__version__

    import select
    from requests.packages.urllib3.util.selectors import EpollSelector, SelectSelector, PollSelector

    if hasattr(select, "epoll"):
        print 'epollo'
        requests.packages.urllib3.util.wait.DefaultSelector = EpollSelector
    elif hasattr(select, "select"):
        print 'select'
        requests.packages.urllib3.util.wait.DefaultSelector = SelectSelector
    elif hasattr(select, "poll"):
        print 'poll'
        requests.packages.urllib3.util.wait.DefaultSelector = PollSelector

    assert requests.get('http://www.python.org').content

The error occurs even when you run the four lines that I posted above in a blank empty Python console?

Run these lines in a new console and report back if this errors with the same error (It shouldn't for `requests==2.13.0`):
```python
import gevent.monkey
gevent.monkey.patch_all()
import requests
requests.get('http://www.google.com')
```

Your work-around is basically what `requests` is doing in the background in it's ported `urllib3.selectors` module. You shouldn't have to do this work-around given the proper patch->import order. If the patching occurs after the import and we assumed that you should use a selector (in this case, `select.epoll()`) that no longer exists in your post-patched `select` module then there are problems. This is why we believe that the patching is occurring before `requests` is imported.

I see... So, it looks like `import sys` if called before patch, throws an exception.

This doesn't throw error

    import gevent.monkey
    gevent.monkey.patch_all()
    import requests
    import sys
    requests.get('http://www.google.com')


This throws exception

    import sys
    import gevent.monkey
    gevent.monkey.patch_all()
    import requests
    requests.get('http://www.python.org')




Again, I cannot be emphatic enough: you must not import *anything* before applying a gevent monkey patch.

This is ultimately a gevent bug, not a Requests bug.

Thank you so much for your help