Skip to content

Commit ae036ee

Browse files
authored
Merge pull request #191 from facelessuser/feature/excludes
Add exclude option
2 parents 8477277 + 1d00d84 commit ae036ee

File tree

13 files changed

+446
-146
lines changed

13 files changed

+446
-146
lines changed

.coveragerc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ omit=
55
[report]
66
omit=
77
wcmatch/pep562.py
8+
exclude_lines =
9+
pragma: no cover
10+
@overload

docs/src/markdown/about/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
- **NEW**: Drop support for Python 3.6.
66
- **NEW**: Switch to Hatch backend instead of Setuptools.
7+
- **NEW**: Add new `exclude` option to `fnmatch`, `pathlib`, and `glob` methods that allows exclusion patterns to be
8+
specified directly without needing to enable `NEGATE` and prepend patterns with `!`. `exclude` accepts a separate
9+
pattern or pattern list. `exclude` should not be used in conjunction with `NEGATE`. One or the other should be used.
710

811
## 8.3
912

docs/src/markdown/fnmatch.md

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ be no limit.
5454
#### `fnmatch.fnmatch` {: #fnmatch}
5555

5656
```py3
57-
def fnmatch(filename, patterns, *, flags=0, limit=1000)
57+
def fnmatch(filename, patterns, *, flags=0, limit=1000, exclude=None)
5858
```
5959

