2013-09-13 2 views
5

Я использую Watchdog для мониторинга каталога и синхронизации его с Dropbox.Python Watchdog: Есть ли способ приостановить наблюдателя?

Я столкнулся с ситуацией, когда каждый раз, когда я загружаю файл из Dropbox, я запускаю событие загрузки, так как мне нужно записать в каталог Watchdog. Это код, который я использую.

event_handler = UploadHandler.UploadHandler() 
observer = Observer() 
observer.schedule(event_handler, path=APP_PATH, recursive=True) 
observer.start() 

try: 
    while True: 
     # Apply download here 
     time.sleep(20) 

except KeyboardInterrupt: 
    observer.stop() 

observer.join() 

Есть ли способ, чтобы «сделать паузу» наблюдателя, а я применяю скачать и «возобновите» это еще раз, когда я сделал?

+0

У меня подобная проблема, и я смотрю на Observer api, чтобы попытаться понять это: https://github.com/gorakhargosh/watchdog/blob/master/src/watchdog/observers/api.py – grammar31

ответ

0

Вы можете переписать метод dispatch_events класса Observer, чтобы пропустить события, которые вы не хотите отправлять. Вот пример того, как сделать это:

class SkipObserver(watchdog.observers.Observer): 
    def __init__(self, *args): 
     Observer.__init__(self, *args) 
     self._skip_list = [] 

    def skip(self, event): 
     with self._lock: 
      self._skip_list.append(event) 

    def dispatch_events(self, event_queue, timeout): 
     event, watch = event_queue.get(block=True, timeout=timeout) 
     try: 
      if event in self._skip_list: 
       self._skip_list.remove(event) 
      else: 
       self._dispatch_event(event, watch) 
     except KeyError: 
      pass 
     event_queue.task_done() 

Теперь замените Observer на SkipObserver в вашем примере и использовать метод skip пропустить события. Опасайтесь использования skip в обработчике, так как это закончится тупиком, skip блокируется, как реализовано здесь. При обработке события наблюдатель заблокирован.

Если вы хотите указать пропуск для каждого обработчика, вы можете использовать аналогичный подход к вышеуказанному.

+0

Я думаю, что это приведет к тому, что он потеряет некоторые события. Я не думаю, что OP в порядке с потерей некоторых сигналов. – manu

+0

@manu: Если вы хотите потерять некоторые события при использовании пропусков (поскольку это блокирование), этого не происходит. – boxdot

0

Я нуждался задержавшись функциональность поэтому я использую следующий наблюдатель:

import time 
import contextlib 
import watchdog.observers 


class PausingObserver(watchdog.observers.Observer): 
    def dispatch_events(self, *args, **kwargs): 
     if not getattr(self, '_is_paused', False): 
      super(PausingObserver, self).dispatch_events(*args, **kwargs) 

    def pause(self): 
     self._is_paused = True 

    def resume(self): 
     time.sleep(self.timeout) # allow interim events to be queued 
     self.event_queue.queue.clear() 
     self._is_paused = False 

    @contextlib.contextmanager 
    def ignore_events(self): 
     self.pause() 
     yield 
     self.resume() 

Затем я могу приостановить наблюдатель непосредственно с pause() и resume() методами, но мой основной случай использования, когда я просто хочу игнорировать любые события, вызванные записью в каталоге я наблюдаю, за которую я использую менеджер контекста:

import os 
import datetime 
import watchdog.events 


class MyHandler(watchdog.events.FileSystemEventHandler): 
    def on_modified(self, event): 
     with OBSERVER.ignore_events(): 
      with open('./watchdir/modifications.log', 'a') as f: 
       f.write(datetime.datetime.now().strftime("%H:%M:%S") + '\n') 

if __name__ == '__main__': 
    watchdir = 'watchdir' 
    if not os.path.exists(watchdir): 
     os.makedirs(watchdir) 

    OBSERVER = PausingObserver() 
    OBSERVER.schedule(MyHandler(), watchdir, recursive=True) 
    OBSERVER.start() 
    try: 
     while True: 
      time.sleep(1) 
    except KeyboardInterrupt: 
     OBSERVER.stop() 
    OBSERVER.join() 

Вы можете проверить это путем сохранения обоих блоков кода в файле, запустив его, и добавление/редактирование/удаление файлов в созданный каталог 'watchdir'. Временные метки ваших модификаций будут добавлены к 'watchdir/changes.log'.

Эта функциональность appears to be built into pyinotify, но эта библиотека работает только в Linux, а сторожевой таймер не зависит от ОС.

0

Проведя много времени (5 утра сейчас, извинения за любые опечатки и прочее), причем оба ответа здесь, безрезультатно, я чувствовал себя глупо и реализовал гораздо более простое решение для своих нужд.

Резюме (код ниже)

  1. Я не использую пользовательский Observer, но вы можете.
  2. Убедитесь, что ваш обработчик событий в том же файле, что вы Заявляя наблюдателя в.
  3. Создать global называется PAUSED или что-то подобное
  4. Внутри on_modified или любой другой функции события вы используете внутри обработчика событий , проверьте, PAUSED is True.
  5. Если True, выйдите, если нет, продолжите и остановите. Затем возобновите работу.

Поместите это в верхней части файла:

global PAUSED 
PAUSED = False 

Поместите это в EventHandler.on_modified() или независимо от вашего обработчика событий, и все функции события вы используете:

# Retrieve global 
global PAUSED 

# If PAUSED, exit 
if PAUSED is True: 
    return 

# If not, pause anything else from running and continue 
PAUSED = True 

# Do stuff here 

# Once finished, allow other things to run 
PAUSED = False 

Рассуждение: Это полностью игнорирует все, что пытается запустить во время паузы. Мне это нужно, потому что Watchdog будет запускать до 5 раз за событие с измененным файлом, потому что файл все еще записывается. Это гарантирует, что он срабатывает только один раз, приостанавливается и не возобновляется до тех пор, пока не исчезнут другие повторяющиеся события.