Skip to content
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

feat: if failed (retry) #820

Merged
merged 3 commits into from
Jul 22, 2024
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
13 changes: 13 additions & 0 deletions docs/overrides.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ SDist.
This will be true if the `PKG-INFO` file exists, that is, if this is coming
from an SDist. Takes a bool.

### `failed` (bool)

This override is a bit special. If a build fails, scikit-build-core will check
to see if there'a a matching `failed = true` override. If there is, the the build will
be retried once with the new settings. This can be used to build a pure-Python fallback
if a build fails, for example:

```toml
[[tool.scikit-build.overrides]]
if.failed = true
wheel.cmake = false
```

## Any matching condition

If you use `if.any` instead of `if`, then the override is true if any one of the
Expand Down
2 changes: 1 addition & 1 deletion src/scikit_build_core/build/_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ def __dir__() -> list[str]:
@functools.lru_cache(1)
def setup_logging(log_level: str) -> None:
level_value = LEVEL_VALUE[log_level]
logger.setLevel(level_value)

ch = logging.StreamHandler()
ch.setLevel(level_value)
# create formatter and add it to the handlers
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
Expand Down
63 changes: 58 additions & 5 deletions src/scikit_build_core/build/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@
import sysconfig
import tempfile
from pathlib import Path
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

from packaging.requirements import Requirement
from packaging.utils import canonicalize_name

from .. import __version__
from .._compat import tomllib
from .._compat.typing import Literal, assert_never
from .._logging import logger, rich_print
from .._logging import LEVEL_VALUE, logger, rich_print
from .._shutil import fix_win_37_all_permissions
from ..builder.builder import Builder, archs_to_tags, get_archs
from ..builder.wheel_tag import WheelTag
from ..cmake import CMake, CMaker
from ..errors import FailedLiveProcessError
from ..settings.skbuild_read_settings import SettingsReader
from ._editable import editable_redirect, libdir_to_installed, mapping_to_modules
from ._init import setup_logging
Expand Down Expand Up @@ -123,6 +124,7 @@
) -> WheelImplReturn:
"""
Build a wheel or just prepare metadata (if wheel dir is None). Can be editable.
Handles one retry attempt if "failed" override present.
"""
state: Literal["sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"]
if exit_after_config:
Expand All @@ -136,9 +138,10 @@
with pyproject_path.open("rb") as ft:
pyproject = tomllib.load(ft)

settings_reader = SettingsReader(pyproject, config_settings or {}, state=state)
settings = settings_reader.settings
setup_logging(settings.logging.level)
settings_reader = SettingsReader(
pyproject, config_settings or {}, state=state, retry=False
)
setup_logging(settings_reader.settings.logging.level)

settings_reader.validate_may_exit()

Expand All @@ -156,6 +159,56 @@
"ninja should not be in build-system.requires - scikit-build-core will inject it as needed"
)

try:
return _build_wheel_impl_impl(
wheel_directory,
metadata_directory,
exit_after_config=exit_after_config,
editable=editable,
state=state,
settings=settings_reader.settings,
pyproject=pyproject,
)
except FailedLiveProcessError as err:
settings_reader = SettingsReader(
pyproject, config_settings or {}, state=state, retry=True
)
if "failed" not in settings_reader.overrides:
raise

Check warning on line 177 in src/scikit_build_core/build/wheel.py

View check run for this annotation

Codecov / codecov/patch

src/scikit_build_core/build/wheel.py#L177

Added line #L177 was not covered by tests

rich_print(
f"\n[yellow bold]*** {' '.join(err.args)} - retrying due to override..."
)

logger.setLevel(LEVEL_VALUE[settings_reader.settings.logging.level])

settings_reader.validate_may_exit()

return _build_wheel_impl_impl(
wheel_directory,
metadata_directory,
exit_after_config=exit_after_config,
editable=editable,
state=state,
settings=settings_reader.settings,
pyproject=pyproject,
)


def _build_wheel_impl_impl(
wheel_directory: str | None,
metadata_directory: str | None,
*,
exit_after_config: bool = False,
editable: bool,
state: Literal["sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"],
settings: ScikitBuildSettings,
pyproject: dict[str, Any],
) -> WheelImplReturn:
"""
Build a wheel or just prepare metadata (if wheel dir is None). Can be editable.
"""

metadata = get_standard_metadata(pyproject, settings)

if metadata.version is None:
Expand Down
4 changes: 4 additions & 0 deletions src/scikit_build_core/resources/scikit-build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,10 @@
"type": "boolean",
"description": "Whether the build is from an sdist."
},
"failed": {
"type": "boolean",
"description": "Matches if the build fails. A build will be retried if there is at least one matching override with this set to true."
},
"env": {
"type": "object",
"patternProperties": {
Expand Down
Loading
Loading