Python LiveReload server that automatically reloads web pages when source files change
—
Cross-platform file system monitoring with support for files, directories, glob patterns, and efficient change detection using polling and platform-specific optimizations.
Create file watcher instances with automatic cross-platform backend selection.
class Watcher:
def __init__(self):
"""
Initialize file watcher with default configuration.
Sets up internal data structures for tracking file modifications,
configures default ignored directories (.git, .hg, .svn, .cvs),
and prepares for file system monitoring.
"""
def get_watcher_class():
"""
Get appropriate watcher class based on system capabilities.
Returns:
class: INotifyWatcher on Linux with pyinotify available,
otherwise standard Watcher class
"""Usage Examples:
from livereload.watcher import get_watcher_class
# Get best available watcher for current system
WatcherClass = get_watcher_class()
watcher = WatcherClass()
# Direct instantiation
from livereload.watcher import Watcher
watcher = Watcher()Register paths for monitoring with optional callbacks, delays, and ignore functions.
def watch(self, path, func=None, delay=0, ignore=None):
"""
Add a watching task for specified path.
Args:
path (str): File path, directory path, or glob pattern to monitor
func (callable): Callback function when changes detected (optional)
delay (float): Delay in seconds before triggering callback (default: 0)
ignore (callable): Custom function to determine ignored files (optional)
"""Usage Examples:
# Watch single file
watcher.watch('config.py')
# Watch directory
watcher.watch('templates/')
# Watch with glob pattern
watcher.watch('**/*.py')
watcher.watch('static/**/*.css')
# Watch with callback
def on_change():
print("Files changed, rebuilding...")
watcher.watch('src/', on_change)
# Watch with delay
watcher.watch('large_files/', delay=2.0)
# Watch with custom ignore function
def ignore_build_files(filename):
return filename.endswith(('.pyc', '.pyo', '.tmp'))
watcher.watch('project/', ignore=ignore_build_files)Monitor file system changes and execute associated callbacks.
def start(self, callback):
"""
Start the watcher with given callback function.
Args:
callback (callable): Function to call when any watched changes occur
Returns:
bool: True if async watching is supported, False for polling mode
"""
def examine(self):
"""
Check for changes and run associated tasks.
Returns:
tuple or None: (modified_filepath, reload_delay) if changes found,
None if no changes detected
"""
def is_changed(self, path, ignore=None):
"""
Check if any files have been added, modified, or removed.
Args:
path (str): Path to check for changes
ignore (callable): Custom ignore function (optional)
Returns:
bool: True if changes detected, False otherwise
"""Usage Examples:
# Start watching with global callback
def global_callback():
print("Changes detected!")
# Returns True if using inotify, False if polling
supports_async = watcher.start(global_callback)
# Manual change examination
result = watcher.examine()
if result:
filepath, delay = result
print(f"File {filepath} changed, delay: {delay}s")
# Check specific path for changes
if watcher.is_changed('config/'):
print("Configuration files changed")Configure which files and directories should be ignored during monitoring.
def ignore_dirs(self, *args):
"""
Add directories to ignore list.
Args:
*args: Variable number of directory names to ignore
"""
def remove_dirs_from_ignore(self, *args):
"""
Remove directories from ignore list.
Args:
*args: Variable number of directory names to stop ignoring
"""
def ignore(self, filename):
"""
Check if filename should be ignored based on default rules.
Args:
filename (str): File name to check
Returns:
bool: True if file should be ignored, False otherwise
"""Usage Examples:
# Add directories to ignore
watcher.ignore_dirs('node_modules', '__pycache__', '.venv')
# Remove directory from ignore list
watcher.remove_dirs_from_ignore('.git') # Now watch .git changes
# Check if file would be ignored
should_ignore = watcher.ignore('temp.pyc') # Returns True
# Custom ignore patterns combined with defaults
def custom_ignore(filename):
# Use default ignore rules
if watcher.ignore(filename):
return True
# Add custom rules
return filename.startswith('temp_') or filename.endswith('.bak')
watcher.watch('project/', ignore=custom_ignore)Detailed file system change detection with granular control over monitoring behavior.
def is_file_removed(self):
"""
Check if any files have been removed since last check.
Returns:
bool: True if files were removed, False otherwise
"""
def is_file_changed(self, path, ignore=None):
"""
Check if specific file has been added or modified.
Args:
path (str): File path to check
ignore (callable): Custom ignore function (optional)
Returns:
bool: True if file changed, False otherwise
"""
def is_folder_changed(self, path, ignore=None):
"""
Check if directory has any changed files.
Args:
path (str): Directory path to check
ignore (callable): Custom ignore function (optional)
Returns:
bool: True if folder contents changed, False otherwise
"""
def get_changed_glob_files(self, path, ignore=None):
"""
Get list of changed files matching glob pattern.
Args:
path (str): Glob pattern to check
ignore (callable): Custom ignore function (optional)
Returns:
list: List of changed files matching pattern
"""Usage Examples:
# Check for removed files
if watcher.is_file_removed():
print("Some files were deleted")
# Check specific file
if watcher.is_file_changed('config.py'):
print("Configuration changed")
# Check directory
if watcher.is_folder_changed('templates/'):
print("Template files changed")
# Get changed files matching pattern
changed_py_files = watcher.get_changed_glob_files('**/*.py')
for file in changed_py_files:
print(f"Python file changed: {file}")Enhanced file watching using Linux inotify for efficient, event-driven monitoring.
class INotifyWatcher(Watcher):
def __init__(self):
"""
Initialize inotify-based watcher (Linux only).
Requires pyinotify package. Provides event-driven file monitoring
instead of polling for better performance and lower resource usage.
"""
def watch(self, path, func=None, delay=None, ignore=None):
"""
Add path to inotify watch list with recursive monitoring.
Args:
path (str): Path to monitor with inotify (supports glob patterns)
func (callable): Callback function (optional)
delay (float): Delay before callback (optional)
ignore (callable): Ignore function (optional)
"""
def start(self, callback):
"""
Start inotify-based watching with Tornado async integration.
Args:
callback (callable): Function to call on changes
Returns:
bool: Always True (supports async watching)
"""
def inotify_event(self, event):
"""
Internal event handler for inotify events.
Args:
event: PyInotify event object
"""Usage Examples:
# Only available on Linux with pyinotify
try:
from livereload.watcher import INotifyWatcher
watcher = INotifyWatcher()
print("Using efficient inotify watching")
except ImportError:
from livereload.watcher import Watcher
watcher = Watcher()
print("Using polling-based watching")
# Same API as regular Watcher
watcher.watch('project/')
watcher.start(lambda: print("Files changed!"))from livereload.watcher import get_watcher_class
import time
# Create custom watching workflow
WatcherClass = get_watcher_class()
watcher = WatcherClass()
# Set up multiple watch targets
watcher.watch('src/*.py', delay=0.5)
watcher.watch('tests/*.py', delay=1.0)
watcher.watch('docs/*.md', delay=2.0)
# Custom ignore function
def ignore_build_artifacts(filename):
ignore_patterns = ['.pyc', '.pyo', '.pyd', '__pycache__', '.pytest_cache']
return any(pattern in filename for pattern in ignore_patterns)
watcher.watch('project/', ignore=ignore_build_artifacts)
# Start monitoring
def handle_changes():
result = watcher.examine()
if result:
filepath, delay = result
print(f"Change detected in {filepath}, waiting {delay}s")
time.sleep(delay)
print("Processing change...")
# Manual polling loop
while True:
handle_changes()
time.sleep(0.1)import subprocess
from livereload.watcher import get_watcher_class
def create_build_watcher():
WatcherClass = get_watcher_class()
watcher = WatcherClass()
def run_tests():
print("Running tests...")
subprocess.run(['python', '-m', 'pytest'])
def compile_assets():
print("Compiling assets...")
subprocess.run(['npm', 'run', 'build'])
def generate_docs():
print("Generating documentation...")
subprocess.run(['sphinx-build', 'docs/', 'docs/_build/'])
# Watch different file types with different actions
watcher.watch('tests/', run_tests, delay=1.0)
watcher.watch('assets/', compile_assets, delay=2.0)
watcher.watch('docs/', generate_docs, delay=3.0)
return watcher
# Use in development workflow
build_watcher = create_build_watcher()
build_watcher.start(lambda: print("Build system active"))Install with Tessl CLI
npx tessl i tessl/pypi-livereload