Skip to content

uv migration#398

Merged
Wizard1209 merged 10 commits into
masterfrom
aux/uv-migration
May 21, 2026
Merged

uv migration#398
Wizard1209 merged 10 commits into
masterfrom
aux/uv-migration

Conversation

@Wizard1209

Copy link
Copy Markdown
Member

Summary

Switches dependency management from Poetry to uv (PEP 621 [project] + PEP 735 [dependency-groups], uv.lock committed). Includes fixes for issues surfaced during verification.

Changes

  • Build system
    • Replace Poetry with uv; pyproject.toml uses standard [project] + [dependency-groups], hatchling as build backend
    • Commit uv.lock; make installuv sync --all-extras --all-groups --link-mode symlink --locked
    • Pin Python to 3.13 via .python-version (matches CI latest tier)
  • Docker images
    • Rewrite both Dockerfiles to use Astral's canonical uv pattern (multi-stage, cache mounts, UV_COMPILE_BYTECODE, UV_LINK_MODE=copy)
    • Fix .dockerignore for uv.lock (was excluding it via leftover Poetry rules)
  • CI
    • GitHub Actions switched to astral-sh/setup-uv@v6
    • make test-ci no longer skips the sandbox suite on Linux silently — $(OSTYPE) is a shell var Make doesn't inherit, replaced with $(shell uname -s) against Linux/Darwin
  • Jupyter / michelson-kernel
    • Breaking: pip install pytezos no longer ships the Jupyter stack as a side effect. The michelson-kernel console script now requires pip install pytezos[jupyter] (pre-3.18 the same effect happened transitively via notebook being a top-level dep)
    • Declare ipykernel>=6 and jupyter-client>=7 explicitly in the jupyter extra (they're imported at module level by michelson_kernel.{cli,kernel})
    • Bump notebook to >=7,<8: notebook 6.x imports distutils.version.LooseVersion, which Python 3.12 removed (PEP 632). The michelson-kernel image (python:3.12-alpine3.22) couldn't launch on master before this. Drop the now-unrecognised --no-mathjax flag from the entrypoint
  • Sandbox stability
    • RpcNode.request now retries kind: temporary 5xx responses (and plain-text prevalidator.ml assertions) with exponential backoff. proto.* errors are explicitly NOT retried so legitimate Michelson failures (script_rejected, FAILWITH) surface immediately
    • Autobaker thread waits one block interval before its first bake — baking the moment the thread starts races with the pending protocol activation and trips prevalidator.ml:1918
    • kill_existing_containers catches DockerException explicitly so it silently no-ops in environments without a docker daemon (was printing "Exception ignored in atexit callback" to stderr)
  • Tests
    • test_onchain_view switched off the dead Harbinger oracle wrapper (KT1F6Amn..., FAILWITHs 900) onto 3Route v4 (KT1V5XKmey...), an active DEX router with a stable getToken(0) view
  • CHANGELOG.md updated with the breaking change and the notebook bump
  • .gitignore adds *_test_results.xml

Test plan

  • make install from a clean checkout
  • make lint (isort, black, ruff, mypy)
  • make test — full local suite passes
  • make test-ci — 4 JUnit XMLs: unit 761 / contract 348 / integration 21 / sandbox 19, all passing
  • docker build for both pytezos.dockerfile and michelson-kernel.dockerfile
  • Stress test: test_1_originate_contract 10x in a row, 10/10 pass

🤖 Generated with Claude Code

Wizard1209 and others added 10 commits May 19, 2026 16:49
- pyproject.toml: convert [tool.poetry] to PEP 621 [project], dev deps
  to PEP 735 [dependency-groups], switch build backend to hatchling.
  notebook moves into a `jupyter` optional-extra.
- Replace poetry.lock with uv.lock; drop generated requirements*.txt
  (Docker now consumes uv.lock directly).
- Makefile: poetry run -> uv run; make update simplified to uv sync -U.
- Dockerfiles: canonical Astral pattern (pinned uv 0.10.4, cache+bind
  mounts, two-step uv sync, UV_COMPILE_BYTECODE/LINK_MODE/NO_DEV/
  PYTHON_DOWNLOADS env). michelson-kernel image installs the jupyter
  extra; the headless pytezos image does not.
- Workflows: astral-sh/setup-uv@v6 in place of pipx install poetry +
  actions/setup-python; uv publish for release; uv.lock in trigger
  path filters. Bump the matrix's "oldest" Python from 3.9 to 3.10
  to match requires-python.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
.dockerignore still allowlisted poetry.lock and requirements** but
uv.lock was excluded by the leading `*` deny rule, so the Dockerfile
bind mount of uv.lock failed during `docker build`.

CLAUDE.md was authored earlier in the migration session but never
checked in. It reflects the new uv-based workflow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-3.18 the Jupyter stack came along with `pip install pytezos`
because `notebook` was a top-level runtime dependency. Now that
notebook lives behind the `jupyter` extra, the `michelson-kernel`
console script (which imports `ipykernel`/`jupyter_client` at module
level) needs the extra to import cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without a pin uv picks the lowest interpreter satisfying
requires-python (>=3.10), which makes black emit a noisy AST-safety
warning whenever its target-version list includes a higher version.
Pinning to 3.13 (the latest CI tier) eliminates the warning and
gives local dev the same Python the latest matrix slot runs on.

The boilerplate Python .gitignore was excluding .python-version; for
a uv-based project it is useful to ship so contributors get the same
interpreter automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kill_existing_containers() is registered atexit and unconditionally
instantiates DockerClient(). When the docker daemon socket is absent
(e.g. inside the published pytezos image, or any CI/sandbox without
DinD), Python's atexit machinery catches the resulting DockerException
but prints it to stderr as "Exception ignored in atexit callback...".

The hook is best-effort cleanup; wrap the whole body in
contextlib.suppress so it stays silent when there is nothing to clean
up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
michelson_kernel/{cli,kernel}.py import ipykernel and jupyter_client
at module level. Previously they were pulled transitively through
notebook 6.x, which made the dependency invisible from pyproject.toml
and fragile against any future change to the notebook pin.

This is purely additive — the resolved versions in uv.lock are
unchanged (ipykernel 6.29.5, jupyter-client 7.4.9).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
notebook==6.5.7 imports distutils unconditionally
(notebook/utils.py: `from distutils.version import LooseVersion`).
Python 3.12 removed distutils, so jupyter-notebook crashed on startup
inside the michelson-kernel image (python:3.12-alpine3.22) — the
ENTRYPOINT had been functionally broken since the image moved to
3.12. Notebook 7 is built on jupyter-server and works on 3.12+.

Also drop the `--no-mathjax` flag — notebook 7's argparser rejects it.

Verified locally: image boots, the michelson kernelspec is registered
and visible via the /api/kernelspecs REST endpoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/pytezos/rpc/node.py: retry transient octez 5xx responses (kind:
  temporary, mempool/prevalidator assertion text), but never retry
  protocol errors (id startswith proto.) — those are domain failures.
- src/pytezos/sandbox/node.py: have the autobaker thread wait one block
  interval before its first bake; baking immediately races with the
  pending protocol activation and trips prevalidator.ml:1918.
- tests/integration_tests/test_callback_view.py: switch test_onchain_view
  off the dead Harbinger wrapper (which FAILWITHs 900) onto 3Route v4
  (KT1V5XKmey...), an active DEX router with a stable getToken view.
- Makefile: $(OSTYPE) is a shell var not exported into Make's env, so the
  test-ci sandbox conditional was always false on Linux and the sandbox
  suite never ran in CI. Switch to $(shell uname -s) compared against
  Linux/Darwin so the gating actually works.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…licitly

Two review remarks on the uv-migration branch addressed in a single fixup:

1. e2a5a51 (".python-version" pin) — the underlying issue was a black
   AST-safety warning emitted whenever it ran on an interpreter lower
   than the highest entry in [tool.black].target-version. The proper
   in-pyproject fix is to align target-version with the actual floor
   declared by requires-python (py310), not to drag a stray
   .python-version into the repo as a side-channel pin. Pytezos still
   supports 3.10–3.13; bumping requires-python would be a real breaking
   change for users for the sake of silencing a dev warning, so we keep
   the floor as is. Revert .python-version and the .gitignore tweak.

2. f7e5192 (atexit silencer) — wrapping the whole hook body in
   suppress(Exception) was too broad: it would also swallow real bugs
   in the container-list path or in container.stop. The only error we
   actually need to absorb is DockerException raised by DockerClient()
   when the daemon socket is unreachable. Replace the outer suppress
   with a narrow try/except DockerException + early return; the inner
   per-container suppress stays as-is (best-effort stop).

Verified:
 - black --check src tests scripts --exclude ".*/docs.py" runs clean
   on both Python 3.10 and 3.13 with no AST warnings.
 - mypy + ruff clean on src/pytezos/sandbox/node.py.
 - kill_existing_containers() with no docker socket returns silently;
   with a working daemon the listing/stop path runs as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown

Test Results

    4 files      4 suites   2m 25s ⏱️
1 125 tests 1 112 ✅ 13 💤 0 ❌
1 149 runs  1 136 ✅ 13 💤 0 ❌

Results for commit 175aa33.

♻️ This comment has been updated with latest results.

@Wizard1209 Wizard1209 merged commit 3d689c8 into master May 21, 2026
8 checks passed
@Wizard1209 Wizard1209 deleted the aux/uv-migration branch May 21, 2026 13:28
@Wizard1209 Wizard1209 mentioned this pull request May 21, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant