Как отслеживать события файловой системы в Python

Прочитав эту статью, вы научитесь обнаруживать изменения в существующих файлах приложения Python. Для этого возьмем хорошо поддерживаемый модуль под названием watchdog

Согласно официальной документации, watchdog  —  это библиотека API Python и утилиты оболочки для мониторинга событий файловой системы.

Он поддерживает как Python 2.7, так и 3.4+. Однако с более старыми версиями рекомендуется применять watchdog < 0.10.0. В этой статье рассмотрим только библиотеку API Python. Приступаем к установке необходимых модулей.

Установка

pip install делает установку простой и понятной. Прежде чем продолжать, настоятельно рекомендуем настроить виртуальную среду. Существует два доступных метода установки.

Установка из PyPI

Выполните в терминале команду:

pip install watchdog

Она установит последнюю версию из PyPI (на момент написания статьи  —  0.10.2).

Установка из репозитория

Вы также можете клонировать репозиторий в локальной папке и установить его содержимое в обычном режиме. Клонируем репозиторий с помощью такой команды:

git clone --recursive git://github.com/gorakhargosh/watchdog.git

Измените рабочий каталог с помощью следующей команды. Убедитесь, что в рабочем каталоге содержится файл с именем setup.py.

cd watchdog

Проведите установку, выполнив команду:

pip install -e.

Одно из основных преимуществ клонирования непосредственно из репозитория  —  так вы получите последнюю версию с дополнительными функциями.

Можно проверить установку, выполнив команду:

pip show watchdog

Теперь перейдем к следующему разделу и начнем писать код на Python.

Реализация

Основные строительные блоки watchdog основаны на следующих классах.

  • Наблюдатель (Observer).
  • Обработчик событий (Event handler).

Следовательно, реализация довольно проста и состоит в следующем.

  1. Создайте экземпляр класса потоков watchdog.observers.Observer.
  2. Определите подкласс обработчика событий с вашей собственной реализацией и создайте из него экземпляр.
  3. Вызовите функцию расписания через экземпляр наблюдателя, прикрепляя обработчик событий. Функция принимает несколько других входных параметров, таких как путь к отслеживаемому каталогу.
  4. Запустите поток наблюдателя и дождитесь, пока он сгенерирует события, которые вызовут исполнение кода внутри обработчика событий.

Обработчик событий

В настоящее время в модуле доступно 4 типа обработчиков событий.

  1. FileSystemEventHandler  —  базовый обработчик событий файловой системы, из которого можно переопределить методы.
  2. PatternMatchingEventHandler сопоставляет заданные шаблоны с путями к файлам, которые связаны с происходящими событиями.
  3. RegexMatchingEventHandler сопоставляет заданные регулярные выражения с путями к файлам, которые связаны с происходящими событиями.
  4. LoggingEventHandler регистрирует все записанные события.

Остальные классы наследуются от FileSystemEventHandler, который предоставляет для переопределения следующие функции.

  • on_any_event  —  обработчик событий Catch-all.
  • on_created вызывается при создании файла или каталога.
  • on_deleted вызывается при удалении файла или каталога.
  • on_modified вызывается при изменении файла или каталога.
  • on_moved вызывается при перемещении или переименовании файла или каталога.

Импорт

Создайте новый файл Python и добавьте в него объявление импорта. Назовем его test.py.

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

Подкласс FileSystemEventHandler

Создайте новый класс, который наследуется от FileSystemEventHandler, и перепишите функции в зависимости от ваших вариантов использования. Назовем его MyHandler, но вы можете выбрать любое удобное для вас имя.

class MyHandler(FileSystemEventHandler):
    def on_any_event(self, event):
        print(event.event_type, event.src_path)

    def on_created(self, event):
        print("on_created", event.src_path)

    def on_deleted(self, event):
        print("on_deleted", event.src_path)

    def on_modified(self, event):
        print("on_modified", event.src_path)

    def on_moved(self, event):
        print("on_moved", event.src_path)

Замените операторы вывода логикой вашей реализации. Для каждой из функций будет представлен входной параметр event, который содержит следующие переменные.

  • event_type  —  тип события в виде строки. По умолчанию значение None.
  • is_directory  —  true, если событие было выдано для каталога. В противном случае  —  false.
  • src_path  —  исходный путь объекта файловой системы, вызвавшего это событие.

Наиболее полезный параметр здесь  —  src_path. Им можно воспользоваться, чтобы определить, какой файл был изменен, прежде чем запускать соответствующую логику.

if(event.src_path == "./path/file.txt"):
    print("Execute your logic here!")

Наблюдатель и обработчик событий

После добавления подкласса можно безопасно создать его экземпляр вместе с классом Observer. Назначьте выбранный путь для процесса отслеживания. В данном случае проверим недавно созданную папку под названием json.

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

Вызов start запустит поток, и при внесении изменений в соответствующий путь будет сгенерировано событие.

event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, path='./json/', recursive=False)
observer.start()

Тест

Чтобы протестировать написанный код, надо реализовать цикл выполнения и предотвратить выход из него. На выходе при возникновении исключения KeyboardInterrupt вызовите функцию stop для очистки ресурсов.

while True:
    try:
        pass
    except KeyboardInterrupt:
        observer.stop()

Сохраните файл Python и запустите его из терминала. Измените имя в соответствии с тем, которое задали раньше.

python test.py

Протестировать все это легко: создайте новый документ, измените его содержимое и удалите из каталога. Вот пример вывода:

Обратите внимание: поведение и результат могут отличаться в зависимости от редактора. Например, у Vim есть известная проблема с событиями типа modified.

“Vim не изменяет файлы без соответствующего указания. Он создает резервные копии файлов, а затем меняет их местами, чтобы заменить файлы, которые вы редактируете на диске. Это означает, что если вы пользуетесь Vim для редактирования файлов, события при изменении этих файлов не будут запускаться watchdog. Возможно, вам потребуется соответствующим образом настроить Vim, чтобы отключить эту функцию”.

Заключение

Вот что мы узнали сегодня.

  • Мы начали с установки модуля watchdog через pip install или непосредственно из репозитория.
  • Затем перешли к подробному изучению доступных функций и опробовали их базовую реализацию. Мы создали подкласс из FileSystemEventHandler и назначили его в качестве входного параметра объекту Observer. Он будет генерировать событие и вызывать соответствующие функции при изменении файлов или папок.
  • Наконец, мы протестировали реализацию с помощью создания нового файла, изменения его содержимого и удаления его из каталога.

Спасибо за чтение.

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Ng Wai Foong: How to Monitor File System Events in Python

Предыдущая статья5 актуальных рекомендаций по оптимизации отладки
Следующая статья5 Команд Linux, заставляющих ахнуть от удивления