Repository: scikit-learn/scikit-learn
File: sklearn/tests/test_min_dependencies_readme.py (Python)

Code before:
        # Assuming pyproject.toml build section has something like "my-package>=2.3.0"
        # Warning: if you try to modify this regex, bear in mind that there can be upper
        # bounds in release branches so "my-package>=2.3.0,<2.5.0"
        pattern = r"([\w-]+)\s*[>=]=\s*([\d\w.]+)"
        for requirement in info:
            match = re.search(pattern, requirement)
            if match is None:
                raise NotImplementedError(
                    f"{requirement} does not match expected regex {pattern!r}. "
                    "Only >= and == are supported for version requirements"
                )

            package, version = match.group(1), match.group(2)
            pyproject_packages.append(package)

            msg = f"Package {package} from {pyproject_section} not found \
                    in _min_depencies.py"
            assert package in expected_packages, msg

            if package in skip_version_check_for:
                continue

            msg = (
                f"{package} has inconsistent minimum versions in pyproject.toml and"
                f" _min_depencies.py: {version} != {expected_packages[package]}"
            )
            assert parse_version(version) == parse_version(
                expected_packages[package]
            ), msg

        msg = f"Packages in {pyproject_section} differ from _min_depencies.py"
        assert sorted(expected_packages.keys()) == sorted(pyproject_packages), msg


def test_min_dependencies_pyproject_toml():
    """Check versions in pyproject.toml is consistent with _min_dependencies."""

    # tomllib is available in Python 3.11
    tomllib = pytest.importorskip("tomllib")
    root_directory = Path(sklearn.__file__).parent.parent
    pyproject_toml_path = root_directory / "pyproject.toml"

    if not pyproject_toml_path.exists():
        # Skip the test if the pyproject.toml file is not available.
        # For instance, when installing scikit-learn from wheels
        pytest.skip("pyproject.toml is not available.")

    with pyproject_toml_path.open("rb") as f:
        pyproject_toml = tomllib.load(f)

    check_pyproject_sections(pyproject_toml, dependent_packages)

Review comment (suggestion):
Thanks for the PR! This seems to go in the direction I had in mind, I'll try to have a closer look at one point.

General comment: the more you can reduce the diff, the more this will make the reviewer's life (my life in this particular case) easier 😉. For example, it seems like you move global variables `min_dependencies_tag_to_packages_without_version` and `pyproject_section_to_min_dependencies_tag` to a function but this function is called once.

Maybe you have a good reason to do it and I would be curious to hear about it, but as a reviewer, I am expecting an "easy" PR to review and I have to take 5-10 minutes to understand just this part and that doesn't help keeping this PR in the "easy to review" category 😅.

Code after:
        # Skip the test if the README.rst file is not available.
        # For instance, when installing scikit-learn from wheels
        pytest.skip("The README.rst file is not available.")

    with readme_file.open("r") as f:
        for line in f:
            matched = pattern.match(line)

            if not matched:
                continue

            package, version = matched.group(1), matched.group(2)
            package = package.lower()

            if package in dependent_packages:
                version = parse_version(version)
                min_version = parse_version(dependent_packages[package][0])

                message = (
                    f"{package} has inconsistent minimum versions in README.rst and"
                    f" _min_depencies.py: {version} != {min_version}"
                )
                assert version == min_version, message


def extract_packages_and_pyproject_tags(dependencies):
    min_depencies_tag_to_packages_without_version = defaultdict(list)
    for package, (min_version, tags) in dependencies.items():
        for t in tags.split(", "):
            min_depencies_tag_to_packages_without_version[t].append(package)

    pyproject_section_to_min_dependencies_tag = {
        "build-system.requires": "build",
        "project.dependencies": "install",
    }
    for tag in min_depencies_tag_to_packages_without_version:
        section = f"project.optional-dependencies.{tag}"
        pyproject_section_to_min_dependencies_tag[section] = tag

    return (
        min_depencies_tag_to_packages_without_version,
        pyproject_section_to_min_dependencies_tag,
    )


def check_pyproject_sections(pyproject_toml, min_dependencies):
    packages, pyproject_tags = extract_packages_and_pyproject_tags(min_dependencies)

    for pyproject_section, min_dependencies_tag in pyproject_tags.items():
        # Special situation for numpy: we have numpy>=2 in
        # build-system.requires to make sure we build wheels against numpy>=2.