Unify Python FFI on PyO3 abi3, retire uniffi (5ipk.10)#7
Merged
Conversation
…k.10) quantwave-python was the last uniffi cdylib: it shipped a py3-none wheel while quantwave-plugins and quantwave-backtest-py shipped cp39-abi3. The custom build_unified_wheel.py existed only to reconcile those mismatched tags — the root cause of the 9gek.1 wheel-tag bug class. Port the entire uniffi surface (50 Records, 35 streaming Objects, 1 Enum, 90 exports, 11 declarative macros) to PyO3 abi3. The transform swaps only attributes — every struct/enum/fn/field name is preserved — so the Python-visible surface (getattr(_quantwave, ...)) is byte-identical. The two symbols uniffi re-cased via heck (BullBearHMM->BullBearHmm, OIZonesResult->OiZonesResult) are pinned with #[pyclass(name = ...)]. Now all three crates build cp39-abi3 → the wheel-tag bug is killed at the source and the merge script becomes a trivial abi3 .so bundler (with a uniform-tag assertion guarding against future non-abi3 regressions). Also: - move backtest.rs into quantwave-backtest-py (delete the cross-crate [lib] path = ../quantwave-python/src/backtest.rs) - generate_api_stubs.py: detect streaming classes via #[pyclass] + inner field (honoring name attrs) instead of #[derive(uniffi::Object)] - drop uniffi-bindgen from pyproject build-requires, ci.yml, release.yml - docs: UniFFI -> PyO3 (roadmap, validation) Incremental scope (user decision): single-crate collapse deferred to a fast-follow bead. Validated: gold parity 28/28, options parity + doctests 53/53, unified wheel installs clean (cp39-abi3, 3 abi3 .so, 221 indicators), all 15 CI sanity checks green, rustfmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…i-bindgen Pre-push wheel smoke caught two named uniffi constructors that the blanket `#[uniffi::constructor]` -> `#[new]` transform mis-converted: BullBearHMM:: bull_bear and GaussianHmmFilterPy::from_params. uniffi exposed these named constructors as classmethods (Class.bull_bear()), so they map to `#[staticmethod]`, not `#[new]` (which would only allow Class()). Also remove the now-dead `uniffi-bindgen==0.31.0` install from the local verify path (quantwave_verify.sh, git-hooks/pre-push, verify_cache.py). Verified: BullBearHmm.bull_bear().next() and build_feature_matrix work; full unified-wheel pypi_smoke_test passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…fracdiff) The dynamic top-level population only bound indicators by SLUG (qw.frac_diff), so the native streaming-class and batch-fn names documented as available (qw.FracDiff, qw.fracdiff, qw.rsi, qw.SuperTrend) were missing — a pre-existing gap left when the old hardcoded `class ta:` aliases were replaced by slug-only population. (Confirmed failing identically on main/uniffi, so not a 5ipk.10 regression; surfaced while validating the PyO3 migration.) Restore native-name binding by iterating dir(_quantwave): bind public callables (classes + batch fns) not already defined, skipping result records/errors (_is_internal_symbol) and the deprecated options helpers (_OPTIONS_SYMBOLS stay routed through __getattr__ so qw.bs_call_price still warns). Auto-syncs as new indicators are added. Fixes test_frac_diff.py (3/3). No regressions: gold parity, options deprecation, metadata codegen, streaming readiness all green (97 passed). The 2 remaining talib failures (test_list_functions/test_rsi_callable) are a distinct TA-Lib map-completeness bug, tracked separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
quantwave-pythonwas the last uniffi cdylib: it shipped apy3-nonewheel whilequantwave-pluginsandquantwave-backtest-pyshippedcp39-abi3. The custombuild_unified_wheel.pyexisted only to reconcile those mismatched tags — the root cause of the 9gek.1 wheel-tag bug class.What
Port the entire uniffi surface to PyO3 abi3. The transform swaps only attributes — every struct/enum/fn/field name is preserved — so the Python-visible surface (
getattr(_quantwave, ...)) is byte-identical.#[derive(uniffi::Record)]#[pyclass(get_all)] + Clone#[derive(uniffi::Object)]#[pyclass]+#[pymethods]#[derive(uniffi::Enum)]#[pyclass(eq, eq_int)]#[uniffi::export]#[pyfunction]/#[pymethods]setup_scaffolding!()#[pymodule]registrationTwo symbols uniffi re-cased via
heck(BullBearHMM→BullBearHmm,OIZonesResult→OiZonesResult) are pinned with#[pyclass(name = ...)]. Two named constructors (bull_bear,from_params) map to#[staticmethod](classmethod-style), not#[new].Now all three crates build
cp39-abi3→ the wheel-tag bug is killed at the source, and the merge script becomes a trivial abi3.sobundler with a uniform-tag assertion.Also:
backtest.rsintoquantwave-backtest-py(delete the cross-crate[lib] path).generate_api_stubs.py: detect streaming classes via#[pyclass]+innerfield.uniffi-bindgenfrom pyproject build-requires, CI, release, and local verify scripts.Scope
Incremental "abi3-everywhere first" (per decision): single-crate collapse deferred to a fast-follow bead.
Validation
cp39-abi3, 3 abi3.so, 221 indicators.pypi_smoke_test.pypasses on the unified wheel.Known pre-existing (NOT introduced here)
test_frac_diff.py(2) andtest_python_dx.py::TestTalib::{test_list_functions,test_rsi_callable}(2) fail identically onmain/uniffi — a pre-existing top-level DX/registry binding bug (tracked in a separate bead). Verified against amainworktree build.🤖 Generated with Claude Code