Skip to content

use watchfiles #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ Watch filesystem and re-execute on changes.

# Status

This is the *first* generation of `doit` `auto` command.
This is the *second* generation of `doit` `auto` command.

It is based on:

- Linux: pyinotify <https://pypi.org/project/pyinotify>
- MAC: macfsevents <https://pypi.python.org/pypi/MacFSEvents>`

Unfortunately both of this projects are not maintained anymore.
It is based on [`watchfiles`](https://pypi.org/project/watchfiles) with support
from the [Notify](https://docs.rs/notify/latest/notify/) rust package.
5 changes: 2 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ package_dir =
packages = doit_auto1
python_requires = >=3.8
install_requires =
macfsevents;sys_platform=='darwin'
pyinotify;sys_platform=='linux'
watchfiles

[options.entry_points]
doit.COMMAND =
auto = doit_auto1:Auto
auto = doit_auto1:Auto
95 changes: 17 additions & 78 deletions src/doit_auto1/filewatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,23 @@
"""

import os.path


def get_platform_system():
"""return platform.system
platform module has many regexp, so importing it is slow...
import only if required
"""
import platform
return platform.system()
import watchfiles


class FileModifyWatcher(object):
"""Use inotify to watch file-system for file modifications
"""Use watchfiles to watch file-system for file modifications

Usage:
1) subclass the method handle_event, action to be performed
2) create an object passing a list of files to be watched
3) call the loop method
"""
supported_platforms = ('Darwin', 'Linux')

def __init__(self, path_list):
"""@param file_list (list-str): files to be watched"""
self.file_list = set()
self.watch_dirs = set() # all dirs to be watched
self.notify_dirs = set() # dirs that generate notification whatever file
self.watch_dirs = set() # all dirs to be watched
self.notify_dirs = set() # dirs that generate notification whatever file
for filename in path_list:
path = os.path.abspath(filename)
if os.path.isfile(path):
Expand All @@ -37,74 +28,22 @@ def __init__(self, path_list):
else:
self.notify_dirs.add(path)
self.watch_dirs.add(path)
self.platform = get_platform_system()
if self.platform not in self.supported_platforms:
msg = "Unsupported platform '%s'\n" % self.platform
msg += ("'auto' command is supported only on %s" %
(self.supported_platforms,))
raise Exception(msg)

def _handle(self, event):
"""calls platform specific handler"""
if self.platform == 'Darwin': # pragma: no cover
filename = event.name
elif self.platform == 'Linux':
filename = event.pathname
if (filename in self.file_list or
os.path.dirname(filename) in self.notify_dirs):
self.handle_event(event)
def _handle(self, changes):
"""calls implementation handler"""
if any(
change[1] in self.file_list
or os.path.dirname(change[1]) in self.notify_dirs
for change in changes
):
return self.handle_event(changes)

def handle_event(self, event):
def handle_event(self, event): # pragma: no cover
"""this should be sub-classed """
raise NotImplementedError

def loop(self):
"""Infinite loop watching for file modifications"""

def _loop_darwin(self): # pragma: no cover
"""loop implementation for darwin platform"""
from fsevents import Observer #pylint: disable=F0401
from fsevents import Stream #pylint: disable=F0401
from fsevents import IN_MODIFY #pylint: disable=F0401

observer = Observer()
handler = self._handle
def fsevent_callback(event):
if event.mask == IN_MODIFY:
handler(event)

for watch_this in self.watch_dirs:
stream = Stream(fsevent_callback, watch_this, file_events=True)
observer.schedule(stream)

observer.daemon = True
observer.run()


def _loop_linux(self, loop_callback):
"""loop implementation for linux platform"""
import pyinotify
handler = self._handle
class EventHandler(pyinotify.ProcessEvent):
def process_default(self, event):
handler(event)

watch_manager = pyinotify.WatchManager()
event_handler = EventHandler()
notifier = pyinotify.Notifier(watch_manager, event_handler)

mask = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_MOVED_TO
for watch_this in self.watch_dirs:
watch_manager.add_watch(watch_this, mask)

notifier.loop(loop_callback)


def loop(self, loop_callback=None):
"""Infinite loop watching for file modifications
@loop_callback: used to stop loop on unittests
"""

if self.platform == 'Darwin': # pragma: no cover
self._loop_darwin()

elif self.platform == 'Linux':
self._loop_linux(loop_callback)
for changes in watchfiles.watch(*self.watch_dirs):
self._handle(changes)
9 changes: 0 additions & 9 deletions tests/test_cmd_auto.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import time
from multiprocessing import Process

import pytest

from doit.cmdparse import DefaultUpdate
from doit.task import Task
from doit.cmd_base import TaskLoader2

from doit_auto1 import filewatch
from doit_auto1 import cmd_auto
from .conftest import CmdFactory


# skip all tests in this module if platform not supported
platform = filewatch.get_platform_system()
pytestmark = pytest.mark.skipif(
'platform not in filewatch.FileModifyWatcher.supported_platforms')


class TestFindFileDeps(object):
def find_deps(self, sel_tasks):
tasks = {
Expand Down