Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --extend-exclude parameter #2005

Merged
merged 10 commits into from Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 8 additions & 17 deletions README.md
Expand Up @@ -135,11 +135,17 @@ Options:
hg|\.mypy_cache|\.nox|\.tox|\.venv|\.svn|_bu
ild|buck-out|build|dist)/]

--extend-exclude TEXT Like --exclude, but adds additional files
thejcannon marked this conversation as resolved.
Show resolved Hide resolved
and directories on top of the excluded
ones. (Useful if you simply want to add to
the default)
thejcannon marked this conversation as resolved.
Show resolved Hide resolved

--force-exclude TEXT Like --exclude, but files and directories
matching this regex will be excluded even
when they are passed explicitly as
arguments.


--stdin-filename TEXT The name of the file when passing it through
stdin. Useful to make sure Black will
respect --force-exclude option on some
Expand Down Expand Up @@ -313,25 +319,10 @@ expressions by Black. Use `[ ]` to denote a significant space character.
line-length = 88
target-version = ['py37']
include = '\.pyi?$'
exclude = '''
extend-exclude = '''
# A regex preceded with ^/ will apply only to files and directories
# in the root of the project.
^/(
(
\.eggs # exclude a few common directories in the
| \.git # root of the project
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
| foo.py # also separately exclude a file named foo.py in
# the root of the project
)
^/foo.py # exclude a file named foo.py in the root of the project (in addition to the defaults)
'''
```

Expand Down
2 changes: 2 additions & 0 deletions docs/change_log.md
Expand Up @@ -28,6 +28,8 @@

- use lowercase hex strings (#1692)

- added `--extend-exclude` argument (#1571)

#### _Packaging_

- Self-contained native _Black_ binaries are now provided for releases via GitHub
Expand Down
5 changes: 5 additions & 0 deletions docs/installation_and_usage.md
Expand Up @@ -95,6 +95,11 @@ Options:
when they are passed explicitly as
arguments.

--extend-exclude TEXT Like --exclude, but adds additional files
and directories on top of the excluded
ones. (Useful if you simply want to add to
the default)

--stdin-filename TEXT The name of the file when passing it through
stdin. Useful to make sure Black will
respect --force-exclude option on some
Expand Down
19 changes: 2 additions & 17 deletions docs/pyproject_toml.md
Expand Up @@ -54,25 +54,10 @@ expressions by Black. Use `[ ]` to denote a significant space character.
line-length = 88
target-version = ['py37']
include = '\.pyi?$'
exclude = '''
extend-exclude = '''
# A regex preceded with ^/ will apply only to files and directories
# in the root of the project.
^/(
(
\.eggs # exclude a few common directories in the
| \.git # root of the project
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
| foo.py # also separately exclude a file named foo.py in
# the root of the project
)
^/foo.py # exclude a file named foo.py in the root of the project (in addition to the defaults)
'''
```

Expand Down
13 changes: 1 addition & 12 deletions pyproject.toml
Expand Up @@ -9,19 +9,8 @@
line-length = 88
target-version = ['py36', 'py37', 'py38']
include = '\.pyi?$'
exclude = '''
extend-exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist

# The following are specific to Black, you probably don't want those.
| blib2to3
| tests/data
Expand Down
75 changes: 50 additions & 25 deletions src/black/__init__.py
Expand Up @@ -461,6 +461,14 @@ def target_version_option_callback(
),
show_default=True,
)
@click.option(
"--extend-exclude",
type=str,
help=(
"Like --exclude, but adds additional files and directories on top of the"
" excluded ones. (Useful if you simply want to add to the default)"
),
)
@click.option(
"--force-exclude",
type=str,
Expand Down Expand Up @@ -537,6 +545,7 @@ def main(
verbose: bool,
include: str,
exclude: str,
extend_exclude: Optional[str],
force_exclude: Optional[str],
stdin_filename: Optional[str],
src: Tuple[str, ...],
Expand Down Expand Up @@ -570,6 +579,7 @@ def main(
verbose=verbose,
include=include,
exclude=exclude,
extend_exclude=extend_exclude,
force_exclude=force_exclude,
report=report,
stdin_filename=stdin_filename,
Expand Down Expand Up @@ -602,6 +612,18 @@ def main(
ctx.exit(report.return_code)


def test_regex(
ctx: click.Context,
regex_name: str,
regex: Optional[str],
) -> Optional[Pattern]:
thejcannon marked this conversation as resolved.
Show resolved Hide resolved
try:
return re_compile_maybe_verbose(regex) if regex else None
except re.error:
err(f"Invalid regular expression for {regex_name} given: {regex!r}")
ctx.exit(2)


def get_sources(
*,
ctx: click.Context,
Expand All @@ -610,28 +632,17 @@ def get_sources(
verbose: bool,
include: str,
exclude: str,
extend_exclude: Optional[str],
force_exclude: Optional[str],
report: "Report",
stdin_filename: Optional[str],
) -> Set[Path]:
"""Compute the set of files to be formatted."""
try:
include_regex = re_compile_maybe_verbose(include)
except re.error:
err(f"Invalid regular expression for include given: {include!r}")
ctx.exit(2)
try:
exclude_regex = re_compile_maybe_verbose(exclude)
except re.error:
err(f"Invalid regular expression for exclude given: {exclude!r}")
ctx.exit(2)
try:
force_exclude_regex = (
re_compile_maybe_verbose(force_exclude) if force_exclude else None
)
except re.error:
err(f"Invalid regular expression for force_exclude given: {force_exclude!r}")
ctx.exit(2)

include_regex = test_regex(ctx, "include", include)
exclude_regex = test_regex(ctx, "exclude", exclude)
extend_exclude_regex = test_regex(ctx, "extend_exclude", extend_exclude)
force_exclude_regex = test_regex(ctx, "force_exclude", force_exclude)

root = find_project_root(src)
sources: Set[Path] = set()
Expand Down Expand Up @@ -672,6 +683,7 @@ def get_sources(
root,
include_regex,
exclude_regex,
extend_exclude_regex,
force_exclude_regex,
report,
gitignore,
Expand Down Expand Up @@ -6110,17 +6122,27 @@ def normalize_path_maybe_ignore(
return normalized_path


def path_is_excluded(
normalized_path: str,
pattern: Pattern[str],
):
match = pattern.search(normalized_path) if pattern else None
return match and match.group(0)


def gen_python_files(
paths: Iterable[Path],
root: Path,
include: Optional[Pattern[str]],
exclude: Pattern[str],
extend_exclude: Optional[Pattern[str]],
force_exclude: Optional[Pattern[str]],
report: "Report",
gitignore: PathSpec,
) -> Iterator[Path]:
"""Generate all files under `path` whose paths are not excluded by the
`exclude_regex` or `force_exclude` regexes, but are included by the `include` regex.
`exclude_regex`, `extend_exclude`, or `force_exclude` regexes,
but are included by the `include` regex.

Symbolic links pointing outside of the `root` directory are ignored.

Expand All @@ -6137,20 +6159,22 @@ def gen_python_files(
report.path_ignored(child, "matches the .gitignore file content")
continue

# Then ignore with `--exclude` and `--force-exclude` options.
# Then ignore with `--exclude` `--extend-exclude` and `--force-exclude` options.
normalized_path = "/" + normalized_path
if child.is_dir():
normalized_path += "/"

exclude_match = exclude.search(normalized_path) if exclude else None
if exclude_match and exclude_match.group(0):
if path_is_excluded(normalized_path, exclude):
report.path_ignored(child, "matches the --exclude regular expression")
continue

force_exclude_match = (
force_exclude.search(normalized_path) if force_exclude else None
)
if force_exclude_match and force_exclude_match.group(0):
if path_is_excluded(normalized_path, extend_exclude):
report.path_ignored(
child, "matches the --extend-exclude regular expression"
)
continue

if path_is_excluded(normalized_path, force_exclude):
report.path_ignored(child, "matches the --force-exclude regular expression")
continue

Expand All @@ -6160,6 +6184,7 @@ def gen_python_files(
root,
include,
exclude,
extend_exclude,
force_exclude,
report,
gitignore,
Expand Down