Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
7 changes: 4 additions & 3 deletions 7 inotify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
For a higher-level interface that remains highly efficient, use the
inotify.watcher package.'''

__author__ = "Bryan O'Sullivan <bos@serpentine.com>"
__author__ = "Bryan O'Sullivan <bos@serpentine.com>, Daniel Franganillo <dfranganillo@gmail.com>"
__version__ = "1.2.2"

from _inotify import *

Expand All @@ -27,14 +28,14 @@ def _read_procfs_value(name):
def read_value():
try:
return int(open(procfs_path + '/' + name).read())
except OSError, err:
except OSError:
return None

read_value.__doc__ = '''Return the value of the %s setting from /proc.

If inotify is not enabled on this system, return None.''' % name

return read_value
return read_value()

max_queued_events = _read_procfs_value('max_queued_events')
max_user_instances = _read_procfs_value('max_user_instances')
Expand Down
1 change: 1 addition & 0 deletions 1 inotify/_inotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ PyObject *read_events(PyObject *self, PyObject *args)
if (PyList_Append(ret, obj) == -1)
goto mybail;

Py_DECREF(obj);
pos += sizeof(struct inotify_event) + in->len;
continue;

Expand Down
83 changes: 68 additions & 15 deletions 83 inotify/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
The AutoWatcher class is more useful, as it automatically watches
newly-created directories on your behalf.'''

__author__ = "Bryan O'Sullivan <bos@serpentine.com>"
__author__ = "Bryan O'Sullivan <bos@serpentine.com>, Daniel Franganillo <dfranganillo@gmail.com>"

import _inotify as inotify
import array
Expand Down Expand Up @@ -58,18 +58,27 @@ class Event(object):
)

def __init__(self, raw, path):

if (isinstance(path, str)):
path = path.decode('utf-8')

self.path = path
self.raw = raw

if raw.name:
self.fullpath = path + '/' + raw.name
self.fullpath = os.path.join(path, raw.name.decode('utf-8'))
self.name = raw.name.decode('utf-8')
else:
self.fullpath = path
self.name = ""

self.wd = raw.wd
self.mask = raw.mask
self.cookie = raw.cookie
self.name = raw.name


def __getstate__(self):
return self.raw

def __repr__(self):
r = repr(self.raw)
return 'Event(path=' + repr(self.path) + ', ' + r[r.find('(')+1:]
Expand Down Expand Up @@ -137,25 +146,32 @@ def add(self, path, mask):
Return the watch descriptor added or modified.'''

path = os.path.normpath(path)
wd = inotify.add_watch(self.fd, path, mask)
self._paths[path] = wd, mask
self._wds[wd] = path, mask
return wd
wd = inotify.add_watch(self.fd, path.encode('utf-8'), mask)

if (wd >= 0):
self._paths[path] = wd, mask
self._wds[wd] = path, mask
return wd
else:
return -1

def remove(self, wd):
'''Remove the given watch.'''

inotify.remove_watch(self.fd, wd)
self._remove(wd)
inotify.remove_watch(self.fd, wd)

def _remove(self, wd):
path_mask = self._wds.pop(wd, None)
if path_mask is not None:
self._paths.pop(path_mask[0])
if wd in self._wds:
path_mask = self._wds[wd]
del(self._wds[wd])
if path_mask[0] in self._paths:
del(self._paths[path_mask[0]])


def path(self, path):
'''Return a (watch descriptor, event mask) pair for the given path.

If the path is not being watched, return None.'''

return self._paths.get(path)
Expand All @@ -167,7 +183,7 @@ def wd(self, wd):
this watcher, return None.'''

return self._wds.get(wd)

def read(self, bufsize=None):
'''Read a list of queued inotify events.

Expand All @@ -177,11 +193,12 @@ def read(self, bufsize=None):

events = []
for evt in inotify.read(self.fd, bufsize):
events.append(Event(evt, self._wds[evt.wd][0]))
if evt.mask & inotify.IN_IGNORED:
self._remove(evt.wd)
elif evt.mask & inotify.IN_UNMOUNT:
self.close()
else:
events.append(Event(evt, self._wds[evt.wd][0]))
return events

def close(self):
Expand Down Expand Up @@ -270,6 +287,7 @@ class AutoWatcher(Watcher):

__slots__ = (
'addfilter',
'moved_from',
)

def __init__(self, addfilter=None):
Expand All @@ -286,8 +304,11 @@ def __init__(self, addfilter=None):

super(AutoWatcher, self).__init__()
self.addfilter = addfilter
self.moved_from = None

_dir_create_mask = inotify.IN_ISDIR | inotify.IN_CREATE
_dir_moved_from = inotify.IN_ISDIR | inotify.IN_MOVED_FROM
_dir_moved_to = inotify.IN_ISDIR | inotify.IN_MOVED_TO

def read(self, bufsize=None):
events = super(AutoWatcher, self).read(bufsize)
Expand All @@ -302,8 +323,40 @@ def read(self, bufsize=None):
except OSError, err:
if err.errno not in self.ignored_errors:
raise
else:
if evt.mask & self._dir_moved_from == self._dir_moved_from:
# a directory is changing its name
self.moved_from = (evt.fullpath, evt.cookie)
else:
if (self.moved_from) and evt.mask & self._dir_moved_to == self._dir_moved_to:
# a directory changed already its name
if (self.moved_from[1] == evt.cookie):
# gotcha
self.replace_name(self.moved_from[0], evt.fullpath)
self.moved_from = None
return events

def replace_name (self, oldpath, fullpath):

for path in self._paths.keys():
# Search for directories below or in same path
if (path.startswith(oldpath)):

# Build new pathame
newpath = fullpath + path[len(oldpath):]

# Get original watch descriptor
wd, mask = self._paths[path]

# Save new watch&mask for path
self._wds[wd] = newpath, mask

# Save wd&mask for the new pathname
self._paths[newpath] = wd, mask

# Delete old key,value
del(self._paths[path])


class Threshold(object):
'''Class that indicates whether a file descriptor has reached a
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.