#1212·watchdog

watchmedo: default "*" and documented "*.py"-style patterns match nothing since the full_match change (#1101)

Author: MohammedAlkindiCreated Aug 14, 2026Updated Aug 24, 2026

Environment

  • watchdog master dda279c (7.0.0-dev), native Windows 11 Home 10.0.26200, Python 3.13.13
  • Not present in any release: git tag --contains 3d98d59 is empty; v6.0.0 (2024-11-01) predates it

Symptom

watchmedo auto-restart never restarts its command, and by the same mechanism watchmedo shell-command / log never fire, when watching an absolute directory — including with the default --patterns "*" and with the --patterns="*.py;*.txt" style the help text documents.

Live check on this machine: watchmedo auto-restart -d <absolute-dir> --patterns "*.txt" --debounce-interval 1 -- python -u child.py starts the child once; creating trigger.txt in the watched directory produces no restart (child output still shows a single CHILD STARTED after the event, and the same run with the pre-#1101 matcher semantics restarts).

Mechanism

#1101 deliberately switched _match_path from PurePath.match() (right-anchored) to full_match() (whole-path), and the 7.0.0-dev changelog documents the library-level consequence: users must write **/*.py instead of *.py. But watchmedo was not adapted to the new semantics — parse_patterns() still hands the user's (or default) patterns straight to the tricks, and event paths are multi-segment, so:

python
from watchdog.utils.patterns import match_any_paths as m
m([r"C:\w\a.txt"], included_patterns=["*"],       case_sensitive=False)  # False  (watchmedo default)
m([r"C:\w\a.txt"], included_patterns=["*.txt"],   case_sensitive=False)  # False  (documented style)
m([r"C:\w\a.txt"], included_patterns=["**"],      case_sensitive=False)  # True
m([r".\a.txt"],    included_patterns=["*"],       case_sensitive=False)  # True   (depth-1 relative still works)
m([r".\sub\a.txt"],included_patterns=["*"],       case_sensitive=False)  # False

On the commit before #1101, all five rows are Truepath.match("*") matched any tail. So the breakage is total for absolute watch paths and partial (depth-1 only) for relative ones, which is presumably why casual testing looks fine.

Why the test suite stays green

The auto-restart tests construct AutoRestartTrick([sys.executable, script]) with no patterns argument, so the handler falls back to the library default ["**"], which full-matches everything. watchmedo itself never produces that default — it always passes parse_patterns() output, whose default is "*". The gap sits exactly between the two defaults, so no existing test crosses it.

What I am not claiming

The engine change itself is intentional and changelog-documented; this issue is only about watchmedo (and its defaults/help text) not having been adapted to it. I also haven't tested the tricks-from-YAML path beyond reading that it feeds the same handler base.

Possible directions

  1. Translate bare relative patterns in parse_patterns() (prepend **/ when a pattern has no separator and no leading **), keeping the CLI's long-documented behavior across the engine change; or
  2. change watchmedo's default from "*" to "**" and document that CLI patterns now need **/ prefixes, matching the library-level changelog entry.

Happy to put together a PR with tests for whichever direction you prefer — (1) keeps existing watchmedo invocations working and is my reading of least surprise, but it does add a translation layer you may not want.