X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/2f3fa1f6d0cbc2a3f31c7440c422da173b068e7b:/src/black/files.py..dc71922c768e543c9c3bbb1db5ea6d7fa801a814:/.vim/bundle/black/src/black/static/git-logo.png diff --git a/src/black/files.py b/src/black/files.py deleted file mode 100644 index 4d7b47a..0000000 --- a/src/black/files.py +++ /dev/null @@ -1,259 +0,0 @@ -from functools import lru_cache -import io -import os -from pathlib import Path -import sys -from typing import ( - Any, - Dict, - Iterable, - Iterator, - List, - Optional, - Pattern, - Sequence, - Tuple, - Union, - TYPE_CHECKING, -) - -from pathspec import PathSpec -from pathspec.patterns.gitwildmatch import GitWildMatchPatternError -import tomli - -from black.output import err -from black.report import Report -from black.handle_ipynb_magics import jupyter_dependencies_are_installed - -if TYPE_CHECKING: - import colorama # noqa: F401 - - -@lru_cache() -def find_project_root(srcs: Sequence[str]) -> Path: - """Return a directory containing .git, .hg, or pyproject.toml. - - 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. - """ - if not srcs: - srcs = [str(Path.cwd().resolve())] - - 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 - - if (directory / ".hg").is_dir(): - return directory - - if (directory / "pyproject.toml").is_file(): - return directory - - return directory - - -def find_pyproject_toml(path_search_start: Tuple[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" - if path_pyproject_toml.is_file(): - return str(path_pyproject_toml) - - try: - path_user_pyproject_toml = find_user_pyproject_toml() - return ( - str(path_user_pyproject_toml) - if path_user_pyproject_toml.is_file() - else None - ) - except PermissionError as e: - # We do not have access to the user-level config directory, so ignore it. - err(f"Ignoring user configuration directory due to {e!r}") - return None - - -def parse_pyproject_toml(path_config: str) -> Dict[str, Any]: - """Parse a pyproject toml file, pulling out relevant parts for Black - - If parsing fails, will raise a tomli.TOMLDecodeError - """ - with open(path_config, encoding="utf8") as f: - pyproject_toml = tomli.load(f) # type: ignore # due to deprecated API usage - config = pyproject_toml.get("tool", {}).get("black", {}) - return {k.replace("--", "").replace("-", "_"): v for k, v in config.items()} - - -@lru_cache() -def find_user_pyproject_toml() -> Path: - r"""Return the path to the top-level user configuration for black. - - This looks for ~\.black on Windows and ~/.config/black on Linux and other - Unix systems. - """ - if sys.platform == "win32": - # Windows - user_config_path = Path.home() / ".black" - else: - config_root = os.environ.get("XDG_CONFIG_HOME", "~/.config") - user_config_path = Path(config_root).expanduser() / "black" - return user_config_path.resolve() - - -@lru_cache() -def get_gitignore(root: Path) -> PathSpec: - """Return a PathSpec matching gitignore content if present.""" - gitignore = root / ".gitignore" - lines: List[str] = [] - if gitignore.is_file(): - with gitignore.open(encoding="utf-8") as gf: - lines = gf.readlines() - try: - return PathSpec.from_lines("gitwildmatch", lines) - except GitWildMatchPatternError as e: - err(f"Could not parse {gitignore}: {e}") - raise - - -def normalize_path_maybe_ignore( - path: Path, root: Path, report: Report -) -> Optional[str]: - """Normalize `path`. May return `None` if `path` was ignored. - - `report` is where "path ignored" output goes. - """ - try: - abspath = path if path.is_absolute() else Path.cwd() / path - normalized_path = abspath.resolve().relative_to(root).as_posix() - except OSError as e: - report.path_ignored(path, f"cannot be read because {e}") - return None - - except ValueError: - if path.is_symlink(): - report.path_ignored(path, f"is a symbolic link that points outside {root}") - return None - - raise - - return normalized_path - - -def path_is_excluded( - normalized_path: str, - pattern: Optional[Pattern[str]], -) -> bool: - match = pattern.search(normalized_path) if pattern else None - return bool(match and match.group(0)) - - -def gen_python_files( - paths: Iterable[Path], - root: Path, - include: Pattern[str], - exclude: Pattern[str], - extend_exclude: Optional[Pattern[str]], - force_exclude: Optional[Pattern[str]], - report: Report, - gitignore: Optional[PathSpec], - *, - verbose: bool, - quiet: bool, -) -> Iterator[Path]: - """Generate all files under `path` whose paths are not excluded by the - `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. - - `report` is where output about exclusions goes. - """ - assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}" - for child in paths: - normalized_path = normalize_path_maybe_ignore(child, root, report) - if normalized_path is None: - continue - - # First ignore files matching .gitignore, if passed - if gitignore is not None and gitignore.match_file(normalized_path): - report.path_ignored(child, "matches the .gitignore file content") - continue - - # Then ignore with `--exclude` `--extend-exclude` and `--force-exclude` options. - normalized_path = "/" + normalized_path - if child.is_dir(): - normalized_path += "/" - - if path_is_excluded(normalized_path, exclude): - report.path_ignored(child, "matches the --exclude regular expression") - continue - - 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 - - if child.is_dir(): - # If gitignore is None, gitignore usage is disabled, while a Falsey - # gitignore is when the directory doesn't have a .gitignore file. - yield from gen_python_files( - child.iterdir(), - root, - include, - exclude, - extend_exclude, - force_exclude, - report, - gitignore + get_gitignore(child) if gitignore is not None else None, - verbose=verbose, - quiet=quiet, - ) - - elif child.is_file(): - if child.suffix == ".ipynb" and not jupyter_dependencies_are_installed( - verbose=verbose, quiet=quiet - ): - continue - include_match = include.search(normalized_path) if include else True - if include_match: - yield child - - -def wrap_stream_for_windows( - f: io.TextIOWrapper, -) -> Union[io.TextIOWrapper, "colorama.AnsiToWin32"]: - """ - Wrap stream with colorama's wrap_stream so colors are shown on Windows. - - If `colorama` is unavailable, the original stream is returned unmodified. - Otherwise, the `wrap_stream()` function determines whether the stream needs - to be wrapped for a Windows environment and will accordingly either return - an `AnsiToWin32` wrapper or the original stream. - """ - try: - from colorama.initialise import wrap_stream - except ImportError: - return f - else: - # Set `strip=False` to avoid needing to modify test_express_diff_with_color. - return wrap_stream(f, convert=None, strip=False, autoreset=False, wrap=True)