ponty / PyVirtualDisplay

Python wrapper for Xvfb, Xephyr and Xvnc
BSD 2-Clause "Simplified" License
714 stars 78 forks source link

ValueError: filedescriptor out of range in select() #90

Open cgiraudeau opened 10 months ago

cgiraudeau commented 10 months ago

I use pyvirtualdisplay in a docker image to do scraping. After a time, I get the following error:

Traceback (most recent call last):
  File "/home/site/wwwroot/retriever/tools/browser_display.py", line 34, in start
    self._display.start()
  File "/usr/local/lib/python3.8/site-packages/pyvirtualdisplay/display.py", line 72, in start
    self._obj.start()
  File "/usr/local/lib/python3.8/site-packages/pyvirtualdisplay/abstractdisplay.py", line 149, in start
    self._start1_has_displayfd()
  File "/usr/local/lib/python3.8/site-packages/pyvirtualdisplay/abstractdisplay.py", line 197, in _start1_has_displayfd
    self.display = int(self._wait_for_pipe_text(rfd))
  File "/usr/local/lib/python3.8/site-packages/pyvirtualdisplay/abstractdisplay.py", line 295, in _wait_for_pipe_text
    (rfd_changed_ls, _, _) = select.select([rfd], [], [], 0.1)
ValueError: filedescriptor out of range in select()

The function select.select can only accept file descriptors below 1024. The solution is to use select.poll in place of select.select.

    def _wait_for_pipe_text(self, rfd):
        s = ""
        poll = select.poll()
        poll.register(rfd, select.POLLIN)

        start_time = time.time()
        while True:
            rfd_changed_ls = poll.poll(0.1)
            if not self.is_alive():
                poll.unregister(rfd)
                raise XStartError(
                    "%s program closed. command: %s stderr: %s"
                    % (self._program, self._command, self.stderr)
                )
            if rfd_changed_ls:
                if rfd in rfd_changed_ls[0]:
                    c = os.read(rfd, 1)
                    if c == b"\n":
                        break
                    s += c.decode("ascii")

            # this timeout is for "eternal" hang. see #62
            if time.time() - start_time >= self._timeout:
                poll.unregister(rfd)
                raise XStartTimeoutError(
                    "No reply from program %s. command:%s"
                    % (
                        self._program,
                        self._command,
                    )
                )

        poll.unregister(rfd)
        return s