Skip to content

Commit

Permalink
🚸 Show partial solution on build errors (#148)
Browse files Browse the repository at this point in the history
* 🚸 Show partial solution on build errors

* ✅ Add test coverage
  • Loading branch information
ddelange authored Nov 28, 2024
1 parent 98a7e3b commit 929df31
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 22 deletions.
9 changes: 7 additions & 2 deletions src/pipgrip/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@
from pipgrip.libs.mixology.package import Package
from pipgrip.libs.mixology.version_solver import VersionSolver
from pipgrip.package_source import PackageSource, render_pin
from pipgrip.pipper import install_packages, read_requirements
from pipgrip.pipper import (
BUILD_FAILURE_STR,
REPORT_FAILURE_STR,
install_packages,
read_requirements,
)

logging.basicConfig(format="%(levelname)s: %(message)s")
logger = logging.getLogger()
Expand Down Expand Up @@ -479,7 +484,7 @@ def main(
exc = None
except RuntimeError as e:
# RuntimeError coming from pipgrip.pipper
if "Failed to download/build wheel" not in str(e):
if REPORT_FAILURE_STR not in str(e) and BUILD_FAILURE_STR not in str(e):
# only continue handling expected RuntimeErrors
raise
solution = solver.solution
Expand Down
12 changes: 8 additions & 4 deletions src/pipgrip/pipper.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@

logger = logging.getLogger(__name__)

REPORT_FAILURE_STR = "Failed to get report for"
BUILD_FAILURE_STR = "Failed to download/build wheel for"
VERSIONS_FAILURE_STR = "Failed to get available versions for"


def read_requirements(path):
re_comments = re.compile(r"(?:^|\s+)#")
Expand Down Expand Up @@ -292,7 +296,7 @@ def _get_available_versions(package, index_url, extra_index_url, pre):
]
_available_versions_cache[cache_key] = available_versions
return available_versions
raise RuntimeError("Failed to get available versions for {}".format(package))
raise RuntimeError("{} {}".format(VERSIONS_FAILURE_STR, package))


def _get_package_report(
Expand Down Expand Up @@ -357,7 +361,7 @@ def _get_package_report(
package, output.strip()
)
)
raise RuntimeError("Failed to get report for {}".format(package))
raise RuntimeError("{} {}".format(REPORT_FAILURE_STR, package))
else:
with io.open(report_file, "r", encoding="utf-8") as fp:
return json.load(fp)
Expand Down Expand Up @@ -397,7 +401,7 @@ def _download_wheel(
package, output.strip()
)
)
raise RuntimeError("Failed to download/build wheel for {}".format(package))
raise RuntimeError("{} {}".format(BUILD_FAILURE_STR, package))
out = out.splitlines()[::-1]
abs_wheel_dir_lower = abs_wheel_dir.lower()
cwd_wheel_dir_lower = cwd_wheel_dir.lower()
Expand Down Expand Up @@ -474,7 +478,7 @@ def _download_wheel(
"\n".join(out[::-1])
)
)
raise RuntimeError("Failed to download/build wheel for {}".format(package))
raise RuntimeError("{} {}".format(BUILD_FAILURE_STR, package))


def _extract_metadata(wheel_fname):
Expand Down
66 changes: 50 additions & 16 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# SPDX-License-Identifier: BSD-3-Clause
import logging
import subprocess

import pytest
from click.testing import CliRunner

Expand Down Expand Up @@ -141,7 +144,13 @@ def mock_stream_bash_command(*args, **kwargs):
return "I passed"


def invoke_patched(func, arguments, monkeypatch, use_report=False, **kwargs):
def mock_stream_bash_command_failure(*args, **kwargs):
raise subprocess.CalledProcessError(1, args[0])


def invoke_patched(
func, arguments, monkeypatch, use_report=False, mock_failure=False, **kwargs
):
def default_environment():
return {
"implementation_name": "cpython",
Expand All @@ -157,16 +166,28 @@ def default_environment():
"sys_platform": "linux",
}

monkeypatch.setattr(
pipgrip.pipper,
"_download_wheel",
mock_download_wheel,
)
monkeypatch.setattr(
pipgrip.pipper,
"_get_package_report",
mock_get_package_report,
)
if mock_failure:
monkeypatch.setattr(
pipgrip.pipper,
"stream_bash_command",
mock_stream_bash_command_failure,
)
else:
monkeypatch.setattr(
pipgrip.pipper,
"stream_bash_command",
mock_stream_bash_command,
)
monkeypatch.setattr(
pipgrip.pipper,
"_download_wheel",
mock_download_wheel,
)
monkeypatch.setattr(
pipgrip.pipper,
"_get_package_report",
mock_get_package_report,
)
if use_report:
monkeypatch.setattr(
pipgrip.pipper,
Expand All @@ -189,11 +210,6 @@ def default_environment():
"default_environment",
default_environment,
)
monkeypatch.setattr(
pipgrip.pipper,
"stream_bash_command",
mock_stream_bash_command,
)
runner = CliRunner()
return runner.invoke(main, arguments, **kwargs)

Expand Down Expand Up @@ -426,6 +442,24 @@ def test_solutions(arguments, expected, monkeypatch):
), "Unexpected output:\n{}".format(result.output.strip())


def test_failue_build(monkeypatch, caplog):
caplog.set_level(logging.DEBUG)
arguments = ["requests[socks]"]
result = invoke_patched(main, arguments, monkeypatch, mock_failure=True)
assert result.exit_code
assert "Best guess" in caplog.text


def test_failue_report(monkeypatch, caplog):
caplog.set_level(logging.DEBUG)
arguments = ["requests[socks]"]
result = invoke_patched(
main, arguments, monkeypatch, use_report=True, mock_failure=True
)
assert result.exit_code
assert "Best guess" in caplog.text


@pytest.mark.parametrize(
"arguments",
[
Expand Down

0 comments on commit 929df31

Please sign in to comment.