Skip to content

Commit

Permalink
Fall back to select if poll does not exist
Browse files Browse the repository at this point in the history
The explanation is in the comment in the code.

Closes: seb-m#78
  • Loading branch information
jstasiak committed Jun 11, 2016
1 parent 4a6fd1e commit cea4ed6
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ python:
- "3.3"
- "3.4"
- "3.5"
- env:
- POLL_PRESENT=YES
- POLL_PRESENT=NO
install:
- pip install -r requirements-dev.txt
- pip install .
Expand Down
38 changes: 37 additions & 1 deletion pyinotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,42 @@ def __init__(self, err):
PyinotifyError.__init__(self, err)


try:
_poll_class = select.poll
except AttributeError:
class _Poll(object):
"""
poll emulator implemented using select.
This is used to make the client code happy in case of select.poll missing.
select.poll is missing when Gevent monkey patching is applied, Eventlet
will soon start doing the same.
See https://github.com/seb-m/pyinotify/issues/78.
"""
def __init__(self):
self._fds = []

def register(self, fd, eventmask):
assert eventmask == select.POLLIN, 'Only POLLIN supported right now'
self._fds.append(fd)

def poll(self, timeout):
timeout_in_seconds = timeout / 1000.0 if timeout is not None else None
can_read, _, _ = select.select(self._fds, [], [], timeout_in_seconds)
return [(fd, select.POLLIN) for fd in can_read]

def unregister(self, fd):
try:
self._fds.remove(fd)
except ValueError:
# poll.unregister is supposed to raise KeyError in case of
# attempting to unregister a descriptor that's not registered.
raise KeyError(fd)

_poll_class = _Poll


class Notifier:
"""
Read notifications, process events.
Expand Down Expand Up @@ -1128,7 +1164,7 @@ def __init__(self, watch_manager, default_proc_fun=None, read_freq=0,
# File descriptor
self._fd = self._watch_manager.get_fd()
# Poll object and registration
self._pollobj = select.poll()
self._pollobj = _poll_class()
self._pollobj.register(self._fd, select.POLLIN)
# This pipe is correctely initialized and used by ThreadedNotifier
self._pipe = (-1, -1)
Expand Down
7 changes: 7 additions & 0 deletions pyinotify_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import unittest
import os

if os.environ.get('POLL_PRESENT') == 'NO':
# This needs to happen before pyinotify is imported so that we can test
# if fallback to select.select() works
import select
del select.poll

import pyinotify
import tempfile
import shutil
Expand Down

0 comments on commit cea4ed6

Please sign in to comment.