From a81c0b940614b0852e1619731acc03f98769348d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 14 Sep 2026 01:24:32 +0000 Subject: [PATCH 1/2] Fix import cel failing in a clean install; smoke test the wheel in CI cel.cli imported Annotated from typing_extensions, which is not a declared dependency of this package. It used to arrive transitively through Typer, but Typer 0.21.2 (February 2026) dropped that dependency, so installing the wheel into an otherwise empty environment left `import cel` raising ModuleNotFoundError. The development lockfile masked the problem because mypy still pulls typing_extensions in. Annotated has been in the standard library since Python 3.9 and this package requires 3.11, so import it from typing. The lint job now builds the wheel, installs it into an empty virtual environment and runs both the import and the `cel` command, so an undeclared runtime dependency fails CI instead of the first user install. Claude-Session: https://claude.ai/code/session_019WbvXZFm8Nb2LXF2kiWoWW --- .github/workflows/ci.yml | 12 ++++++++++++ CHANGELOG.md | 13 +++++++++++++ python/cel/cli.py | 3 +-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46ad906..5fd29b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,6 +100,18 @@ jobs: uvx ty check test_types.py rm test_types.py echo "✅ Type checker integration working" + + - name: Smoke test the wheel in an empty environment + # The dev environment carries packages the wheel does not declare (mypy pulls + # in typing_extensions, for example), so an undeclared runtime import only + # shows up in an install that has nothing but the wheel and its dependencies. + run: | + uv run maturin build --release --out smoke-dist + uv venv --no-project smoke-venv + uv pip install --python smoke-venv/bin/python smoke-dist/*.whl + smoke-venv/bin/python -c "import cel; assert cel.evaluate('1 + 1') == 2" + smoke-venv/bin/cel '1 + 2' + smoke-venv/bin/cel --version linux: runs-on: ${{ matrix.platform.runner }} needs: [test, lint] diff --git a/CHANGELOG.md b/CHANGELOG.md index 7786f0b..f85e962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- **`import cel` failed in a clean install.** `cel.cli` imported `Annotated` from + `typing_extensions`, which is not one of this package's declared dependencies. It + used to arrive transitively through Typer, but Typer 0.21.2 (February 2026) dropped + that dependency, so `pip install common-expression-language` into an environment + with nothing else in it left `import cel` raising `ModuleNotFoundError`. The + development lockfile masked this because mypy still pulls `typing_extensions` in. + `Annotated` now comes from the standard library (`typing`), which has provided it + since Python 3.9. CI now installs the built wheel into an empty virtual environment + and imports the package and runs the `cel` command, so an undeclared runtime + dependency fails the build. + ## [0.9.0] - 2026-09-09 Upgrades to cel-rust 0.14.5, which brings native `type()`, range-checked diff --git a/python/cel/cli.py b/python/cel/cli.py index 22ea1e1..216cc38 100644 --- a/python/cel/cli.py +++ b/python/cel/cli.py @@ -16,7 +16,7 @@ import time from importlib.metadata import PackageNotFoundError, version from pathlib import Path -from typing import Any, Dict, Optional, Tuple +from typing import Annotated, Any, Dict, Optional, Tuple import typer @@ -35,7 +35,6 @@ from rich.panel import Panel from rich.syntax import Syntax from rich.table import Table -from typing_extensions import Annotated # Import directly from relative modules to avoid circular imports from .cel import Context, evaluate From 6dc553aed9f38ae6ee972aa0b58f9d47cf3486b6 Mon Sep 17 00:00:00 2001 From: Brian Thorne Date: Tue, 15 Sep 2026 20:03:15 +1200 Subject: [PATCH 2/2] Pin the smoke-test venv to the interpreter the wheel was built with The wheel is not abi3, so uv venv --no-project must not pick whichever Python the runner discovers first. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5fd29b3..87de2eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,7 @@ jobs: # shows up in an install that has nothing but the wheel and its dependencies. run: | uv run maturin build --release --out smoke-dist - uv venv --no-project smoke-venv + uv venv --no-project --python "$(uv run python -c 'import sys; print(sys.executable)')" smoke-venv uv pip install --python smoke-venv/bin/python smoke-dist/*.whl smoke-venv/bin/python -c "import cel; assert cel.evaluate('1 + 1') == 2" smoke-venv/bin/cel '1 + 2'