6060
`fnmatch` takes a file name, a pattern (or list of patterns), and flags. It also allows configuring the [max pattern
61-
limit](#multi-pattern-limits). It will return a boolean indicating whether the file name was matched by the pattern(s).
61+
limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes a pattern or
62+
a list of patterns. It will return a boolean indicating whether the file name was matched by the pattern(s).
6263

6364
```pycon3
6465
>>> from wcmatch import fnmatch
@@ -74,10 +75,21 @@ When applying multiple patterns, a file matches if it matches any of the pattern
7475
True
7576
```
7677

77-
Exclusion patterns are allowed as well. When exclusion patterns are used in conjunction with inclusion patterns, a file
78-
will be considered matched if one of the inclusion patterns match **and** none of the exclusion patterns match. If an
79-
exclusion pattern is given without any inclusion patterns, the pattern will match nothing. Exclusion patterns are meant
80-
to filter other patterns, not match anything by themselves.
78+
Exclusions can be used by taking advantage of the `exclude` parameter. It takes a single exclude pattern or a list of
79+
patterns. Files that match the exclude pattern will not be matched.
80+
81+
```pycon3
82+
>>> from wcmatch import fnmatch
83+
>>> fnmatch.fnmatch('test.py', '*', exclude='*.py')
84+
False
85+
>>> fnmatch.fnmatch('test.txt', '*', exclude='*.py')
86+
True
87+
```
88+
89+
Inline exclusion patterns are allowed as well. When exclusion patterns are used in conjunction with inclusion patterns,
90+
a file will be considered matched if one of the inclusion patterns match **and** none of the exclusion patterns match.
91+
If an exclusion pattern is given without any inclusion patterns, the pattern will match nothing. Exclusion patterns are
92+
meant to filter other patterns, not match anything by themselves.
8193

8294
```pycon3
8395
>>> from wcmatch import fnmatch
@@ -107,14 +119,18 @@ True
107119
!!! new "New 6.0"
108120
`limit` was added in 6.0.
109121

122+
!!! new "New 8.4"
123+
`exclude` parameter was added.
124+
110125
#### `fnmatch.filter` {: #filter}
111126

112127
```py3
113-
def filter(filenames, patterns, *, flags=0, limit=1000):
128+
def filter(filenames, patterns, *, flags=0, limit=1000, exclude=None):
114129
```
115130

116131
`filter` takes a list of filenames, a pattern (or list of patterns), and flags. It also allows configuring the [max
117-
pattern limit](#multi-pattern-limits). It returns a list of all files that matched the pattern(s). The same logic used for
132+
pattern limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes a
133+
pattern or a list of patterns.It returns a list of all files that matched the pattern(s). The same logic used for
118134
[`fnmatch`](#fnmatch) is used for `filter`, albeit more efficient for processing multiple files.
119135

120136
```pycon3
@@ -126,16 +142,20 @@ pattern limit](#multi-pattern-limits). It returns a list of all files that match
126142
!!! new "New 6.0"
127143
`limit` was added in 6.0.
128144

145+
!!! new "New 8.4"
146+
`exclude` parameter was added.
147+
129148
#### `fnmatch.translate` {: #translate}
130149

131150
```py3
132-
def translate(patterns, *, flags=0, limit=1000):
151+
def translate(patterns, *, flags=0, limit=1000, exclude=None):
133152
```
134153

135154
`translate` takes a file pattern (or list of patterns) and flags. It also allows configuring the [max pattern
136-
limit](#multi-pattern-limits). It returns two lists: one for inclusion patterns and one for exclusion patterns. The
137-
lists contain the regular expressions used for matching the given patterns. It should be noted that a file is considered
138-
matched if it matches at least one inclusion pattern and matches **none** of the exclusion patterns.
155+
limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes a pattern or
156+
a list of patterns. It returns two lists: one for inclusion patterns and one for exclusion patterns. The lists contain
157+
the regular expressions used for matching the given patterns. It should be noted that a file is considered matched if it
158+
matches at least one inclusion pattern and matches **none** of the exclusion patterns.
139159

140160
```pycon3
141161
>>> from wcmatch import fnmatch
@@ -165,6 +185,9 @@ we wrap the entire group to be captured: `#!py3 '+(a)'` --> `#!py3 r'((a)+)'`.
165185
!!! new "New 7.1"
166186
Translate patterns now provide capturing groups for [`EXTMATCH`](#extmatch) groups.
167187

188+
!!! new "New 8.4"
189+
`exclude` parameter was added.
190+
168191
#### `fnmatch.escape` {: #escape}
169192

170193
```py3
@@ -246,6 +269,12 @@ Assuming the `SPLIT` flag, this means using it in a pattern such as `inclusion|!
246269
If it is desired, you can force exclusion patterns, when no inclusion pattern is provided, to assume all files match
247270
unless the file matches the excluded pattern. This is done with the [`NEGATEALL`](#negateall) flag.
248271

272+
`NEGATE` enables [`DOTMATCH`](#dotglob) in all exclude patterns, this cannot be disabled. This will not affect the
273+
inclusion patterns.
274+
275+
If `NEGATE` is set and exclusion patterns are passed via a matching function's `exclude` parameter, `NEGATE` will be
276+
ignored and the `exclude` patterns will be used instead. Either `exclude` or `NEGATE` should be used, not both.
277+
249278
#### `fnmatch.NEGATEALL, fnmatch.A` {: #negateall}
250279

251280
`NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the

docs/src/markdown/glob.md

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,13 @@ no limit.
167167
#### `glob.glob` {: #glob}
168168
169169
```py3
170-
def glob(patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000):
170+
def glob(patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000, exclude=None):
171171
```
172172

173173
`glob` takes a pattern (or list of patterns), flags, and an optional root directory (string or path-like object) and/or
174-
directory file descriptor. It also allows configuring the [max pattern limit](#multi-pattern-limits). When executed it
175-
will crawl the file system returning matching files.
174+
directory file descriptor. It also allows configuring the [max pattern limit](#multi-pattern-limits). Exclusion patterns
175+
can be specified via the `exclude` parameter which takes a pattern or a list of patterns.When executed it will crawl the
176+
file system returning matching files.
176177

177178
!!! warning "Path-like Input Support"
178179
Path-like object input support is only available in Python 3.6+ as the path-like protocol was added in Python 3.6.
@@ -299,10 +300,13 @@ Additionally, you can use `dir_fd` and specify a root directory with a directory
299300
!!! new "New 8.2"
300301
`dir_fd` parameter was added in 8.2.
301302

303+
!!! new "New 8.4"
304+
`exclude` parameter was added.
305+
302306
#### `glob.iglob` {: #iglob}
303307

304308
```py3
305-
def iglob(patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000):
309+
def iglob(patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000, exclude=None):
306310
```
307311

308312
`iglob` is just like [`glob`](#glob) except it returns an iterator.
@@ -322,15 +326,19 @@ def iglob(patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000):
322326
!!! new "New 8.2"
323327
`dir_fd` parameter was added in 8.2.
324328

329+
!!! new "New 8.4"
330+
`exclude` parameter was added.
331+
325332
#### `glob.globmatch` {: #globmatch}
326333

327334
```py3
328-
def globmatch(filename, patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000):
335+
def globmatch(filename, patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000, exclude=None):
329336
```
330337

331338
`globmatch` takes a file name (string or path-like object), a pattern (or list of patterns), flags, and an optional root
332-
directory and/or file descriptor. It also allows configuring the [max pattern limit](#multi-pattern-limits). It will
333-
return a boolean indicating whether the file path was matched by the pattern(s).
339+
directory and/or file descriptor. It also allows configuring the [max pattern limit](#multi-pattern-limits). Exclusion
340+
patterns can be specified via the `exclude` parameter which takes a pattern or a list of patterns. It will return a
341+
boolean indicating whether the file path was matched by the pattern(s).
334342

335343
```pycon3
336344
>>> from wcmatch import glob
@@ -457,16 +465,20 @@ True
457465
!!! new "New 8.2"
458466
`dir_fd` parameter was added in 8.2.
459467

468+
!!! new "New 8.4"
469+
`exclude` parameter was added.
470+
460471
#### `glob.globfilter` {: #globfilter}
461472

462473
```py3
463-
def globfilter(filenames, patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000):
474+
def globfilter(filenames, patterns, *, flags=0, root_dir=None, dir_fd=None, limit=1000, method=None):
464475
```
465476

466477
`globfilter` takes a list of file paths (strings or path-like objects), a pattern (or list of patterns), flags, and an
467-
optional root directory and/or directory file descriptor. It also allows configuring the
468-
[max pattern limit](#multi-pattern-limits). It returns a list of all files paths that matched the pattern(s). The same
469-
logic used for [`globmatch`](#globmatch) is used for `globfilter`, albeit more efficient for processing multiple files.
478+
optional root directory and/or directory file descriptor. It also allows configuring the
479+
[max pattern limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes
480+
a pattern or a list of patterns.It returns a list of all files paths that matched the pattern(s). The same logic used
481+
for [`globmatch`](#globmatch) is used for `globfilter`, albeit more efficient for processing multiple files.
470482

471483
!!! warning "Path-like Input Support"
472484
Path-like object input support is only available in Python 3.6+ as the path-like protocol was added in Python 3.6.
@@ -492,16 +504,20 @@ be matched by `GLOBSTAR`. See [`globmatch`](#globmatch) for examples.
492504
!!! new "New 8.2"
493505
`dir_fd` parameter was added in 8.2.
494506

507+
!!! new "New 8.4"
508+
`exclude` parameter was added.
509+
495510
#### `glob.translate` {: #translate}
496511

497512
```py3
498-
def translate(patterns, *, flags=0, limit=1000):
513+
def translate(patterns, *, flags=0, limit=1000, exclude=None):
499514
```
500515

501516
`translate` takes a file pattern (or list of patterns) and flags. It also allows configuring the [max pattern
502-
limit](#multi-pattern-limits). It returns two lists: one for inclusion patterns and one for exclusion patterns. The
503-
lists contain the regular expressions used for matching the given patterns. It should be noted that a file is considered
504-
matched if it matches at least one inclusion pattern and matches **none** of the exclusion patterns.
517+
limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes a pattern or
518+
a list of patterns. It returns two lists: one for inclusion patterns and one for exclusion patterns. The lists contain
519+
the regular expressions used for matching the given patterns. It should be noted that a file is considered matched if it
520+
matches at least one inclusion pattern and matches **none** of the exclusion patterns.
505521

506522
```pycon3
507523
>>> from wcmatch import glob
@@ -531,6 +547,9 @@ we wrap the entire group to be captured: `#!py3 '+(a)'` --> `#!py3 r'((a)+)'`.
531547
!!! new "New 7.1"
532548
Translate patterns now provide capturing groups for [`EXTGLOB`](#extglob) groups.
533549

550+
!!! new "New 8.4"
551+
`exclude` parameter was added.
552+
534553
#### `glob.escape` {: #escape}
535554

536555
```py3
@@ -759,6 +778,9 @@ unless the file matches the excluded pattern. This is done with the [`NEGATEALL`
759778
`NEGATE` enables [`DOTGLOB`](#dotglob) in all exclude patterns, this cannot be disabled. This will not affect the
760779
inclusion patterns.
761780

781+
If `NEGATE` is set and exclusion patterns are passed via a matching or glob function's `exclude` parameter, `NEGATE`
782+
will be ignored and the `exclude` patterns will be used instead. Either `exclude` or `NEGATE` should be used, not both.
783+
762784
#### `glob.NEGATEALL, glob.A` {: #negateall}
763785

764786
`NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the

docs/src/markdown/pathlib.md

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,12 @@ PosixPath('/usr/local/bin')
240240
#### `PurePath.match` {: #match}
241241

242242
```py3
243-
def match(self, patterns, *, flags=0, limit=1000):
243+
def match(self, patterns, *, flags=0, limit=1000, exclude=None):
244244
```
245245

246246
`match` takes a pattern (or list of patterns), and flags. It also allows configuring the [max pattern
247-
limit](#multi-pattern-limits). It will return a boolean indicating whether the object's file path was matched by the
247+
limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes a pattern or
248+
a list of patterns. It will return a boolean indicating whether the object's file path was matched by the
248249
pattern(s).
249250

250251
`match` mimics Python's `pathlib` version of `match`. Python's `match` uses a right to left evaluation. Wildcard Match
@@ -279,15 +280,18 @@ True
279280
!!! new "New 6.0"
280281
`limit` was added in 6.0.
281282

283+
!!! new "New 8.4"
284+
`exclude` parameter was added.
285+
282286
#### `PurePath.globmatch` {: #globmatch}
283287

284288
```py3
285-
def globmatch(self, patterns, *, flags=0, limit=1000):
289+
def globmatch(self, patterns, *, flags=0, limit=1000, exclude=None):
286290
```
287291

288292
`globmatch` takes a pattern (or list of patterns), and flags. It also allows configuring the [max pattern
289-
limit](#multi-pattern-limits).It will return a boolean indicating whether the objects file path was matched by the
290-
pattern(s).
293+
limit](#multi-pattern-limits). Exclusion patterns can be specified via the `exclude` parameter which takes a pattern or
294+
a list of patterns. It will return a boolean indicating whether the objects file path was matched by the pattern(s).
291295

292296
`globmatch` is similar to [`match`](#match) except it does not use the same recursive logic that
293297
[`match`](#match) does. In all other respects, it behaves the same.
@@ -310,17 +314,20 @@ True
310314
!!! new "New 6.0"
311315
`limit` was added in 6.0.
312316

317+
!!! new "New 8.4"
318+
`exclude` parameter was added.
319+
313320
#### `Path.glob` {: #glob}
314321

315322
```py3
316-
def glob(self, patterns, *, flags=0, limit=1000):
323+
def glob(self, patterns, *, flags=0, limit=1000, exclude=None):
317324
```
318325

319326
`glob` takes a pattern (or list of patterns) and flags. It also allows configuring the [max pattern
320327
limit](#multi-pattern-limits). It will crawl the file system, relative to the current [`Path`](#path) object,
321328
returning a generator of [`Path`](#path) objects. If a file/folder matches any regular, inclusion pattern, it is
322-
considered a match. If a file matches *any* exclusion pattern (when enabling the [`NEGATE`](#negate) flag), then
323-
it will not be returned.
329+
considered a match. If a file matches *any* exclusion pattern (specified via `exclude` or using negation patterns when
330+
enabling the [`NEGATE`](#negate) flag), then it will not be returned.
324331

325332
This method calls our own [`iglob`](./glob.md#iglob) implementation, and as such, should behave in the same manner
326333
in respect to features, the one exception being that instead of returning path strings in the generator, it will return
@@ -340,17 +347,20 @@ working directory.
340347
!!! new "New 6.0"
341348
`limit` was added in 6.0.
342349

350+
!!! new "New 8.4"
351+
`exclude` parameter was added.
352+
343353
#### `Path.rglob` {: #rglob}
344354

345355
```py3
346-
def rglob(self, patterns, *, flags=0, path_limit=1000):
356+
def rglob(self, patterns, *, flags=0, path_limit=1000, exclude=None):
347357
```
348358

349359
`rglob` takes a pattern (or list of patterns) and flags. It also allows configuring the [max pattern
350360
limit](#multi-pattern-limits). It will crawl the file system, relative to the current [`Path`](#path) object,
351361
returning a generator of [`Path`](#path) objects. If a file/folder matches any regular patterns, it is considered
352-
a match. If a file matches *any* exclusion pattern (when enabling the [`NEGATE`](#negate) flag), then it will be
353-
not be returned.
362+
a match. If a file matches *any* exclusion pattern (specified via `exclude` or using negation patterns when enabling
363+
the [`NEGATE`](#negate) flag), then it will be not be returned.
354364

355365
`rglob` mimics Python's [`pathlib`][pathlib] version of `rglob` in that it uses a recursive logic. What this means is
356366
that when you are matching a path in the form `some/path/name`, the patterns `name`, `path/name` and `some/path/name`
@@ -370,6 +380,9 @@ the same.
370380
!!! new "New 6.0"
371381
`limit` was added in 6.0.
372382

383+
!!! new "New 8.4"
384+
`exclude` parameter was added.
385+
373386
## Flags
374387

375388
#### `pathlib.CASE, pathlib.C` {: #case}
@@ -401,6 +414,9 @@ unless the file matches the excluded pattern. This is done with the [`NEGATEALL`
401414
`NEGATE` enables [`DOTGLOB`](#dotglob) in all exclude patterns, this cannot be disabled. This will not affect the
402415
inclusion patterns.
403416

417+
If `NEGATE` is set and exclusion patterns are passed via a matching or glob function's `exclude` parameter, `NEGATE`
418+
will be ignored and the `exclude` patterns will be used instead. Either `exclude` or `NEGATE` should be used, not both.
419+
404420
#### `pathlib.NEGATEALL, pathlib.A` {: #negateall}
405421

406422
`NEGATEALL` can force exclusion patterns, when no inclusion pattern is provided, to assume all files match unless the

0 commit comments

Comments
 (0)