Skip to content

Commit dc02fcb

Browse files
Forward warnings from build-backend to build-frontend (#213)
This makes it possible for build-frontends to surface this information to end users. --------- Co-authored-by: Pradyun Gedam <[email protected]> Co-authored-by: Pradyun Gedam <[email protected]>
1 parent 21478a7 commit dc02fcb

File tree

6 files changed

+60
-14
lines changed

6 files changed

+60
-14
lines changed

src/pyproject_hooks/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import TYPE_CHECKING
55

66
from ._impl import (
7+
BuildBackendWarning,
78
BackendUnavailable,
89
BuildBackendHookCaller,
910
HookMissing,
@@ -14,6 +15,7 @@
1415

1516
__version__ = "1.2.0"
1617
__all__ = [
18+
"BuildBackendWarning",
1719
"BackendUnavailable",
1820
"BackendInvalid",
1921
"HookMissing",

src/pyproject_hooks/_impl.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from os.path import join as pjoin
88
from subprocess import STDOUT, check_call, check_output
99
from typing import TYPE_CHECKING, Any, Iterator, Mapping, Optional, Sequence
10+
import warnings
1011

1112
from ._in_process import _in_proc_script_path
1213

@@ -35,6 +36,10 @@ def read_json(path: str) -> Mapping[str, Any]:
3536
return json.load(f)
3637

3738

39+
class BuildBackendWarning(UserWarning):
40+
"""Will be emitted for every UserWarning emitted by the hook process."""
41+
42+
3843
class BackendUnavailable(Exception):
3944
"""Will be raised if the backend cannot be imported in the hook process."""
4045

@@ -407,4 +412,12 @@ def _call_hook(self, hook_name: str, kwargs: Mapping[str, Any]) -> Any:
407412
)
408413
if data.get("hook_missing"):
409414
raise HookMissing(data.get("missing_hook_name") or hook_name)
415+
416+
for w in data.get("warnings", []):
417+
warnings.warn_explicit(
418+
message=w["message"],
419+
category=BuildBackendWarning,
420+
filename=w["filename"],
421+
lineno=w["lineno"],
422+
)
410423
return data["return_val"]

src/pyproject_hooks/_in_process/_in_process.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from importlib import import_module
2424
from importlib.machinery import PathFinder
2525
from os.path import join as pjoin
26+
import warnings
2627

2728
# This file is run as a script, and `import wrappers` is not zip-safe, so we
2829
# include write_json() and read_json() from wrappers.py.
@@ -368,20 +369,30 @@ def main():
368369

369370
hook_input = read_json(pjoin(control_dir, "input.json"))
370371

371-
json_out = {"unsupported": False, "return_val": None}
372-
try:
373-
json_out["return_val"] = hook(**hook_input["kwargs"])
374-
except BackendUnavailable as e:
375-
json_out["no_backend"] = True
376-
json_out["traceback"] = e.traceback
377-
json_out["backend_error"] = e.message
378-
except GotUnsupportedOperation as e:
379-
json_out["unsupported"] = True
380-
json_out["traceback"] = e.traceback
381-
except HookMissing as e:
382-
json_out["hook_missing"] = True
383-
json_out["missing_hook_name"] = e.hook_name or hook_name
384-
372+
with warnings.catch_warnings(record=True) as captured_warnings:
373+
json_out = {"unsupported": False, "return_val": None}
374+
try:
375+
json_out["return_val"] = hook(**hook_input["kwargs"])
376+
except BackendUnavailable as e:
377+
json_out["no_backend"] = True
378+
json_out["traceback"] = e.traceback
379+
json_out["backend_error"] = e.message
380+
except GotUnsupportedOperation as e:
381+
json_out["unsupported"] = True
382+
json_out["traceback"] = e.traceback
383+
except HookMissing as e:
384+
json_out["hook_missing"] = True
385+
json_out["missing_hook_name"] = e.hook_name or hook_name
386+
387+
json_out["warnings"] = [
388+
{
389+
"message": str(w.message),
390+
"filename": w.filename,
391+
"lineno": w.lineno,
392+
}
393+
for w in captured_warnings
394+
if isinstance(w.category, type) and issubclass(w.category, UserWarning)
395+
]
385396
write_json(json_out, pjoin(control_dir, "output.json"), indent=2)
386397

387398

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Test "backend" defining nothing other than a hook that logs a warning.
2+
"""
3+
4+
import warnings
5+
6+
7+
def get_requires_for_build_wheel(config_settings):
8+
warnings.warn("this is my example warning")
9+
return []
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["eg_buildsys"]
3+
build-backend = "buildsys_warnings"

tests/test_call_hooks.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from pyproject_hooks import (
1414
BackendUnavailable,
15+
BuildBackendWarning,
1516
BuildBackendHookCaller,
1617
UnsupportedOperation,
1718
default_subprocess_runner,
@@ -225,3 +226,10 @@ def test__supported_features(pkg, expected):
225226
with modified_env({"PYTHONPATH": BUILDSYS_PKGS}):
226227
res = hooks._supported_features()
227228
assert res == expected
229+
230+
231+
def test_warnings():
232+
hooks = get_hooks("pkg-with-warnings")
233+
with modified_env({"PYTHONPATH": BUILDSYS_PKGS}):
234+
with pytest.warns(BuildBackendWarning, match="this is my example warning"):
235+
hooks.get_requires_for_build_wheel({})

0 commit comments

Comments
 (0)