From 9ae3fa8ecd40d7a3092968fc6dd03b454052004a Mon Sep 17 00:00:00 2001 From: MilesCranmerBot Date: Sun, 28 Jun 2026 14:06:53 +0000 Subject: [PATCH 1/5] chore(deps): consolidate GitHub Actions version bumps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - julia-actions/setup-julia v2→v3 - docker/login-action v3→v4 - docker/metadata-action v5→v6 - docker/setup-qemu-action v3→v4 - docker/setup-buildx-action v3→v4 - docker/build-push-action v6→v7 Closes #1225 Closes #1170 --- .github/workflows/CI.yml | 6 +++--- .github/workflows/docker_deploy.yml | 10 +++++----- .github/workflows/docs.yml | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index be27f15d5..908b73ee2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -50,7 +50,7 @@ jobs: steps: - uses: actions/checkout@v7 - name: "Set up Julia" - uses: julia-actions/setup-julia@v2 + uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.julia-version }} - name: "Cache Julia" @@ -223,7 +223,7 @@ jobs: steps: - uses: actions/checkout@v7 - name: "Set up Julia" - uses: julia-actions/setup-julia@v2 + uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.julia-version }} - name: "Set up Python" @@ -255,7 +255,7 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: pip - - uses: julia-actions/setup-julia@v2 + - uses: julia-actions/setup-julia@v3 with: version: ${{ matrix.julia-version }} diff --git a/.github/workflows/docker_deploy.yml b/.github/workflows/docker_deploy.yml index f3dc6aecc..03d35aea1 100644 --- a/.github/workflows/docker_deploy.yml +++ b/.github/workflows/docker_deploy.yml @@ -25,13 +25,13 @@ jobs: - name: Checkout uses: actions/checkout@v7 - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@v4 if: github.event_name != 'pull_request' with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub registry - uses: docker/login-action@v3 + uses: docker/login-action@v4 if: github.event_name != 'pull_request' with: registry: ghcr.io @@ -39,7 +39,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Docker meta id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: # List of Docker images to use as base name for tags images: | @@ -58,9 +58,9 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . platforms: ${{ matrix.arch }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 110b552dc..b2720268a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -41,7 +41,7 @@ jobs: - uses: actions/setup-python@v6 with: python-version: '3.11' - - uses: julia-actions/setup-julia@v2 + - uses: julia-actions/setup-julia@v3 with: version: '1' - name: Install julia deps From 6dd02b6774a613f466616939727e3ab85020d95e Mon Sep 17 00:00:00 2001 From: MilesCranmerBot Date: Sun, 28 Jun 2026 14:10:58 +0000 Subject: [PATCH 2/5] chore(deps): consolidate Python dependency range widening MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - juliacall >=0.9.28,<0.9.29 → >=0.9.28,<0.9.36 - ipykernel >=6,<7 → >=6,<8 - jax[cpu] >=0.4,<0.6 → >=0.4,<0.7 - pytest-cov >=5,<7 → >=5,<8 Closes #1031 Closes #1213 Closes #1214 Closes #1217 Closes #1139 --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fccd37f7a..51d0bc1f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ "pandas>=0.21.0,<4.0.0", "numpy>=1.13.0,<3.0.0", "scikit_learn>=1.0.0,<2.0.0", - "juliacall>=0.9.28,<0.9.29", + "juliacall>=0.9.28,<0.9.36", "click>=7.0.0,<9.0.0", "typing-extensions>=4.0.0,<5.0.0", ] @@ -35,15 +35,15 @@ docs = [ dev = [ "coverage>=7,<8", "beartype>=0.19,<0.23", - "ipykernel>=6,<7", + "ipykernel>=6,<8", "ipython>=8,<9", - "jax[cpu]>=0.4,<0.6", + "jax[cpu]>=0.4,<0.7", "jupyter>=1,<2", "mypy>=1,<3", "nbval>=0.11,<0.12", "pandas-stubs", "pre-commit>=3.0,<5", - "pytest-cov>=5,<7", + "pytest-cov>=5,<8", "pytest>=8,<10", "tensorboard>=2,<3", "torch>=2,<3", From ac1c00a09d15f657c7a65da882024b220896f483 Mon Sep 17 00:00:00 2001 From: MilesCranmerBot Date: Sun, 28 Jun 2026 14:24:23 +0000 Subject: [PATCH 3/5] chore(deps): widen pyjuliacall range in environment.yml to match pyproject.toml --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 6ef91fbe5..8a03713c5 100644 --- a/environment.yml +++ b/environment.yml @@ -7,6 +7,6 @@ dependencies: - pandas>=0.21.0,<4.0.0 - numpy>=1.13.0,<3.0.0 - scikit-learn>=1.0.0,<2.0.0 - - pyjuliacall>=0.9.28,<0.9.29 + - pyjuliacall>=0.9.28,<0.9.36 - click>=7.0.0,<9.0.0 - typing-extensions>=4.0.0,<5.0.0 From 419f38dfe4a9a4cc8748923d2e746d38258ff263 Mon Sep 17 00:00:00 2001 From: MilesCranmerBot Date: Sun, 28 Jun 2026 18:12:56 +0000 Subject: [PATCH 4/5] chore(deps): sync jax range with release-v1 backport Co-authored-by: Miles Cranmer --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 51d0bc1f1..6d2af2c4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dev = [ "beartype>=0.19,<0.23", "ipykernel>=6,<8", "ipython>=8,<9", - "jax[cpu]>=0.4,<0.7", + "jax[cpu]>=0.4,<0.11", "jupyter>=1,<2", "mypy>=1,<3", "nbval>=0.11,<0.12", From 11cddda5a10888e277dc31aed2d555e588b301c8 Mon Sep 17 00:00:00 2001 From: MilesCranmerBot Date: Sun, 28 Jun 2026 18:24:41 +0000 Subject: [PATCH 5/5] fix: handle subprocess.CalledProcessError in registry fallback The try_with_registry_fallback function only caught JuliaError types with 'Unsatisfiable requirements detected' messages. When juliapkg invokes julia as a subprocess and the Pkg server returns HTTP 404 for a registry hash, the error surfaces as subprocess.CalledProcessError instead. This caused all CI jobs that import pysr to fail without attempting the 'eager' registry fallback. Co-authored-by: Miles Cranmer --- pysr/julia_registry_helpers.py | 36 ++++++++++++++++++++++++++++++---- pysr/test/test_startup.py | 25 +++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/pysr/julia_registry_helpers.py b/pysr/julia_registry_helpers.py index ad34a98b1..12a3e5321 100644 --- a/pysr/julia_registry_helpers.py +++ b/pysr/julia_registry_helpers.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +import subprocess import warnings from collections.abc import Callable from typing import TypeVar @@ -12,6 +13,36 @@ PREFERENCE_KEY = "JULIA_PKG_SERVER_REGISTRY_PREFERENCE" +def _contains_registry_operation(value) -> bool: + if isinstance(value, (list, tuple)): + text = "\n".join(str(item) for item in value) + else: + text = str(value) + return "Pkg.Registry" in text or "/registry/" in text + + +def _is_registry_error(error: Exception) -> bool: + error_type = str(type(error)) + error_message = str(error) + if "JuliaError" in error_type: + return any( + phrase in error_message + for phrase in ( + "Unsatisfiable requirements detected", + "could not download", + "/registry/", + "Registry.update", + ) + ) + if isinstance(error, subprocess.CalledProcessError): + return any( + _contains_registry_operation(value) + for value in (error.cmd, error.output, error.stderr) + if value is not None + ) + return False + + def try_with_registry_fallback(f: Callable[..., T], *args, **kwargs) -> T: """Execute function with modified Julia registry preference. @@ -22,10 +53,7 @@ def try_with_registry_fallback(f: Callable[..., T], *args, **kwargs) -> T: try: return f(*args, **kwargs) except Exception as initial_error: - # Check if this is a Julia registry error by looking at the error message - if "JuliaError" not in str( - type(initial_error) - ) or "Unsatisfiable requirements detected" not in str(initial_error): + if not _is_registry_error(initial_error): raise initial_error old_value = os.environ.get(PREFERENCE_KEY, None) diff --git a/pysr/test/test_startup.py b/pysr/test/test_startup.py index 8bd81cd93..05c984452 100644 --- a/pysr/test/test_startup.py +++ b/pysr/test/test_startup.py @@ -210,6 +210,31 @@ def test_julia_error_triggers_fallback(self): # Verify environment is restored self.assertEqual(os.environ[PREFERENCE_KEY], "conservative") + def test_subprocess_registry_error_triggers_fallback(self): + os.environ[PREFERENCE_KEY] = "conservative" + attempts = [] + + def failing_then_successful_operation(): + attempts.append(os.environ[PREFERENCE_KEY]) + if len(attempts) == 1: + raise subprocess.CalledProcessError( + 1, + [ + "julia", + "--startup-file=no", + "-e", + "import Pkg\nPkg.Registry.update()\nPkg.add([])", + ], + ) + return "success" + + with self.assertWarns(Warning): + result = try_with_registry_fallback(failing_then_successful_operation) + + self.assertEqual(result, "success") + self.assertEqual(attempts, ["conservative", "eager"]) + self.assertEqual(os.environ[PREFERENCE_KEY], "conservative") + def test_eager_mode_fails_directly(self): os.environ[PREFERENCE_KEY] = "eager"