diff --git a/CHANGES.rst b/CHANGES.rst index f056ddd6d..69eed03b2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -20,8 +20,15 @@ development at the same time, such as 4.5.x and 5.0. Unreleased ---------- -Nothing yet. +- The semantics of stars in file patterns has been clarified in the docs. A + leading or trailing star matches any number of path components, like a double + star would. This is different than the behavior of a star in the middle of a + pattern. This discrepancy was `identified by Sviatoslav Sydorenko + `_, who `provided patient detailed diagnosis `_ and + graciously agreed to a pragmatic resolution. +.. _starbad: https://github.com/nedbat/coveragepy/issues/1407#issuecomment-1631085209 +.. _pull 1650: https://github.com/nedbat/coveragepy/pull/1650 .. scriv-start-here @@ -32,7 +39,7 @@ Version 7.3.0 — 2023-08-12 - Added a :meth:`.Coverage.collect` context manager to start and stop coverage data collection. - + - Dropped support for Python 3.7. - Fix: in unusual circumstances, SQLite cannot be set to asynchronous mode. diff --git a/doc/source.rst b/doc/source.rst index 44b84f001..20a1f3ba4 100644 --- a/doc/source.rst +++ b/doc/source.rst @@ -181,12 +181,46 @@ File patterns File path patterns are used for include and omit, and for combining path remapping. They follow common shell syntax: -- ``*`` matches any number of file name characters, not including the directory - separator. - - ``?`` matches a single file name character. +- ``*`` matches any number of file name characters, not including the directory + separator. As a special case, if a pattern starts with ``*/``, it is treated + as ``**/``, and if a pattern ends with ``/*``, it is treated as ``/**``. + - ``**`` matches any number of nested directory names, including none. - Both ``/`` and ``\`` will match either a slash or a backslash, to make cross-platform matching easier. + +- A pattern with no directory separators matches the file name in any + subdirectory. + +Some examples: + +.. list-table:: + :widths: 20 20 20 + :header-rows: 1 + + * - Pattern + - Matches + - Doesn't Match + * - a*.py + - | anything.py + | sub1/sub2/another.py + - | cat.py + * - sub/\*/\*.py + - | sub/a/main.py + | sub/b/another.py + - | sub/foo.py + | sub/m1/m2/foo.py + * - sub/\*\*/\*.py + - | sub/something.py + | sub/a/main.py + | sub/b/another.py + | sub/m1/m2/foo.py + - | sub1/anything.py + | sub1/more/code/main.py + * - \*/sub/\* + - | some/where/sub/more/something.py + | sub/hello.py + - | sub1/anything.py diff --git a/tests/test_files.py b/tests/test_files.py index ae3a5e2b2..09da65c20 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -235,9 +235,24 @@ def globs_to_regex_params( ), globs_to_regex_params( ["*/foo"], case_insensitive=False, partial=True, - matches=["abc/foo/hi.py", "foo/hi.py"], + matches=["abc/foo/hi.py", "foo/hi.py", "abc/def/foo/hi.py"], nomatches=["abc/xfoo/hi.py"], ), + globs_to_regex_params( + ["*c/foo"], case_insensitive=False, partial=True, + matches=["abc/foo/hi.py"], + nomatches=["abc/xfoo/hi.py", "foo/hi.py", "def/abc/foo/hi.py"], + ), + globs_to_regex_params( + ["foo/x*"], case_insensitive=False, partial=True, + matches=["foo/x", "foo/xhi.py", "foo/x/hi.py"], + nomatches=[], + ), + globs_to_regex_params( + ["foo/x*"], case_insensitive=False, partial=False, + matches=["foo/x", "foo/xhi.py"], + nomatches=["foo/x/hi.py"], + ), globs_to_regex_params( ["**/foo"], matches=["foo", "hello/foo", "hi/there/foo"],