Stability & deprecation policy (2.0)¶
As of 2.0, qtviz renews the 1.0 promise: the surface you hold in your head
stays put. 2.0 was the one planned clean break (the Mark IR + uniform
surface, [D121]–[D136], amended pre-publication by [D140]) — 71 names, one
channel vocabulary, one norm spec,
.opts()/show() — and the freeze now pins that surface
(FROZEN_2_0). This page defines exactly what the promise covers and how it
can change.
What is public¶
- Every name in
qtviz.__all__— the elements, composition (Overlay/Layout/View/show), data binding (col/lit/tabular/gridded/stream), styling (Theme/Norm/OverlayOptions/AxisSpec…), events, reactive primitives, and the adapter entry points. The suite pins this list exactly (test_api_freeze.py) — it cannot drift silently. (Typing aliases and internal machinery left the contract in 2.0:Accessor,Expression,ColorSpec,StreamRef,DMapBinding,negotiate,auto_negotiateremain importable from their submodules but are no longer frozen names.) - The extension contracts: the
Backendprotocol (2.0 addshonored_options(),requires_display, and mark drawers), theqtviz.backendsentry-point group ([D125] — a third-party backend registers with zero qtviz edits), theDataRef/TabularRef/GriddedRefcontract (includingmaterialize(max_cells=),window(),subscribe()+version()for live refs), and the typed event dataclasses. Third-party backends and data adapters build on these; see Writing a backend. - Documented behavior contracts: honor-or-warn (§3.4 — a recommended
option is honored or warns, never silently dropped; since 2.0 declared
once per element as
HONORED_NATIVE/HONORED_BY_LOWERINGand proven by the [D123] perturbation guard), capability honesty (a declared capability has a code path), R1 (every coordinate crossing the seam is data space), and legend honesty ([D48]).
What is NOT public¶
- Underscore modules and attributes (
qtviz.core._scales,_renderers,_qtviz_legend, …) — internal, changeable at any time. - The objects returned by
handle.native()/View.native()— the escape valve is stable as an entry point; what it returns is backend-native and non-portable by design ([D53]). - Backend-internal layouts (Plotly figure-dict shapes, pyqtgraph item composition, the webengine bridge protocol).
- The
design/corpus — decisions, not API.
Versioning¶
qtviz follows semver:
- Patch (2.0.x): fixes only, no surface or behavior-contract changes.
- Minor (2.x.0): additive surface (new elements, options, methods) and completed deprecations. Additions update the freeze list + CHANGELOG in the same change.
- Major: anything that breaks the public surface without a deprecation path.
Deprecation path¶
- The name keeps working and emits a
DeprecationWarningnaming its replacement. - It stays for at least two minor releases after the warning first ships.
- Removal lands in a minor release, called out in the CHANGELOG.
Non-fatal behavioral degradation (an option a backend can't honor) is a
QtvizWarning — filterable, and never silent.
Current ledger¶
| Name | Warned since | Removal |
|---|---|---|
| (empty — the 2.0 break cleared the ledger) |
The 1.x ledger for the record: qtviz.Options (warned 0.2.0, removed 1.1)
and the qtwebplot import shim (warned 0.1.0, removed 1.0). The 1.x→2.0
renames — and the [D137] pre-publication amendment — shipped without
deprecation shims: a deliberate one-time exception made while the project was
pre-public with no external users. From the first PyPI publish onward that
exception is dead and the deprecation path above applies in full; the rename
tables are in the 2.0.0 CHANGELOG entry.
The channel vocabulary and by/color_by¶
Two documented rules the vocabulary test enforces
(tests/qtviz/test_channel_vocabulary.py):
- Every data binding is a keyword accessor from the fixed 10-role set
(
x y z u v value by lo hi err) plus the two value→visual encodings (color_by,size_by). A submodule is inqtviz.__all__iff it carries public API not re-exported at top level ([D140]). by=groups rows into series (palette-cycled, one legend entry per category);color_by=encodes a value per point into color (a continuous ramp or categorical mapping). Bars legitimately takes both ([D139]).
Release mechanics¶
Releases ship to PyPI (pip install qtviz) via trusted publishing on a
vX.Y.Z tag, with the docs deployed to GitHub Pages. CI runs ruff, mypy, and
the offscreen suite on every PR; the full gate list (suite, benchmarks, ruff,
mypy, coverage, strict docs build) is release-blocking and recorded in
RELEASING.md.