]>
git.madduck.net Git - etc/vim.git/blobdiff - src/black/files.py
madduck's git repository
Every one of the projects in this repository is available at the canonical
URL git://git.madduck.net/madduck/pub/<projectpath> — see
each project's metadata for the exact URL.
All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@ git. madduck. net .
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
SSH access, as well as push access can be individually
arranged .
If you use my repositories frequently, consider adding the following
snippet to ~/.gitconfig and using the third clone URL listed for each
project:
[url "git://git.madduck.net/madduck/"]
insteadOf = madduck:
-from functools import lru_cache
-from pathlib import Path
+from functools import lru_cache
+from pathlib import Path
+from mypy_extensions import mypyc_attr
from pathspec import PathSpec
from pathspec import PathSpec
+from pathspec.patterns.gitwildmatch import GitWildMatchPatternError
+if sys.version_info >= (3, 11):
+ try:
+ import tomllib
+ except ImportError:
+ # Help users on older alphas
+ if not TYPE_CHECKING:
+ import tomli as tomllib
+else:
+ import tomli as tomllib
+
+from black.handle_ipynb_magics import jupyter_dependencies_are_installed
from black.output import err
from black.report import Report
from black.output import err
from black.report import Report
-def find_project_root(srcs: Sequence[str]) -> Path:
+def find_project_root(
+ srcs: Sequence[str], stdin_filename: Optional[str] = None
+) -> Tuple[Path, str]:
"""Return a directory containing .git, .hg, or pyproject.toml.
That directory will be a common parent of all files and directories
"""Return a directory containing .git, .hg, or pyproject.toml.
That directory will be a common parent of all files and directories
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 no directory in the tree contains a marker that would specify it's the
project root, the root of the file system is returned.
+
+ Returns a two-tuple with the first element as the project root path and
+ the second element as a string describing the method by which the
+ project root was discovered.
+ if stdin_filename is not None:
+ srcs = tuple(stdin_filename if s == "-" else s for s in srcs)
- return Path("/").resolve()
+ srcs = [str(Path.cwd().resolve())]
path_srcs = [Path(Path.cwd(), src).resolve() for src in srcs]
path_srcs = [Path(Path.cwd(), src).resolve() for src in srcs]
for directory in (common_base, *common_base.parents):
if (directory / ".git").exists():
for directory in (common_base, *common_base.parents):
if (directory / ".git").exists():
+ return directory, ".git directory"
if (directory / ".hg").is_dir():
if (directory / ".hg").is_dir():
+ return directory, ".hg directory"
if (directory / "pyproject.toml").is_file():
if (directory / "pyproject.toml").is_file():
+ return directory, "pyproject.toml"
+ return directory, "file system root"
def find_pyproject_toml(path_search_start: Tuple[str, ...]) -> Optional[str]:
"""Find the absolute filepath to a pyproject.toml if it exists"""
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_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)
path_pyproject_toml = path_project_root / "pyproject.toml"
if path_pyproject_toml.is_file():
return str(path_pyproject_toml)
if path_user_pyproject_toml.is_file()
else None
)
if path_user_pyproject_toml.is_file()
else None
)
- except PermissionError as e:
+ except (PermissionError, RuntimeError) 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
# 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
+@mypyc_attr(patchable=True)
def parse_pyproject_toml(path_config: str) -> Dict[str, Any]:
"""Parse a pyproject toml file, pulling out relevant parts for Black
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 toml.Toml DecodeError
+ If parsing fails, will raise a tomllib.TOML DecodeError
- pyproject_toml = toml.load(path_config)
+ with open(path_config, "rb") as f:
+ pyproject_toml = tomllib.load(f)
config = pyproject_toml.get("tool", {}).get("black", {})
return {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
config = pyproject_toml.get("tool", {}).get("black", {})
return {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
This looks for ~\.black on Windows and ~/.config/black on Linux and other
Unix systems.
This looks for ~\.black on Windows and ~/.config/black on Linux and other
Unix systems.
+
+ May raise:
+ - RuntimeError: if the current user has no homedir
+ - PermissionError: if the current process cannot access the user's homedir
"""
if sys.platform == "win32":
# Windows
"""
if sys.platform == "win32":
# Windows
gitignore = root / ".gitignore"
lines: List[str] = []
if gitignore.is_file():
gitignore = root / ".gitignore"
lines: List[str] = []
if gitignore.is_file():
- with gitignore.open() as gf:
+ with gitignore.open(encoding="utf-8" ) as gf:
- return PathSpec.from_lines("gitwildmatch", lines)
+ try:
+ return PathSpec.from_lines("gitwildmatch", lines)
+ except GitWildMatchPatternError as e:
+ err(f"Could not parse {gitignore}: {e}")
+ raise
def normalize_path_maybe_ignore(
def normalize_path_maybe_ignore(
- path: Path, root: Path, report: Report
+ path: Path,
+ root: Path,
+ report: Optional[Report] = None,
) -> Optional[str]:
"""Normalize `path`. May return `None` if `path` was ignored.
) -> Optional[str]:
"""Normalize `path`. May return `None` if `path` was ignored.
"""
try:
abspath = path if path.is_absolute() else Path.cwd() / path
"""
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}" )
+ normalized_path = abspath.resolve()
+ try :
+ root_relative_path = normalized_path.relative_to(root).as_posix( )
+ except ValueError:
+ if report:
+ report.path_ignored(
+ path, f"is a symbolic link that points outside {root}"
+ )
+ except OSError as e:
+ if report:
+ report.path_ignored(path, f"cannot be read because {e}")
+ return None
+ return root_relative _path
force_exclude: Optional[Pattern[str]],
report: Report,
gitignore: Optional[PathSpec],
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,
) -> Iterator[Path]:
"""Generate all files under `path` whose paths are not excluded by the
`exclude_regex`, `extend_exclude`, or `force_exclude` regexes,
continue
if child.is_dir():
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,
yield from gen_python_files(
child.iterdir(),
root,
extend_exclude,
force_exclude,
report,
extend_exclude,
force_exclude,
report,
+ gitignore + get_gitignore(child) if gitignore is not None else None,
+ verbose=verbose,
+ quiet=quiet,
+ 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
include_match = include.search(normalized_path) if include else True
if include_match:
yield child