From 3515dbec5e8f556b3d6fe8ff021970675012aa3d Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 11 Jun 2024 18:02:35 +0200 Subject: [PATCH 01/18] Replace `sys.exit` in `conda_build.build.bundle_conda` (#5367) --- conda_build/build.py | 15 +++++++++------ tests/test_build.py | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/conda_build/build.py b/conda_build/build.py index 3be68748b9..3f7dc0470a 100644 --- a/conda_build/build.py +++ b/conda_build/build.py @@ -1753,13 +1753,16 @@ def bundle_conda( output["script"], args[0], ) - if "system32" in args[0] and "bash" in args[0]: - print( - "ERROR :: WSL bash.exe detected, this will not work (PRs welcome!). Please\n" - " use MSYS2 packages. Add `m2-base` and more (depending on what your" - " script needs) to `requirements/build` instead." + if ( + # WSL bash is always the same path, it is an alias to the default + # distribution as configured by the user + on_win and Path("C:\\Windows\\System32\\bash.exe").samefile(args[0]) + ): + raise CondaBuildUserError( + "WSL bash.exe is not supported. Please use MSYS2 packages. Add " + "`m2-base` and more (depending on what your script needs) to " + "`requirements/build` instead." ) - sys.exit(1) else: args = interpreter.split(" ") diff --git a/tests/test_build.py b/tests/test_build.py index af5abb0f70..f1a9f11736 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -15,6 +15,7 @@ from typing import TYPE_CHECKING import pytest +from conda.common.compat import on_win from conda_build import api, build from conda_build.exceptions import CondaBuildUserError @@ -22,6 +23,8 @@ from .utils import get_noarch_python_meta, metadata_dir if TYPE_CHECKING: + from pytest_mock import MockerFixture + from conda_build.metadata import MetaData @@ -345,3 +348,24 @@ def test_copy_readme(testing_metadata: MetaData, readme: str): Path(testing_metadata.config.work_dir, readme).touch() build.copy_readme(testing_metadata) assert Path(testing_metadata.config.info_dir, readme).exists() + + +@pytest.mark.skipif(not on_win, reason="WSL is only on Windows") +def test_wsl_unsupported( + testing_metadata: MetaData, + mocker: MockerFixture, + tmp_path: Path, +): + mocker.patch( + "conda_build.os_utils.external.find_executable", + return_value="C:\\Windows\\System32\\bash.exe", + ) + + (script := tmp_path / "install.sh").touch() + with pytest.raises(CondaBuildUserError): + build.bundle_conda( + output={"script": script}, + metadata=testing_metadata, + env={}, + stats={}, + ) From 45be77d9f69838acdea50c03df14fa4589108c05 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:53:09 -0400 Subject: [PATCH 02/18] [pre-commit.ci] pre-commit autoupdate (#5366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.7 → v0.4.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.7...v0.4.8) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bc17df8d27..3569699b92 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,7 +58,7 @@ repos: # auto format Python codes within docstrings - id: blacken-docs - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.7 + rev: v0.4.8 hooks: # lint & attempt to correct failures (e.g. pyupgrade) - id: ruff From 7328626750250e2fd9d820bf795e8811dd78b067 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Mon, 17 Jun 2024 03:25:48 -0400 Subject: [PATCH 03/18] Replace `sys.exit` in `conda_build.build.handle_anaconda_upload` (#5369) --- conda_build/build.py | 9 ++++++--- tests/test_build.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/conda_build/build.py b/conda_build/build.py index 3f7dc0470a..25b64c30ff 100644 --- a/conda_build/build.py +++ b/conda_build/build.py @@ -3977,7 +3977,10 @@ def build_tree( return list(built_packages.keys()) -def handle_anaconda_upload(paths, config): +def handle_anaconda_upload( + paths: Iterable[str | os.PathLike | Path], + config: Config, +) -> None: from .os_utils.external import find_executable paths = utils.ensure_list(paths) @@ -4011,7 +4014,7 @@ def handle_anaconda_upload(paths, config): "# To have conda build upload to anaconda.org automatically, use\n" f"# {prompter}conda config --set anaconda_upload yes\n" ) - no_upload_message += f"anaconda upload{joiner}" + joiner.join(paths) + no_upload_message += f"anaconda upload{joiner}" + joiner.join(map(str, paths)) if not upload: print(no_upload_message) @@ -4019,7 +4022,7 @@ def handle_anaconda_upload(paths, config): if not anaconda: print(no_upload_message) - sys.exit( + raise CondaBuildUserError( "Error: cannot locate anaconda command (required for upload)\n" "# Try:\n" f"# {prompter}conda install anaconda-client" diff --git a/tests/test_build.py b/tests/test_build.py index f1a9f11736..4078d8273e 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -25,6 +25,7 @@ if TYPE_CHECKING: from pytest_mock import MockerFixture + from conda_build.config import Config from conda_build.metadata import MetaData @@ -369,3 +370,14 @@ def test_wsl_unsupported( env={}, stats={}, ) + + +def test_handle_anaconda_upload(testing_config: Config, mocker: MockerFixture): + mocker.patch( + "conda_build.os_utils.external.find_executable", + return_value=None, + ) + testing_config.anaconda_upload = True + + with pytest.raises(CondaBuildUserError): + build.handle_anaconda_upload((), testing_config) From 07d81a699077f2ec30b47bbdacd85684edecb318 Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Mon, 17 Jun 2024 16:09:50 +0200 Subject: [PATCH 04/18] Ignore `conda-index` warnings (#5373) --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a8b907644a..9bc5272e8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,9 @@ filterwarnings = [ "error::DeprecationWarning:conda_build", # ignore numpy.distutils error 'ignore:\s+`numpy.distutils` is deprecated:DeprecationWarning:conda_build._load_setup_py_data', + # ignore conda-index error + "ignore::PendingDeprecationWarning:conda_index", + "ignore::DeprecationWarning:conda_index", ] markers = [ "serial: execute test serially (to avoid race conditions)", From 8f1e9658cb5badf150a52fdf5da81640da4b4b26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:51:12 -0400 Subject: [PATCH 05/18] Bump CodSpeedHQ/action from 2.4.1 to 2.4.2 in /.github/workflows (#5375) Bumps [CodSpeedHQ/action](https://github.com/codspeedhq/action) from 2.4.1 to 2.4.2. - [Release notes](https://github.com/codspeedhq/action/releases) - [Changelog](https://github.com/CodSpeedHQ/action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codspeedhq/action/compare/0b631f8998f2389eb5144632b6f9f8fabd33a86e...f11c406b8c87cda176ff341ed4925bc98086f6d1) --- updated-dependencies: - dependency-name: CodSpeedHQ/action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8848caaf26..979fbe6030 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -229,7 +229,7 @@ jobs: run: conda list --show-channel-urls - name: Run Benchmarks - uses: CodSpeedHQ/action@0b631f8998f2389eb5144632b6f9f8fabd33a86e + uses: CodSpeedHQ/action@f11c406b8c87cda176ff341ed4925bc98086f6d1 with: token: ${{ secrets.CODSPEED_TOKEN }} run: $CONDA/envs/test/bin/pytest --codspeed From a44b0ac9cf54845e48b5d543f19e875158344a3e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:51:27 -0400 Subject: [PATCH 06/18] [pre-commit.ci] pre-commit autoupdate (#5374) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.8 → v0.4.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.8...v0.4.9) - [github.com/python-jsonschema/check-jsonschema: 0.28.4 → 0.28.5](https://github.com/python-jsonschema/check-jsonschema/compare/0.28.4...0.28.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3569699b92..3d9674cf43 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,7 +58,7 @@ repos: # auto format Python codes within docstrings - id: blacken-docs - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.8 + rev: v0.4.9 hooks: # lint & attempt to correct failures (e.g. pyupgrade) - id: ruff @@ -87,7 +87,7 @@ repos: tests/ ) - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.4 + rev: 0.28.5 hooks: # verify github syntaxes - id: check-github-workflows From 747fe52006d536fa0441b23e55d233251e04bdb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:36:30 +0000 Subject: [PATCH 07/18] Bump codecov/codecov-action from 4.4.1 to 4.5.0 in /.github/workflows (#5376) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.4.1 to 4.5.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/125fc84a9a348dbcf27191600683ec096ec9021c...e28ff129e5465c2c0dcc6f003fc735cb6ae0c673) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 979fbe6030..a93d7982d7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -150,7 +150,7 @@ jobs: -m "${{ env.PYTEST_MARKER }}" - name: Upload Coverage - uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: flags: ${{ runner.os }},${{ runner.arch }},${{ matrix.python-version }},${{ matrix.test-type }} @@ -317,7 +317,7 @@ jobs: -m "${{ env.PYTEST_MARKER }}" - name: Upload Coverage - uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: flags: ${{ runner.os }},${{ runner.arch }},${{ matrix.python-version }},${{ matrix.test-type }} @@ -417,7 +417,7 @@ jobs: -m "${{ env.PYTEST_MARKER }}" - name: Upload Coverage - uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: flags: ${{ runner.os }},${{ runner.arch }},${{ matrix.python-version }},${{ matrix.test-type }} From 7d74dd63a31082ac0474841076eaebb1955a7baa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:01:10 +0000 Subject: [PATCH 08/18] Bump actions/checkout from 4.1.6 to 4.1.7 in /.github/workflows (#5377) Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.6 to 4.1.7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/a5ac7e51b41094c92402da3b24376905380afc29...692973e3d937129bcbf40652eb9f2f61becf3332) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/builds-review.yaml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/labels.yml | 2 +- .github/workflows/tests.yml | 12 ++++++------ .github/workflows/upload.yml | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/builds-review.yaml b/.github/workflows/builds-review.yaml index 44c8bfcd90..488b188025 100644 --- a/.github/workflows/builds-review.yaml +++ b/.github/workflows/builds-review.yaml @@ -48,7 +48,7 @@ jobs: # Clean checkout of specific git ref needed for package metadata version # which needs env vars GIT_DESCRIBE_TAG and GIT_BUILD_STR: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ github.ref }} clean: true diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8fc64ab735..ef62e267f0 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,7 +22,7 @@ jobs: if: '!github.event.repository.fork' runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 - name: Setup diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index dec559a105..0189478992 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -19,7 +19,7 @@ jobs: GLOBAL: https://raw.githubusercontent.com/conda/infra/main/.github/global.yml LOCAL: .github/labels.yml steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - id: has_local uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3.0.0 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a93d7982d7..37fb169862 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -45,7 +45,7 @@ jobs: code: ${{ steps.filter.outputs.code }} steps: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 # dorny/paths-filter needs git clone for non-PR events # https://github.com/dorny/paths-filter#supported-workflows if: github.event_name != 'pull_request' @@ -102,7 +102,7 @@ jobs: steps: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 @@ -182,7 +182,7 @@ jobs: steps: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 @@ -262,7 +262,7 @@ jobs: steps: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 @@ -366,7 +366,7 @@ jobs: steps: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 @@ -504,7 +504,7 @@ jobs: # Clean checkout of specific git ref needed for package metadata version # which needs env vars GIT_DESCRIBE_TAG and GIT_BUILD_STR: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ github.ref }} clean: true diff --git a/.github/workflows/upload.yml b/.github/workflows/upload.yml index 3d3ff55a96..475131a0a1 100644 --- a/.github/workflows/upload.yml +++ b/.github/workflows/upload.yml @@ -27,7 +27,7 @@ jobs: ARCHIVE_NAME: ${{ github.event.repository.name }}-${{ github.ref_name }} steps: - name: Checkout Source - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Create Release Directory run: mkdir -p release From 4457362847b002ed4f6ce5c77a3f05f9325b449f Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Tue, 18 Jun 2024 04:25:34 -0400 Subject: [PATCH 09/18] Replace `sys.exit` call in `conda_build.build.tests_failed` (#5370) --- conda_build/build.py | 9 +++++++-- tests/cli/test_main_build.py | 6 +++--- tests/test_api_build.py | 7 ++++--- tests/test_api_test.py | 3 ++- tests/test_build.py | 10 ++++++++++ tests/test_subpackages.py | 3 ++- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/conda_build/build.py b/conda_build/build.py index 25b64c30ff..42fe0d5c21 100644 --- a/conda_build/build.py +++ b/conda_build/build.py @@ -3553,7 +3553,12 @@ def test( return True -def tests_failed(package_or_metadata, move_broken, broken_dir, config): +def tests_failed( + package_or_metadata: str | os.PathLike | Path | MetaData, + move_broken: bool, + broken_dir: str | os.PathLike | Path, + config: Config, +) -> None: """ Causes conda to exit if any of the given package's tests failed. @@ -3581,7 +3586,7 @@ def tests_failed(package_or_metadata, move_broken, broken_dir, config): _delegated_update_index( os.path.dirname(os.path.dirname(pkg)), verbose=config.debug, threads=1 ) - sys.exit("TESTS FAILED: " + os.path.basename(pkg)) + raise CondaBuildUserError("TESTS FAILED: " + os.path.basename(pkg)) @deprecated( diff --git a/tests/cli/test_main_build.py b/tests/cli/test_main_build.py index 9f4ce1cbb0..ed56cabceb 100644 --- a/tests/cli/test_main_build.py +++ b/tests/cli/test_main_build.py @@ -16,7 +16,7 @@ Config, zstd_compression_level_default, ) -from conda_build.exceptions import DependencyNeedsBuildingError +from conda_build.exceptions import CondaBuildUserError, DependencyNeedsBuildingError from conda_build.os_utils.external import find_executable from conda_build.utils import get_build_folders, on_win, package_has_file @@ -165,7 +165,7 @@ def test_build_long_test_prefix_default_enabled(mocker, testing_workdir): main_build.execute(args) args.append("--no-long-test-prefix") - with pytest.raises(SystemExit): + with pytest.raises(CondaBuildUserError): main_build.execute(args) @@ -483,7 +483,7 @@ def test_test_extra_dep(testing_metadata): main_build.execute(args) # missing click dep will fail tests - with pytest.raises(SystemExit): + with pytest.raises(CondaBuildUserError): args = [output, "-t"] # extra_deps will add it in main_build.execute(args) diff --git a/tests/test_api_build.py b/tests/test_api_build.py index 4199b9ec68..514db4f223 100644 --- a/tests/test_api_build.py +++ b/tests/test_api_build.py @@ -38,6 +38,7 @@ from conda_build.exceptions import ( BuildScriptException, CondaBuildException, + CondaBuildUserError, DependencyNeedsBuildingError, OverDependingError, OverLinkingError, @@ -279,7 +280,7 @@ def test_no_include_recipe_meta_yaml(testing_metadata, testing_config): )[0] assert not package_has_file(output_file, "info/recipe/meta.yaml") - with pytest.raises(SystemExit): + with pytest.raises(CondaBuildUserError): # we are testing that even with the recipe excluded, we still get the tests in place output_file = api.build( os.path.join(metadata_dir, "_no_include_recipe"), config=testing_config @@ -545,7 +546,7 @@ def test_skip_existing_url(testing_metadata, testing_workdir, capfd): def test_failed_tests_exit_build(testing_config): """https://github.com/conda/conda-build/issues/1112""" - with pytest.raises(SystemExit, match="TESTS FAILED"): + with pytest.raises(CondaBuildUserError, match="TESTS FAILED"): api.build( os.path.join(metadata_dir, "_test_failed_test_exits"), config=testing_config ) @@ -1808,7 +1809,7 @@ def test_downstream_tests(testing_config): upstream = os.path.join(metadata_dir, "_test_downstreams/upstream") downstream = os.path.join(metadata_dir, "_test_downstreams/downstream") api.build(downstream, config=testing_config, notest=True) - with pytest.raises(SystemExit): + with pytest.raises(CondaBuildUserError): api.build(upstream, config=testing_config) diff --git a/tests/test_api_test.py b/tests/test_api_test.py index 2bb76838aa..10200d5a99 100644 --- a/tests/test_api_test.py +++ b/tests/test_api_test.py @@ -9,6 +9,7 @@ import pytest from conda_build import api +from conda_build.exceptions import CondaBuildUserError from .utils import metadata_dir @@ -63,5 +64,5 @@ def test_api_extra_dep(testing_metadata): api.test(output, config=testing_metadata.config, extra_deps=["click"]) # missing click dep will fail tests - with pytest.raises(SystemExit): + with pytest.raises(CondaBuildUserError): api.test(output, config=testing_metadata.config) diff --git a/tests/test_build.py b/tests/test_build.py index 4078d8273e..f7c3f2ba8c 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -381,3 +381,13 @@ def test_handle_anaconda_upload(testing_config: Config, mocker: MockerFixture): with pytest.raises(CondaBuildUserError): build.handle_anaconda_upload((), testing_config) + + +def test_tests_failed(testing_metadata: MetaData, tmp_path: Path): + with pytest.raises(CondaBuildUserError): + build.tests_failed( + package_or_metadata=testing_metadata, + move_broken=True, + broken_dir=tmp_path, + config=testing_metadata.config, + ) diff --git a/tests/test_subpackages.py b/tests/test_subpackages.py index 11e43383d0..4307eb0f5b 100644 --- a/tests/test_subpackages.py +++ b/tests/test_subpackages.py @@ -11,6 +11,7 @@ from conda.base.context import context from conda_build import api, utils +from conda_build.exceptions import CondaBuildUserError from conda_build.metadata import MetaDataTuple from conda_build.render import finalize_metadata @@ -292,7 +293,7 @@ def test_per_output_tests(testing_config): @pytest.mark.sanity def test_per_output_tests_script(testing_config): recipe_dir = os.path.join(subpackage_dir, "_output_test_script") - with pytest.raises(SystemExit): + with pytest.raises(CondaBuildUserError): api.build(recipe_dir, config=testing_config) From ee7d0cea9831565ee3cef19708bad05ae930b2d5 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Fri, 21 Jun 2024 08:40:30 -0500 Subject: [PATCH 10/18] Set PIP_* env vars for outputs/script (#5368) * Set PIP_* env vars for outputs/script * Add test * add news --- conda_build/build.py | 20 ++++++++++++------- news/5368-pip-outputs | 19 ++++++++++++++++++ .../script_install_files/subpackage1.py | 2 ++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 news/5368-pip-outputs diff --git a/conda_build/build.py b/conda_build/build.py index 42fe0d5c21..9bce326305 100644 --- a/conda_build/build.py +++ b/conda_build/build.py @@ -1775,6 +1775,7 @@ def bundle_conda( env_output["RECIPE_DIR"] = metadata.path env_output["MSYS2_PATH_TYPE"] = "inherit" env_output["CHERE_INVOKING"] = "1" + _set_env_variables_for_build(metadata, env_output) for var in utils.ensure_list(metadata.get_value("build/script_env")): if "=" in var: val = var.split("=", 1)[1] @@ -3060,13 +3061,7 @@ def construct_metadata_for_test(recipedir_or_package, config): return m, hash_input -def write_build_scripts(m, script, build_file): - # TODO: Prepending the prefixes here should probably be guarded by - # if not m.activate_build_script: - # Leaving it as is, for now, since we need a quick, non-disruptive patch release. - with utils.path_prepended(m.config.host_prefix, False): - with utils.path_prepended(m.config.build_prefix, False): - env = environ.get_dict(m=m) +def _set_env_variables_for_build(m, env): env["CONDA_BUILD_STATE"] = "BUILD" # hard-code this because we never want pip's build isolation @@ -3098,6 +3093,17 @@ def write_build_scripts(m, script, build_file): if "replacements" in env: del env["replacements"] + +def write_build_scripts(m, script, build_file): + # TODO: Prepending the prefixes here should probably be guarded by + # if not m.activate_build_script: + # Leaving it as is, for now, since we need a quick, non-disruptive patch release. + with utils.path_prepended(m.config.host_prefix, False): + with utils.path_prepended(m.config.build_prefix, False): + env = environ.get_dict(m=m) + + _set_env_variables_for_build(m, env) + work_file = join(m.config.work_dir, "conda_build.sh") env_file = join(m.config.work_dir, "build_env_setup.sh") with open(env_file, "w") as bf: diff --git a/news/5368-pip-outputs b/news/5368-pip-outputs new file mode 100644 index 0000000000..ce2e6bb0f2 --- /dev/null +++ b/news/5368-pip-outputs @@ -0,0 +1,19 @@ +### Enhancements + +* PIP_* env variables are set when building outputs in multi-output recipes. (#3993 via #5368) + +### Bug fixes + +* + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/test-recipes/split-packages/script_install_files/subpackage1.py b/tests/test-recipes/split-packages/script_install_files/subpackage1.py index 22cf26111b..2f64db8201 100644 --- a/tests/test-recipes/split-packages/script_install_files/subpackage1.py +++ b/tests/test-recipes/split-packages/script_install_files/subpackage1.py @@ -2,6 +2,8 @@ out_path = os.path.join(os.environ['PREFIX'], 'subpackage_file_1') +assert "PIP_NO_INDEX" in os.environ + with open(out_path, 'w') as f: f.write("weeee") From fbbc2981632b0298ec7ba6ed0123d446e04514e3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:00:57 -0400 Subject: [PATCH 11/18] [pre-commit.ci] pre-commit autoupdate (#5386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.4.9 → v0.4.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.9...v0.4.10) - [github.com/python-jsonschema/check-jsonschema: 0.28.5 → 0.28.6](https://github.com/python-jsonschema/check-jsonschema/compare/0.28.5...0.28.6) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3d9674cf43..f22a702d86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,7 +58,7 @@ repos: # auto format Python codes within docstrings - id: blacken-docs - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.9 + rev: v0.4.10 hooks: # lint & attempt to correct failures (e.g. pyupgrade) - id: ruff @@ -87,7 +87,7 @@ repos: tests/ ) - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.5 + rev: 0.28.6 hooks: # verify github syntaxes - id: check-github-workflows From 3a09f13445ac59dc457db2aa7a52e7a5eb1f5d09 Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 25 Jun 2024 15:18:25 +0200 Subject: [PATCH 12/18] perf: use pickle's loads/dumps as a faster deepcopy (#5281) * Use pickle's loads/dumps as a faster deepcopy Signed-off-by: Marcel Bargull * ref: use clearer protocol spec * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Create 5281-perf-deepcopy * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml * Update pyproject.toml --------- Signed-off-by: Marcel Bargull Co-authored-by: Marcel Bargull Co-authored-by: Matthew R. Becker Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- conda_build/config.py | 8 ++++++-- news/5281-perf-deepcopy | 3 +++ pyproject.toml | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 news/5281-perf-deepcopy diff --git a/conda_build/config.py b/conda_build/config.py index 86fbe438d1..465058701f 100644 --- a/conda_build/config.py +++ b/conda_build/config.py @@ -9,6 +9,7 @@ import copy import math import os +import pickle import re import shutil import time @@ -820,9 +821,12 @@ def clean_pkgs(self): def copy(self) -> Config: new = copy.copy(self) - new.variant = copy.deepcopy(self.variant) + # Use picke.loads(pickle.dumps(...) as a faster copy.deepcopy alternative. + new.variant = pickle.loads(pickle.dumps(self.variant, pickle.HIGHEST_PROTOCOL)) if hasattr(self, "variants"): - new.variants = copy.deepcopy(self.variants) + new.variants = pickle.loads( + pickle.dumps(self.variants, pickle.HIGHEST_PROTOCOL) + ) return new # context management - automatic cleanup if self.dirty or self.keep_old_work is not True diff --git a/news/5281-perf-deepcopy b/news/5281-perf-deepcopy new file mode 100644 index 0000000000..b445074ea1 --- /dev/null +++ b/news/5281-perf-deepcopy @@ -0,0 +1,3 @@ +### Enhancements + +* Increased performance by using pickle instead of deepcopy. (#5281) diff --git a/pyproject.toml b/pyproject.toml index 9bc5272e8c..2726b59495 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,6 +129,7 @@ filterwarnings = [ # ignore conda-index error "ignore::PendingDeprecationWarning:conda_index", "ignore::DeprecationWarning:conda_index", + "ignore:Python 3.14 will, by default, filter extracted tar archives and reject files or modify their metadata:DeprecationWarning", ] markers = [ "serial: execute test serially (to avoid race conditions)", From c7a1e9bd9c6f65e3a634a6534b70c1204a713f8f Mon Sep 17 00:00:00 2001 From: "Matthew R. Becker" Date: Tue, 25 Jun 2024 11:08:42 -0500 Subject: [PATCH 13/18] perf: only set level if needed (#5384) --- conda_build/utils.py | 3 ++- news/5384-test-log-level | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 news/5384-test-log-level diff --git a/conda_build/utils.py b/conda_build/utils.py index e5e8d9c8c2..997349df5b 100644 --- a/conda_build/utils.py +++ b/conda_build/utils.py @@ -1653,7 +1653,8 @@ def get_logger(name, level=logging.INFO, dedupe=True, add_stdout_stderr_handlers logging.config.dictConfig(config_dict) level = config_dict.get("loggers", {}).get(name, {}).get("level", level) log = logging.getLogger(name) - log.setLevel(level) + if log.level != level: + log.setLevel(level) if dedupe: log.addFilter(dedupe_filter) diff --git a/news/5384-test-log-level b/news/5384-test-log-level new file mode 100644 index 0000000000..69d1682488 --- /dev/null +++ b/news/5384-test-log-level @@ -0,0 +1,3 @@ +### Enhancements + +* Reduced performance overheads of logging. (#5384) From c49182fe41334efe0aa187187556e7d12193658a Mon Sep 17 00:00:00 2001 From: "Matthew R. Becker" Date: Thu, 27 Jun 2024 13:28:10 -0500 Subject: [PATCH 14/18] ci: update to latest intel osx runner and download 10.15 SDK (#5387) --- .github/workflows/tests.yml | 34 +++++++++++++++++++------ news/5387-ci-osx-sdk | 3 +++ tests/conftest.py | 49 +++++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 news/5387-ci-osx-sdk diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 37fb169862..badc12fd03 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -337,11 +337,10 @@ jobs: needs: changes if: github.event_name == 'schedule' || needs.changes.outputs.code == 'true' - # Old macOS needed for old SDK (see xcode step below) - # This is needed for some MACOSX_DEPLOYMENT_TARGET tests - # We could also install SDKs from a external provider in the future - # if we want to update this runner to a non-deprecated version - runs-on: macos-11 + # we still need intel macs so we are stuck on macos-13 (not -14 or -latest) + # the issue is that there are recipes that depend on packages + # that do not exist for osx-arm64 - see #5388 + runs-on: macos-13 defaults: run: # https://github.com/conda-incubator/setup-miniconda#use-a-default-shell @@ -376,7 +375,9 @@ jobs: - name: Cache Conda uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 with: - path: ~/conda_pkgs_dir + path: | + ~/conda_pkgs_dir + ~/macosx_sdks key: cache-${{ env.HASH }} - name: Setup Miniconda @@ -385,8 +386,23 @@ jobs: condarc-file: .github/condarc run-post: false # skip post cleanup - - name: Xcode Install - run: sudo xcode-select --switch /Applications/Xcode_11.7.app + - name: SDK Download + run: | + echo "MACOSX_SDK_DIR=${HOME}/macosx_sdks" >> "$GITHUB_ENV" + export MACOSX_SDK_DIR=${HOME}/macosx_sdks + echo "MACOSX_SDK_VERSION=10.15" >> "$GITHUB_ENV" + export MACOSX_SDK_VERSION=10.15 + echo "MACOSX_SDK_ROOT=${MACOSX_SDK_DIR}/MacOSX${MACOSX_SDK_VERSION}.sdk" >> "$GITHUB_ENV" + export MACOSX_SDK_ROOT=${MACOSX_SDK_DIR}/MacOSX${MACOSX_SDK_VERSION}.sdk + + if [ ! -d ${MACOSX_SDK_DIR} ]; then mkdir ${MACOSX_SDK_DIR}; fi + if [ ! -d ${MACOSX_SDK_ROOT} ]; then + url="https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX${MACOSX_SDK_VERSION}.sdk.tar.xz" + curl -L --output MacOSX${MACOSX_SDK_VERSION}.sdk.tar.xz "${url}" + sdk_sha256=ac75d9e0eb619881f5aa6240689fce862dcb8e123f710032b7409ff5f4c3d18b + echo "${sdk_sha256} *MacOSX${MACOSX_SDK_VERSION}.sdk.tar.xz" | shasum -a 256 -c + tar -xf MacOSX${MACOSX_SDK_VERSION}.sdk.tar.xz -C "${MACOSX_SDK_DIR}" + fi - name: Conda Install run: > @@ -415,6 +431,8 @@ jobs: --cov=conda_build -n auto -m "${{ env.PYTEST_MARKER }}" + env: + CONDA_BUILD_SYSROOT: ${{ env.MACOSX_SDK_ROOT }} - name: Upload Coverage uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 diff --git a/news/5387-ci-osx-sdk b/news/5387-ci-osx-sdk new file mode 100644 index 0000000000..d732ed9644 --- /dev/null +++ b/news/5387-ci-osx-sdk @@ -0,0 +1,3 @@ +### Other + +* Updated the CI to download the MacOSX 10.15 SDK. diff --git a/tests/conftest.py b/tests/conftest.py index 465cab6fcc..cd66dddb97 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -105,7 +105,15 @@ def boolify(v): exit_on_verify_error=exit_on_verify_error_default, conda_pkg_format=conda_pkg_format_default, ) - result = Config(variant=None, **testing_config_kwargs) + + if on_mac and "CONDA_BUILD_SYSROOT" in os.environ: + var_dict = { + "CONDA_BUILD_SYSROOT": [os.environ["CONDA_BUILD_SYSROOT"]], + } + else: + var_dict = None + + result = Config(variant=var_dict, **testing_config_kwargs) result._testing_config_kwargs = testing_config_kwargs assert result.no_rewrite_stdout_env is False assert result._src_cache_root is None @@ -204,24 +212,35 @@ def variants_conda_build_sysroot(monkeypatch, request): if not on_mac: return {} - monkeypatch.setenv( - "CONDA_BUILD_SYSROOT", - subprocess.run( - ["xcrun", "--sdk", "macosx", "--show-sdk-path"], - check=True, - capture_output=True, - text=True, - ).stdout.strip(), - ) - monkeypatch.setenv( - "MACOSX_DEPLOYMENT_TARGET", - subprocess.run( + # if we do not speciy a custom sysroot, we get what the + # current SDK has + if "CONDA_BUILD_SYSROOT" not in os.environ: + monkeypatch.setenv( + "CONDA_BUILD_SYSROOT", + subprocess.run( + ["xcrun", "--sdk", "macosx", "--show-sdk-path"], + check=True, + capture_output=True, + text=True, + ).stdout.strip(), + ) + + mdt = subprocess.run( ["xcrun", "--sdk", "macosx", "--show-sdk-version"], check=True, capture_output=True, text=True, - ).stdout.strip(), - ) + ).stdout.strip() + else: + # custom sysroots always have names like MacOSX.sdk + mdt = ( + os.path.basename(os.environ["CONDA_BUILD_SYSROOT"]) + .replace("MacOSX", "") + .replace(".sdk", "") + ) + + monkeypatch.setenv("MACOSX_DEPLOYMENT_TARGET", mdt) + return request.param From 22bc38a6715fd11cb9a00ddb83c843bee1788ba9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:01:51 -0400 Subject: [PATCH 15/18] Bump actions/add-to-project from 1.0.1 to 1.0.2 in /.github/workflows (#5395) Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/actions/add-to-project/releases) - [Commits](https://github.com/actions/add-to-project/compare/9bfe908f2eaa7ba10340b31e314148fcfe6a2458...244f685bbc3b7adfa8466e08b698b5577571133e) --- updated-dependencies: - dependency-name: actions/add-to-project dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index 297ac2263a..4eda798e06 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -13,7 +13,7 @@ jobs: if: '!github.event.repository.fork' runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@9bfe908f2eaa7ba10340b31e314148fcfe6a2458 # v1.0.1 + - uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2 with: # issues are added to the Planning project # PRs are added to the Review project From 2ba431f352ab289347d3676865a4fee898946ff1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:02:49 -0400 Subject: [PATCH 16/18] [pre-commit.ci] pre-commit autoupdate (#5394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/blacken-docs: 1.16.0 → 1.18.0](https://github.com/asottile/blacken-docs/compare/1.16.0...1.18.0) - [github.com/astral-sh/ruff-pre-commit: v0.4.10 → v0.5.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.10...v0.5.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f22a702d86..5be138c7c4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,12 +53,12 @@ repos: files: \.py$ args: [--license-filepath, .github/disclaimer.txt, --no-extra-eol] - repo: https://github.com/asottile/blacken-docs - rev: 1.16.0 + rev: 1.18.0 hooks: # auto format Python codes within docstrings - id: blacken-docs - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.10 + rev: v0.5.0 hooks: # lint & attempt to correct failures (e.g. pyupgrade) - id: ruff From 87194f681b8c50a2502bdf5a60c5ffe8e08281ab Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Mon, 8 Jul 2024 12:17:19 -0400 Subject: [PATCH 17/18] Replace `sys.exit` calls in `conda_build/metadata.py` (#5371) * Update exceptions imports/usage in metadata.py * Replace sys.exit call with CondaBuildUserError for select_lines() function * Add unit test for CondaBuildUserError exception in select_lines test * Replace sys.exit call in _git_clean() and add unit test * Replace sys.exit call in check_bad_chrs() and add unit test * Update import statements and remove sys.exit call from yamlize() * Mark _get_env_path() for deprecation * Remove sys.exit call from parse_until_resolved() and add unit test * Remove sys.exit call from _get_contents() * Ignore deprecation warnings in metadata.py tests, point to correct exception in test_jinja_typo in test_api_build.py * Relax match string in error assertion for Windows * Revert 'cleanup' code changes from #5255 --- conda_build/metadata.py | 122 +++++++++++++++++++--------------------- tests/test_api_build.py | 2 +- tests/test_metadata.py | 74 ++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 64 deletions(-) diff --git a/conda_build/metadata.py b/conda_build/metadata.py index d3ee86f214..527fc99e6a 100644 --- a/conda_build/metadata.py +++ b/conda_build/metadata.py @@ -12,18 +12,27 @@ import warnings from collections import OrderedDict from functools import lru_cache -from os.path import isfile, join +from os.path import isdir, isfile, join from typing import TYPE_CHECKING, NamedTuple, overload +import yaml from bs4 import UnicodeDammit -from conda.base.context import context +from conda.base.context import locate_prefix_by_name from conda.gateways.disk.read import compute_sum from conda.models.match_spec import MatchSpec from frozendict import deepfreeze -from . import exceptions, utils +from . import utils from .config import Config, get_or_merge_config from .deprecations import deprecated +from .exceptions import ( + CondaBuildException, + CondaBuildUserError, + DependencyNeedsBuildingError, + RecipeError, + UnableToParse, + UnableToParseMissingJinja2, +) from .features import feature_list from .license_family import ensure_valid_license_family from .utils import ( @@ -46,6 +55,7 @@ ) if TYPE_CHECKING: + from pathlib import Path from typing import Any, Literal, Self OutputDict = dict[str, Any] @@ -336,12 +346,12 @@ def select_lines(text: str, namespace: dict[str, Any], variants_in_place: bool) if value: lines.append(line) except Exception as e: - sys.exit( - f"Error: Invalid selector in meta.yaml line {i + 1}:\n" - f"offending line:\n" - f"{line}\n" + raise CondaBuildUserError( + f"Invalid selector in meta.yaml line {i + 1}:\n" + f"offending selector:\n" + f" [{selector}]\n" f"exception:\n" - f"{e.__class__.__name__}: {e}\n" + f" {e.__class__.__name__}: {e}\n" ) return "\n".join(lines) + "\n" @@ -356,10 +366,10 @@ def yamlize(data): jinja2 # Avoid pyflakes failure: 'jinja2' imported but unused except ImportError: - raise exceptions.UnableToParseMissingJinja2(original=e) + raise UnableToParseMissingJinja2(original=e) print("Problematic recipe:", file=sys.stderr) print(data, file=sys.stderr) - raise exceptions.UnableToParse(original=e) + raise UnableToParse(original=e) def ensure_valid_fields(meta): @@ -400,9 +410,7 @@ def _trim_None_strings(meta_dict): def ensure_valid_noarch_value(meta): build_noarch = meta.get("build", {}).get("noarch") if build_noarch and build_noarch not in NOARCH_TYPES: - raise exceptions.CondaBuildException( - f"Invalid value for noarch: {build_noarch}" - ) + raise CondaBuildException(f"Invalid value for noarch: {build_noarch}") def _get_all_dependencies(metadata, envs=("host", "build", "run")): @@ -444,7 +452,7 @@ def check_circular_dependencies( error = "Circular dependencies in recipe: \n" for pair in pairs: error += " {} <-> {}\n".format(*pair) - raise exceptions.RecipeError(error) + raise RecipeError(error) def _check_circular_dependencies( @@ -477,7 +485,7 @@ def _check_circular_dependencies( error = "Circular dependencies in recipe: \n" for pair in pairs: error += " {} <-> {}\n".format(*pair) - raise exceptions.RecipeError(error) + raise RecipeError(error) def _check_run_constrained(metadata_tuples): @@ -495,7 +503,7 @@ def _check_run_constrained(metadata_tuples): f"Reason: {exc}" ) if errors: - raise exceptions.RecipeError("\n".join(["", *errors])) + raise RecipeError("\n".join(["", *errors])) def _variants_equal(metadata, output_metadata): @@ -539,7 +547,7 @@ def ensure_matching_hashes(output_metadata): error += "Mismatching package: {} (id {}); dep: {}; consumer package: {}\n".format( *prob ) - raise exceptions.RecipeError( + raise RecipeError( "Mismatching hashes in recipe. Exact pins in dependencies " "that contribute to the hash often cause this. Can you " "change one or more exact pins to version bound constraints?\n" @@ -766,19 +774,18 @@ def _git_clean(source_meta): If more than one field is used to specified, exit and complain. """ - git_rev_tags_old = ("git_branch", "git_tag") git_rev = "git_rev" git_rev_tags = (git_rev,) + git_rev_tags_old - has_rev_tags = tuple(bool(source_meta.get(tag, "")) for tag in git_rev_tags) - if sum(has_rev_tags) > 1: - msg = "Error: multiple git_revs:" - msg += ", ".join( - f"{key}" for key, has in zip(git_rev_tags, has_rev_tags) if has - ) - sys.exit(msg) + + keys = [key for key in (git_rev, "git_branch", "git_tag") if key in source_meta] + if not keys: + # git_branch, git_tag, nor git_rev specified, return as-is + return source_meta + elif len(keys) > 1: + raise CondaBuildUserError(f"Multiple git_revs: {', '.join(keys)}") # make a copy of the input so we have no side-effects ret_meta = source_meta.copy() @@ -801,15 +808,16 @@ def _str_version(package_meta): return package_meta -def check_bad_chrs(s, field): - bad_chrs = "=@#$%^&*:;\"'\\|<>?/ " +def check_bad_chrs(value: str, field: str) -> None: + bad_chrs = set("=@#$%^&*:;\"'\\|<>?/ ") if field in ("package/version", "build/string"): - bad_chrs += "-" + bad_chrs.add("-") if field != "package/version": - bad_chrs += "!" - for c in bad_chrs: - if c in s: - sys.exit(f"Error: bad character '{c}' in {field}: {s}") + bad_chrs.add("!") + if invalid := bad_chrs.intersection(value): + raise CondaBuildUserError( + f"Bad character(s) ({''.join(sorted(invalid))}) in {field}: {value}." + ) def get_package_version_pin(build_reqs, name): @@ -882,20 +890,17 @@ def build_string_from_metadata(metadata): return build_str -# This really belongs in conda, and it is int conda.cli.common, -# but we don't presently have an API there. -def _get_env_path(env_name_or_path): - if not os.path.isdir(env_name_or_path): - for envs_dir in list(context.envs_dirs) + [os.getcwd()]: - path = os.path.join(envs_dir, env_name_or_path) - if os.path.isdir(path): - env_name_or_path = path - break - bootstrap_metadir = os.path.join(env_name_or_path, "conda-meta") - if not os.path.isdir(bootstrap_metadir): - print(f"Bootstrap environment '{env_name_or_path}' not found") - sys.exit(1) - return env_name_or_path +@deprecated( + "24.7", "24.9", addendum="Use `conda.base.context.locate_prefix_by_name` instead." +) +def _get_env_path( + env_name_or_path: str | os.PathLike | Path, +) -> str | os.PathLike | Path: + return ( + env_name_or_path + if isdir(env_name_or_path) + else locate_prefix_by_name(env_name_or_path) + ) def _get_dependencies_from_environment(env_name_or_path): @@ -1124,7 +1129,7 @@ def finalize_outputs_pass( fm.name(), deepfreeze({k: fm.config.variant[k] for k in fm.get_used_vars()}), ] = (output_d, fm) - except exceptions.DependencyNeedsBuildingError as e: + except DependencyNeedsBuildingError as e: if not permit_unsatisfiable_variants: raise else: @@ -1427,12 +1432,11 @@ def parse_until_resolved( ): """variant contains key-value mapping for additional functions and values for jinja2 variables""" - # undefined_jinja_vars is refreshed by self.parse again - undefined_jinja_vars = () # store the "final" state that we think we're in. reloading the meta.yaml file # can reset it (to True) final = self.final - # always parse again at least once. + + # always parse again at least once self.parse_again( permit_undefined_jinja=True, allow_no_other_outputs=allow_no_other_outputs, @@ -1440,6 +1444,8 @@ def parse_until_resolved( ) self.final = final + # recursively parse again so long as each iteration has fewer undefined jinja variables + undefined_jinja_vars = () while set(undefined_jinja_vars) != set(self.undefined_jinja_vars): undefined_jinja_vars = self.undefined_jinja_vars self.parse_again( @@ -1448,18 +1454,8 @@ def parse_until_resolved( bypass_env_check=bypass_env_check, ) self.final = final - if undefined_jinja_vars: - self.parse_again( - permit_undefined_jinja=False, - allow_no_other_outputs=allow_no_other_outputs, - bypass_env_check=bypass_env_check, - ) - sys.exit( - f"Undefined Jinja2 variables remain ({self.undefined_jinja_vars}). Please enable " - "source downloading and try again." - ) - # always parse again at the end, too. + # always parse again at the end without permit_undefined_jinja self.parse_again( permit_undefined_jinja=False, allow_no_other_outputs=allow_no_other_outputs, @@ -2116,8 +2112,8 @@ def _get_contents( except jinja2.TemplateError as ex: if "'None' has not attribute" in str(ex): ex = "Failed to run jinja context function" - sys.exit( - f"Error: Failed to render jinja template in {self.meta_path}:\n{str(ex)}" + raise CondaBuildUserError( + f"Failed to render jinja template in {self.meta_path}:\n{str(ex)}" ) finally: if "CONDA_BUILD_STATE" in os.environ: diff --git a/tests/test_api_build.py b/tests/test_api_build.py index 514db4f223..5f5e3f2263 100644 --- a/tests/test_api_build.py +++ b/tests/test_api_build.py @@ -504,7 +504,7 @@ def test_recursive_fail(testing_config): @pytest.mark.sanity def test_jinja_typo(testing_config): - with pytest.raises(SystemExit, match="GIT_DSECRIBE_TAG"): + with pytest.raises(CondaBuildUserError, match="GIT_DSECRIBE_TAG"): api.build( os.path.join(fail_dir, "source_git_jinja2_oops"), config=testing_config ) diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 1b9fc34258..b8dc9df8e4 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -5,6 +5,7 @@ import os import subprocess import sys +from contextlib import nullcontext from itertools import product from typing import TYPE_CHECKING @@ -15,12 +16,15 @@ from conda_build import api from conda_build.config import Config +from conda_build.exceptions import CondaBuildUserError from conda_build.metadata import ( FIELDS, OPTIONALLY_ITERABLE_FIELDS, MetaData, _hash_dependencies, + check_bad_chrs, get_selectors, + sanitize, select_lines, yamlize, ) @@ -30,6 +34,8 @@ from .utils import metadata_dir, metadata_path, thisdir if TYPE_CHECKING: + from pathlib import Path + from pytest import MonkeyPatch @@ -200,6 +206,7 @@ def test_clobber_section_data(testing_metadata): @pytest.mark.serial +@pytest.mark.filterwarnings("ignore", category=PendingDeprecationWarning) def test_build_bootstrap_env_by_name(testing_metadata): assert not any( "git" in pkg for pkg in testing_metadata.meta["requirements"].get("build", []) @@ -218,6 +225,7 @@ def test_build_bootstrap_env_by_name(testing_metadata): subprocess.check_call(cmd.split()) +@pytest.mark.filterwarnings("ignore", category=PendingDeprecationWarning) def test_build_bootstrap_env_by_path(testing_metadata): assert not any( "git" in pkg for pkg in testing_metadata.meta["requirements"].get("build", []) @@ -549,3 +557,69 @@ def test_get_section(testing_metadata: MetaData): assert isinstance(section, list) else: assert isinstance(section, dict) + + +def test_select_lines_invalid(): + with pytest.raises( + CondaBuildUserError, + match=r"Invalid selector in meta\.yaml", + ): + select_lines("text # [{bad]", {}, variants_in_place=True) + + +@pytest.mark.parametrize( + "keys,expected", + [ + pytest.param([], {}, id="git_tag"), + pytest.param(["git_tag"], {"git_rev": "rev"}, id="git_tag"), + pytest.param(["git_branch"], {"git_rev": "rev"}, id="git_branch"), + pytest.param(["git_rev"], {"git_rev": "rev"}, id="git_rev"), + pytest.param(["git_tag", "git_branch"], None, id="git_tag + git_branch"), + pytest.param(["git_tag", "git_rev"], None, id="git_tag + git_rev"), + pytest.param(["git_branch", "git_rev"], None, id="git_branch + git_rev"), + pytest.param( + ["git_tag", "git_branch", "git_rev"], + None, + id="git_tag + git_branch + git_rev", + ), + ], +) +def test_sanitize_source(keys: list[str], expected: dict[str, str] | None) -> None: + with pytest.raises( + CondaBuildUserError, + match=r"Multiple git_revs:", + ) if expected is None else nullcontext(): + assert sanitize({"source": {key: "rev" for key in keys}}) == { + "source": expected + } + + +@pytest.mark.parametrize( + "value,field,invalid", + [ + pytest.param("good", "field", None, id="valid field"), + pytest.param("!@d&;-", "field", "!&;@", id="invalid field"), + pytest.param("good", "package/version", None, id="valid package/version"), + pytest.param("!@d&;-", "package/version", "&-;@", id="invalid package/version"), + pytest.param("good", "build/string", None, id="valid build/string"), + pytest.param("!@d&;-", "build/string", "!&-;@", id="invalid build/string"), + ], +) +def test_check_bad_chrs(value: str, field: str, invalid: str) -> None: + with pytest.raises( + CondaBuildUserError, + match=rf"Bad character\(s\) \({invalid}\) in {field}: {value}\.", + ) if invalid else nullcontext(): + check_bad_chrs(value, field) + + +def test_parse_until_resolved(testing_metadata: MetaData, tmp_path: Path) -> None: + (recipe := tmp_path / (name := "meta.yaml")).write_text("{{ UNDEFINED[:2] }}") + testing_metadata._meta_path = recipe + testing_metadata._meta_name = name + + with pytest.raises( + CondaBuildUserError, + match=("Failed to render jinja template"), + ): + testing_metadata.parse_until_resolved() From 6d7805c97aa6de56346e62a9d1d3582cac00ddb8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 12:42:21 -0400 Subject: [PATCH 18/18] [pre-commit.ci] pre-commit autoupdate (#5400) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.5.0 → v0.5.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.0...v0.5.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5be138c7c4..f9c1ef586e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,7 +58,7 @@ repos: # auto format Python codes within docstrings - id: blacken-docs - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.0 + rev: v0.5.1 hooks: # lint & attempt to correct failures (e.g. pyupgrade) - id: ruff