<s> """<STR_LIT>""" <EOL> from __future__ import with_statement <EOL> from watchdog . utils import platform <EOL> if not platform . is_bsd ( ) and not platform . is_darwin ( ) : <EOL> raise ImportError <EOL> import threading <EOL> import errno <EOL> import sys <EOL> import stat <EOL> import os <EOL> if sys . version_info < ( <NUM_LIT:2> , <NUM_LIT:7> , <NUM_LIT:0> ) : <EOL> import select_backport as select <EOL> else : <EOL> import select <EOL> from pathtools . path import absolute_path <EOL> from watchdog . observers . api import ( <EOL> BaseObserver , <EOL> EventEmitter , <EOL> DEFAULT_OBSERVER_TIMEOUT , <EOL> DEFAULT_EMITTER_TIMEOUT <EOL> ) <EOL> from watchdog . utils . dirsnapshot import DirectorySnapshot <EOL> from watchdog . events import ( <EOL> DirMovedEvent , <EOL> DirDeletedEvent , <EOL> DirCreatedEvent , <EOL> DirModifiedEvent , <EOL> FileMovedEvent , <EOL> FileDeletedEvent , <EOL> FileCreatedEvent , <EOL> FileModifiedEvent , <EOL> EVENT_TYPE_MOVED , <EOL> EVENT_TYPE_DELETED , <EOL> EVENT_TYPE_CREATED <EOL> ) <EOL> MAX_EVENTS = <NUM_LIT> <EOL> O_EVTONLY = <NUM_LIT> <EOL> if platform . is_darwin ( ) : <EOL> WATCHDOG_OS_OPEN_FLAGS = O_EVTONLY <EOL> else : <EOL> WATCHDOG_OS_OPEN_FLAGS = os . O_RDONLY | os . O_NONBLOCK <EOL> WATCHDOG_KQ_FILTER = select . KQ_FILTER_VNODE <EOL> WATCHDOG_KQ_EV_FLAGS = select . KQ_EV_ADD | select . KQ_EV_ENABLE | select . KQ_EV_CLEAR <EOL> WATCHDOG_KQ_FFLAGS = ( <EOL> select . KQ_NOTE_DELETE | <EOL> select . KQ_NOTE_WRITE | <EOL> select . KQ_NOTE_EXTEND | <EOL> select . KQ_NOTE_ATTRIB | <EOL> select . KQ_NOTE_LINK | <EOL> select . KQ_NOTE_RENAME | <EOL> select . KQ_NOTE_REVOKE <EOL> ) <EOL> def is_deleted ( kev ) : <EOL> """<STR_LIT>""" <EOL> return kev . fflags & select . KQ_NOTE_DELETE <EOL> def is_modified ( kev ) : <EOL> """<STR_LIT>""" <EOL> fflags = kev . fflags <EOL> return ( fflags & select . KQ_NOTE_EXTEND ) or ( fflags & select . KQ_NOTE_WRITE ) <EOL> def is_attrib_modified ( kev ) : <EOL> """<STR_LIT>""" <EOL> return kev . fflags & select . KQ_NOTE_ATTRIB <EOL> def is_renamed ( kev ) : <EOL> """<STR_LIT>""" <EOL> return kev . fflags & select . KQ_NOTE_RENAME <EOL> class KeventDescriptorSet ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self ) : <EOL> self . _descriptors = set ( ) <EOL> self . _descriptor_for_path = dict ( ) <EOL> self . _descriptor_for_fd = dict ( ) <EOL> self . _kevents = list ( ) <EOL> self . _lock = threading . Lock ( ) <EOL> @ property <EOL> def kevents ( self ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> return self . _kevents <EOL> @ property <EOL> def paths ( self ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> return list ( self . _descriptor_for_path . keys ( ) ) <EOL> def get_for_fd ( self , fd ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> return self . _descriptor_for_fd [ fd ] <EOL> def get ( self , path ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> path = absolute_path ( path ) <EOL> return self . _get ( path ) <EOL> def __contains__ ( self , path ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> path = absolute_path ( path ) <EOL> return self . _has_path ( path ) <EOL> def add ( self , path , is_directory ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> path = absolute_path ( path ) <EOL> if not self . _has_path ( path ) : <EOL> self . _add_descriptor ( KeventDescriptor ( path , is_directory ) ) <EOL> def remove ( self , path ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> path = absolute_path ( path ) <EOL> if self . _has_path ( path ) : <EOL> self . _remove_descriptor ( self . _get ( path ) ) <EOL> def clear ( self ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> for descriptor in self . _descriptors : <EOL> descriptor . close ( ) <EOL> self . _descriptors . clear ( ) <EOL> self . _descriptor_for_fd . clear ( ) <EOL> self . _descriptor_for_path . clear ( ) <EOL> self . _kevents = [ ] <EOL> def _get ( self , path ) : <EOL> """<STR_LIT>""" <EOL> return self . _descriptor_for_path [ path ] <EOL> def _has_path ( self , path ) : <EOL> """<STR_LIT>""" <EOL> return path in self . _descriptor_for_path <EOL> def _add_descriptor ( self , descriptor ) : <EOL> """<STR_LIT>""" <EOL> self . _descriptors . add ( descriptor ) <EOL> self . _kevents . append ( descriptor . kevent ) <EOL> self . _descriptor_for_path [ descriptor . path ] = descriptor <EOL> self . _descriptor_for_fd [ descriptor . fd ] = descriptor <EOL> def _remove_descriptor ( self , descriptor ) : <EOL> """<STR_LIT>""" <EOL> self . _descriptors . remove ( descriptor ) <EOL> del self . _descriptor_for_fd [ descriptor . fd ] <EOL> del self . _descriptor_for_path [ descriptor . path ] <EOL> self . _kevents . remove ( descriptor . kevent ) <EOL> descriptor . close ( ) <EOL> class KeventDescriptor ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , path , is_directory ) : <EOL> self . _path = absolute_path ( path ) <EOL> self . _is_directory = is_directory <EOL> self . _fd = os . open ( path , WATCHDOG_OS_OPEN_FLAGS ) <EOL> self . _kev = select . kevent ( self . _fd , <EOL> filter = WATCHDOG_KQ_FILTER , <EOL> flags = WATCHDOG_KQ_EV_FLAGS , <EOL> fflags = WATCHDOG_KQ_FFLAGS ) <EOL> @ property <EOL> def fd ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _fd <EOL> @ property <EOL> def path ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _path <EOL> @ property <EOL> def kevent ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _kev <EOL> @ property <EOL> def is_directory ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _is_directory <EOL> def close ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> os . close ( self . fd ) <EOL> except OSError : <EOL> pass <EOL> @ property <EOL> def key ( self ) : <EOL> return ( self . path , self . is_directory ) <EOL> def __eq__ ( self , descriptor ) : <EOL> return self . key == descriptor . key <EOL> def __ne__ ( self , descriptor ) : <EOL> return self . key != descriptor . key <EOL> def __hash__ ( self ) : <EOL> return hash ( self . key ) <EOL> def __repr__ ( self ) : <EOL> return "<STR_LIT>" % ( self . path , self . is_directory ) <EOL> class KqueueEmitter ( EventEmitter ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , event_queue , watch , timeout = DEFAULT_EMITTER_TIMEOUT ) : <EOL> EventEmitter . __init__ ( self , event_queue , watch , timeout ) <EOL> self . _kq = select . kqueue ( ) <EOL> self . _lock = threading . RLock ( ) <EOL> self . _descriptors = KeventDescriptorSet ( ) <EOL> def walker_callback ( path , stat_info , self = self ) : <EOL> self . _register_kevent ( path , stat . S_ISDIR ( stat_info . st_mode ) ) <EOL> self . _snapshot = DirectorySnapshot ( watch . path , <EOL> watch . is_recursive , <EOL> walker_callback ) <EOL> def _register_kevent ( self , path , is_directory ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> self . _descriptors . add ( path , is_directory ) <EOL> except OSError as e : <EOL> if e . errno == errno . ENOENT : <EOL> pass <EOL> else : <EOL> raise <EOL> def _unregister_kevent ( self , path ) : <EOL> """<STR_LIT>""" <EOL> self . _descriptors . remove ( path ) <EOL> def queue_event ( self , event ) : <EOL> """<STR_LIT>""" <EOL> EventEmitter . queue_event ( self , event ) <EOL> if event . event_type == EVENT_TYPE_CREATED : <EOL> self . _register_kevent ( event . src_path , event . is_directory ) <EOL> elif event . event_type == EVENT_TYPE_MOVED : <EOL> self . _unregister_kevent ( event . src_path ) <EOL> self . _register_kevent ( event . dest_path , event . is_directory ) <EOL> elif event . event_type == EVENT_TYPE_DELETED : <EOL> self . _unregister_kevent ( event . src_path ) <EOL> def _queue_dirs_modified ( self , <EOL> dirs_modified , <EOL> ref_snapshot , <EOL> new_snapshot ) : <EOL> """<STR_LIT>""" <EOL> if dirs_modified : <EOL> for dir_modified in dirs_modified : <EOL> self . queue_event ( DirModifiedEvent ( dir_modified ) ) <EOL> diff_events = new_snapshot - ref_snapshot <EOL> for file_created in diff_events . files_created : <EOL> self . queue_event ( FileCreatedEvent ( file_created ) ) <EOL> for directory_created in diff_events . dirs_created : <EOL> self . queue_event ( DirCreatedEvent ( directory_created ) ) <EOL> def _queue_events_except_renames_and_dir_modifications ( self , event_list ) : <EOL> """<STR_LIT>""" <EOL> files_renamed = set ( ) <EOL> dirs_renamed = set ( ) <EOL> dirs_modified = set ( ) <EOL> for kev in event_list : <EOL> descriptor = self . _descriptors . get_for_fd ( kev . ident ) <EOL> src_path = descriptor . path <EOL> if is_deleted ( kev ) : <EOL> if descriptor . is_directory : <EOL> self . queue_event ( DirDeletedEvent ( src_path ) ) <EOL> else : <EOL> self . queue_event ( FileDeletedEvent ( src_path ) ) <EOL> elif is_attrib_modified ( kev ) : <EOL> if descriptor . is_directory : <EOL> self . queue_event ( DirModifiedEvent ( src_path ) ) <EOL> else : <EOL> self . queue_event ( FileModifiedEvent ( src_path ) ) <EOL> elif is_modified ( kev ) : <EOL> if descriptor . is_directory : <EOL> dirs_modified . add ( src_path ) <EOL> else : <EOL> self . queue_event ( FileModifiedEvent ( src_path ) ) <EOL> elif is_renamed ( kev ) : <EOL> if descriptor . is_directory : <EOL> dirs_renamed . add ( src_path ) <EOL> else : <EOL> files_renamed . add ( src_path ) <EOL> return files_renamed , dirs_renamed , dirs_modified <EOL> def _queue_renamed ( self , <EOL> src_path , <EOL> is_directory , <EOL> ref_snapshot , <EOL> new_snapshot ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> ref_stat_info = ref_snapshot . stat_info ( src_path ) <EOL> except KeyError : <EOL> if is_directory : <EOL> self . queue_event ( DirCreatedEvent ( src_path ) ) <EOL> self . queue_event ( DirDeletedEvent ( src_path ) ) <EOL> else : <EOL> self . queue_event ( FileCreatedEvent ( src_path ) ) <EOL> self . queue_event ( FileDeletedEvent ( src_path ) ) <EOL> return <EOL> try : <EOL> dest_path = absolute_path ( <EOL> new_snapshot . path_for_inode ( ref_stat_info . st_ino ) ) <EOL> if is_directory : <EOL> event = DirMovedEvent ( src_path , dest_path ) <EOL> if self . watch . is_recursive : <EOL> for sub_event in event . sub_moved_events ( ) : <EOL> self . queue_event ( sub_event ) <EOL> self . queue_event ( event ) <EOL> else : <EOL> self . queue_event ( FileMovedEvent ( src_path , dest_path ) ) <EOL> except KeyError : <EOL> if is_directory : <EOL> self . queue_event ( DirDeletedEvent ( src_path ) ) <EOL> else : <EOL> self . queue_event ( FileDeletedEvent ( src_path ) ) <EOL> def _read_events ( self , timeout = None ) : <EOL> """<STR_LIT>""" <EOL> return self . _kq . control ( self . _descriptors . kevents , <EOL> MAX_EVENTS , <EOL> timeout ) <EOL> def queue_events ( self , timeout ) : <EOL> """<STR_LIT>""" <EOL> with self . _lock : <EOL> try : <EOL> event_list = self . _read_events ( timeout ) <EOL> files_renamed , dirs_renamed , dirs_modified = ( <EOL> self . _queue_events_except_renames_and_dir_modifications ( event_list ) ) <EOL> new_snapshot = DirectorySnapshot ( self . watch . path , <EOL> self . watch . is_recursive ) <EOL> ref_snapshot = self . _snapshot <EOL> self . _snapshot = new_snapshot <EOL> if files_renamed or dirs_renamed or dirs_modified : <EOL> for src_path in files_renamed : <EOL> self . _queue_renamed ( src_path , <EOL> False , <EOL> ref_snapshot , <EOL> new_snapshot ) <EOL> for src_path in dirs_renamed : <EOL> self . _queue_renamed ( src_path , <EOL> True , <EOL> ref_snapshot , <EOL> new_snapshot ) <EOL> self . _queue_dirs_modified ( dirs_modified , <EOL> ref_snapshot , <EOL> new_snapshot ) <EOL> except OSError as e : <EOL> if e . errno == errno . EBADF : <EOL> pass <EOL> else : <EOL> raise <EOL> def on_thread_stop ( self ) : <EOL> with self . _lock : <EOL> self . _descriptors . clear ( ) <EOL> self . _kq . close ( ) <EOL> class KqueueObserver ( BaseObserver ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , timeout = DEFAULT_OBSERVER_TIMEOUT ) : <EOL> BaseObserver . __init__ ( self , emitter_class = KqueueEmitter , timeout = timeout ) </s>
