Skip to content

Commit dcc7f3b

Browse files
committed
Support --exclude more than once on command line
The result is an "OR" of all the patterns provided. Should be fully backward compatible to existing folks. Fixes #10310
1 parent d3fe55a commit dcc7f3b

File tree

6 files changed

+50
-38
lines changed

6 files changed

+50
-38
lines changed

docs/source/command_line.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ for full details, see :ref:`running-mypy`.
5959
pass ``--exclude '/setup\.py$'``. Similarly, you can ignore discovering
6060
directories with a given name by e.g. ``--exclude /build/`` or
6161
those matching a subpath with ``--exclude /project/vendor/``. To ignore
62-
multiple files / directories / paths, you can combine expressions with
63-
``|``, e.g ``--exclude '/setup\.py$|/build/'``.
62+
multiple files / directories / paths, you can provide the --exclude
63+
flag more than once, e.g ``--exclude '/setup\.py$' --exclude '/build/'``.
6464

6565
Note that this flag only affects recursive directory tree discovery, that
6666
is, when mypy is discovering files within a directory tree or submodules of

docs/source/config_file.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ section of the command line docs.
201201

202202
A regular expression that matches file names, directory names and paths
203203
which mypy should ignore while recursively discovering files to check.
204-
Use forward slashes on all platforms.
204+
Use forward slashes on all platforms. May be specified more than once.
205205

206206
For more details, see :option:`--exclude <mypy --exclude>`.
207207

mypy/main.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -864,11 +864,13 @@ def add_invertible_flag(flag: str,
864864
group=code_group)
865865
code_group.add_argument(
866866
"--exclude",
867+
action="append",
867868
metavar="PATTERN",
868-
default="",
869+
default=[],
869870
help=(
870871
"Regular expression to match file names, directory names or paths which mypy should "
871-
"ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'"
872+
"ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'. "
873+
"May be specified more than once, eg. --exclude a --exclude b"
872874
)
873875
)
874876
code_group.add_argument(

mypy/modulefinder.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -500,16 +500,21 @@ def find_modules_recursive(self, module: str) -> List[BuildSource]:
500500
return sources
501501

502502

503-
def matches_exclude(subpath: str, exclude: str, fscache: FileSystemCache, verbose: bool) -> bool:
504-
if not exclude:
503+
def matches_exclude(subpath: str,
504+
excludes: List[str],
505+
fscache: FileSystemCache,
506+
verbose: bool) -> bool:
507+
if not excludes:
505508
return False
506509
subpath_str = os.path.relpath(subpath).replace(os.sep, "/")
507510
if fscache.isdir(subpath):
508511
subpath_str += "/"
509-
if re.search(exclude, subpath_str):
510-
if verbose:
511-
print("TRACE: Excluding {}".format(subpath_str), file=sys.stderr)
512-
return True
512+
for exclude in excludes:
513+
if re.search(exclude, subpath_str):
514+
if verbose:
515+
print("TRACE: Excluding {} (matches pattern {})".format(subpath_str, exclude),
516+
file=sys.stderr)
517+
return True
513518
return False
514519

515520

mypy/options.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def __init__(self) -> None:
100100
# top-level __init__.py to your packages.
101101
self.explicit_package_bases = False
102102
# File names, directory names or subpaths to avoid checking
103-
self.exclude: str = ""
103+
self.exclude: List[str] = []
104104

105105
# disallow_any options
106106
self.disallow_any_generics = False

mypy/test/test_find_sources.py

+31-26
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ def test_find_sources_exclude(self) -> None:
298298
}
299299

