We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot use docker with eventlet since #2865
Before #2865, it was possible to use docker-py with a eventlet-based project.
However, after the inclusion of a tests for using poll(), i now have errors, see below.

This is expected: eventlet removes poll function on the select module on purpose. See https://github.com/eventlet/eventlet/issues/608#issuecomment-612359458

So instead of checking if the platform is win32, we should check if the select module have a poll method. Which also make it more cross-platform compatible as per select.poll documentation (https://docs.python.org/3/library/select.html#select.poll - Not supported by all operating systems, but not mentionning win32 exactly.)

```
.venv/lib/python3.11/site-packages/docker/utils/socket.py:156: in consume_socket_output                                       [64/1813]
    return bytes().join(frames)                                                                                                        
.venv/lib/python3.11/site-packages/docker/api/client.py:422: in <genexpr>                                                              
    gen = (data for (_, data) in gen)                                                                                                  
.venv/lib/python3.11/site-packages/docker/utils/socket.py:113: in frames_iter_no_tty                                                   
    (stream, n) = next_frame_header(socket)                                                                                            
.venv/lib/python3.11/site-packages/docker/utils/socket.py:85: in next_frame_header                                                     
    data = read_exactly(socket, 8)                                                                                                     
.venv/lib/python3.11/site-packages/docker/utils/socket.py:70: in read_exactly                                                          
    next_data = read(socket, n - len(data))                                                                                            
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _      
                                                                                                                                       
socket = <socket.SocketIO object at 0x7f0f24f04c10>, n = 8                                                                             
                                                                                                                                       
    def read(socket, n=4096):                                                                                                          
        """                                                                                                                            
        Reads at most n bytes from socket                                                                                              
        """                                                                                                                            
                                                                                                                                       
        recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)                                                           
                                                                                                                                       
        if not isinstance(socket, NpipeSocket):                                                                                        
            if sys.platform == 'win32':                                                                                                
                # Limited to 1024                                  
                select.select([socket], [], [])                    
            else:                
>               poll = select.poll()                               
E               AttributeError: module 'select' has no attribute 'poll'                                                                

.venv/lib/python3.11/site-packages/docker/utils/socket.py:39: AttributeError   
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docker/utils/socket.py`
Content:
```
1 import errno
2 import os
3 import select
4 import socket as pysocket
5 import struct
6 import sys
7 
8 try:
9     from ..transport import NpipeSocket
10 except ImportError:
11     NpipeSocket = type(None)
12 
13 
14 STDOUT = 1
15 STDERR = 2
16 
17 
18 class SocketError(Exception):
19     pass
20 
21 
22 # NpipeSockets have their own error types
23 # pywintypes.error: (109, 'ReadFile', 'The pipe has been ended.')
24 NPIPE_ENDED = 109
25 
26 
27 def read(socket, n=4096):
28     """
29     Reads at most n bytes from socket
30     """
31 
32     recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)
33 
34     if not isinstance(socket, NpipeSocket):
35         if sys.platform == 'win32':
36             # Limited to 1024
37             select.select([socket], [], [])
38         else:
39             poll = select.poll()
40             poll.register(socket, select.POLLIN | select.POLLPRI)
41             poll.poll()
42 
43     try:
44         if hasattr(socket, 'recv'):
45             return socket.recv(n)
46         if isinstance(socket, getattr(pysocket, 'SocketIO')):
47             return socket.read(n)
48         return os.read(socket.fileno(), n)
49     except OSError as e:
50         if e.errno not in recoverable_errors:
51             raise
52     except Exception as e:
53         is_pipe_ended = (isinstance(socket, NpipeSocket) and
54                          len(e.args) > 0 and
55                          e.args[0] == NPIPE_ENDED)
56         if is_pipe_ended:
57             # npipes don't support duplex sockets, so we interpret
58             # a PIPE_ENDED error as a close operation (0-length read).
59             return ''
60         raise
61 
62 
63 def read_exactly(socket, n):
64     """
65     Reads exactly n bytes from socket
66     Raises SocketError if there isn't enough data
67     """
68     data = bytes()
69     while len(data) < n:
70         next_data = read(socket, n - len(data))
71         if not next_data:
72             raise SocketError("Unexpected EOF")
73         data += next_data
74     return data
75 
76 
77 def next_frame_header(socket):
78     """
79     Returns the stream and size of the next frame of data waiting to be read
80     from socket, according to the protocol defined here:
81 
82     https://docs.docker.com/engine/api/v1.24/#attach-to-a-container
83     """
84     try:
85         data = read_exactly(socket, 8)
86     except SocketError:
87         return (-1, -1)
88 
89     stream, actual = struct.unpack('>BxxxL', data)
90     return (stream, actual)
91 
92 
93 def frames_iter(socket, tty):
94     """
95     Return a generator of frames read from socket. A frame is a tuple where
96     the first item is the stream number and the second item is a chunk of data.
97 
98     If the tty setting is enabled, the streams are multiplexed into the stdout
99     stream.
100     """
101     if tty:
102         return ((STDOUT, frame) for frame in frames_iter_tty(socket))
103     else:
104         return frames_iter_no_tty(socket)
105 
106 
107 def frames_iter_no_tty(socket):
108     """
109     Returns a generator of data read from the socket when the tty setting is
110     not enabled.
111     """
112     while True:
113         (stream, n) = next_frame_header(socket)
114         if n < 0:
115             break
116         while n > 0:
117             result = read(socket, n)
118             if result is None:
119                 continue
120             data_length = len(result)
121             if data_length == 0:
122                 # We have reached EOF
123                 return
124             n -= data_length
125             yield (stream, result)
126 
127 
128 def frames_iter_tty(socket):
129     """
130     Return a generator of data read from the socket when the tty setting is
131     enabled.
132     """
133     while True:
134         result = read(socket)
135         if len(result) == 0:
136             # We have reached EOF
137             return
138         yield result
139 
140 
141 def consume_socket_output(frames, demux=False):
142     """
143     Iterate through frames read from the socket and return the result.
144 
145     Args:
146 
147         demux (bool):
148             If False, stdout and stderr are multiplexed, and the result is the
149             concatenation of all the frames. If True, the streams are
150             demultiplexed, and the result is a 2-tuple where each item is the
151             concatenation of frames belonging to the same stream.
152     """
153     if demux is False:
154         # If the streams are multiplexed, the generator returns strings, that
155         # we just need to concatenate.
156         return bytes().join(frames)
157 
158     # If the streams are demultiplexed, the generator yields tuples
159     # (stdout, stderr)
160     out = [None, None]
161     for frame in frames:
162         # It is guaranteed that for each frame, one and only one stream
163         # is not None.
164         assert frame != (None, None)
165         if frame[0] is not None:
166             if out[0] is None:
167                 out[0] = frame[0]
168             else:
169                 out[0] += frame[0]
170         else:
171             if out[1] is None:
172                 out[1] = frame[1]
173             else:
174                 out[1] += frame[1]
175     return tuple(out)
176 
177 
178 def demux_adaptor(stream_id, data):
179     """
180     Utility to demultiplex stdout and stderr when reading frames from the
181     socket.
182     """
183     if stream_id == STDOUT:
184         return (data, None)
185     elif stream_id == STDERR:
186         return (None, data)
187     else:
188         raise ValueError(f'{stream_id} is not a valid stream')
189
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/docker/utils/socket.py b/docker/utils/socket.py
--- a/docker/utils/socket.py
+++ b/docker/utils/socket.py
@@ -3,7 +3,6 @@
 import select
 import socket as pysocket
 import struct
-import sys
 
 try:
     from ..transport import NpipeSocket
@@ -32,7 +31,7 @@
     recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)
 
     if not isinstance(socket, NpipeSocket):
-        if sys.platform == 'win32':
+        if not hasattr(select, "poll"):
             # Limited to 1024
             select.select([socket], [], [])
         else:

{"golden_diff": "diff --git a/docker/utils/socket.py b/docker/utils/socket.py\n--- a/docker/utils/socket.py\n+++ b/docker/utils/socket.py\n@@ -3,7 +3,6 @@\n import select\n import socket as pysocket\n import struct\n-import sys\n \n try:\n     from ..transport import NpipeSocket\n@@ -32,7 +31,7 @@\n     recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)\n \n     if not isinstance(socket, NpipeSocket):\n-        if sys.platform == 'win32':\n+        if not hasattr(select, \"poll\"):\n             # Limited to 1024\n             select.select([socket], [], [])\n         else:\n", "issue": "Cannot use docker with eventlet since #2865\nBefore #2865, it was possible to use docker-py with a eventlet-based project.\r\nHowever, after the inclusion of a tests for using poll(), i now have errors, see below.\r\n\r\nThis is expected: eventlet removes poll function on the select module on purpose. See https://github.com/eventlet/eventlet/issues/608#issuecomment-612359458\r\n\r\nSo instead of checking if the platform is win32, we should check if the select module have a poll method. Which also make it more cross-platform compatible as per select.poll documentation (https://docs.python.org/3/library/select.html#select.poll - Not supported by all operating systems, but not mentionning win32 exactly.)\r\n\r\n```\r\n.venv/lib/python3.11/site-packages/docker/utils/socket.py:156: in consume_socket_output                                       [64/1813]\r\n    return bytes().join(frames)                                                                                                        \r\n.venv/lib/python3.11/site-packages/docker/api/client.py:422: in <genexpr>                                                              \r\n    gen = (data for (_, data) in gen)                                                                                                  \r\n.venv/lib/python3.11/site-packages/docker/utils/socket.py:113: in frames_iter_no_tty                                                   \r\n    (stream, n) = next_frame_header(socket)                                                                                            \r\n.venv/lib/python3.11/site-packages/docker/utils/socket.py:85: in next_frame_header                                                     \r\n    data = read_exactly(socket, 8)                                                                                                     \r\n.venv/lib/python3.11/site-packages/docker/utils/socket.py:70: in read_exactly                                                          \r\n    next_data = read(socket, n - len(data))                                                                                            \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _      \r\n                                                                                                                                       \r\nsocket = <socket.SocketIO object at 0x7f0f24f04c10>, n = 8                                                                             \r\n                                                                                                                                       \r\n    def read(socket, n=4096):                                                                                                          \r\n        \"\"\"                                                                                                                            \r\n        Reads at most n bytes from socket                                                                                              \r\n        \"\"\"                                                                                                                            \r\n                                                                                                                                       \r\n        recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)                                                           \r\n                                                                                                                                       \r\n        if not isinstance(socket, NpipeSocket):                                                                                        \r\n            if sys.platform == 'win32':                                                                                                \r\n                # Limited to 1024                                  \r\n                select.select([socket], [], [])                    \r\n            else:                \r\n>               poll = select.poll()                               \r\nE               AttributeError: module 'select' has no attribute 'poll'                                                                \r\n\r\n.venv/lib/python3.11/site-packages/docker/utils/socket.py:39: AttributeError   \r\n```\n", "before_files": [{"content": "import errno\nimport os\nimport select\nimport socket as pysocket\nimport struct\nimport sys\n\ntry:\n    from ..transport import NpipeSocket\nexcept ImportError:\n    NpipeSocket = type(None)\n\n\nSTDOUT = 1\nSTDERR = 2\n\n\nclass SocketError(Exception):\n    pass\n\n\n# NpipeSockets have their own error types\n# pywintypes.error: (109, 'ReadFile', 'The pipe has been ended.')\nNPIPE_ENDED = 109\n\n\ndef read(socket, n=4096):\n    \"\"\"\n    Reads at most n bytes from socket\n    \"\"\"\n\n    recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)\n\n    if not isinstance(socket, NpipeSocket):\n        if sys.platform == 'win32':\n            # Limited to 1024\n            select.select([socket], [], [])\n        else:\n            poll = select.poll()\n            poll.register(socket, select.POLLIN | select.POLLPRI)\n            poll.poll()\n\n    try:\n        if hasattr(socket, 'recv'):\n            return socket.recv(n)\n        if isinstance(socket, getattr(pysocket, 'SocketIO')):\n            return socket.read(n)\n        return os.read(socket.fileno(), n)\n    except OSError as e:\n        if e.errno not in recoverable_errors:\n            raise\n    except Exception as e:\n        is_pipe_ended = (isinstance(socket, NpipeSocket) and\n                         len(e.args) > 0 and\n                         e.args[0] == NPIPE_ENDED)\n        if is_pipe_ended:\n            # npipes don't support duplex sockets, so we interpret\n            # a PIPE_ENDED error as a close operation (0-length read).\n            return ''\n        raise\n\n\ndef read_exactly(socket, n):\n    \"\"\"\n    Reads exactly n bytes from socket\n    Raises SocketError if there isn't enough data\n    \"\"\"\n    data = bytes()\n    while len(data) < n:\n        next_data = read(socket, n - len(data))\n        if not next_data:\n            raise SocketError(\"Unexpected EOF\")\n        data += next_data\n    return data\n\n\ndef next_frame_header(socket):\n    \"\"\"\n    Returns the stream and size of the next frame of data waiting to be read\n    from socket, according to the protocol defined here:\n\n    https://docs.docker.com/engine/api/v1.24/#attach-to-a-container\n    \"\"\"\n    try:\n        data = read_exactly(socket, 8)\n    except SocketError:\n        return (-1, -1)\n\n    stream, actual = struct.unpack('>BxxxL', data)\n    return (stream, actual)\n\n\ndef frames_iter(socket, tty):\n    \"\"\"\n    Return a generator of frames read from socket. A frame is a tuple where\n    the first item is the stream number and the second item is a chunk of data.\n\n    If the tty setting is enabled, the streams are multiplexed into the stdout\n    stream.\n    \"\"\"\n    if tty:\n        return ((STDOUT, frame) for frame in frames_iter_tty(socket))\n    else:\n        return frames_iter_no_tty(socket)\n\n\ndef frames_iter_no_tty(socket):\n    \"\"\"\n    Returns a generator of data read from the socket when the tty setting is\n    not enabled.\n    \"\"\"\n    while True:\n        (stream, n) = next_frame_header(socket)\n        if n < 0:\n            break\n        while n > 0:\n            result = read(socket, n)\n            if result is None:\n                continue\n            data_length = len(result)\n            if data_length == 0:\n                # We have reached EOF\n                return\n            n -= data_length\n            yield (stream, result)\n\n\ndef frames_iter_tty(socket):\n    \"\"\"\n    Return a generator of data read from the socket when the tty setting is\n    enabled.\n    \"\"\"\n    while True:\n        result = read(socket)\n        if len(result) == 0:\n            # We have reached EOF\n            return\n        yield result\n\n\ndef consume_socket_output(frames, demux=False):\n    \"\"\"\n    Iterate through frames read from the socket and return the result.\n\n    Args:\n\n        demux (bool):\n            If False, stdout and stderr are multiplexed, and the result is the\n            concatenation of all the frames. If True, the streams are\n            demultiplexed, and the result is a 2-tuple where each item is the\n            concatenation of frames belonging to the same stream.\n    \"\"\"\n    if demux is False:\n        # If the streams are multiplexed, the generator returns strings, that\n        # we just need to concatenate.\n        return bytes().join(frames)\n\n    # If the streams are demultiplexed, the generator yields tuples\n    # (stdout, stderr)\n    out = [None, None]\n    for frame in frames:\n        # It is guaranteed that for each frame, one and only one stream\n        # is not None.\n        assert frame != (None, None)\n        if frame[0] is not None:\n            if out[0] is None:\n                out[0] = frame[0]\n            else:\n                out[0] += frame[0]\n        else:\n            if out[1] is None:\n                out[1] = frame[1]\n            else:\n                out[1] += frame[1]\n    return tuple(out)\n\n\ndef demux_adaptor(stream_id, data):\n    \"\"\"\n    Utility to demultiplex stdout and stderr when reading frames from the\n    socket.\n    \"\"\"\n    if stream_id == STDOUT:\n        return (data, None)\n    elif stream_id == STDERR:\n        return (None, data)\n    else:\n        raise ValueError(f'{stream_id} is not a valid stream')\n", "path": "docker/utils/socket.py"}], "after_files": [{"content": "import errno\nimport os\nimport select\nimport socket as pysocket\nimport struct\n\ntry:\n    from ..transport import NpipeSocket\nexcept ImportError:\n    NpipeSocket = type(None)\n\n\nSTDOUT = 1\nSTDERR = 2\n\n\nclass SocketError(Exception):\n    pass\n\n\n# NpipeSockets have their own error types\n# pywintypes.error: (109, 'ReadFile', 'The pipe has been ended.')\nNPIPE_ENDED = 109\n\n\ndef read(socket, n=4096):\n    \"\"\"\n    Reads at most n bytes from socket\n    \"\"\"\n\n    recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)\n\n    if not isinstance(socket, NpipeSocket):\n        if not hasattr(select, \"poll\"):\n            # Limited to 1024\n            select.select([socket], [], [])\n        else:\n            poll = select.poll()\n            poll.register(socket, select.POLLIN | select.POLLPRI)\n            poll.poll()\n\n    try:\n        if hasattr(socket, 'recv'):\n            return socket.recv(n)\n        if isinstance(socket, getattr(pysocket, 'SocketIO')):\n            return socket.read(n)\n        return os.read(socket.fileno(), n)\n    except OSError as e:\n        if e.errno not in recoverable_errors:\n            raise\n    except Exception as e:\n        is_pipe_ended = (isinstance(socket, NpipeSocket) and\n                         len(e.args) > 0 and\n                         e.args[0] == NPIPE_ENDED)\n        if is_pipe_ended:\n            # npipes don't support duplex sockets, so we interpret\n            # a PIPE_ENDED error as a close operation (0-length read).\n            return ''\n        raise\n\n\ndef read_exactly(socket, n):\n    \"\"\"\n    Reads exactly n bytes from socket\n    Raises SocketError if there isn't enough data\n    \"\"\"\n    data = bytes()\n    while len(data) < n:\n        next_data = read(socket, n - len(data))\n        if not next_data:\n            raise SocketError(\"Unexpected EOF\")\n        data += next_data\n    return data\n\n\ndef next_frame_header(socket):\n    \"\"\"\n    Returns the stream and size of the next frame of data waiting to be read\n    from socket, according to the protocol defined here:\n\n    https://docs.docker.com/engine/api/v1.24/#attach-to-a-container\n    \"\"\"\n    try:\n        data = read_exactly(socket, 8)\n    except SocketError:\n        return (-1, -1)\n\n    stream, actual = struct.unpack('>BxxxL', data)\n    return (stream, actual)\n\n\ndef frames_iter(socket, tty):\n    \"\"\"\n    Return a generator of frames read from socket. A frame is a tuple where\n    the first item is the stream number and the second item is a chunk of data.\n\n    If the tty setting is enabled, the streams are multiplexed into the stdout\n    stream.\n    \"\"\"\n    if tty:\n        return ((STDOUT, frame) for frame in frames_iter_tty(socket))\n    else:\n        return frames_iter_no_tty(socket)\n\n\ndef frames_iter_no_tty(socket):\n    \"\"\"\n    Returns a generator of data read from the socket when the tty setting is\n    not enabled.\n    \"\"\"\n    while True:\n        (stream, n) = next_frame_header(socket)\n        if n < 0:\n            break\n        while n > 0:\n            result = read(socket, n)\n            if result is None:\n                continue\n            data_length = len(result)\n            if data_length == 0:\n                # We have reached EOF\n                return\n            n -= data_length\n            yield (stream, result)\n\n\ndef frames_iter_tty(socket):\n    \"\"\"\n    Return a generator of data read from the socket when the tty setting is\n    enabled.\n    \"\"\"\n    while True:\n        result = read(socket)\n        if len(result) == 0:\n            # We have reached EOF\n            return\n        yield result\n\n\ndef consume_socket_output(frames, demux=False):\n    \"\"\"\n    Iterate through frames read from the socket and return the result.\n\n    Args:\n\n        demux (bool):\n            If False, stdout and stderr are multiplexed, and the result is the\n            concatenation of all the frames. If True, the streams are\n            demultiplexed, and the result is a 2-tuple where each item is the\n            concatenation of frames belonging to the same stream.\n    \"\"\"\n    if demux is False:\n        # If the streams are multiplexed, the generator returns strings, that\n        # we just need to concatenate.\n        return bytes().join(frames)\n\n    # If the streams are demultiplexed, the generator yields tuples\n    # (stdout, stderr)\n    out = [None, None]\n    for frame in frames:\n        # It is guaranteed that for each frame, one and only one stream\n        # is not None.\n        assert frame != (None, None)\n        if frame[0] is not None:\n            if out[0] is None:\n                out[0] = frame[0]\n            else:\n                out[0] += frame[0]\n        else:\n            if out[1] is None:\n                out[1] = frame[1]\n            else:\n                out[1] += frame[1]\n    return tuple(out)\n\n\ndef demux_adaptor(stream_id, data):\n    \"\"\"\n    Utility to demultiplex stdout and stderr when reading frames from the\n    socket.\n    \"\"\"\n    if stream_id == STDOUT:\n        return (data, None)\n    elif stream_id == STDERR:\n        return (None, data)\n    else:\n        raise ValueError(f'{stream_id} is not a valid stream')\n", "path": "docker/utils/socket.py"}]}