Skip to content

Commit 42797ce

Browse files
committed
migrate watchgod -> watchfiles
1 parent 9225b95 commit 42797ce

File tree

3 files changed

+38
-56
lines changed

3 files changed

+38
-56
lines changed

jinja2html/__main__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import websockets
1818

1919
from rich.logging import RichHandler
20-
from watchgod import awatch, Change
20+
from watchfiles import awatch, Change
2121

22-
from .core import Context, is_css_js, JinjaWatcher, WebsiteManager
22+
from .core import Context, is_css_js, WebsiteManager
2323

2424

2525
_SESSIONS = defaultdict(list)
@@ -76,7 +76,7 @@ async def changed_files_handler(wm: WebsiteManager) -> None:
7676
Args:
7777
wm (WebsiteManager): The WebsiteManager to associate with this asyncio loop
7878
"""
79-
async for changes in awatch(wm.context.input_dir, watcher_cls=JinjaWatcher, watcher_kwargs={"context": wm.context}):
79+
async for changes in awatch(wm.context.input_dir, watch_filter=wm.jinja_filter):
8080
l: set[Path] = set()
8181
build_all = notify_all = False
8282

jinja2html/core.py

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,24 @@
66
import shutil
77

88
from collections import deque, Iterable
9-
from os import DirEntry, scandir
9+
from os import scandir
1010
from pathlib import Path
11-
from typing import Union
1211

1312
import jinja2
1413

1514
from bs4 import BeautifulSoup
16-
from watchgod import DefaultWatcher
15+
from watchfiles import Change, DefaultFilter
1716

1817

1918
log = logging.getLogger(__name__)
2019

20+
_FILE_PATTERN = re.compile(r"[^.].+\.(html|htm|css|js)", re.IGNORECASE)
2121

22-
class Context:
23-
"""Collects shared configuration and simple methods for determining which files/directories to watch. There should only be one instance of this during the program's lifeycle."""
22+
# _NOT_DIR_PATTERN = re.compile(r"(\.|venv_|__pycache)")
2423

25-
_FILE_PATTERN = re.compile(r"[^.].+\.(html|htm|css|js)", re.IGNORECASE)
2624

27-
_NOT_DIR_PATTERN = re.compile(r"(\.|venv_|__pycache)")
25+
class Context:
26+
"""Collects shared configuration and simple methods for determining which files/directories to watch. There should only be one instance of this during the program's lifeycle."""
2827

2928
def __init__(self, input_dir: Path = Path("."), output_dir: Path = Path("out"), template_dir: str = "templates", ignore_list: set[Path] = set(), dev_mode: bool = False) -> None:
3029
"""Initializer, creates a new `Context`. For best results, all `Path` type arguments should be absolute (this is automatically done in the initializer, but if you want to change the properties after initializing, make sure you do this).
@@ -88,27 +87,16 @@ def is_config_json(self, f: Path) -> bool:
8887
"""
8988
return f == self.config_json
9089

91-
def should_watch_file(self, entry: DirEntry) -> bool:
92-
"""Determines whether a file should be watched. For use with the output of `os.scandir`
90+
def should_watch_file(self, p: str) -> bool:
91+
"""Determines whether a file should be watched.
9392
9493
Args:
95-
entry (DirEntry): The file to check.
94+
entry (str): The path to the file to check. Must be a full path.
9695
9796
Returns:
9897
bool: `True` if the file should be watched.
9998
"""
100-
return Context._FILE_PATTERN.match(entry.name) or self.is_config_json(Path(entry.path))
101-
102-
def should_watch_dir(self, entry: DirEntry) -> bool:
103-
"""Determines whether a directory should be watched. For use with the output of `os.scandir`
104-
105-
Args:
106-
entry (DirEntry): The directory to check.
107-
108-
Returns:
109-
bool: `True` if the directory should be watched.
110-
"""
111-
return Path(entry.path) not in self.ignore_list and not Context._NOT_DIR_PATTERN.match(entry.name)
99+
return _FILE_PATTERN.match(p) or self.is_config_json(Path(p))
112100

113101

114102
class WebsiteManager:
@@ -121,6 +109,7 @@ def __init__(self, context: Context) -> None:
121109
context (Context): The `Context` to use.
122110
"""
123111
self.context = context
112+
self.jinja_filter = JinjaFilter(context)
124113

