Skip to content

Commit

Permalink
Replace sys.exit calls in conda_build/inspect_pkg.py (#5393)
Browse files Browse the repository at this point in the history
* Replace sys.exit calls in conda_build/inspect_pkg.py

* Update exceptions in unit tests

* use alternate method to capture logs in test_menuinst_validation_fails_bad_json

---------

Co-authored-by: Daniel Holth <dholth@anaconda.com>
  • Loading branch information
beeankha and dholth authored Jul 9, 2024
1 parent 6d7805c commit 4fd7d54
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 17 deletions.
15 changes: 11 additions & 4 deletions conda_build/inspect_pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from conda.core.prefix_data import PrefixData
from conda.models.records import PrefixRecord

from .exceptions import CondaBuildUserError
from .os_utils.ldd import (
get_linkages,
get_package_obj_files,
Expand Down Expand Up @@ -219,9 +220,13 @@ def inspect_linkages(
sysroot: str = "",
) -> str:
if not packages and not untracked and not all_packages:
sys.exit("At least one package or --untracked or --all must be provided")
raise CondaBuildUserError(
"At least one package or --untracked or --all must be provided"
)
elif on_win:
sys.exit("Error: conda inspect linkages is only implemented in Linux and OS X")
raise CondaBuildUserError(
"`conda inspect linkages` is only implemented on Linux and macOS"
)

prefix = Path(prefix)
installed = {prec.name: prec for prec in PrefixData(str(prefix)).iter_records()}
Expand All @@ -237,7 +242,7 @@ def inspect_linkages(
if name == untracked_package:
obj_files = get_untracked_obj_files(prefix)
elif name not in installed:
sys.exit(f"Package {name} is not installed in {prefix}")
raise CondaBuildUserError(f"Package {name} is not installed in {prefix}")
else:
obj_files = get_package_obj_files(installed[name], prefix)

Expand Down Expand Up @@ -308,7 +313,9 @@ def inspect_objects(
groupby: str = "package",
):
if not on_mac:
sys.exit("Error: conda inspect objects is only implemented in OS X")
raise CondaBuildUserError(
"`conda inspect objects` is only implemented on macOS"
)

prefix = Path(prefix)
installed = {prec.name: prec for prec in PrefixData(str(prefix)).iter_records()}
Expand Down
5 changes: 3 additions & 2 deletions tests/cli/test_main_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from conda_build import api
from conda_build.cli import main_inspect
from conda_build.exceptions import CondaBuildUserError
from conda_build.utils import on_win

from ..utils import metadata_dir
Expand All @@ -23,7 +24,7 @@ def test_inspect_linkages(testing_workdir, capfd):
# get a package that has known object output
args = ["linkages", "python"]
if on_win:
with pytest.raises(SystemExit) as exc:
with pytest.raises(CondaBuildUserError) as exc:
main_inspect.execute(args)
assert "conda inspect linkages is only implemented in Linux and OS X" in exc
else:
Expand All @@ -36,7 +37,7 @@ def test_inspect_objects(testing_workdir, capfd):
# get a package that has known object output
args = ["objects", "python"]
if sys.platform != "darwin":
with pytest.raises(SystemExit) as exc:
with pytest.raises(CondaBuildUserError) as exc:
main_inspect.execute(args)
assert "conda inspect objects is only implemented in OS X" in exc
else:
Expand Down
5 changes: 3 additions & 2 deletions tests/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
import pytest

from conda_build import api
from conda_build.exceptions import CondaBuildUserError


def test_inspect_linkages():
if sys.platform == "win32":
with pytest.raises(SystemExit) as exc:
with pytest.raises(CondaBuildUserError) as exc:
out_string = api.inspect_linkages("python")
assert "conda inspect linkages is only implemented in Linux and OS X" in exc
else:
Expand All @@ -20,7 +21,7 @@ def test_inspect_linkages():

def test_inspect_objects():
if sys.platform != "darwin":
with pytest.raises(SystemExit) as exc:
with pytest.raises(CondaBuildUserError) as exc:
out_string = api.inspect_objects("python")
assert "conda inspect objects is only implemented in OS X" in exc
else:
Expand Down
28 changes: 26 additions & 2 deletions tests/test_inspect_pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
import pytest
from conda.core.prefix_data import PrefixData

from conda_build.inspect_pkg import which_package
from conda_build.utils import on_win
from conda_build.exceptions import CondaBuildUserError
from conda_build.inspect_pkg import inspect_linkages, inspect_objects, which_package
from conda_build.utils import on_mac, on_win


def test_which_package(tmp_path: Path):
Expand Down Expand Up @@ -271,3 +272,26 @@ def test_which_package_battery(tmp_path: Path):

# missing files should return no packages
assert not len(list(which_package(tmp_path / "missing", tmp_path)))


def test_inspect_linkages_no_packages():
with pytest.raises(CondaBuildUserError):
inspect_linkages([])


@pytest.mark.skipif(not on_win, reason="inspect_linkages is available")
def test_inspect_linkages_on_win():
with pytest.raises(CondaBuildUserError):
inspect_linkages(["packages"])


@pytest.mark.skipif(on_win, reason="inspect_linkages is not available")
def test_inspect_linkages_not_installed():
with pytest.raises(CondaBuildUserError):
inspect_linkages(["not_installed_pkg"])


@pytest.mark.skipif(on_mac, reason="inspect_objects is only available on macOS")
def test_inspect_objects_not_on_mac():
with pytest.raises(CondaBuildUserError):
inspect_objects([])
38 changes: 31 additions & 7 deletions tests/test_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import pytest

import conda_build.utils
from conda_build import api, post
from conda_build.utils import (
get_site_packages,
Expand Down Expand Up @@ -138,7 +139,7 @@ def test_menuinst_validation_fails_bad_schema(testing_config, caplog, tmp_path):
assert "ValidationError" in captured_text


def test_menuinst_validation_fails_bad_json(testing_config, caplog, tmp_path):
def test_menuinst_validation_fails_bad_json(testing_config, monkeypatch, tmp_path):
"3rd check - non-parsable JSON fails validation"
recipe = Path(metadata_dir, "_menu_json_validation")
recipe_tmp = tmp_path / "_menu_json_validation"
Expand All @@ -147,13 +148,36 @@ def test_menuinst_validation_fails_bad_json(testing_config, caplog, tmp_path):
menu_json_contents = menu_json.read_text()
menu_json.write_text(menu_json_contents + "Make this an invalid JSON")

with caplog.at_level(logging.WARNING):
api.build(str(recipe_tmp), config=testing_config, notest=True)
# suspect caplog fixture may fail; use monkeypatch instead.
records = []

captured_text = caplog.text
assert "Found 'Menu/*.json' files but couldn't validate:" not in captured_text
assert "not a valid menuinst JSON document" in captured_text
assert "JSONDecodeError" in captured_text
class MonkeyLogger:
def __getattr__(self, name):
return self.warning

def warning(self, *args, **kwargs):
records.append((*args, kwargs))

monkeylogger = MonkeyLogger()

def get_monkey_logger(*args, **kwargs):
return monkeylogger

# For some reason it uses get_logger in the individual functions, instead of
# a module-level global that we could easily patch.
monkeypatch.setattr(conda_build.utils, "get_logger", get_monkey_logger)

api.build(str(recipe_tmp), config=testing_config, notest=True)

# without %s substitution
messages = [record[0] for record in records]

assert "Found 'Menu/*.json' files but couldn't validate: %s" not in messages
assert "'%s' is not a valid menuinst JSON document!" in messages
assert any(
isinstance(record[-1].get("exc_info"), json.JSONDecodeError)
for record in records
)


def test_file_hash(testing_config, caplog, tmp_path):
Expand Down

0 comments on commit 4fd7d54

Please sign in to comment.