diff --git a/pytest_watch/command.py b/pytest_watch/command.py index 4a8d84e..0d25033 100644 --- a/pytest_watch/command.py +++ b/pytest_watch/command.py @@ -13,6 +13,9 @@ --ext Comma-separated list of file extensions that can trigger a new test run when changed (default: .py). Use --ext=* to allow any file (including .pyc). + --skip A glob, all events matching the mask will be ignored. + Multiple masks are supported, comma separated (no space). + Use --skip .#*.py,flycheck_*.py to ignore Emacs temp files. --config Load configuration from `file` instead of trying to locate one of the implicit configuration files. -c --clear Clear the screen before each run. @@ -79,6 +82,10 @@ def main(argv=None): if args['--config']: pytest_args.extend(['-c', args['--config']]) + skip_masks = [] + if args['--skip']: + skip_masks = args['--skip'].split(',') + # Merge config file options if not merge_config(args, pytest_args, verbose=args['--verbose']): return 0 @@ -109,6 +116,7 @@ def main(argv=None): return watch(entries=directories, ignore=args['--ignore'], extensions=extensions, + skip_masks=skip_masks, beep_on_failure=not args['--nobeep'], auto_clear=args['--clear'], wait=args['--wait'] or '--pdb' in pytest_args, diff --git a/pytest_watch/watcher.py b/pytest_watch/watcher.py index f69497f..4724e19 100644 --- a/pytest_watch/watcher.py +++ b/pytest_watch/watcher.py @@ -5,6 +5,7 @@ import subprocess import time from traceback import format_exc +from pathlib import Path try: from queue import Queue @@ -77,10 +78,12 @@ class EventListener(FileSystemEventHandler): """ Listens for changes to files and re-runs tests after each change. """ - def __init__(self, extensions=[], event_queue=None): + + def __init__(self, extensions=[], skip_masks=[], event_queue=None): super(EventListener, self).__init__() self.event_queue = event_queue or Queue() self.extensions = extensions or DEFAULT_EXTENSIONS + self.skip_masks = skip_masks def on_any_event(self, event): """ @@ -99,7 +102,8 @@ def on_any_event(self, event): # Filter files that don't match the allowed extensions if not event.is_directory and self.extensions != ALL_EXTENSIONS: src_ext = os.path.splitext(src_path)[1].lower() - src_included = src_ext in self.extensions + should_skip = any([Path(src_path).match(mask) for mask in self.skip_masks]) + src_included = src_ext in self.extensions and not should_skip dest_included = False if dest_path: dest_ext = os.path.splitext(dest_path)[1].lower() @@ -216,7 +220,7 @@ def run_hook(cmd, *args): subprocess.call(command, shell=True) -def watch(entries=[], ignore=[], extensions=[], beep_on_failure=True, +def watch(entries=[], ignore=[], extensions=[], skip_masks=[], beep_on_failure=True, auto_clear=False, wait=False, beforerun=None, afterrun=None, onpass=None, onfail=None, onexit=None, runner=None, spool=None, poll=False, verbose=False, quiet=False, pytest_args=[]): @@ -237,7 +241,7 @@ def watch(entries=[], ignore=[], extensions=[], beep_on_failure=True, raise ValueError('Directory not found: ' + entry) # Setup event handler - event_listener = EventListener(extensions) + event_listener = EventListener(extensions, skip_masks=skip_masks) # Setup watchdog observer = PollingObserver() if poll else Observer()