300300
# file name
301-
options.exclude = r"/f\.py$"
301+
options.exclude = [r"/f\.py$"]
302302
fscache = FakeFSCache(files)
303303
assert find_sources(["/"], options, fscache) == [
304304
("a2", "/pkg"),
@@ -309,7 +309,7 @@ def test_find_sources_exclude(self) -> None:
309309
assert find_sources(["/pkg/a2/b/f.py"], options, fscache) == [('a2.b.f', '/pkg')]
310310

311311
# directory name
312-
options.exclude = "/a1/"
312+
options.exclude = ["/a1/"]
313313
fscache = FakeFSCache(files)
314314
assert find_sources(["/"], options, fscache) == [
315315
("a2", "/pkg"),
@@ -323,13 +323,13 @@ def test_find_sources_exclude(self) -> None:
323323
with pytest.raises(InvalidSourceList):
324324
find_sources(["/pkg/a1/b"], options, fscache)
325325

326-
options.exclude = "/a1/$"
326+
options.exclude = ["/a1/$"]
327327
assert find_sources(["/pkg/a1"], options, fscache) == [
328328
('e', '/pkg/a1/b/c/d'), ('f', '/pkg/a1/b')
329329
]
330330

331331
# paths
332-
options.exclude = "/pkg/a1/"
332+
options.exclude = ["/pkg/a1/"]
333333
fscache = FakeFSCache(files)
334334
assert find_sources(["/"], options, fscache) == [
335335
("a2", "/pkg"),
@@ -339,15 +339,17 @@ def test_find_sources_exclude(self) -> None:
339339
with pytest.raises(InvalidSourceList):
340340
find_sources(["/pkg/a1"], options, fscache)
341341

342-
options.exclude = "/(a1|a3)/"
343-
fscache = FakeFSCache(files)
344-
assert find_sources(["/"], options, fscache) == [
345-
("a2", "/pkg"),
346-
("a2.b.c.d.e", "/pkg"),
347-
("a2.b.f", "/pkg"),
348-
]
342+
# OR two patterns together
343+
for orred in [["/(a1|a3)/"], ["a1", "a3"], ["a3", "a1"]]:
344+
options.exclude = orred
345+
fscache = FakeFSCache(files)
346+
assert find_sources(["/"], options, fscache) == [
347+
("a2", "/pkg"),
348+
("a2.b.c.d.e", "/pkg"),
349+
("a2.b.f", "/pkg"),
350+
]
349351

350-
options.exclude = "b/c/"
352+
options.exclude = ["b/c/"]
351353
fscache = FakeFSCache(files)
352354
assert find_sources(["/"], options, fscache) == [
353355
("a2", "/pkg"),
@@ -356,19 +358,22 @@ def test_find_sources_exclude(self) -> None:
356358
]
357359

358360
# nothing should be ignored as a result of this
359-
options.exclude = "|".join((
361+
big_exclude1 = [
360362
"/pkg/a/", "/2", "/1", "/pk/", "/kg", "/g.py", "/bc", "/xxx/pkg/a2/b/f.py"
361363
"xxx/pkg/a2/b/f.py",
362-
))
363-
fscache = FakeFSCache(files)
364-
assert len(find_sources(["/"], options, fscache)) == len(files)
365-
366-
files = {
367-
"pkg/a1/b/c/d/e.py",
368-
"pkg/a1/b/f.py",
369-
"pkg/a2/__init__.py",
370-
"pkg/a2/b/c/d/e.py",
371-
"pkg/a2/b/f.py",
372-
}
373-
fscache = FakeFSCache(files)
374-
assert len(find_sources(["."], options, fscache)) == len(files)
364+
]
365+
big_exclude2 = ["|".join(big_exclude1)]
366+
for big_exclude in [big_exclude1, big_exclude2]:
367+
options.exclude = big_exclude
368+
fscache = FakeFSCache(files)
369+
assert len(find_sources(["/"], options, fscache)) == len(files)
370+
371+
files = {
372+
"pkg/a1/b/c/d/e.py",
373+
"pkg/a1/b/f.py",
374+
"pkg/a2/__init__.py",
375+
"pkg/a2/b/c/d/e.py",
376+
"pkg/a2/b/f.py",
377+
}
378+
fscache = FakeFSCache(files)
379+
assert len(find_sources(["."], options, fscache)) == len(files)

0 commit comments

Comments
 (0)