Skip to content

Commit

Permalink
Do not create conda error reports for common / expected exceptions (#…
Browse files Browse the repository at this point in the history
…5264)

* Make CondaBuildException subclass CondaError and add new BuildScriptException
* re-raise CalledProcessError as BuildScriptException
  • Loading branch information
jaimergp committed May 22, 2024
1 parent 9c0ceec commit 5f5eebe
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 27 deletions.
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.
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("*"))
)
@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

0 comments on commit 5f5eebe

Please sign in to comment.