Skip to content

Commit

Permalink
feat: if failed (retry) (#820)
Browse files Browse the repository at this point in the history
One of the steps for #112.

---------

Signed-off-by: Henry Schreiner <[email protected]>
  • Loading branch information
henryiii authored Jul 22, 2024
1 parent 9bc0d97 commit 681e6a2
Show file tree
Hide file tree
Showing 12 changed files with 373 additions and 52 deletions.
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 @@ def _build_wheel_impl(
) -> 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 @@ def _build_wheel_impl(
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 @@ def _build_wheel_impl(
"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

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

0 comments on commit 681e6a2

Please sign in to comment.