summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2016-05-06 08:07:37 (GMT)
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-05-16 22:32:40 (GMT)
commit82844a07596b5714b0245eae14952e5479bb432a (patch)
tree2a8997e5220e80d3feb19930812a0cc54be235b0
parent8d49bef632a0486e0172e543a6c2622398ed7a8c (diff)
downloadpoky-82844a07596b5714b0245eae14952e5479bb432a.tar.gz
bitbake: bitbake/pyinotify.py: Upgrade to py3 version
(Bitbake rev: 7d145937092191543c15a9eccbc826e5e69824b7) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/pyinotify.py256
1 files changed, 101 insertions, 155 deletions
diff --git a/bitbake/lib/pyinotify.py b/bitbake/lib/pyinotify.py
index 2dae002..4eb03b0 100644
--- a/bitbake/lib/pyinotify.py
+++ b/bitbake/lib/pyinotify.py
@@ -42,13 +42,14 @@ class UnsupportedPythonVersionError(PyinotifyError):
42 @param version: Current Python version 42 @param version: Current Python version
43 @type version: string 43 @type version: string
44 """ 44 """
45 err = 'Python %s is unsupported, requires at least Python 2.4' 45 PyinotifyError.__init__(self,
46 PyinotifyError.__init__(self, err % version) 46 ('Python %s is unsupported, requires '
47 'at least Python 3.0') % version)
47 48
48 49
49# Check Python version 50# Check Python version
50import sys 51import sys
51if sys.version_info < (2, 4): 52if sys.version_info < (3, 0):
52 raise UnsupportedPythonVersionError(sys.version) 53 raise UnsupportedPythonVersionError(sys.version)
53 54
54 55
@@ -68,6 +69,8 @@ from datetime import datetime, timedelta
68import time 69import time
69import re 70import re
70import asyncore 71import asyncore
72import glob
73import locale
71import subprocess 74import subprocess
72 75
73try: 76try:
@@ -76,12 +79,6 @@ except ImportError:
76 pass # Will fail on Python 2.4 which has reduce() builtin anyway. 79 pass # Will fail on Python 2.4 which has reduce() builtin anyway.
77 80
78try: 81try:
79 from glob import iglob as glob
80except ImportError:
81 # Python 2.4 does not have glob.iglob().
82 from glob import glob as glob
83
84try:
85 import ctypes 82 import ctypes
86 import ctypes.util 83 import ctypes.util
87except ImportError: 84except ImportError:
@@ -95,9 +92,7 @@ except ImportError:
95 92
96__author__ = "seb@dbzteam.org (Sebastien Martini)" 93__author__ = "seb@dbzteam.org (Sebastien Martini)"
97 94
98__version__ = "0.9.5" 95__version__ = "0.9.6"
99
100__metaclass__ = type # Use new-style classes by default
101 96
102 97
103# Compatibity mode: set to True to improve compatibility with 98# Compatibity mode: set to True to improve compatibility with
@@ -122,6 +117,9 @@ class INotifyWrapper:
122 """ 117 """
123 @staticmethod 118 @staticmethod
124 def create(): 119 def create():
120 """
121 Factory method instanciating and returning the right wrapper.
122 """
125 # First, try to use ctypes. 123 # First, try to use ctypes.
126 if ctypes: 124 if ctypes:
127 inotify = _CtypesLibcINotifyWrapper() 125 inotify = _CtypesLibcINotifyWrapper()
@@ -173,7 +171,7 @@ class _INotifySyscallsWrapper(INotifyWrapper):
173 def _inotify_init(self): 171 def _inotify_init(self):
174 try: 172 try:
175 fd = inotify_syscalls.inotify_init() 173 fd = inotify_syscalls.inotify_init()
176 except IOError, err: 174 except IOError as err:
177 self._last_errno = err.errno 175 self._last_errno = err.errno
178 return -1 176 return -1
179 return fd 177 return fd
@@ -181,7 +179,7 @@ class _INotifySyscallsWrapper(INotifyWrapper):
181 def _inotify_add_watch(self, fd, pathname, mask): 179 def _inotify_add_watch(self, fd, pathname, mask):
182 try: 180 try:
183 wd = inotify_syscalls.inotify_add_watch(fd, pathname, mask) 181 wd = inotify_syscalls.inotify_add_watch(fd, pathname, mask)
184 except IOError, err: 182 except IOError as err:
185 self._last_errno = err.errno 183 self._last_errno = err.errno
186 return -1 184 return -1
187 return wd 185 return wd
@@ -189,7 +187,7 @@ class _INotifySyscallsWrapper(INotifyWrapper):
189 def _inotify_rm_watch(self, fd, wd): 187 def _inotify_rm_watch(self, fd, wd):
190 try: 188 try:
191 ret = inotify_syscalls.inotify_rm_watch(fd, wd) 189 ret = inotify_syscalls.inotify_rm_watch(fd, wd)
192 except IOError, err: 190 except IOError as err:
193 self._last_errno = err.errno 191 self._last_errno = err.errno
194 return -1 192 return -1
195 return ret 193 return ret
@@ -213,17 +211,8 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
213 except (OSError, IOError): 211 except (OSError, IOError):
214 pass # Will attemp to load it with None anyway. 212 pass # Will attemp to load it with None anyway.
215 213
216 if sys.version_info >= (2, 6): 214 self._libc = ctypes.CDLL(libc_name, use_errno=True)
217 self._libc = ctypes.CDLL(libc_name, use_errno=True) 215 self._get_errno_func = ctypes.get_errno
218 self._get_errno_func = ctypes.get_errno
219 else:
220 self._libc = ctypes.CDLL(libc_name)
221 try:
222 location = self._libc.__errno_location
223 location.restype = ctypes.POINTER(ctypes.c_int)
224 self._get_errno_func = lambda: location().contents.value
225 except AttributeError:
226 pass
227 216
228 # Eventually check that libc has needed inotify bindings. 217 # Eventually check that libc has needed inotify bindings.
229 if (not hasattr(self._libc, 'inotify_init') or 218 if (not hasattr(self._libc, 'inotify_init') or
@@ -241,9 +230,8 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
241 return True 230 return True
242 231
243 def _get_errno(self): 232 def _get_errno(self):
244 if self._get_errno_func is not None: 233 assert self._get_errno_func
245 return self._get_errno_func() 234 return self._get_errno_func()
246 return None
247 235
248 def _inotify_init(self): 236 def _inotify_init(self):
249 assert self._libc is not None 237 assert self._libc is not None
@@ -251,6 +239,11 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
251 239
252 def _inotify_add_watch(self, fd, pathname, mask): 240 def _inotify_add_watch(self, fd, pathname, mask):
253 assert self._libc is not None 241 assert self._libc is not None
242 # Encodes path to a bytes string. This conversion seems required because
243 # ctypes.create_string_buffer seems to manipulate bytes internally.
244 # Moreover it seems that inotify_add_watch does not work very well when
245 # it receives an ctypes.create_unicode_buffer instance as argument.
246 pathname = pathname.encode(sys.getfilesystemencoding())
254 pathname = ctypes.create_string_buffer(pathname) 247 pathname = ctypes.create_string_buffer(pathname)
255 return self._libc.inotify_add_watch(fd, pathname, mask) 248 return self._libc.inotify_add_watch(fd, pathname, mask)
256 249
@@ -258,10 +251,6 @@ class _CtypesLibcINotifyWrapper(INotifyWrapper):
258 assert self._libc is not None 251 assert self._libc is not None
259 return self._libc.inotify_rm_watch(fd, wd) 252 return self._libc.inotify_rm_watch(fd, wd)
260 253
261 def _sysctl(self, *args):
262 assert self._libc is not None
263 return self._libc.sysctl(*args)
264
265 254
266# Logging 255# Logging
267def logger_init(): 256def logger_init():
@@ -278,97 +267,58 @@ log = logger_init()
278 267
279 268
280# inotify's variables 269# inotify's variables
281class SysCtlINotify: 270class ProcINotify:
282 """ 271 """
283 Access (read, write) inotify's variables through sysctl. Usually it 272 Access (read, write) inotify's variables through /proc/sys/. Note that
284 requires administrator rights to update them. 273 usually it requires administrator rights to update them.
285 274
286 Examples: 275 Examples:
287 - Read max_queued_events attribute: myvar = max_queued_events.value 276 - Read max_queued_events attribute: myvar = max_queued_events.value
288 - Update max_queued_events attribute: max_queued_events.value = 42 277 - Update max_queued_events attribute: max_queued_events.value = 42
289 """ 278 """
290 279 def __init__(self, attr):
291 inotify_attrs = {'max_user_instances': 1, 280 self._base = "/proc/sys/fs/inotify"
292 'max_user_watches': 2, 281 self._attr = attr
293 'max_queued_events': 3}
294
295 def __init__(self, attrname, inotify_wrapper):
296 # FIXME: right now only supporting ctypes
297 assert ctypes
298 self._attrname = attrname
299 self._inotify_wrapper = inotify_wrapper
300 sino = ctypes.c_int * 3
301 self._attr = sino(5, 20, SysCtlINotify.inotify_attrs[attrname])
302
303 @staticmethod
304 def create(attrname):
305 """
306 Factory method instanciating and returning the right wrapper.
307 """
308 # FIXME: right now only supporting ctypes
309 if ctypes is None:
310 return None
311 inotify_wrapper = _CtypesLibcINotifyWrapper()
312 if not inotify_wrapper.init():
313 return None
314 return SysCtlINotify(attrname, inotify_wrapper)
315 282
316 def get_val(self): 283 def get_val(self):
317 """ 284 """
318 Gets attribute's value. Raises OSError if the operation failed. 285 Gets attribute's value.
319 286
320 @return: stored value. 287 @return: stored value.
321 @rtype: int 288 @rtype: int
289 @raise IOError: if corresponding file in /proc/sys cannot be read.
322 """ 290 """
323 oldv = ctypes.c_int(0) 291 with open(os.path.join(self._base, self._attr), 'r') as file_obj:
324 size = ctypes.c_int(ctypes.sizeof(oldv)) 292 return int(file_obj.readline())
325 sysctl = self._inotify_wrapper._sysctl
326 res = sysctl(self._attr, 3,
327 ctypes.c_voidp(ctypes.addressof(oldv)),
328 ctypes.addressof(size),
329 None, 0)
330 if res == -1:
331 raise OSError(self._inotify_wrapper.get_errno(),
332 self._inotify_wrapper.str_errno())
333 return oldv.value
334 293
335 def set_val(self, nval): 294 def set_val(self, nval):
336 """ 295 """
337 Sets new attribute's value. Raises OSError if the operation failed. 296 Sets new attribute's value.
338 297
339 @param nval: replaces current value by nval. 298 @param nval: replaces current value by nval.
340 @type nval: int 299 @type nval: int
300 @raise IOError: if corresponding file in /proc/sys cannot be written.
341 """ 301 """
342 oldv = ctypes.c_int(0) 302 with open(os.path.join(self._base, self._attr), 'w') as file_obj:
343 sizeo = ctypes.c_int(ctypes.sizeof(oldv)) 303 file_obj.write(str(nval) + '\n')
344 newv = ctypes.c_int(nval)
345 sizen = ctypes.c_int(ctypes.sizeof(newv))
346 sysctl = self._inotify_wrapper._sysctl
347 res = sysctl(self._attr, 3,
348 ctypes.c_voidp(ctypes.addressof(oldv)),
349 ctypes.addressof(sizeo),
350 ctypes.c_voidp(ctypes.addressof(newv)),
351 sizen)
352 if res == -1:
353 raise OSError(self._inotify_wrapper.get_errno(),
354 self._inotify_wrapper.str_errno())
355 304
356 value = property(get_val, set_val) 305 value = property(get_val, set_val)
357 306
358 def __repr__(self): 307 def __repr__(self):
359 return '<%s=%d>' % (self._attrname, self.get_val()) 308 return '<%s=%d>' % (self._attr, self.get_val())
360 309
361 310
362# Inotify's variables 311# Inotify's variables
363# 312#
364# FIXME: currently these variables are only accessible when ctypes is used, 313# Note: may raise IOError if the corresponding value in /proc/sys
365# otherwise there are set to None. 314# cannot be accessed.
366# 315#
367# read: myvar = max_queued_events.value 316# Examples:
368# update: max_queued_events.value = 42 317# - read: myvar = max_queued_events.value
318# - update: max_queued_events.value = 42
369# 319#
370for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'): 320for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
371 globals()[attrname] = SysCtlINotify.create(attrname) 321 globals()[attrname] = ProcINotify(attrname)
372 322
373 323
374class EventsCodes: 324class EventsCodes:
@@ -536,7 +486,7 @@ class _Event:
536 continue 486 continue
537 if attr == 'mask': 487 if attr == 'mask':
538 value = hex(getattr(self, attr)) 488 value = hex(getattr(self, attr))
539 elif isinstance(value, basestring) and not value: 489 elif isinstance(value, str) and not value:
540 value = "''" 490 value = "''"
541 s += ' %s%s%s' % (output_format.field_name(attr), 491 s += ' %s%s%s' % (output_format.field_name(attr),
542 output_format.punctuation('='), 492 output_format.punctuation('='),
@@ -628,7 +578,7 @@ class Event(_Event):
628 self.name)) 578 self.name))
629 else: 579 else:
630 self.pathname = os.path.abspath(self.path) 580 self.pathname = os.path.abspath(self.path)
631 except AttributeError, err: 581 except AttributeError as err:
632 # Usually it is not an error some events are perfectly valids 582 # Usually it is not an error some events are perfectly valids
633 # despite the lack of these attributes. 583 # despite the lack of these attributes.
634 log.debug(err) 584 log.debug(err)
@@ -718,8 +668,8 @@ class _SysProcessEvent(_ProcessEvent):
718 and self._mv. 668 and self._mv.
719 """ 669 """
720 date_cur_ = datetime.now() 670 date_cur_ = datetime.now()
721 for seq in [self._mv_cookie, self._mv]: 671 for seq in (self._mv_cookie, self._mv):
722 for k in seq.keys(): 672 for k in list(seq.keys()):
723 if (date_cur_ - seq[k][1]) > timedelta(minutes=1): 673 if (date_cur_ - seq[k][1]) > timedelta(minutes=1):
724 log.debug('Cleanup: deleting entry %s', seq[k][0]) 674 log.debug('Cleanup: deleting entry %s', seq[k][0])
725 del seq[k] 675 del seq[k]
@@ -767,9 +717,9 @@ class _SysProcessEvent(_ProcessEvent):
767 continue 717 continue
768 rawevent = _RawEvent(created_dir_wd, flags, 0, name) 718 rawevent = _RawEvent(created_dir_wd, flags, 0, name)
769 self._notifier.append_event(rawevent) 719 self._notifier.append_event(rawevent)
770 except OSError, err: 720 except OSError as err:
771 msg = "process_IN_CREATE, invalid directory %s: %s" 721 msg = "process_IN_CREATE, invalid directory: %s"
772 log.debug(msg % (created_dir, str(err))) 722 log.debug(msg % str(err))
773 return self.process_default(raw_event) 723 return self.process_default(raw_event)
774 724
775 def process_IN_MOVED_FROM(self, raw_event): 725 def process_IN_MOVED_FROM(self, raw_event):
@@ -1097,8 +1047,8 @@ class Stats(ProcessEvent):
1097 @type filename: string 1047 @type filename: string
1098 """ 1048 """
1099 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL 1049 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
1100 fd = os.open(filename, flags, 0600) 1050 fd = os.open(filename, flags, 0o0600)
1101 os.write(fd, str(self)) 1051 os.write(fd, bytes(self.__str__(), locale.getpreferredencoding()))
1102 os.close(fd) 1052 os.close(fd)
1103 1053
1104 def __str__(self, scale=45): 1054 def __str__(self, scale=45):
@@ -1107,7 +1057,7 @@ class Stats(ProcessEvent):
1107 return '' 1057 return ''
1108 1058
1109 m = max(stats.values()) 1059 m = max(stats.values())
1110 unity = float(scale) / m 1060 unity = scale / m
1111 fmt = '%%-26s%%-%ds%%s' % (len(output_format.field_value('@' * scale)) 1061 fmt = '%%-26s%%-%ds%%s' % (len(output_format.field_value('@' * scale))
1112 + 1) 1062 + 1)
1113 def func(x): 1063 def func(x):
@@ -1149,7 +1099,7 @@ class Notifier:
1149 @type default_proc_fun: instance of ProcessEvent 1099 @type default_proc_fun: instance of ProcessEvent
1150 @param read_freq: if read_freq == 0, events are read asap, 1100 @param read_freq: if read_freq == 0, events are read asap,
1151 if read_freq is > 0, this thread sleeps 1101 if read_freq is > 0, this thread sleeps
1152 max(0, read_freq - timeout) seconds. But if 1102 max(0, read_freq - (timeout / 1000)) seconds. But if
1153 timeout is None it may be different because 1103 timeout is None it may be different because
1154 poll is blocking waiting for something to read. 1104 poll is blocking waiting for something to read.
1155 @type read_freq: int 1105 @type read_freq: int
@@ -1161,8 +1111,9 @@ class Notifier:
1161 until the amount of events to read is >= threshold. 1111 until the amount of events to read is >= threshold.
1162 At least with read_freq set you might sleep. 1112 At least with read_freq set you might sleep.
1163 @type threshold: int 1113 @type threshold: int
1164 @param timeout: 1114 @param timeout: see read_freq above. If provided, it must be set in
1165 https://docs.python.org/3/library/select.html#polling-objects 1115 milliseconds. See
1116 https://docs.python.org/3/library/select.html#select.poll.poll
1166 @type timeout: int 1117 @type timeout: int
1167 """ 1118 """
1168 # Watch Manager instance 1119 # Watch Manager instance
@@ -1228,7 +1179,8 @@ class Notifier:
1228 milliseconds. 1179 milliseconds.
1229 1180
1230 @param timeout: If specified it overrides the corresponding instance 1181 @param timeout: If specified it overrides the corresponding instance
1231 attribute _timeout. 1182 attribute _timeout. timeout must be sepcified in
1183 milliseconds.
1232 @type timeout: int 1184 @type timeout: int
1233 1185
1234 @return: New events to read. 1186 @return: New events to read.
@@ -1240,8 +1192,8 @@ class Notifier:
1240 if timeout is None: 1192 if timeout is None:
1241 timeout = self._timeout 1193 timeout = self._timeout
1242 ret = self._pollobj.poll(timeout) 1194 ret = self._pollobj.poll(timeout)
1243 except select.error, err: 1195 except select.error as err:
1244 if err[0] == errno.EINTR: 1196 if err.args[0] == errno.EINTR:
1245 continue # interrupted, retry 1197 continue # interrupted, retry
1246 else: 1198 else:
1247 raise 1199 raise
@@ -1271,7 +1223,7 @@ class Notifier:
1271 try: 1223 try:
1272 # Read content from file 1224 # Read content from file
1273 r = os.read(self._fd, queue_size) 1225 r = os.read(self._fd, queue_size)
1274 except Exception, msg: 1226 except Exception as msg:
1275 raise NotifierError(msg) 1227 raise NotifierError(msg)
1276 log.debug('Event queue size: %d', queue_size) 1228 log.debug('Event queue size: %d', queue_size)
1277 rsum = 0 # counter 1229 rsum = 0 # counter
@@ -1281,9 +1233,11 @@ class Notifier:
1281 wd, mask, cookie, fname_len = struct.unpack('iIII', 1233 wd, mask, cookie, fname_len = struct.unpack('iIII',
1282 r[rsum:rsum+s_size]) 1234 r[rsum:rsum+s_size])
1283 # Retrieve name 1235 # Retrieve name
1284 fname, = struct.unpack('%ds' % fname_len, 1236 bname, = struct.unpack('%ds' % fname_len,
1285 r[rsum + s_size:rsum + s_size + fname_len]) 1237 r[rsum + s_size:rsum + s_size + fname_len])
1286 rawevent = _RawEvent(wd, mask, cookie, fname) 1238 # FIXME: should we explictly call sys.getdefaultencoding() here ??
1239 uname = bname.decode()
1240 rawevent = _RawEvent(wd, mask, cookie, uname)
1287 if self._coalesce: 1241 if self._coalesce:
1288 # Only enqueue new (unique) events. 1242 # Only enqueue new (unique) events.
1289 raweventstr = str(rawevent) 1243 raweventstr = str(rawevent)
@@ -1326,13 +1280,10 @@ class Notifier:
1326 def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull, 1280 def __daemonize(self, pid_file=None, stdin=os.devnull, stdout=os.devnull,
1327 stderr=os.devnull): 1281 stderr=os.devnull):
1328 """ 1282 """
1329 @param pid_file: file where the pid will be written. If pid_file=None 1283 pid_file: file where the pid will be written. If pid_file=None the pid
1330 the pid is written to 1284 is written to /var/run/<sys.argv[0]|pyinotify>.pid, if
1331 /var/run/<sys.argv[0]|pyinotify>.pid, if pid_file=False 1285 pid_file=False no pid_file is written.
1332 no pid_file is written. 1286 stdin, stdout, stderr: files associated to common streams.
1333 @param stdin:
1334 @param stdout:
1335 @param stderr: files associated to common streams.
1336 """ 1287 """
1337 if pid_file is None: 1288 if pid_file is None:
1338 dirname = '/var/run/' 1289 dirname = '/var/run/'
@@ -1354,7 +1305,7 @@ class Notifier:
1354 if (pid == 0): 1305 if (pid == 0):
1355 # child 1306 # child
1356 os.chdir('/') 1307 os.chdir('/')
1357 os.umask(022) 1308 os.umask(0o022)
1358 else: 1309 else:
1359 # parent 2 1310 # parent 2
1360 os._exit(0) 1311 os._exit(0)
@@ -1364,9 +1315,9 @@ class Notifier:
1364 1315
1365 fd_inp = os.open(stdin, os.O_RDONLY) 1316 fd_inp = os.open(stdin, os.O_RDONLY)
1366 os.dup2(fd_inp, 0) 1317 os.dup2(fd_inp, 0)
1367 fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0600) 1318 fd_out = os.open(stdout, os.O_WRONLY|os.O_CREAT, 0o0600)
1368 os.dup2(fd_out, 1) 1319 os.dup2(fd_out, 1)
1369 fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0600) 1320 fd_err = os.open(stderr, os.O_WRONLY|os.O_CREAT, 0o0600)
1370 os.dup2(fd_err, 2) 1321 os.dup2(fd_err, 2)
1371 1322
1372 # Detach task 1323 # Detach task
@@ -1375,8 +1326,9 @@ class Notifier:
1375 # Write pid 1326 # Write pid
1376 if pid_file != False: 1327 if pid_file != False:
1377 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL 1328 flags = os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW|os.O_EXCL
1378 fd_pid = os.open(pid_file, flags, 0600) 1329 fd_pid = os.open(pid_file, flags, 0o0600)
1379 os.write(fd_pid, str(os.getpid()) + '\n') 1330 os.write(fd_pid, bytes(str(os.getpid()) + '\n',
1331 locale.getpreferredencoding()))
1380 os.close(fd_pid) 1332 os.close(fd_pid)
1381 # Register unlink function 1333 # Register unlink function
1382 atexit.register(lambda : os.unlink(pid_file)) 1334 atexit.register(lambda : os.unlink(pid_file))
@@ -1441,9 +1393,12 @@ class Notifier:
1441 Close inotify's instance (close its file descriptor). 1393 Close inotify's instance (close its file descriptor).
1442 It destroys all existing watches, pending events,... 1394 It destroys all existing watches, pending events,...
1443 This method is automatically called at the end of loop(). 1395 This method is automatically called at the end of loop().
1396 Afterward it is invalid to access this instance.
1444 """ 1397 """
1445 self._pollobj.unregister(self._fd) 1398 if self._fd is not None:
1446 os.close(self._fd) 1399 self._pollobj.unregister(self._fd)
1400 os.close(self._fd)
1401 self._fd = None
1447 self._sys_proc_fun = None 1402 self._sys_proc_fun = None
1448 1403
1449 1404
@@ -1468,7 +1423,7 @@ class ThreadedNotifier(threading.Thread, Notifier):
1468 @type default_proc_fun: instance of ProcessEvent 1423 @type default_proc_fun: instance of ProcessEvent
1469 @param read_freq: if read_freq == 0, events are read asap, 1424 @param read_freq: if read_freq == 0, events are read asap,
1470 if read_freq is > 0, this thread sleeps 1425 if read_freq is > 0, this thread sleeps
1471 max(0, read_freq - timeout) seconds. 1426 max(0, read_freq - (timeout / 1000)) seconds.
1472 @type read_freq: int 1427 @type read_freq: int
1473 @param threshold: File descriptor will be read only if the accumulated 1428 @param threshold: File descriptor will be read only if the accumulated
1474 size to read becomes >= threshold. If != 0, you likely 1429 size to read becomes >= threshold. If != 0, you likely
@@ -1478,8 +1433,9 @@ class ThreadedNotifier(threading.Thread, Notifier):
1478 until the amount of events to read is >= threshold. At 1433 until the amount of events to read is >= threshold. At
1479 least with read_freq you might sleep. 1434 least with read_freq you might sleep.
1480 @type threshold: int 1435 @type threshold: int
1481 @param timeout: 1436 @param timeout: see read_freq above. If provided, it must be set in
1482 https://docs.python.org/3/library/select.html#polling-objects 1437 milliseconds. See
1438 https://docs.python.org/3/library/select.html#select.poll.poll
1483 @type timeout: int 1439 @type timeout: int
1484 """ 1440 """
1485 # Init threading base class 1441 # Init threading base class
@@ -1498,7 +1454,7 @@ class ThreadedNotifier(threading.Thread, Notifier):
1498 Stop notifier's loop. Stop notification. Join the thread. 1454 Stop notifier's loop. Stop notification. Join the thread.
1499 """ 1455 """
1500 self._stop_event.set() 1456 self._stop_event.set()
1501 os.write(self._pipe[1], 'stop') 1457 os.write(self._pipe[1], b'stop')
1502 threading.Thread.join(self) 1458 threading.Thread.join(self)
1503 Notifier.stop(self) 1459 Notifier.stop(self)
1504 self._pollobj.unregister(self._pipe[0]) 1460 self._pollobj.unregister(self._pipe[0])
@@ -1699,7 +1655,6 @@ class Watch:
1699class ExcludeFilter: 1655class ExcludeFilter:
1700 """ 1656 """
1701 ExcludeFilter is an exclusion filter. 1657 ExcludeFilter is an exclusion filter.
1702
1703 """ 1658 """
1704 def __init__(self, arg_lst): 1659 def __init__(self, arg_lst):
1705 """ 1660 """
@@ -1731,16 +1686,13 @@ class ExcludeFilter:
1731 1686
1732 def _load_patterns_from_file(self, filename): 1687 def _load_patterns_from_file(self, filename):
1733 lst = [] 1688 lst = []
1734 file_obj = file(filename, 'r') 1689 with open(filename, 'r') as file_obj:
1735 try:
1736 for line in file_obj.readlines(): 1690 for line in file_obj.readlines():
1737 # Trim leading an trailing whitespaces 1691 # Trim leading an trailing whitespaces
1738 pattern = line.strip() 1692 pattern = line.strip()
1739 if not pattern or pattern.startswith('#'): 1693 if not pattern or pattern.startswith('#'):
1740 continue 1694 continue
1741 lst.append(pattern) 1695 lst.append(pattern)
1742 finally:
1743 file_obj.close()
1744 return lst 1696 return lst
1745 1697
1746 def _match(self, regex, path): 1698 def _match(self, regex, path):
@@ -1764,7 +1716,6 @@ class WatchManagerError(Exception):
1764 """ 1716 """
1765 WatchManager Exception. Raised on error encountered on watches 1717 WatchManager Exception. Raised on error encountered on watches
1766 operations. 1718 operations.
1767
1768 """ 1719 """
1769 def __init__(self, msg, wmd): 1720 def __init__(self, msg, wmd):
1770 """ 1721 """
@@ -1851,7 +1802,7 @@ class WatchManager:
1851 """ 1802 """
1852 try: 1803 try:
1853 del self._wmd[wd] 1804 del self._wmd[wd]
1854 except KeyError, err: 1805 except KeyError as err:
1855 log.error('Cannot delete unknown watch descriptor %s' % str(err)) 1806 log.error('Cannot delete unknown watch descriptor %s' % str(err))
1856 1807
1857 @property 1808 @property
@@ -1868,13 +1819,7 @@ class WatchManager:
1868 """ 1819 """
1869 Format path to its internal (stored in watch manager) representation. 1820 Format path to its internal (stored in watch manager) representation.
1870 """ 1821 """
1871 # Unicode strings are converted back to strings, because it seems 1822 # path must be a unicode string (str) and is just normalized.
1872 # that inotify_add_watch from ctypes does not work well when
1873 # it receives an ctypes.create_unicode_buffer instance as argument.
1874 # Therefore even wd are indexed with bytes string and not with
1875 # unicode paths.
1876 if isinstance(path, unicode):
1877 path = path.encode(sys.getfilesystemencoding())
1878 return os.path.normpath(path) 1823 return os.path.normpath(path)
1879 1824
1880 def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter): 1825 def __add_watch(self, path, mask, proc_fun, auto_add, exclude_filter):
@@ -1890,13 +1835,14 @@ class WatchManager:
1890 return wd 1835 return wd
1891 watch = Watch(wd=wd, path=path, mask=mask, proc_fun=proc_fun, 1836 watch = Watch(wd=wd, path=path, mask=mask, proc_fun=proc_fun,
1892 auto_add=auto_add, exclude_filter=exclude_filter) 1837 auto_add=auto_add, exclude_filter=exclude_filter)
1838 # wd are _always_ indexed with their original unicode paths in wmd.
1893 self._wmd[wd] = watch 1839 self._wmd[wd] = watch
1894 log.debug('New %s', watch) 1840 log.debug('New %s', watch)
1895 return wd 1841 return wd
1896 1842
1897 def __glob(self, path, do_glob): 1843 def __glob(self, path, do_glob):
1898 if do_glob: 1844 if do_glob:
1899 return glob(path) 1845 return glob.iglob(path)
1900 else: 1846 else:
1901 return [path] 1847 return [path]
1902 1848
@@ -1907,11 +1853,8 @@ class WatchManager:
1907 Add watch(s) on the provided |path|(s) with associated |mask| flag 1853 Add watch(s) on the provided |path|(s) with associated |mask| flag
1908 value and optionally with a processing |proc_fun| function and 1854 value and optionally with a processing |proc_fun| function and
1909 recursive flag |rec| set to True. 1855 recursive flag |rec| set to True.
1910 Ideally |path| components should not be unicode objects. Note that 1856 All |path| components _must_ be str (i.e. unicode) objects.
1911 although unicode paths are accepted there are converted to byte 1857 If |path| is already watched it is ignored, but if it is called with
1912 strings before a watch is put on that path. The encoding used for
1913 converting the unicode object is given by sys.getfilesystemencoding().
1914 If |path| si already watched it is ignored, but if it is called with
1915 option rec=True a watch is put on each one of its not-watched 1858 option rec=True a watch is put on each one of its not-watched
1916 subdirectory. 1859 subdirectory.
1917 1860
@@ -1945,10 +1888,9 @@ class WatchManager:
1945 the class' constructor. 1888 the class' constructor.
1946 @type exclude_filter: callable object 1889 @type exclude_filter: callable object
1947 @return: dict of paths associated to watch descriptors. A wd value 1890 @return: dict of paths associated to watch descriptors. A wd value
1948 is positive if the watch was added sucessfully, 1891 is positive if the watch was added sucessfully, otherwise
1949 otherwise the value is negative. If the path was invalid 1892 the value is negative. If the path was invalid or was already
1950 or was already watched it is not included into this returned 1893 watched it is not included into this returned dictionary.
1951 dictionary.
1952 @rtype: dict of {str: int} 1894 @rtype: dict of {str: int}
1953 """ 1895 """
1954 ret_ = {} # return {path: wd, ...} 1896 ret_ = {} # return {path: wd, ...}
@@ -1958,6 +1900,11 @@ class WatchManager:
1958 1900
1959 # normalize args as list elements 1901 # normalize args as list elements
1960 for npath in self.__format_param(path): 1902 for npath in self.__format_param(path):
1903 # Require that path be a unicode string
1904 if not isinstance(npath, str):
1905 ret_[path] = -3
1906 continue
1907
1961 # unix pathname pattern expansion 1908 # unix pathname pattern expansion
1962 for apath in self.__glob(npath, do_glob): 1909 for apath in self.__glob(npath, do_glob):
1963 # recursively list subdirs according to rec param 1910 # recursively list subdirs according to rec param
@@ -2242,7 +2189,6 @@ class WatchManager:
2242 "Make watch manager ignoring new events.") 2189 "Make watch manager ignoring new events.")
2243 2190
2244 2191
2245
2246class RawOutputFormat: 2192class RawOutputFormat:
2247 """ 2193 """
2248 Format string representations. 2194 Format string representations.