Skip to content

feat: get_requires_for_dynamic_metadata #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions src/scikit_build_core/build/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,30 @@ def build_sdist(


def get_requires_for_build_sdist(
config_settings: dict[str, str | list[str]] | None = None # noqa: ARG001
config_settings: dict[str, str | list[str]] | None = None
) -> list[str]:
return ["pathspec", "pyproject_metadata"]
from ..builder.get_requires import GetRequires

requires = GetRequires(config_settings)

return [
"pathspec",
"pyproject_metadata",
*requires.dynamic_metadata(),
]


def get_requires_for_build_wheel(
config_settings: dict[str, str | list[str]] | None = None,
) -> list[str]:
from ..builder.get_requires import cmake_ninja_for_build_wheel
from ..builder.get_requires import GetRequires

requires = GetRequires(config_settings)

return [
"pathspec",
"pyproject_metadata",
*cmake_ninja_for_build_wheel(config_settings),
*requires.cmake(),
*requires.ninja(),
*requires.dynamic_metadata(),
]
81 changes: 51 additions & 30 deletions src/scikit_build_core/builder/get_requires.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

import dataclasses
import functools
import importlib
import os
import sys
from collections.abc import Mapping
Expand All @@ -20,7 +22,7 @@
from ..resources import resources
from ..settings.skbuild_read_settings import SettingsReader

__all__ = ["cmake_ninja_for_build_wheel"]
__all__ = ["GetRequires"]


def __dir__() -> list[str]:
Expand All @@ -38,40 +40,59 @@ def is_known_platform(platforms: frozenset[str]) -> bool:
return any(tag.platform in platforms for tag in sys_tags())


