0
# File Watching System
1
2
Cross-platform file system monitoring with support for files, directories, glob patterns, and efficient change detection using polling and platform-specific optimizations.
3
4
## Capabilities
5
6
### Watcher Initialization
7
8
Create file watcher instances with automatic cross-platform backend selection.
9
10
```python { .api }
11
class Watcher:
12
def __init__(self):
13
"""
14
Initialize file watcher with default configuration.
15
16
Sets up internal data structures for tracking file modifications,
17
configures default ignored directories (.git, .hg, .svn, .cvs),
18
and prepares for file system monitoring.
19
"""
20
21
def get_watcher_class():
22
"""
23
Get appropriate watcher class based on system capabilities.
24
25
Returns:
26
class: INotifyWatcher on Linux with pyinotify available,
27
otherwise standard Watcher class
28
"""
29
```
30
31
**Usage Examples:**
32
33
```python
34
from livereload.watcher import get_watcher_class
35
36
# Get best available watcher for current system
37
WatcherClass = get_watcher_class()
38
watcher = WatcherClass()
39
40
# Direct instantiation
41
from livereload.watcher import Watcher
42
watcher = Watcher()
43
```
44
45
### Watch Registration
46
47
Register paths for monitoring with optional callbacks, delays, and ignore functions.
48
49
```python { .api }
50
def watch(self, path, func=None, delay=0, ignore=None):
51
"""
52
Add a watching task for specified path.
53
54
Args:
55
path (str): File path, directory path, or glob pattern to monitor
56
func (callable): Callback function when changes detected (optional)
57
delay (float): Delay in seconds before triggering callback (default: 0)
58
ignore (callable): Custom function to determine ignored files (optional)
59
"""
60
```
61
62
**Usage Examples:**
63
64
```python
65
# Watch single file
66
watcher.watch('config.py')
67
68
# Watch directory
69
watcher.watch('templates/')
70
71
# Watch with glob pattern
72
watcher.watch('**/*.py')
73
watcher.watch('static/**/*.css')
74
75
# Watch with callback
76
def on_change():
77
print("Files changed, rebuilding...")
78
79
watcher.watch('src/', on_change)
80
81
# Watch with delay
82
watcher.watch('large_files/', delay=2.0)
83
84
# Watch with custom ignore function
85
def ignore_build_files(filename):
86
return filename.endswith(('.pyc', '.pyo', '.tmp'))
87
88
watcher.watch('project/', ignore=ignore_build_files)
89
```
90
91
### Change Detection
92
93
Monitor file system changes and execute associated callbacks.
94
95
```python { .api }
96
def start(self, callback):
97
"""
98
Start the watcher with given callback function.
99
100
Args:
101
callback (callable): Function to call when any watched changes occur
102
103
Returns:
104
bool: True if async watching is supported, False for polling mode
105
"""
106
107
def examine(self):
108
"""
109
Check for changes and run associated tasks.
110
111
Returns:
112
tuple or None: (modified_filepath, reload_delay) if changes found,
113
None if no changes detected
114
"""
115
116
def is_changed(self, path, ignore=None):
117
"""
118
Check if any files have been added, modified, or removed.
119
120
Args:
121
path (str): Path to check for changes
122
ignore (callable): Custom ignore function (optional)
123
124
Returns:
125
bool: True if changes detected, False otherwise
126
"""
127
```
128
129
**Usage Examples:**
130
131
```python
132
# Start watching with global callback
133
def global_callback():
134
print("Changes detected!")
135
136
# Returns True if using inotify, False if polling
137
supports_async = watcher.start(global_callback)
138
139
# Manual change examination
140
result = watcher.examine()
141
if result:
142
filepath, delay = result
143
print(f"File {filepath} changed, delay: {delay}s")
144
145
# Check specific path for changes
146
if watcher.is_changed('config/'):
147
print("Configuration files changed")
148
```
149
150
### Ignore Configuration
151
152
Configure which files and directories should be ignored during monitoring.
153
154
```python { .api }
155
def ignore_dirs(self, *args):
156
"""
157
Add directories to ignore list.
158
159
Args:
160
*args: Variable number of directory names to ignore
161
"""
162
163
def remove_dirs_from_ignore(self, *args):
164
"""
165
Remove directories from ignore list.
166
167
Args:
168
*args: Variable number of directory names to stop ignoring
169
"""
170
171
def ignore(self, filename):
172
"""
173
Check if filename should be ignored based on default rules.
174
175
Args:
176
filename (str): File name to check
177
178
Returns:
179
bool: True if file should be ignored, False otherwise
180
"""
181
```
182
183
**Usage Examples:**
184
185
```python
186
# Add directories to ignore
187
watcher.ignore_dirs('node_modules', '__pycache__', '.venv')
188
189
# Remove directory from ignore list
190
watcher.remove_dirs_from_ignore('.git') # Now watch .git changes
191
192
# Check if file would be ignored
193
should_ignore = watcher.ignore('temp.pyc') # Returns True
194
195
# Custom ignore patterns combined with defaults
196
def custom_ignore(filename):
197
# Use default ignore rules
198
if watcher.ignore(filename):
199
return True
200
# Add custom rules
201
return filename.startswith('temp_') or filename.endswith('.bak')
202
203
watcher.watch('project/', ignore=custom_ignore)
204
```
205
206
### Advanced Change Detection
207
208
Detailed file system change detection with granular control over monitoring behavior.
209
210
```python { .api }
211
def is_file_removed(self):
212
"""
213
Check if any files have been removed since last check.
214
215
Returns:
216
bool: True if files were removed, False otherwise
217
"""
218
219
def is_file_changed(self, path, ignore=None):
220
"""
221
Check if specific file has been added or modified.
222
223
Args:
224
path (str): File path to check
225
ignore (callable): Custom ignore function (optional)
226
227
Returns:
228
bool: True if file changed, False otherwise
229
"""
230
231
def is_folder_changed(self, path, ignore=None):
232
"""
233
Check if directory has any changed files.
234
235
Args:
236
path (str): Directory path to check
237
ignore (callable): Custom ignore function (optional)
238
239
Returns:
240
bool: True if folder contents changed, False otherwise
241
"""
242
243
def get_changed_glob_files(self, path, ignore=None):
244
"""
245
Get list of changed files matching glob pattern.
246
247
Args:
248
path (str): Glob pattern to check
249
ignore (callable): Custom ignore function (optional)
250
251
Returns:
252
list: List of changed files matching pattern
253
"""
254
```
255
256
**Usage Examples:**
257
258
```python
259
# Check for removed files
260
if watcher.is_file_removed():
261
print("Some files were deleted")
262
263
# Check specific file
264
if watcher.is_file_changed('config.py'):
265
print("Configuration changed")
266
267
# Check directory
268
if watcher.is_folder_changed('templates/'):
269
print("Template files changed")
270
271
# Get changed files matching pattern
272
changed_py_files = watcher.get_changed_glob_files('**/*.py')
273
for file in changed_py_files:
274
print(f"Python file changed: {file}")
275
```
276
277
### Linux inotify Optimization
278
279
Enhanced file watching using Linux inotify for efficient, event-driven monitoring.
280
281
```python { .api }
282
class INotifyWatcher(Watcher):
283
def __init__(self):
284
"""
285
Initialize inotify-based watcher (Linux only).
286
287
Requires pyinotify package. Provides event-driven file monitoring
288
instead of polling for better performance and lower resource usage.
289
"""
290
291
def watch(self, path, func=None, delay=None, ignore=None):
292
"""
293
Add path to inotify watch list with recursive monitoring.
294
295
Args:
296
path (str): Path to monitor with inotify (supports glob patterns)
297
func (callable): Callback function (optional)
298
delay (float): Delay before callback (optional)
299
ignore (callable): Ignore function (optional)
300
"""
301
302
def start(self, callback):
303
"""
304
Start inotify-based watching with Tornado async integration.
305
306
Args:
307
callback (callable): Function to call on changes
308
309
Returns:
310
bool: Always True (supports async watching)
311
"""
312
313
def inotify_event(self, event):
314
"""
315
Internal event handler for inotify events.
316
317
Args:
318
event: PyInotify event object
319
"""
320
```
321
322
**Usage Examples:**
323
324
```python
325
# Only available on Linux with pyinotify
326
try:
327
from livereload.watcher import INotifyWatcher
328
watcher = INotifyWatcher()
329
print("Using efficient inotify watching")
330
except ImportError:
331
from livereload.watcher import Watcher
332
watcher = Watcher()
333
print("Using polling-based watching")
334
335
# Same API as regular Watcher
336
watcher.watch('project/')
337
watcher.start(lambda: print("Files changed!"))
338
```
339
340
## Advanced Usage
341
342
### Custom Watch Workflows
343
344
```python
345
from livereload.watcher import get_watcher_class
346
import time
347
348
# Create custom watching workflow
349
WatcherClass = get_watcher_class()
350
watcher = WatcherClass()
351
352
# Set up multiple watch targets
353
watcher.watch('src/*.py', delay=0.5)
354
watcher.watch('tests/*.py', delay=1.0)
355
watcher.watch('docs/*.md', delay=2.0)
356
357
# Custom ignore function
358
def ignore_build_artifacts(filename):
359
ignore_patterns = ['.pyc', '.pyo', '.pyd', '__pycache__', '.pytest_cache']
360
return any(pattern in filename for pattern in ignore_patterns)
361
362
watcher.watch('project/', ignore=ignore_build_artifacts)
363
364
# Start monitoring
365
def handle_changes():
366
result = watcher.examine()
367
if result:
368
filepath, delay = result
369
print(f"Change detected in {filepath}, waiting {delay}s")
370
time.sleep(delay)
371
print("Processing change...")
372
373
# Manual polling loop
374
while True:
375
handle_changes()
376
time.sleep(0.1)
377
```
378
379
### Integration with Build Systems
380
381
```python
382
import subprocess
383
from livereload.watcher import get_watcher_class
384
385
def create_build_watcher():
386
WatcherClass = get_watcher_class()
387
watcher = WatcherClass()
388
389
def run_tests():
390
print("Running tests...")
391
subprocess.run(['python', '-m', 'pytest'])
392
393
def compile_assets():
394
print("Compiling assets...")
395
subprocess.run(['npm', 'run', 'build'])
396
397
def generate_docs():
398
print("Generating documentation...")
399
subprocess.run(['sphinx-build', 'docs/', 'docs/_build/'])
400
401
# Watch different file types with different actions
402
watcher.watch('tests/', run_tests, delay=1.0)
403
watcher.watch('assets/', compile_assets, delay=2.0)
404
watcher.watch('docs/', generate_docs, delay=3.0)
405
406
return watcher
407
408
# Use in development workflow
409
build_watcher = create_build_watcher()
410
build_watcher.start(lambda: print("Build system active"))
411
```