Skip to content

Release Notes — v1.18

Release date: May 2026

This release ships the most significant structural change since v1.0: weevr is now distributed as two PyPI wheels sharing a single weevr namespace. pip install weevr continues to install the complete Spark engine; a new pip install weevr-core makes the pure-Python validation, planner, and telemetry-contract surface available without PySpark. Both wheels publish to PyPI in lockstep at the same version on every release. Existing users see no behavior change.


Two wheels, one namespace

Source now lives under packages/, declared as a uv workspace at the repository root. Two wheels build from that workspace:

Wheel Concern Depends on
weevr-core Pure-Python validation, planner, telemetry contracts. Installable without PySpark. pydantic, pyyaml
weevr Spark engine, runtime helpers, OneLake/Fabric integration. weevr-core (same version)

The split is physical, not semantic. No public API renames, no signature changes, no behavior tweaks. Every existing import path that worked under pip install weevr keeps working unchanged. The work that landed under v1.17 (PEP 562 lazy Context, pure-helper extractions, the no-PySpark lock test) was the prerequisite that made this split safe.

What moved to weevr-core

Pure-Python modules whose concern could sensibly exist outside an engine run — schemas, config resolvers, the planner graph, telemetry contract types — now ship from weevr-core:

  • weevr.model.* — every Pydantic model.
  • weevr.errors.* — the full exception hierarchy.
  • The pure half of weevr.config: parser, resolver, validation, inheritance, locations, macros, warp, audit_templates, duration.
  • The contract types in weevr.telemetry: results, span, trace, events.
  • weevr.engine.planner and weevr.engine.formatting (DAG construction and pure-Python formatters used by result rendering).
  • Root-level weevr.result, weevr.duration, weevr.reserved_words.

What stayed in weevr

Anything that orchestrates execution, touches Spark, talks to the Fabric runtime, or coordinates state — weevr.context, weevr.engine.executor/runner/cache_manager/display/hooks/ lookups/conditions/column_sets/resources/result/variables, weevr.operations.*, weevr.state.*, weevr.telemetry.collector/ logging, and the two Spark-bound config helpers weevr.config.fabric / weevr.config.paths.

Federated namespaces

Three sub-packages now ship files from both wheels: weevr.config (core ships __init__.py + pure helpers; engine adds fabric.py and paths.py), weevr.engine (engine ships __init__.py + Spark-bound modules; core adds planner.py and formatting.py), and weevr.telemetry (engine ships __init__.py + runtime helpers; core adds the contract types). The top-level weevr.__init__.py stays in the engine wheel.

In a normal pip install both wheels' files merge into one site-packages/weevr/ directory and Python's import machinery resolves through the single owning __init__.py. In editable workspace installs each wheel's src/ is a separate sys.path entry, so federated __init__.py files extend __path__ to pull the sibling wheel's contributions back into the namespace.

Two new install personas

pip install weevr (existing users)

Behavior is unchanged. The engine wheel declares weevr-core as a same-version runtime dependency, so the resolver always installs both wheels in one shot. Every existing import resolves identically:

from weevr import Context
from weevr.config import load_config
from weevr.model.thread import Thread
from weevr.engine.planner import build_plan

pip install weevr-core (new in 1.18)

Installs only the pure-Python distribution. The validation API, Pydantic models, planner graph, and telemetry contracts all import without PySpark on sys.path:

from weevr.config import load_config       # works
from weevr.model.thread import Thread       # works
from weevr.engine.planner import build_plan # works (pure-Python)

from weevr import Context                   # ImportError — engine wheel not installed

This is the persona that unblocks weevr-cli, native docs generation, stored-run summary rendering, and any other tool that needs to read or validate .weevr/ projects without paying for Spark.

Restricted-network Fabric installs that upload wheels manually now need to upload both files; see the Fabric runtime guide for the updated example.

CI and tooling

  • Both wheels build from the workspace root via uv build --all-packages and publish through one pypa/gh-action-pypi-publish step. release-please bumps the version line in both pyproject.toml files (and both uv.lock entries) atomically on every release PR. The first lockstep release (this one) is the empirical confirmation.
  • A new integration suite at tests/integration/test_dual_install_modes.py (gated by the install_smoke marker) builds both wheels, installs them into isolated venvs, and asserts that the documented import paths resolve in core-only and full modes — wired into the release workflow as a pre-publish gate via the WEEVR_SMOKE_DIST env var, so the smoke test exercises the same artifacts the publish step uploads.
  • tests/weevr/test_lazy_init_consistency.py keeps the PEP 562 lazy modules' _LAZY_ATTRS map in sync with their __all__.
  • mkdocstrings reads from a deep-merged tree at .docs-merged/ (assembled by scripts/mkdocs_merge_weevr.py at config time) so reference pages span both src roots.
  • pyright config downgrades reportMissingImports and reportAttributeAccessIssue for the federated cross-wheel imports it cannot merge; runtime resolution remains locked by the full pytest suite.

Backwards compatibility

  • pip install weevr behavior is identical for existing users — the install pulls both wheels, every import path resolves unchanged, no behavior or signature changes.
  • git log --follow is preserved on every relocated file (Phase B was pure git mv — no content edits on moves).
  • No new credentials, no new session-state mutation, no new YAML fields. The 1.17 lazy-Context contract is preserved exactly; the four PEP 562 lazy attributes (Context, RunResult, ExecutionMode, LoadedConfig) still resolve to the same underlying objects.

1.18.1 patch (2026-05-27)

A defect surfaced in v1.18.0 affecting the new core-only install persona: ReservedWordConfig(strategy="rename", ...) raised ImportError when the engine wheel was absent. The ReservedWordConfig validator performed a function-local import through the engine-wheel back-compat shim weevr.operations.reserved_words instead of the canonical core module weevr.reserved_words. Both modules export the same resolve_effective_words symbol, so installs that had both wheels were unaffected — the failure mode was silent until a weevr-core-only caller exercised the rename strategy.

v1.18.1 swaps the import to the canonical core path, restoring the core/engine layer-direction invariant that the workspace split was designed to enforce. A regression test lock now exercises the rename-strategy validator under an in-process weevr.operations import blocker so the violation cannot silently return. No API change; no behavior change for installs with both wheels.

What's next

The new core-only persona is the foundation; consumer adoption is the follow-on work:

  • weevr-cli migrates from hand-written JSON Schemas to from weevr.config import load_config (separate topic, not part of v1.18). Validation will widen to include cross-field validators, filename-stem matching, and the full inheritance cascade that the CLI's schemas could not previously express.
  • Native project documentation generation (per-weave DAG, thread lineage, target contracts) becomes possible without Spark — the planner and warp-discovery surfaces that this feature needs all ship from weevr-core.
  • Stored-run summary rendering (reading serialized telemetry outside the originating notebook) becomes possible on the weevr.telemetry.results/span/trace/events contract types shipped from core.

None of these features ship in 1.18; the wheel split simply removes the install-time blocker that prevented them.