125114
def find_acceptable_files(self) -> set[Path]:
126115
"""Recursively searches the input directory, according to the input context, for files that should be processed. Useful for cases when the whole website needs to be rebuilt.
@@ -134,11 +123,13 @@ def find_acceptable_files(self) -> set[Path]:
134123
while l:
135124
with scandir(l.popleft()) as it:
136125
for entry in it:
126+
entry_as_path = Path(entry)
127+
137128
if entry.is_file():
138-
if self.context.should_watch_file(entry):
139-
files.add(Path(entry.path))
129+
if self.context.should_watch_file(entry.path):
130+
files.add(entry_as_path)
140131
else: # is_dir()
141-
if self.context.should_watch_dir(entry) and Path(entry.path) != self.context.template_dir:
132+
if entry_as_path not in self.context.ignore_list and entry_as_path != self.context.template_dir and self.jinja_filter(Change.added, entry.path):
142133
l.append(entry.path)
143134

144135
return files
@@ -178,7 +169,7 @@ def build_files(self, files: Iterable[Path] = (), auto_find: bool = False) -> No
178169
body_tag.append(script_tag)
179170

180171
# add livereload script
181-
body_tag.append(soup.new_tag("script", src="https://cdnjs.cloudflare.com/ajax/libs/livereload-js/3.3.2/livereload.min.js", integrity="sha512-XO7rFek26Xn8H4HecfAv2CwBbYsJE+RovkwE0nc0kYD+1yJr2OQOOEKSjOsmzE8rTrjP6AoXKFMqReMHj0Pjkw==", crossorigin="anonymous"))
172+
body_tag.append(soup.new_tag("script", src="https://cdnjs.cloudflare.com/ajax/libs/livereload-js/3.4.1/livereload.min.js", integrity="sha512-rclIrxzYHDmi28xeUES7WqX493chZ4LFEdbjMAUYiosJlKqham0ZujKU539fTFnZywE0c76XIRl9pLJ05OJPKA==", crossorigin="anonymous"))
182173
output = str(soup)
183174

184175
output_path.write_text(output)
@@ -189,41 +180,29 @@ def build_files(self, files: Iterable[Path] = (), auto_find: bool = False) -> No
189180
log.error("Unable to build HTML!", exc_info=True)
190181

191182

192-
class JinjaWatcher(DefaultWatcher):
193-
"""An `AllWatcher` subclass for use with `watchgod`"""
183+
class JinjaFilter(DefaultFilter):
184+
"""A `DefaultFilter` subclass which only finds jinja2html-related files, for use `watchfiles`."""
194185

195-
def __init__(self, root_path: Union[Path, str] = None, context: Context = Context()) -> None:
196-
"""Initializer, creates a new `JinjaWatcher`.
186+
def __init__(self, context: Context) -> None:
187+
"""Initializer, creates a new `JinjaFilter`.
197188
198189
Args:
199-
root_path (Union[Path, str], optional): The root path (input) directory to watch. Defaults to None.
200-
context (Context, optional): The `Context` to use. Defaults to Context().
190+
context (Context): The `Context` to use.
201191
"""
202192
self.context = context
193+
super().__init__(ignore_paths=tuple(context.ignore_list))
203194

204-
super().__init__(root_path or context.input_dir)
205-
206-
def should_watch_file(self, entry: DirEntry) -> bool:
207-
"""Determines whether a file should be watched.
208-
209-
Args:
210-
entry (DirEntry): The file to check.
211-
212-
Returns:
213-
bool: `True` if the file should be watched.
214-
"""
215-
return self.context.should_watch_file(entry)
216-
217-
def should_watch_dir(self, entry: DirEntry) -> bool:
218-
"""Determines whether a directory should be watched.
195+
def __call__(self, change: Change, path: str) -> bool:
196+
"""Gets called by `watchfiles` when it checks if changes to a path should be reported.
219197
220198
Args:
221-
entry (DirEntry): The directory to check.
199+
change (Change): The kind of `Change` detected
200+
path (str): The path that was changed.
222201
223202
Returns:
224-
bool: `True` if the directory should be watched.
203+
bool: `True` if the change should be reported.
225204
"""
226-
return self.context.should_watch_dir(entry)
205+
return self.context.should_watch_file(path) and super().__call__(change, path)
227206

228207

229208
def _is_ext(f: Path, ext: tuple[str]) -> bool:

requirements.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
beautifulsoup4==4.11.1
22
Jinja2==3.1.2
3-
lxml==4.8.0
4-
rich==12.4.4
5-
watchgod==0.8.2
3+
lxml==4.9.1
4+
rich==12.5.1
5+
# starlette==0.20.4
6+
# watchgod==0.8.2
7+
# uvicorn[standard]==0.18.2
8+
watchfiles==0.16.1
69
websockets==10.3

0 commit comments

Comments
 (0)