Skip to content

Move most CI from mamba to uv - #860

Merged
d-chambers merged 4 commits into
devfrom
uv-ci
Aug 11, 2026
Merged

Move most CI from mamba to uv#860
d-chambers merged 4 commits into
devfrom
uv-ci

Conversation

@d-chambers

@d-chambers d-chambers commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Description

Moves most of CI from micromamba to uv, keeping a single conda job.

The conda layer had become vestigial. The environment files only listed packages that also ship PyPI wheels, and every job then ran pip install -e ".[dev]" on top anyway, so the conda solve was buying nothing. pytables was the last dependency that genuinely needed conda, and it is no longer used anywhere in dascore/ or tests/. tk is not needed either, since the test workflows force MPLBACKEND=Agg.

Why now

The Actions cache budget was the real motivator. Before this change the repo sat at 10.42 GB against the 10 GB limit, of which the mamba environment caches were 7.03 GB across 23 entries (one per os × python × env-file × week, 250–590 MB each). That is what kept evicting the test-data cache.

Install time improves too, most visibly on Windows:

mamba (warm cache) uv (cold, measured in CI)
ubuntu 32–41 s 11–14 s
macOS 39–62 s 17–22 s
windows 132–187 s 55–59 s

The uv column is the install-dascore step across the three test_code Python versions in run 31483746055, with caching off, so these are cold installs against warm-cache mamba numbers. One outlier: test_code (windows-latest, 3.12) took 153 s in that run while 3.13 and 3.14 took 55 s and 59 s.

The other jobs land in the same range — min-deps installs at 12–14 s (ubuntu), 10–15 s (macOS) and 32–35 s (windows), and network_tests at 13 s (ubuntu) and 28 s (macOS). The one retained conda job (conda_env) spends 29 s in mamba-install-dascore.

