Skip to content

Commit

Permalink
Support --exclude more than once on command line
Browse files Browse the repository at this point in the history
The result is an "OR" of all the patterns provided.
Should be fully backward compatible to existing folks.

Fixes #10310
  • Loading branch information
nipunn1313 committed Oct 13, 2021
1 parent d3fe55a commit dcc7f3b
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 38 deletions.
4 changes: 2 additions & 2 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ for full details, see :ref:`running-mypy`.
pass ``--exclude '/setup\.py$'``. Similarly, you can ignore discovering
directories with a given name by e.g. ``--exclude /build/`` or
those matching a subpath with ``--exclude /project/vendor/``. To ignore
multiple files / directories / paths, you can combine expressions with
``|``, e.g ``--exclude '/setup\.py$|/build/'``.
multiple files / directories / paths, you can provide the --exclude
flag more than once, e.g ``--exclude '/setup\.py$' --exclude '/build/'``.

Note that this flag only affects recursive directory tree discovery, that
is, when mypy is discovering files within a directory tree or submodules of
Expand Down
2 changes: 1 addition & 1 deletion docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ section of the command line docs.

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

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

Expand Down
6 changes: 4 additions & 2 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,11 +864,13 @@ def add_invertible_flag(flag: str,
group=code_group)
code_group.add_argument(
"--exclude",
action="append",
metavar="PATTERN",
default="",
default=[],
help=(
"Regular expression to match file names, directory names or paths which mypy should "
"ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'"
"ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'. "
"May be specified more than once, eg. --exclude a --exclude b"
)
)
code_group.add_argument(
Expand Down
17 changes: 11 additions & 6 deletions mypy/modulefinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,21 @@ def find_modules_recursive(self, module: str) -> List[BuildSource]:
return sources


def matches_exclude(subpath: str, exclude: str, fscache: FileSystemCache, verbose: bool) -> bool:
if not exclude:
def matches_exclude(subpath: str,
excludes: List[str],
fscache: FileSystemCache,
verbose: bool) -> bool:
if not excludes:
return False
subpath_str = os.path.relpath(subpath).replace(os.sep, "/")
if fscache.isdir(subpath):
subpath_str += "/"
if re.search(exclude, subpath_str):
if verbose:
print("TRACE: Excluding {}".format(subpath_str), file=sys.stderr)
return True
for exclude in excludes:
if re.search(exclude, subpath_str):
if verbose:
print("TRACE: Excluding {} (matches pattern {})".format(subpath_str, exclude),
file=sys.stderr)
return True
return False


Expand Down
2 changes: 1 addition & 1 deletion mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def __init__(self) -> None:
# top-level __init__.py to your packages.
self.explicit_package_bases = False
# File names, directory names or subpaths to avoid checking
self.exclude: str = ""
self.exclude: List[str] = []

# disallow_any options
self.disallow_any_generics = False
Expand Down
57 changes: 31 additions & 26 deletions mypy/test/test_find_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def test_find_sources_exclude(self) -> None:
}

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

# directory name
options.exclude = "/a1/"
options.exclude = ["/a1/"]
fscache = FakeFSCache(files)
assert find_sources(["/"], options, fscache) == [
("a2", "/pkg"),
Expand All @@ -323,13 +323,13 @@ def test_find_sources_exclude(self) -> None:
with pytest.raises(InvalidSourceList):
find_sources(["/pkg/a1/b"], options, fscache)

options.exclude = "/a1/$"
options.exclude = ["/a1/$"]
assert find_sources(["/pkg/a1"], options, fscache) == [
('e', '/pkg/a1/b/c/d'), ('f', '/pkg/a1/b')
]

# paths
options.exclude = "/pkg/a1/"
options.exclude = ["/pkg/a1/"]
fscache = FakeFSCache(files)
assert find_sources(["/"], options, fscache) == [
("a2", "/pkg"),
Expand All @@ -339,15 +339,17 @@ def test_find_sources_exclude(self) -> None:
with pytest.raises(InvalidSourceList):
find_sources(["/pkg/a1"], options, fscache)

options.exclude = "/(a1|a3)/"
fscache = FakeFSCache(files)
assert find_sources(["/"], options, fscache) == [
("a2", "/pkg"),
("a2.b.c.d.e", "/pkg"),
("a2.b.f", "/pkg"),
]
# OR two patterns together
for orred in [["/(a1|a3)/"], ["a1", "a3"], ["a3", "a1"]]:
options.exclude = orred
fscache = FakeFSCache(files)
assert find_sources(["/"], options, fscache) == [
("a2", "/pkg"),
("a2.b.c.d.e", "/pkg"),
("a2.b.f", "/pkg"),
]

options.exclude = "b/c/"
options.exclude = ["b/c/"]
fscache = FakeFSCache(files)
assert find_sources(["/"], options, fscache) == [
("a2", "/pkg"),
Expand All @@ -356,19 +358,22 @@ def test_find_sources_exclude(self) -> None:
]

# nothing should be ignored as a result of this
options.exclude = "|".join((
big_exclude1 = [
"/pkg/a/", "/2", "/1", "/pk/", "/kg", "/g.py", "/bc", "/xxx/pkg/a2/b/f.py"
"xxx/pkg/a2/b/f.py",
))
fscache = FakeFSCache(files)
assert len(find_sources(["/"], options, fscache)) == len(files)

files = {
"pkg/a1/b/c/d/e.py",
"pkg/a1/b/f.py",
"pkg/a2/__init__.py",
"pkg/a2/b/c/d/e.py",
"pkg/a2/b/f.py",
}
fscache = FakeFSCache(files)
assert len(find_sources(["."], options, fscache)) == len(files)
]
big_exclude2 = ["|".join(big_exclude1)]
for big_exclude in [big_exclude1, big_exclude2]:
options.exclude = big_exclude
fscache = FakeFSCache(files)
assert len(find_sources(["/"], options, fscache)) == len(files)

files = {
"pkg/a1/b/c/d/e.py",
"pkg/a1/b/f.py",
"pkg/a2/__init__.py",
"pkg/a2/b/c/d/e.py",
"pkg/a2/b/f.py",
}
fscache = FakeFSCache(files)
assert len(find_sources(["."], options, fscache)) == len(files)

0 comments on commit dcc7f3b

Please sign in to comment.