Repository: psf/black
File: src/black/__init__.py (Python)

Code before:
) -> Iterator[Path]:
    """Generate all files under `path` whose paths are not excluded by
    `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 gitignore.match_file(normalized_path):
            report.path_ignored(child, "matches the .gitignore file content")
            continue

        # Then ignore with `exclude` and `--force-exclude` options.
        normalized_path = "/" + normalized_path
        if child.is_dir():
            normalized_path += "/"

        is_excluded = False
        for opt_name, exclude in zip(("--exclude", "--force-exclude"), exclude_regexes):
            exclude_match = exclude.search(normalized_path) if exclude else None
            if exclude_match and exclude_match.group(0):
                report.path_ignored(child, f"matches the {opt_name} regular expression")
                is_excluded = True
                break
        if is_excluded:
            continue

        if child.is_dir():
            yield from gen_python_files(
                child.iterdir(), root, include, exclude_regexes, report, gitignore
            )

        elif child.is_file():
            include_match = include.search(normalized_path) if include else True
            if include_match:
                yield child


@lru_cache()
def find_project_root(srcs: Iterable[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`.

Review comment (suggestion):
This makes me a bit uneasy because it assumes that `exclude_regexes` exactly matches these two flags, when the type doesn't demand that. It would be cleaner to make exclude_regex and force_exclude_regex separate arguments to this function, or to make `exclude_regexes` an iterable of (option name, pattern) pairs.

Code after:
    """Generate all files under `path` whose paths are not excluded by the
    `exclude_regex` 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 gitignore.match_file(normalized_path):
            report.path_ignored(child, "matches the .gitignore file content")
            continue

        # Then ignore with `--exclude` and `--force-exclude` options.
        normalized_path = "/" + normalized_path
        if child.is_dir():
            normalized_path += "/"

        exclude_match = exclude.search(normalized_path) if exclude else None
        if exclude_match and exclude_match.group(0):
            report.path_ignored(child, "matches the --exclude regular expression")
            continue

        force_exclude_match = (
            force_exclude.search(normalized_path) if force_exclude else None
        )
        if force_exclude_match and force_exclude_match.group(0):
            report.path_ignored(child, "matches the --force-exclude regular expression")
            continue

        if child.is_dir():
            yield from gen_python_files(
                child.iterdir(),
                root,
                include,
                exclude,
                force_exclude,
                report,
                gitignore,
            )

        elif child.is_file():
            include_match = include.search(normalized_path) if include else True
            if include_match:
                yield child