3RNN/Lib/site-packages/sklearn/tests/test_min_dependencies_readme.py
2024-05-26 19:49:15 +02:00

138 lines
4.6 KiB
Python

"""Tests for the minimum dependencies in README.rst and pyproject.toml"""
import os
import platform
import re
from collections import defaultdict
from pathlib import Path
import pytest
import sklearn
from sklearn._min_dependencies import dependent_packages
from sklearn.utils.fixes import parse_version
min_depencies_tag_to_packages_without_version = defaultdict(list)
for package, (min_version, extras) in dependent_packages.items():
for extra in extras.split(", "):
min_depencies_tag_to_packages_without_version[extra].append(package)
min_dependencies_tag_to_pyproject_section = {
"build": "build-system.requires",
"install": "project.dependencies",
}
for tag in min_depencies_tag_to_packages_without_version:
min_dependencies_tag_to_pyproject_section[tag] = (
f"project.optional-dependencies.{tag}"
)
def test_min_dependencies_readme():
# Test that the minimum dependencies in the README.rst file are
# consistent with the minimum dependencies defined at the file:
# sklearn/_min_dependencies.py
if platform.python_implementation() == "PyPy":
pytest.skip("PyPy does not always share the same minimum deps")
pattern = re.compile(
r"(\.\. \|)"
+ r"(([A-Za-z]+\-?)+)"
+ r"(MinVersion\| replace::)"
+ r"( [0-9]+\.[0-9]+(\.[0-9]+)?)"
)
readme_path = Path(sklearn.__file__).parent.parent
readme_file = readme_path / "README.rst"
if not os.path.exists(readme_file):
# 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(2), matched.group(5)
package = package.lower()
if package in dependent_packages:
version = parse_version(version)
min_version = parse_version(dependent_packages[package][0])
assert version == min_version, f"{package} has a mismatched version"
def check_pyproject_section(
pyproject_section, min_dependencies_tag, skip_version_check_for=None
):
# tomllib is available in Python 3.11
tomllib = pytest.importorskip("tomllib")
if skip_version_check_for is None:
skip_version_check_for = []
expected_packages = min_depencies_tag_to_packages_without_version[
min_dependencies_tag
]
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)
pyproject_section_keys = pyproject_section.split(".")
info = pyproject_toml
for key in pyproject_section_keys:
info = info[key]
pyproject_build_min_versions = {}
for requirement in info:
if ">=" in requirement:
package, version = requirement.split(">=")
elif "==" in requirement:
package, version = requirement.split("==")
else:
raise NotImplementedError(
f"{requirement} not supported yet in this test. "
"Only >= and == are supported for version requirements"
)
pyproject_build_min_versions[package] = version
assert sorted(pyproject_build_min_versions) == sorted(expected_packages)
for package, version in pyproject_build_min_versions.items():
version = parse_version(version)
expected_min_version = parse_version(dependent_packages[package][0])
if package in skip_version_check_for:
continue
assert version == expected_min_version, f"{package} has a mismatched version"
@pytest.mark.parametrize(
"min_dependencies_tag, pyproject_section",
min_dependencies_tag_to_pyproject_section.items(),
)
def test_min_dependencies_pyproject_toml(pyproject_section, min_dependencies_tag):
"""Check versions in pyproject.toml is consistent with _min_dependencies."""
# NumPy is more complex because build-time (>=1.25) and run-time (>=1.19.5)
# requirement currently don't match
skip_version_check_for = ["numpy"] if min_dependencies_tag == "build" else None
check_pyproject_section(
pyproject_section,
min_dependencies_tag,
skip_version_check_for=skip_version_check_for,
)