diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3b3d2f..64bc561 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,11 @@ jobs: os: - ubuntu-latest - windows-latest - - macos-latest + # Pinned: Homebrew bottles on macos-latest (macOS 26) carry + # minos 26.0, which delocate rejects against the 15.0 wheel + # target below. Keep this image and MACOSX_DEPLOYMENT_TARGET + # in sync if either changes. + - macos-15 steps: - name: Checkout source @@ -42,9 +46,12 @@ jobs: with: python-version: "3.12" - - name: Add gforran to PATH (macOS) + - name: Install gfortran (macOS) if: runner.os == 'macOS' - run: echo "$(brew --prefix gcc)/bin" >> "$GITHUB_PATH" + run: | + brew install gcc || brew link --overwrite gcc + echo "$(brew --prefix gcc)/bin" >> "$GITHUB_PATH" + "$(brew --prefix gcc)/bin/gfortran" --version - name: Install MinGW via Chocolatey (Windows) if: runner.os == 'Windows' diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index 9d0b04d..e6d8741 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -23,7 +23,11 @@ jobs: os: - ubuntu-latest - windows-latest - - macos-latest + # Pinned: Homebrew bottles on macos-latest (macOS 26) carry + # minos 26.0, which delocate rejects against the 15.0 wheel + # target below. Keep this image and MACOSX_DEPLOYMENT_TARGET + # in sync if either changes. + - macos-15 steps: - name: Checkout source @@ -37,9 +41,12 @@ jobs: with: python-version: "3.12" - - name: Add gfortran to PATH (macOS) + - name: Install gfortran (macOS) if: runner.os == 'macOS' - run: echo "$(brew --prefix gcc)/bin" >> "$GITHUB_PATH" + run: | + brew install gcc || brew link --overwrite gcc + echo "$(brew --prefix gcc)/bin" >> "$GITHUB_PATH" + "$(brew --prefix gcc)/bin/gfortran" --version - name: Install Python dependencies run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 86fe98f..23c86b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + # macos pinned to 15 to match the wheel target used in build.yml + # and release-pypi.yml; see the note there. + os: [ubuntu-latest, windows-latest, macos-15] python-version: ${{ fromJson(needs.fetch-python-versions.outputs.supported_versions) }} steps: @@ -50,9 +52,12 @@ jobs: with: fetch-depth: 0 - - name: Add gfortran to PATH (macOS) + - name: Install gfortran (macOS) if: runner.os == 'macOS' - run: echo "$(brew --prefix gcc)/bin" >> "$GITHUB_PATH" + run: | + brew install gcc || brew link --overwrite gcc + echo "$(brew --prefix gcc)/bin" >> "$GITHUB_PATH" + "$(brew --prefix gcc)/bin/gfortran" --version - name: Install MinGW via Chocolatey (Windows) if: runner.os == 'Windows' diff --git a/tests/test_banana_no_constraints.py b/tests/test_banana_no_constraints.py index 2bd3983..5e8f4c4 100644 --- a/tests/test_banana_no_constraints.py +++ b/tests/test_banana_no_constraints.py @@ -13,7 +13,9 @@ def banana_func(x: NDArray[np.floating]) -> np.floating: def test_banana_no_constraints() -> None: lb = [-3, -1] ub = [2, 6] - result = pso(banana_func, lb, ub, debug=True) + # Seeded: PSO is stochastic, and unseeded this assertion fails on + # roughly 1 in 75 runs at atol=0.001. + result = pso(banana_func, lb, ub, debug=True, seed=2) xopt, fopt = result.x, result.fun if not np.allclose(xopt, [1.0, 1.0], atol=0.001): msg = f"Expected xopt close to [1.0, 1.0], got {xopt}" diff --git a/tests/test_banana_with_constraints.py b/tests/test_banana_with_constraints.py index 9122b17..5cd2f26 100644 --- a/tests/test_banana_with_constraints.py +++ b/tests/test_banana_with_constraints.py @@ -19,7 +19,9 @@ def banana_constraint(x: NDArray[np.floating]) -> list[float]: def test_banana_with_constraints() -> None: lb = [-3, -1] ub = [2, 6] - result = pso(banana_func, lb, ub, f_ieqcons=banana_constraint, debug=True) + result = pso( + banana_func, lb, ub, f_ieqcons=banana_constraint, debug=True, seed=2 + ) xopt, fopt = result.x, result.fun if not np.allclose(xopt, [0.5, 0.75], atol=0.1): msg = f"Expected xopt close to [0.5, 0.75], got {xopt}"