def cmake_ninja_for_build_wheel(
config_settings: Mapping[str, str | list[str]] | None = None
def _load_get_requires_hook(
mod_name: str,
config_settings: Mapping[str, list[str] | str] | None = None,
) -> list[str]:
settings = SettingsReader.from_file("pyproject.toml", config_settings).settings

packages = []
cmake_min = Version(settings.cmake.minimum_version)
cmake = best_program(get_cmake_programs(module=False), minimum_version=cmake_min)
if cmake is None:
packages.append(f"cmake>={cmake_min}")
else:
logger.debug("Found system CMake: {} - not requiring PyPI package", cmake)
module = importlib.import_module(mod_name)
hook = getattr(module, "get_requires_for_dynamic_metadata", None)
return [] if hook is None else hook(config_settings) # type: ignore[no-any-return]


@dataclasses.dataclass
class GetRequires:
config_settings: Mapping[str, list[str] | str] | None = None

if (
not sys.platform.startswith("win")
and os.environ.get("CMAKE_GENERATOR", "Ninja") == "Ninja"
and not os.environ.get("CMAKE_MAKE_PROGRAM", "")
):
ninja_min = Version(settings.ninja.minimum_version)
ninja = best_program(
get_ninja_programs(module=False), minimum_version=ninja_min
def __post_init__(self) -> None:
self._settings = SettingsReader.from_file(
"pyproject.toml", self.config_settings
).settings

def cmake(self) -> list[str]:
cmake_min = Version(self._settings.cmake.minimum_version)
cmake = best_program(
get_cmake_programs(module=False), minimum_version=cmake_min
)
if ninja is None:
if (
not settings.ninja.make_fallback
or is_known_platform(known_wheels("ninja"))
or not list(get_make_programs())
):
packages.append(f"ninja>={ninja_min}")
else:
if cmake is None:
return [f"cmake>={cmake_min}"]
logger.debug("Found system CMake: {} - not requiring PyPI package", cmake)
return []

def ninja(self) -> list[str]:
if (
not sys.platform.startswith("win")
and os.environ.get("CMAKE_GENERATOR", "Ninja") == "Ninja"
and not os.environ.get("CMAKE_MAKE_PROGRAM", "")
):
ninja_min = Version(self._settings.ninja.minimum_version)
ninja = best_program(
get_ninja_programs(module=False), minimum_version=ninja_min
)
if ninja is None:
if (
not self._settings.ninja.make_fallback
or is_known_platform(known_wheels("ninja"))
or not list(get_make_programs())
):
return [f"ninja>={ninja_min}"]
logger.debug(
"Found system Make & not on known platform - not requiring PyPI package for Ninja"
)
else:
logger.debug("Found system Ninja: {} - not requiring PyPI package", ninja)
return []

return packages
def dynamic_metadata(self) -> list[str]:
retval = []
for plugins in self._settings.metadata.values():
retval += _load_get_requires_hook(plugins, self.config_settings)
return retval
6 changes: 6 additions & 0 deletions src/scikit_build_core/metadata/fancy_pypi_readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ def dynamic_metadata(
"text": build_text(config.fragments, config.substitutions),
}
}


def get_requires_for_dynamic_metadata(
_config_settings: dict[str, list[str] | str] | None = None,
) -> list[str]:
return ["hatch-fancy-pypi-readme"]
6 changes: 6 additions & 0 deletions src/scikit_build_core/metadata/setuptools_scm.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ def dynamic_metadata(
version: str = _get_version(config)

return {"version": version}


def get_requires_for_dynamic_metadata(
_config_settings: dict[str, list[str] | str] | None = None,
) -> list[str]:
return ["setuptools-scm"]
15 changes: 10 additions & 5 deletions src/scikit_build_core/setuptools/build_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
prepare_metadata_for_build_wheel,
)

from ..builder.get_requires import cmake_ninja_for_build_wheel

if hasattr(setuptools.build_meta, "build_editable"):
from setuptools.build_meta import build_editable # type: ignore[attr-defined]

Expand Down Expand Up @@ -40,25 +38,32 @@ def get_requires_for_build_sdist(
setuptools_reqs = setuptools.build_meta.get_requires_for_build_sdist(
config_settings
)
return [*setuptools_reqs, *cmake_ninja_for_build_wheel(config_settings)]
return [*setuptools_reqs]


def get_requires_for_build_wheel(
config_settings: dict[str, str | list[str]] | None = None
) -> list[str]:
from ..builder.get_requires import GetRequires

requires = GetRequires(config_settings)

setuptools_reqs = setuptools.build_meta.get_requires_for_build_wheel(
config_settings
)

return [*setuptools_reqs, *cmake_ninja_for_build_wheel(config_settings)]
return [*setuptools_reqs, *requires.cmake(), *requires.ninja()]


if hasattr(setuptools.build_meta, "get_requires_for_build_editable"):

def get_requires_for_build_editable(
config_settings: dict[str, str | list[str]] | None = None
) -> list[str]:
from ..builder.get_requires import GetRequires

requires = GetRequires(config_settings)
setuptools_reqs = setuptools.build_meta.get_requires_for_build_editable( # type: ignore[attr-defined]
config_settings
)
return [*setuptools_reqs, *cmake_ninja_for_build_wheel(config_settings)]
return [*setuptools_reqs, *requires.cmake(), *requires.ninja()]
6 changes: 6 additions & 0 deletions tests/test_dynamic_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from scikit_build_core._compat import tomllib
from scikit_build_core.build import build_wheel
from scikit_build_core.builder.get_requires import GetRequires
from scikit_build_core.settings.metadata import get_standard_metadata
from scikit_build_core.settings.skbuild_read_settings import SettingsReader

Expand Down Expand Up @@ -141,6 +142,11 @@ def test_plugin_metadata(tmp_path, monkeypatch):
"Fragment #1Fragment #2", None, "text/x-rst"
)

assert set(GetRequires().dynamic_metadata()) == {
"hatch-fancy-pypi-readme",
"setuptools-scm",
}


def test_faulty_metadata(monkeypatch):
monkeypatch.chdir(DYNAMIC)
Expand Down
18 changes: 10 additions & 8 deletions tests/test_get_requires.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys
from pathlib import Path

from scikit_build_core.builder.get_requires import cmake_ninja_for_build_wheel
from scikit_build_core.builder.get_requires import GetRequires

ninja = [] if sys.platform.startswith("win") else ["ninja>=1.5"]

Expand All @@ -24,7 +24,8 @@ def test_get_requires_for_build_wheel(fp, monkeypatch):
monkeypatch.setattr(shutil, "which", which_mock)
monkeypatch.delenv("CMAKE_GENERATOR", raising=False)
fp.register([cmake, "--version"], stdout="3.14.0")
assert cmake_ninja_for_build_wheel() == ["cmake>=3.15", *ninja]
assert GetRequires().cmake() == ["cmake>=3.15"]
assert GetRequires().ninja() == [*ninja]


def test_get_requires_for_build_wheel_uneeded(fp, monkeypatch):
Expand All @@ -33,7 +34,8 @@ def test_get_requires_for_build_wheel_uneeded(fp, monkeypatch):
monkeypatch.setattr(shutil, "which", which_mock)
monkeypatch.delenv("CMAKE_GENERATOR", raising=False)
fp.register([cmake, "--version"], stdout="3.18.0")
assert cmake_ninja_for_build_wheel() == [*ninja]
assert GetRequires().cmake() == []
assert GetRequires().ninja() == [*ninja]


def test_get_requires_for_build_wheel_settings(fp, monkeypatch):
Expand All @@ -43,10 +45,8 @@ def test_get_requires_for_build_wheel_settings(fp, monkeypatch):
monkeypatch.delenv("CMAKE_GENERATOR", raising=False)
fp.register([cmake, "--version"], stdout="3.18.0")
config = {"cmake.minimum-version": "3.20"}
assert cmake_ninja_for_build_wheel(config) == [
"cmake>=3.20",
*ninja,
]
assert GetRequires(config).cmake() == ["cmake>=3.20"]
assert GetRequires(config).ninja() == [*ninja]


def test_get_requires_for_build_wheel_pyproject(fp, monkeypatch, tmp_path):
Expand All @@ -62,4 +62,6 @@ def test_get_requires_for_build_wheel_pyproject(fp, monkeypatch, tmp_path):
monkeypatch.setattr(shutil, "which", which_mock)
monkeypatch.delenv("CMAKE_GENERATOR", raising=False)
fp.register([cmake, "--version"], stdout="3.18.0")
assert cmake_ninja_for_build_wheel() == ["cmake>=3.21", *ninja]

assert GetRequires().cmake() == ["cmake>=3.21"]
assert GetRequires().ninja() == [*ninja]