Skip to content

Forward warning options to subprocess #216

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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: 12 additions & 1 deletion src/pyproject_hooks/_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
import tempfile
from contextlib import contextmanager
from itertools import chain
from os.path import abspath
from os.path import join as pjoin
from subprocess import STDOUT, check_call, check_output
Expand Down Expand Up @@ -380,6 +381,15 @@ def build_sdist(
},
)

def _get_warnopts(self) -> Iterator[str]:
"""
Reconstruct Python's warn options that are active for the current process,
so that it can be forwarded to a subprocess.
"""
# `sys.warnoptions` is documented/mentioned in
# https://docs.python.org/3.13/library/warnings.html#describing-warning-filters
return chain.from_iterable(("-W", opt) for opt in sys.warnoptions)
Copy link
Contributor Author

@abravalheri abravalheri May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python docs do mention that sys.warnoptions should not be modified but they do not prevent reading it.

In fact, docs for 3.12 even include examples using it for quick checks https://docs.python.org/3.12/library/warnings.html#overriding-the-default-filter:

import sys

if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")


def _call_hook(self, hook_name: str, kwargs: Mapping[str, Any]) -> Any:
extra_environ = {"_PYPROJECT_HOOKS_BUILD_BACKEND": self.build_backend}

Expand All @@ -394,8 +404,9 @@ def _call_hook(self, hook_name: str, kwargs: Mapping[str, Any]) -> Any:
# Run the hook in a subprocess
with _in_proc_script_path() as script:
python = self.python_executable
opts = self._get_warnopts()
self._subprocess_runner(
[python, abspath(str(script)), hook_name, td],
[python, *opts, abspath(str(script)), hook_name, td],
cwd=self.source_dir,
extra_environ=extra_environ,
)
Expand Down
23 changes: 23 additions & 0 deletions tests/test_call_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import zipfile
from os.path import abspath, dirname
from os.path import join as pjoin
from subprocess import CalledProcessError
from unittest.mock import Mock

import pytest
Expand Down Expand Up @@ -233,3 +234,25 @@ def test_warnings():
with modified_env({"PYTHONPATH": BUILDSYS_PKGS}):
with pytest.warns(BuildBackendWarning, match="this is my example warning"):
hooks.get_requires_for_build_wheel({})


def test_forward_warnopts(monkeypatch, recwarn):
hooks = get_hooks("pkg-with-warnings")

monkeypatch.setattr(
BuildBackendHookCaller, "_get_warnopts", lambda _: ["-W", "ignore"]
)
with modified_env({"PYTHONPATH": BUILDSYS_PKGS}):
hooks.get_requires_for_build_wheel({})
assert len(recwarn) == 0 # All subprocess warnings were ignored.

monkeypatch.setattr(
BuildBackendHookCaller, "_get_warnopts", lambda _: ["-W", "error"]
)
with modified_env({"PYTHONPATH": BUILDSYS_PKGS}):
with pytest.raises(CalledProcessError):
# The `match` argument does not work against the exception in the
# subprocess, but we have a sanity check in place: the same call
# worked above when the warnings were ignored, so we known this is
# caused by the new warnings filter.
hooks.get_requires_for_build_wheel({})
Loading