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

Do not create conda error reports for common / expected exceptions #5264

Merged
merged 10 commits into from
May 22, 2024
47 changes: 30 additions & 17 deletions conda_build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@
from . import environ, noarch_python, source, tarcheck, utils
from .config import Config
from .create_test import create_all_test_files
from .exceptions import CondaBuildException, DependencyNeedsBuildingError
from .exceptions import (
BuildScriptException,
CondaBuildException,
DependencyNeedsBuildingError,
)
from .index import _delegated_update_index, get_build_index
from .metadata import FIELDS, MetaData
from .os_utils import external
Expand Down Expand Up @@ -1781,12 +1785,15 @@ def bundle_conda(output, metadata: MetaData, env, stats, **kw):
_write_activation_text(dest_file, metadata)

bundle_stats = {}
utils.check_call_env(
[*args, dest_file],
cwd=metadata.config.work_dir,
env=env_output,
stats=bundle_stats,
)
try:
utils.check_call_env(
[*args, dest_file],
cwd=metadata.config.work_dir,
env=env_output,
stats=bundle_stats,
)
except subprocess.CalledProcessError as exc:
raise BuildScriptException(str(exc), caused_by=exc) from exc
log_stats(bundle_stats, f"bundling {metadata.name()}")
if stats is not None:
stats[stats_key(metadata, f"bundle_{metadata.name()}")] = bundle_stats
Expand Down Expand Up @@ -2459,9 +2466,12 @@ def build(

with codecs.getwriter("utf-8")(open(build_file, "wb")) as bf:
bf.write(script)
windows.build(
m, build_file, stats=build_stats, provision_only=provision_only
)
try:
windows.build(
m, build_file, stats=build_stats, provision_only=provision_only
)
except subprocess.CalledProcessError as exc:
raise BuildScriptException(str(exc), caused_by=exc) from exc
else:
build_file = join(m.path, "build.sh")
if isfile(build_file) and script:
Expand Down Expand Up @@ -2503,13 +2513,16 @@ def build(
del env["CONDA_BUILD"]

# this should raise if any problems occur while building
utils.check_call_env(
cmd,
env=env,
rewrite_stdout_env=rewrite_env,
cwd=src_dir,
stats=build_stats,
)
try:
utils.check_call_env(
cmd,
env=env,
rewrite_stdout_env=rewrite_env,
cwd=src_dir,
stats=build_stats,
)
except subprocess.CalledProcessError as exc:
raise BuildScriptException(str(exc), caused_by=exc) from exc
utils.remove_pycache_from_scripts(m.config.host_prefix)
if build_stats and not provision_only:
log_stats(build_stats, f"building {m.name()}")
Expand Down
14 changes: 10 additions & 4 deletions conda_build/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
# SPDX-License-Identifier: BSD-3-Clause
import textwrap

from conda import CondaError

SEPARATOR = "-" * 70

indent = lambda s: textwrap.fill(textwrap.dedent(s))


class CondaBuildException(Exception):
class CondaBuildException(CondaError):
pass


Expand Down Expand Up @@ -107,22 +109,26 @@ class BuildLockError(CondaBuildException):
"""Raised when we failed to acquire a lock."""


class OverLinkingError(RuntimeError):
class OverLinkingError(RuntimeError, CondaBuildException):
def __init__(self, error, *args):
self.error = error
self.msg = f"overlinking check failed \n{error}"
super().__init__(self.msg)


class OverDependingError(RuntimeError):
class OverDependingError(RuntimeError, CondaBuildException):
def __init__(self, error, *args):
self.error = error
self.msg = f"overdepending check failed \n{error}"
super().__init__(self.msg)


class RunPathError(RuntimeError):
class RunPathError(RuntimeError, CondaBuildException):
def __init__(self, error, *args):
self.error = error
self.msg = f"runpaths check failed \n{error}"
super().__init__(self.msg)


class BuildScriptException(CondaBuildException):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package:
name: pkg
version: '1.0'
source:
path: .
outputs:
- name: pkg-output
build:
script:
- exit 1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exit 1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exit 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package:
name: pkg
version: '1.0'
source:
path: .
outputs:
- name: pkg-output
script: exit_1.sh # [unix]
script: exit_1.bat # [win]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package:
name: pkg
version: '1.0'
source:
path: .
build:
script: exit 1
47 changes: 41 additions & 6 deletions tests/test_api_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from conda_build import __version__, api, exceptions
from conda_build.config import Config
from conda_build.exceptions import (
BuildScriptException,
CondaBuildException,
DependencyNeedsBuildingError,
OverDependingError,
Expand Down Expand Up @@ -383,7 +384,7 @@ def test_dirty_variable_available_in_build_scripts(testing_config):
testing_config.dirty = True
api.build(recipe, config=testing_config)

with pytest.raises(subprocess.CalledProcessError):
with pytest.raises(BuildScriptException):
testing_config.dirty = False
api.build(recipe, config=testing_config)

Expand Down Expand Up @@ -816,13 +817,13 @@ def test_disable_pip(testing_metadata):
testing_metadata.meta["build"]["script"] = (
'python -c "import pip; print(pip.__version__)"'
)
with pytest.raises(subprocess.CalledProcessError):
with pytest.raises(BuildScriptException):
api.build(testing_metadata)

testing_metadata.meta["build"]["script"] = (
'python -c "import setuptools; print(setuptools.__version__)"'
)
with pytest.raises(subprocess.CalledProcessError):
with pytest.raises(BuildScriptException):
api.build(testing_metadata)


Expand Down Expand Up @@ -1539,7 +1540,7 @@ def test_setup_py_data_in_env(testing_config):
# should pass with any modern python (just not 3.5)
api.build(recipe, config=testing_config)
# make sure it fails with our special python logic
with pytest.raises(subprocess.CalledProcessError):
with pytest.raises(BuildScriptException):
api.build(recipe, config=testing_config, python="3.5")


Expand Down Expand Up @@ -1945,7 +1946,7 @@ def test_add_pip_as_python_dependency_from_condarc_file(
testing_metadata, testing_workdir, add_pip_as_python_dependency, monkeypatch
):
"""
Test whether settings from .condarc files are heeded.
Test whether settings from .condarc files are needed.
Copy link
Contributor

@beeankha beeankha May 22, 2024

Choose a reason for hiding this comment

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

Suggested change
Test whether settings from .condarc files are needed.
Test whether settings from .condarc files are heeded.

I think this wording edit needs to be reverted, since this test seems to be checking whether or not the settings in the .condarc files are actually being taken into account/paid attention to (?)

ref: https://github.com/conda/conda-libmamba-solver/issues/393
"""
# TODO: SubdirData._cache_ clearing might not be needed for future conda versions.
Expand All @@ -1961,10 +1962,44 @@ def test_add_pip_as_python_dependency_from_condarc_file(
if add_pip_as_python_dependency:
check_build_fails = nullcontext()
else:
check_build_fails = pytest.raises(subprocess.CalledProcessError)
check_build_fails = pytest.raises(BuildScriptException)

conda_rc = Path(testing_workdir, ".condarc")
conda_rc.write_text(f"add_pip_as_python_dependency: {add_pip_as_python_dependency}")
with env_var("CONDARC", conda_rc, reset_context):
with check_build_fails:
api.build(testing_metadata)


@pytest.mark.parametrize(
"recipe", sorted(Path(metadata_dir, "_build_script_errors").glob("*"))
kenodegard marked this conversation as resolved.
Show resolved Hide resolved
)
@pytest.mark.parametrize("debug", (False, True))
def test_conda_build_script_errors_without_conda_info_handlers(tmp_path, recipe, debug):
env = os.environ.copy()
if debug:
env["CONDA_VERBOSITY"] = "3"
process = subprocess.run(
["conda", "build", recipe],
env=env,
capture_output=True,
text=True,
check=False,
cwd=tmp_path,
)
assert process.returncode > 0
all_output = process.stdout + "\n" + process.stderr

# These should NOT appear in the output
assert ">>> ERROR REPORT <<<" not in all_output
assert "An unexpected error has occurred." not in all_output
assert "Conda has prepared the above report." not in all_output

# These should appear
assert "returned non-zero exit status 1" in all_output

# With verbose mode, we should actually see the traceback
if debug:
assert "Traceback" in all_output
assert "CalledProcessError" in all_output
assert "returned non-zero exit status 1" in all_output