X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/865f536143e73da60f7c6b60924eb2472deb1cfe..537ea8df35b1004bdb228b483907fb5dd92e5257:/src/black/__init__.py diff --git a/src/black/__init__.py b/src/black/__init__.py index 41c688b..930f2cb 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -267,7 +267,7 @@ def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> b return all(feature in VERSION_TO_FEATURES[version] for version in target_versions) -def find_pyproject_toml(path_search_start: str) -> Optional[str]: +def find_pyproject_toml(path_search_start: Iterable[str]) -> Optional[str]: """Find the absolute filepath to a pyproject.toml if it exists""" path_project_root = find_project_root(path_search_start) path_pyproject_toml = path_project_root / "pyproject.toml" @@ -306,11 +306,19 @@ def read_pyproject_toml( if not config: return None + else: + # Sanitize the values to be Click friendly. For more information please see: + # https://github.com/psf/black/issues/1458 + # https://github.com/pallets/click/issues/1567 + config = { + k: str(v) if not isinstance(v, (list, dict)) else v + for k, v in config.items() + } target_version = config.get("target_version") if target_version is not None and not isinstance(target_version, list): raise click.BadOptionUsage( - "target-version", f"Config key target-version must be a list" + "target-version", "Config key target-version must be a list" ) default_map: Dict[str, Any] = {} @@ -463,7 +471,7 @@ def target_version_option_callback( ), is_eager=True, callback=read_pyproject_toml, - help="Read configuration from PATH.", + help="Read configuration from FILE path.", ) @click.pass_context def main( @@ -1633,8 +1641,10 @@ class Line: # one line in the original code. # Grab the first and last line numbers, skipping generated leaves - first_line = next((l.lineno for l in self.leaves if l.lineno != 0), 0) - last_line = next((l.lineno for l in reversed(self.leaves) if l.lineno != 0), 0) + first_line = next((leaf.lineno for leaf in self.leaves if leaf.lineno != 0), 0) + last_line = next( + (leaf.lineno for leaf in reversed(self.leaves) if leaf.lineno != 0), 0 + ) if first_line == last_line: # We look at the last two leaves since a comma or an @@ -2710,15 +2720,15 @@ def transform_line( # split altogether. result: List[Line] = [] try: - for l in transform(line, features): - if str(l).strip("\n") == line_str: + for transformed_line in transform(line, features): + if str(transformed_line).strip("\n") == line_str: raise CannotTransform( "Line transformer returned an unchanged result" ) result.extend( transform_line( - l, + transformed_line, line_length=line_length, normalize_strings=normalize_strings, features=features, @@ -2752,7 +2762,7 @@ class StringTransformer(ABC): StringTransformer to be applied? Transformations: - If the given Line meets all of the above requirments, which string + If the given Line meets all of the above requirements, which string transformations can you expect to be applied to it by this StringTransformer? @@ -3611,7 +3621,7 @@ class StringSplitter(CustomSplitMapMixin, BaseStringSplitter): # We MAY choose to drop the 'f' prefix from substrings that don't # contain any f-expressions, but ONLY if the original f-string - # containes at least one f-expression. Otherwise, we will alter the AST + # contains at least one f-expression. Otherwise, we will alter the AST # of the program. drop_pointless_f_prefix = ("f" in prefix) and re.search( self.RE_FEXPR, LL[string_idx].value, re.VERBOSE @@ -3701,7 +3711,7 @@ class StringSplitter(CustomSplitMapMixin, BaseStringSplitter): max_bidx = max_break_idx - 2 if line_needs_plus() else max_break_idx maybe_break_idx = self.__get_break_idx(rest_value, max_bidx) if maybe_break_idx is None: - # If we are unable to algorthmically determine a good split + # If we are unable to algorithmically determine a good split # and this string has custom splits registered to it, we # fall back to using them--which means we have to start # over from the beginning. @@ -4278,7 +4288,7 @@ class StringParenWrapper(CustomSplitMapMixin, BaseStringSplitter): class StringParser: """ A state machine that aids in parsing a string's "trailer", which can be - either non-existant, an old-style formatting sequence (e.g. `% varX` or `% + either non-existent, an old-style formatting sequence (e.g. `% varX` or `% (varX, varY)`), or a method-call / attribute access (e.g. `.format(varX, varY)`). @@ -4372,7 +4382,7 @@ class StringParser: was directly after the string leaf in question (e.g. if our target string is `line.leaves[i]` then the first call to this method must be `line.leaves[i + 1]`). - * On the next call to this function, the leaf paramater passed in + * On the next call to this function, the leaf parameter passed in MUST be the leaf directly following @leaf. Returns: @@ -4577,7 +4587,7 @@ def append_leaves(new_line: Line, old_line: Line, leaves: List[Leaf]) -> None: All of the leaves in @leaves are duplicated. The duplicates are then appended to @new_line and used to replace their originals in the underlying - Node structure. Any comments attatched to the old leaves are reattached to + Node structure. Any comments attached to the old leaves are reattached to the new leaves. Pre-conditions: @@ -4836,7 +4846,7 @@ def bracket_split_build_line( no_commas = ( original.is_def and opening_bracket.value == "(" - and not any(l.type == token.COMMA for l in leaves) + and not any(leaf.type == token.COMMA for leaf in leaves) ) if original.is_import or no_commas: @@ -4866,9 +4876,9 @@ def dont_increase_indentation(split_func: Transformer) -> Transformer: @wraps(split_func) def split_wrapper(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: - for l in split_func(line, features): - normalize_prefix(l.leaves[0], inside_brackets=True) - yield l + for line in split_func(line, features): + normalize_prefix(line.leaves[0], inside_brackets=True) + yield line return split_wrapper @@ -5815,8 +5825,8 @@ def gen_python_files( def find_project_root(srcs: Iterable[str]) -> Path: """Return a directory containing .git, .hg, or pyproject.toml. - That directory can be one of the directories passed in `srcs` or their - common parent. + That directory will be a common parent of all files and directories + passed in `srcs`. If no directory in the tree contains a marker that would specify it's the project root, the root of the file system is returned. @@ -5824,11 +5834,20 @@ def find_project_root(srcs: Iterable[str]) -> Path: if not srcs: return Path("/").resolve() - common_base = min(Path(src).resolve() for src in srcs) - if common_base.is_dir(): - # Append a fake file so `parents` below returns `common_base_dir`, too. - common_base /= "fake-file" - for directory in common_base.parents: + path_srcs = [Path(Path.cwd(), src).resolve() for src in srcs] + + # A list of lists of parents for each 'src'. 'src' is included as a + # "parent" of itself if it is a directory + src_parents = [ + list(path.parents) + ([path] if path.is_dir() else []) for path in path_srcs + ] + + common_base = max( + set.intersection(*(set(parents) for parents in src_parents)), + key=lambda path: path.parts, + ) + + for directory in (common_base, *common_base.parents): if (directory / ".git").exists(): return directory @@ -6006,13 +6025,14 @@ def _stringify_ast( else: # Constant strings may be indented across newlines, if they are - # docstrings; fold spaces after newlines when comparing + # docstrings; fold spaces after newlines when comparing. Similarly, + # trailing and leading space may be removed. if ( isinstance(node, ast.Constant) and field == "value" and isinstance(value, str) ): - normalized = re.sub(r"\n[ \t]+", "\n ", value) + normalized = re.sub(r" *\n[ \t]+", "\n ", value).strip() else: normalized = value yield f"{' ' * (depth+2)}{normalized!r}, # {value.__class__.__name__}"