Skip to content

Commit

Permalink
Merge pull request #22 from isvoboda/initiable-watcher
Browse files Browse the repository at this point in the history
Add watcher args
  • Loading branch information
samuelcolvin authored Nov 15, 2018
2 parents 38f9b08 + b68f90e commit cb8b399
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
45 changes: 44 additions & 1 deletion tests/test_watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from pytest_toolbox import mktree

from watchgod import AllWatcher, Change, DefaultWatcher, PythonWatcher, awatch, watch
from watchgod import AllWatcher, Change, DefaultWatcher, PythonWatcher, RegExpWatcher, awatch, watch

tree = {
'foo': {
Expand Down Expand Up @@ -91,6 +91,29 @@ def test_python(tmpdir):
assert watcher.check() == {(Change.modified, str(tmpdir.join('foo/spam.py')))}


def test_regexp(tmpdir):
mktree(tmpdir, tree)

re_files = r'^.*(\.txt|\.js)$'
re_dirs = r'^(?:(?!recursive_dir).)*$'

watcher = RegExpWatcher(str(tmpdir), re_files, re_dirs)
changes = watcher.check()
assert changes == set()

sleep(0.01)
tmpdir.join('foo/spam.py').write('xxx')
tmpdir.join('foo/bar.txt').write('change')
tmpdir.join('foo/borec.txt').write('ahoy')
tmpdir.join('foo/borec-js.js').write('peace')
tmpdir.join('foo/recursive_dir/b.js').write('borec')

assert watcher.check() == {
(Change.modified, str(tmpdir.join('foo/bar.txt'))),
(Change.added, str(tmpdir.join('foo/borec.txt'))),
(Change.added, str(tmpdir.join('foo/borec-js.js')))}


def test_does_not_exist(caplog):
AllWatcher('/foo/bar')
assert "error walking file system: FileNotFoundError [Errno 2] No such file or directory: '/foo/bar'" in caplog.text
Expand All @@ -114,6 +137,26 @@ def check(self):
assert next(iter_) == {'r2'}


def test_watch_watcher_kwargs(mocker):
class FakeWatcher:
def __init__(self, path, arg1=None, arg2=None):
self._results = iter([
{arg1},
set(),
{arg2},
set(),
])

def check(self):
return next(self._results)

kwargs = dict(arg1='foo', arg2='bar')

iter_ = watch('xxx', watcher_cls=FakeWatcher, watcher_kwargs=kwargs, debounce=5, normal_sleep=2, min_sleep=1)
assert next(iter_) == {kwargs['arg1']}
assert next(iter_) == {kwargs['arg2']}


def test_watch_stop():
class FakeWatcher:
def __init__(self, path):
Expand Down
12 changes: 8 additions & 4 deletions watchgod/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import functools
import logging
import os
import signal
Expand All @@ -8,7 +9,7 @@
from multiprocessing import Process
from pathlib import Path
from time import time
from typing import Any, Awaitable, Callable, Dict, Set, Tuple, Type, Union
from typing import Any, Awaitable, Callable, Dict, Optional, Set, Tuple, Type, Union

from .watcher import AllWatcher, Change, DefaultWatcher, PythonWatcher

Expand Down Expand Up @@ -52,12 +53,13 @@ class awatch:
3.5 doesn't support yield in coroutines so we need all this fluff. Yawwwwn.
"""
__slots__ = (
'_loop', '_path', '_watcher_cls', '_debounce', '_min_sleep', '_stop_event', '_normal_sleep', '_w', 'lock',
'_executor'
'_loop', '_path', '_watcher_cls', '_watcher_kwargs', '_debounce', '_min_sleep', '_stop_event', '_normal_sleep',
'_w', 'lock', '_executor'
)

def __init__(self, path: Union[Path, str], *,
watcher_cls: Type[AllWatcher]=DefaultWatcher,
watcher_kwargs: Optional[Dict[str, Any]]=None,
debounce=1600,
normal_sleep=400,
min_sleep=50,
Expand All @@ -67,6 +69,7 @@ def __init__(self, path: Union[Path, str], *,
self._executor = ThreadPoolExecutor(max_workers=4)
self._path = path
self._watcher_cls = watcher_cls
self._watcher_kwargs = watcher_kwargs or dict()
self._debounce = debounce
self._normal_sleep = normal_sleep
self._min_sleep = min_sleep
Expand All @@ -80,7 +83,8 @@ def __aiter__(self):

async def __anext__(self):
if not self._w:
self._w = await self.run_in_executor(self._watcher_cls, self._path)
self._w = await self.run_in_executor(
functools.partial(self._watcher_cls, self._path, **self._watcher_kwargs))
check_time = 0
changes = set()
last_change = 0
Expand Down
15 changes: 14 additions & 1 deletion watchgod/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import re
from enum import IntEnum

__all__ = 'Change', 'AllWatcher', 'DefaultDirWatcher', 'DefaultWatcher', 'PythonWatcher'
__all__ = 'Change', 'AllWatcher', 'DefaultDirWatcher', 'DefaultWatcher', 'PythonWatcher', 'RegExpWatcher'
logger = logging.getLogger('watchgod.watcher')


Expand Down Expand Up @@ -78,3 +78,16 @@ def should_watch_file(self, entry):
class PythonWatcher(DefaultDirWatcher):
def should_watch_file(self, entry):
return entry.name.endswith(('.py', '.pyx', '.pyd'))


class RegExpWatcher(AllWatcher):
def __init__(self, root_path, re_files=None, re_dirs=None):
self.re_files = re.compile(re_files) if re_files is not None else re_files
self.re_dirs = re.compile(re_dirs) if re_files is not None else re_dirs
super().__init__(root_path)

def should_watch_file(self, entry):
return self.re_files.match(entry.path)

def should_watch_dir(self, entry):
return self.re_dirs.match(entry.path)

0 comments on commit cb8b399

Please sign in to comment.