X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/b2067aabbfa900366326ab7ab7d5a208059f5dab..6fa60ba39d137bff08a7aa78beffa4773eb24121:/black.py diff --git a/black.py b/black.py index 488f581..61b884a 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__)) @@ -126,6 +130,7 @@ class FileMode(Flag): AUTO_DETECT = 0 PYTHON36 = 1 PYI = 2 + NO_STRING_NORMALIZATION = 4 @click.command() @@ -182,6 +187,34 @@ class FileMode(Flag): "**kwargs. [default: per-file auto-detection]" ), ) +@click.option( + "-S", + "--skip-string-normalization", + is_flag=True, + help="Don't normalize string quotes or prefixes.", +) +@click.option( + "--include", + type=str, + default=DEFAULT_INCLUDES, + help=( + "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( + "--exclude", + type=str, + default=DEFAULT_EXCLUDES, + help=( + "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.version_option(version=__version__) @click.argument( "src", @@ -199,15 +232,28 @@ def main( fast: bool, pyi: bool, 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) @@ -227,6 +273,8 @@ def main( mode |= FileMode.PYTHON36 if pyi: mode |= FileMode.PYI + if skip_string_normalization: + mode |= FileMode.NO_STRING_NORMALIZATION report = Report(check=check, quiet=quiet) if len(sources) == 0: out("No paths given. Nothing to do 😴") @@ -487,8 +535,11 @@ def format_str( future_imports = get_future_imports(src_node) is_pyi = bool(mode & FileMode.PYI) py36 = bool(mode & FileMode.PYTHON36) or is_python36(src_node) + normalize_strings = not bool(mode & FileMode.NO_STRING_NORMALIZATION) lines = LineGenerator( - remove_u_prefix=py36 or "unicode_literals" in future_imports, is_pyi=is_pyi + remove_u_prefix=py36 or "unicode_literals" in future_imports, + is_pyi=is_pyi, + normalize_strings=normalize_strings, ) elt = EmptyLineTracker(is_pyi=is_pyi) empty_line = Line() @@ -1286,6 +1337,7 @@ class LineGenerator(Visitor[Line]): """ is_pyi: bool = False + normalize_strings: bool = True current_line: Line = Factory(Line) remove_u_prefix: bool = False @@ -1354,7 +1406,7 @@ class LineGenerator(Visitor[Line]): else: normalize_prefix(node, inside_brackets=any_open_brackets) - if node.type == token.STRING: + if self.normalize_strings and node.type == token.STRING: normalize_string_prefix(node, remove_u_prefix=self.remove_u_prefix) normalize_string_quotes(node) if node.type not in WHITESPACE: @@ -2736,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