What changed

  • New .github/actions/install-dascore (setup-python + setup-uv + uv pip install --system) replaces .github/actions/mamba-install-dascore in every workflow except one.
  • One conda job is kept (conda_env in runtests.yml, ubuntu + default python). DASCore ships on conda-forge, so that install path still deserves a smoke test. At one (os, python) it costs a single ~530 MB cache per week instead of ~15.
  • upload_pypi.yml no longer solves a whole conda environment just to reach python -m build.
  • Deleted .github/doc_environment.yml, .github/min_deps_environment.yml, and .github/test_condarc.yml (the last of which nothing referenced).
  • The docs extra now declares ipykernel, jupyter-client, nbclient, and nbformat. Quarto executes the {python} cells in docs/*.qmd through jupyter, and that was only ever supplied by doc_environment.yml — without this the doc build breaks.
  • profile.yml installs [profile,extras] rather than [profile]. The IO benchmarks suppress DependencyError, so a format whose optional dependency is missing is silently not benchmarked; environment.yml used to supply xarray/findiff on top of [profile]. Note this widens benchmark coverage, so CodSpeed will want a fresh baseline on dev.

Caching is deliberately off

Not an oversight — setup-uv's default cache prunes with uv cache prune --ci, which drops the downloaded wheels. Measured: it shrinks the cache from 874 MB to 73 MB, saves only ~1.7 s of a ~13 s install, and an offline install from a pruned cache fails outright, so it does not even buy resilience to a PyPI blip. UV_HTTP_RETRIES=5 addresses that directly instead, at no cache cost.

If we want caching later, runtests.yml carries a comment with the recipe: enable-cache: true plus prune-cache: false (~240 MB compressed per os/python), and a stable key — not setup-uv's default cache-dependency-glob, which hashes pyproject.toml. That file changes on nearly every reader PR since each new format adds an entry point, and caches are ref-scoped, so the default would mint a fresh copy of every matrix entry per PR. Probably worth revisiting once dev lands on master and there are fewer matrices in flight.

Verification

  • uv pip compile --extra dev --no-build resolves to pure wheels for all 12 combinations of python 3.11–3.14 × {manylinux_2_28, windows-msvc, macos-arm64}. Nothing in the dependency set needs a source build on the runners.
  • Full test suite in a uv-only venv: 8747 passed, 97 skipped, 2 xfailed.
  • python scripts/build_api_docs.py runs clean in a uv-only venv (1116 files, 3526 links, 0 bad), and quarto executes {python} cells against it. A full local quarto render docs was still in progress at the time of opening; the documentation label is set so CI builds the docs here, which is the authoritative check.
  • pre-commit run --all passes, including actionlint and zizmor.

test_free_threaded.yml and test_wasm.yml are untouched — they were already pip-based, not mamba-based.

Review fixes (second commit)

Worth calling out because two were latent bugs rather than polish:

  • pyyaml was missing from the docs extra. Quarto's own notebook driver does from yaml import safe_load, and [docs] resolved without it. The doc builds only worked because [dev] pulls pyyaml in transitively via pre-commit — so pip install dascore[docs] && quarto render docs would have failed, and dropping pre-commit from [test] would have broken all three doc workflows.
  • environment.yml was not in runtests.yml's paths filter, so a PR editing only that file would not have run the very job added to guard it.
  • conda_env installs [test] rather than the [dev] default, so pip does not layer ~30 PyPI distributions over the environment being checked.
  • The python-version guard compares component-wise and strips the free-threaded suffix, so a future caller can pin 3.14.2 or 3.14t without a spurious failure.
  • The dev-install doc now tells uv users to run uv pip install; a uv venv has no pip of its own, so a bare pip install would silently install into whatever is next on PATH.

Follow-ups, not done here

environment.yml is missing three of dascore's required deps (packaging, rich, universal-pathlib), which pip supplies from PyPI. Adding them would make the conda job a truer test of the conda stack, but it risks the one remaining conda solve and is better done on its own.

Changelog

none

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes.
  • documented the new feature with docstrings and/or appropriate doc page.
  • included tests. See testing guidelines.
  • added the "ready_for_review" tag once the PR is ready to be reviewed.

Summary by CodeRabbit

  • New Features

    • Added streamlined Python environment setup across development, testing, documentation, profiling, and package publishing workflows.
    • Added configurable installation options for Python versions, dependency groups, package installation, and test-data preparation.
    • Added dedicated Conda environment validation while standardizing other checks on uv.
  • Documentation

    • Expanded contributor guidance for creating, activating, and refreshing uv environments.
    • Updated documentation build and dependency configuration.
  • Bug Fixes

    • Improved workflow shell execution and documentation build reliability.
    • Reduced network-related test failures by avoiding unnecessary reverse-DNS lookups.

The conda layer had become vestigial: the environment files only listed
packages that also ship PyPI wheels, and every job then ran
`pip install -e ".[dev]"` on top anyway. pytables was the last dependency
that genuinely needed conda, and it is no longer used.

Replaces .github/actions/mamba-install-dascore with an install-dascore
action built on setup-python + setup-uv. A single conda job (conda_env in
runtests.yml) is kept because DASCore ships on conda-forge and that install
path deserves a smoke test.

Dependency caching is deliberately off. The mamba environment caches filled
7 GB of the repo's 10 GB budget and kept evicting the test-data cache, while
a cold uv install of [dev] is ~15s. runtests.yml records what to do if we
want caching back later.

Quarto executes the {python} cells in docs/*.qmd through jupyter, which was
only ever supplied by doc_environment.yml, so the docs extra now declares
ipykernel, jupyter-client, nbclient and nbformat.

Also deletes .github/test_condarc.yml, which nothing referenced.
- Add pyyaml to the docs extra. Quarto's own notebook driver does
  `from yaml import safe_load`, and `[docs]` alone resolved without it;
  the doc builds only worked because [dev] pulls pyyaml in transitively
  through pre-commit.
- Add environment.yml to runtests.yml's paths filter. The conda_env job
  exists to guard that file, but a PR touching only it triggered no run.
- Install [test] rather than [dev] in conda_env, so pip does not layer
  ~30 PyPI distributions over the environment being checked.
- Compare python versions component-wise and strip the free-threaded
  suffix, so a caller may pin '3.14.2' or '3.14t' without a false failure.
- Tell contributors using uv to run `uv pip install`; a uv virtual
  environment has no pip of its own, so a bare `pip install` silently
  installs into whatever is next on PATH.
@d-chambers d-chambers added the documentation Improvements or additions to documentation label Aug 11, 2026
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@d-chambers, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 14 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 79420ffb-2ebf-4c06-9d59-d3422d3210e4

📥 Commits

Reviewing files that changed from the base of the PR and between 9d9ea03 and 0545438.

📒 Files selected for processing (1)
  • .github/workflows/runtests.yml
📝 Walkthrough

Walkthrough

The PR adds a shared uv-based DASCore installer, migrates most workflows from Conda, keeps one Conda smoke-test job, standardizes Bash usage, updates publishing, documents uv development setup, expands documentation dependencies, and changes HTTP test fixtures to avoid reverse DNS lookups.

Changes

CI installation migration

Layer / File(s) Summary
Shared installer and shell execution
.github/actions/install-dascore/action.yml, .github/actions/build-docs/action.yml, .github/actions/prep_doc_build/action.yml
Adds the configurable Install DASCore composite action. Documentation actions now use standard Bash shells.
Workflow installation paths
.github/workflows/build_deploy_*.yaml, .github/workflows/get_coverage.yml, .github/workflows/profile.yml, .github/workflows/run_min_dep_tests.yml, .github/workflows/runtests.yml, .github/workflows/test_doc_build.yml, .github/actions/mamba-install-dascore/action.yml
Most workflows use the shared installer and uv-based dependencies. Login-shell wrappers and explicit Conda environment inputs are removed. A dedicated conda_env smoke-test job remains.
PyPI publishing environment
.github/workflows/upload_pypi.yml
Publishing uses standalone Python and uv setup. The build package installs through uv pip, and distribution creation uses standard Bash.
Developer setup and documentation dependencies
docs/contributing/dev_install.qmd, pyproject.toml
Documents uv environment creation, activation, installation, and refresh steps. Adds notebook and YAML dependencies to the docs group.
HTTP test server setup
tests/test_io/conftest.py
HTTP fixtures use custom server classes that bind sockets without reverse DNS lookups.

Possibly related PRs

  • DASDAE/dascore#504: Directly updates the documentation CI workflows and actions that this PR migrates to install-dascore.
  • DASDAE/dascore#547: Modifies the shared documentation-build actions and master documentation workflow.
  • DASDAE/dascore#591: Modifies the same CI installation actions and workflows, including Python-version and caching configuration.

Suggested labels: CI

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: moving most CI installation from mamba to uv while retaining the relevant scope.
Description check ✅ Passed The description is detailed, explains the motivation and changes, documents verification results, and includes the required checklist.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch uv-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the CI continuous integration label Aug 11, 2026
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (c97545e) to head (0545438).
⚠️ Report is 1 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #860   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          176       176           
  Lines        19372     19275   -97     
=========================================
- Hits         19372     19275   -97     
Flag Coverage Δ
network 48.11% <ø> (-0.25%) ⬇️
unittests 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

HTTPServer.server_bind calls socket.getfqdn(host) only to populate
server_name. On the macOS runner that lookup for 127.0.0.1 blocks past
the 30s pytest-timeout, so every test drawing on a served fixture failed
during setup. It surfaced when CI moved to setup-python's macOS framework
build, but the lookup was never wanted: nothing reads server_name.

Bind through TCPServer and fill server_name/server_port in directly.
The re-enable recipe lives in the PR description; the workflow only needs
to say why caching is off and where to look.
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

✅ Documentation built:
👉 Download
Note: You must be logged in to github and a DASDAE member to access the link.

@d-chambers
d-chambers merged commit 6d14884 into dev Aug 11, 2026
28 checks passed
@d-chambers
d-chambers deleted the uv-ci branch August 11, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI continuous integration documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant