X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/8ebbd268880f15834b70910a6dc61e1ee7596b7c..435aa7ac4ab54d9bc30ee4d75859435c97493bb5:/black.py?ds=sidebyside diff --git a/black.py b/black.py index 4599bdd..7587ba8 100644 --- a/black.py +++ b/black.py @@ -46,6 +46,10 @@ from blib2to3.pgen2.parse import ParseError __version__ = "18.5b1" DEFAULT_LINE_LENGTH = 88 +DEFAULT_EXCLUDES = ( + r"/(\.git|\.hg|\.mypy_cache|\.tox|\.venv|_build|buck-out|build|dist)/" +) +DEFAULT_INCLUDES = r"\.pyi?$" CACHE_DIR = Path(user_cache_dir("black", version=__version__)) @@ -138,6 +142,29 @@ class FileMode(Flag): help="How many character per line to allow.", show_default=True, ) +@click.option( + "--py36", + is_flag=True, + help=( + "Allow using Python 3.6-only syntax on all input files. This will put " + "trailing commas in function signatures and calls also after *args and " + "**kwargs. [default: per-file auto-detection]" + ), +) +@click.option( + "--pyi", + is_flag=True, + help=( + "Format all input files like typing stubs regardless of file extension " + "(useful when piping source on standard input)." + ), +) +@click.option( + "-S", + "--skip-string-normalization", + is_flag=True, + help="Don't normalize string quotes or prefixes.", +) @click.option( "--check", is_flag=True, @@ -158,37 +185,36 @@ class FileMode(Flag): help="If --fast given, skip temporary sanity checks. [default: --safe]", ) @click.option( - "-q", - "--quiet", - is_flag=True, + "--include", + type=str, + default=DEFAULT_INCLUDES, help=( - "Don't emit non-error messages to stderr. Errors are still emitted, " - "silence those with 2>/dev/null." + "A regular expression that matches files and directories that should be " + "included on recursive searches. On Windows, use forward slashes for " + "directories." ), + show_default=True, ) @click.option( - "--pyi", - is_flag=True, + "--exclude", + type=str, + default=DEFAULT_EXCLUDES, help=( - "Consider all input files typing stubs regardless of file extension " - "(useful when piping source on standard input)." + "A regular expression that matches files and directories that should be " + "excluded on recursive searches. On Windows, use forward slashes for " + "directories." ), + show_default=True, ) @click.option( - "--py36", + "-q", + "--quiet", is_flag=True, help=( - "Allow using Python 3.6-only syntax on all input files. This will put " - "trailing commas in function signatures and calls also after *args and " - "**kwargs. [default: per-file auto-detection]" + "Don't emit non-error messages to stderr. Errors are still emitted, " + "silence those with 2>/dev/null." ), ) -@click.option( - "-S", - "--skip-string-normalization", - is_flag=True, - help="Don't normalize string quotes or prefixes.", -) @click.version_option(version=__version__) @click.argument( "src", @@ -208,14 +234,26 @@ def main( py36: bool, skip_string_normalization: bool, quiet: bool, + include: str, + exclude: str, src: List[str], ) -> None: """The uncompromising code formatter.""" sources: List[Path] = [] + try: + include_regex = re.compile(include) + except re.error: + err(f"Invalid regular expression for include given: {include!r}") + ctx.exit(2) + try: + exclude_regex = re.compile(exclude) + except re.error: + err(f"Invalid regular expression for exclude given: {exclude!r}") + ctx.exit(2) for s in src: p = Path(s) if p.is_dir(): - sources.extend(gen_python_files_in_dir(p)) + sources.extend(gen_python_files_in_dir(p, include_regex, exclude_regex)) elif p.is_file(): # if a file was explicitly given, we don't care about its extension sources.append(p) @@ -2750,33 +2788,35 @@ def get_future_imports(node: Node) -> Set[str]: return imports -PYTHON_EXTENSIONS = {".py", ".pyi"} -BLACKLISTED_DIRECTORIES = { - "build", - "buck-out", - "dist", - "_build", - ".git", - ".hg", - ".mypy_cache", - ".tox", - ".venv", -} - - -def gen_python_files_in_dir(path: Path) -> Iterator[Path]: - """Generate all files under `path` which aren't under BLACKLISTED_DIRECTORIES - and have one of the PYTHON_EXTENSIONS. +def gen_python_files_in_dir( + path: Path, include: Pattern[str], exclude: Pattern[str] +) -> Iterator[Path]: + """Generate all files under `path` whose paths are not excluded by the + `exclude` regex, but are included by the `include` regex. """ + for child in path.iterdir(): + searchable_path = str(child.as_posix()) + if Path(child.parts[0]).is_dir(): + searchable_path = "/" + searchable_path if child.is_dir(): - if child.name in BLACKLISTED_DIRECTORIES: + searchable_path = searchable_path + "/" + exclude_match = exclude.search(searchable_path) + if exclude_match and len(exclude_match.group()) > 0: continue - yield from gen_python_files_in_dir(child) + yield from gen_python_files_in_dir(child, include, exclude) - elif child.is_file() and child.suffix in PYTHON_EXTENSIONS: - yield child + else: + include_match = include.search(searchable_path) + exclude_match = exclude.search(searchable_path) + if ( + child.is_file() + and include_match + and len(include_match.group()) > 0 + and (not exclude_match or len(exclude_match.group()) == 0) + ): + yield child @dataclass