From f95cadef847643bfe0596fd49a18297cf380c275 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Fri, 28 Jun 2024 13:16:08 -0400 Subject: [PATCH 1/3] Replace sys.exit calls in conda_build/inspect_pkg.py --- conda_build/inspect_pkg.py | 15 +++++++++++---- tests/test_inspect_pkg.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/conda_build/inspect_pkg.py b/conda_build/inspect_pkg.py index 5747f3a7b8..54ec2c6f28 100644 --- a/conda_build/inspect_pkg.py +++ b/conda_build/inspect_pkg.py @@ -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, @@ -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()} @@ -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) @@ -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()} diff --git a/tests/test_inspect_pkg.py b/tests/test_inspect_pkg.py index dae6d7f6ca..4f20b85105 100644 --- a/tests/test_inspect_pkg.py +++ b/tests/test_inspect_pkg.py @@ -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): @@ -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([]) From 0d396fd339cb6f37b2a3ada478484bb71205156b Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Fri, 28 Jun 2024 15:22:39 -0400 Subject: [PATCH 2/3] Update exceptions in unit tests --- tests/cli/test_main_inspect.py | 5 +++-- tests/test_inspect.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/cli/test_main_inspect.py b/tests/cli/test_main_inspect.py index b8931b5220..83859bf441 100644 --- a/tests/cli/test_main_inspect.py +++ b/tests/cli/test_main_inspect.py @@ -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 @@ -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: @@ -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: diff --git a/tests/test_inspect.py b/tests/test_inspect.py index cd90ba98ae..04acf2728b 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -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: @@ -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: From fd308688876b39687fa502e12dcc3735dcf5e5c7 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Tue, 9 Jul 2024 11:13:33 -0400 Subject: [PATCH 3/3] use alternate method to capture logs in test_menuinst_validation_fails_bad_json --- tests/test_post.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/tests/test_post.py b/tests/test_post.py index eb2672218a..e0eb59237f 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -9,6 +9,7 @@ import pytest +import conda_build.utils from conda_build import api, post from conda_build.utils import ( get_site_packages, @@ -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" @@ -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):