feat(deps): optional xorq#278
Merged
Merged
Conversation
xorq is removed from core dependencies and moved to an optional
`[xorq]` extra. `pip install boring-semantic-layer` now installs and
works without xorq; core querying, YAML round-trips, and named
profiles all function against plain ibis backends.
Key changes:
- `_xorq.py`: dual-source shim — tries xorq, falls back to plain
ibis equivalents; exposes `HAS_XORQ` flag; provides pure-Python
fallbacks for `to_node`, `walk_nodes`, `replace_nodes`, `from_ibis`
(identity), and a `map_ibis` stub
- `profile.py`: gates XorqProfile path on `HAS_XORQ`; skips xorq_dir
discovery when xorq absent
- `serialization/__init__.py`: guards `from_tagged` with the same
`try_import_xorq()` + ImportError pattern already used in `to_tagged`
- `serialization/tag_handler.py`: guards module-level TagHandler usage
with `HAS_XORQ`; `bsl_tag_handler = None` when xorq absent
- `pyproject.toml`: xorq moved to `[xorq]` optional extra; `dev` gains
`xorq`; new `test-core` extra for xorq-free CI
- CI: adds `test-no-xorq` job that installs without xorq and asserts
the suite passes (xorq tests skip, not error)
- Tests: `importorskip("xorq")` added to 5 files with top-level xorq
imports; fixed xorq-availability detection in two roundtrip test
files; `test_xorq_rebuild.py` importorskip moved before tag_handler
import; `test_dependency_groups.py` updated for new extra structure
Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Gate deploy-docs and release-pypi on test-no-xorq so a xorq-free regression cannot slip through to a PyPI release - Align examples extra floor with the new xorq extra (>=0.3.25) and drop the redundant bare "xorq" pin - Remove explicit pyarrow from test-core; it arrives transitively via ibis-framework[duckdb] and BSL has no direct pyarrow import Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch from `uv pip install --system ".[test-core,mcp]"` to `uv sync --all-extras --no-extra xorq --no-extra examples --no-extra dev` so the no-xorq environment mirrors the full dev install, minus the three extras that directly depend on xorq as a package. - Use `uv run python` / `uv run pytest` consistently (no bare executables). - Drop the hardcoded test path and `-x -q` flags; let pytest discover naturally (same as `make test`) and just ignore the integration suite which requires external services not set up in this job. Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The rolling-window regression test used xorq.api.window, causing a module-level import of xorq and a collection error in the test-no-xorq CI job. ibis.window accepts the same rows=/order_by= arguments, so there is no reason to depend on xorq here. Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Optional extras (xorq, mcp, agent, viz-*) are now installed via --all-extras in CI rather than a boring-semantic-layer[...] bundle in the dev extra, keeping dev as pure developer tooling. Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Use --no-extra xorq --no-extra examples so the test-no-xorq job validates core BSL without those optional dependencies. Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add pytest.importorskip("xorq") at module level so these test files
are skipped cleanly in environments without the xorq extra.
Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
xorq.vendor.ibis is no longer available; use the standard ibis import directly in test_date_filter_fix and demo_bsl_v2. Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- test_dependency_groups: assert dev has tooling (not a self-referential bundle) and that all optional extras exist as top-level keys - test_measure_reference_styles: skip serialization roundtrip test when xorq is not installed Assisted-by: Claude Sonnet 4.6 <noreply@anthropic.com>
os.path.expandvars silently leaves undefined ${VAR} references in place, so
without xorq the plain-ibis connection path turned `database: ${MISSING}` into
a DuckDB file literally named "${MISSING}" instead of failing. Add
_expand_env_vars(), which raises ProfileError on any undefined variable
(matching xorq's strict behavior). Coupled to this PR: the bug only manifests
on the new no-xorq _connect_plain_ibis() path.
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
Two code paths behaved differently when xorq was absent, because the shim's plain-ibis fallbacks don't replicate xorq's runtime semantics: - _rebind_join_backends / _rebind_to_canonical_backend: the try/except ImportError guard never fires now that the shim always provides walk_nodes/relations, so the plain-ibis path rebuilt an equal-but-distinct expression for no benefit. Without xorq there is only one backend, so return the inputs unchanged. - The dimension-only shortcut engaged or not depending on whether xorq was installed: with xorq, from_ibis(proxy) pollutes the tracking proxy so static column extraction fails (shortcut disabled); without xorq it succeeds (shortcut enabled), yielding a different result set for the same query. Dict/string filters resolve through the backend (deferred) and aren't statically introspectable, so they now explicitly disable the shortcut in both environments (tagged __bsl_deferred_resolution__ in query.py). Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
BSL's to_untagged() returns xorq-vendored ibis when xorq is installed, and those expressions reject a plain ibis.window (LegacyWindowBuilder) and can't be compiled by plain ibis.to_sql. Build windows / call to_sql via the established shim idiom `from boring_semantic_layer._xorq import ibis as xibis` (as in expr.py), which is plain ibis without xorq and vendored ibis with it — so the no-xorq job exercises plain ibis and the full job exercises xorq. xorq.window is not functionally different; it's the same ibis code under xorq's namespace, needed only for type identity. Also parametrize the two SQL-generation tests and the two filter-value conversion tests, and assert flavor-agnostically via result.type().is_timestamp(). Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
…fail
Convert the three remaining xorq-only test files from the manual
try/except + @skipif pattern to module-level pytest.importorskip("xorq"),
matching the eleven files that already use it (e.g. test_calc_analyzer.py).
test_dependency_groups.py is intentionally left as-is since it tests the
dependency-group mechanism itself.
Also clarify the projection-pushdown xfail comments: the marker is unconditional
(pushdown is disabled for all backends, not just xorq); the few xpasses under
plain ibis are incidental SQL matches, not the feature working.
Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
This PR introduced a second, near-duplicate test job (test-no-xorq). Collapse both into one matrix over the install extras (full / no-xorq), each running the pytest suite (the no-xorq leg ignores integration, as before). Extract the xorq-only build steps (examples + docs-build + skills-check) into a dedicated build job, since the no-xorq leg can't run them. Update deploy-docs and release-pypi gates to needs: [test, build]. Coverage is preserved — the steps move, nothing is dropped. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
Relock from main's pins so the lockfile diff reflects only the extras restructure (no incidental version bumps), and resync requirements-dev.txt (which was already stale vs main's lock — xorq 0.3.5 listed, 0.3.25 locked). Add a comment on the test-core extra clarifying it is the no-xorq CI leg's baseline test environment, pulled in via 'uv sync --all-extras' to provide a duckdb backend (and pyarrow) without xorq or the examples extra. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
The no-xorq walk_nodes fallback re-implemented a depth-first traversal that already exists, nearly verbatim, in graph_utils.walk_nodes — and was never reached without xorq (its only callers are HAS_XORQ-short-circuited or xorq-gated). Replace it with a raising stub. replace_nodes stays a real delegation to ibis Node.replace since graph_utils.replace_nodes reaches it. Also trim three verbose backend-rebinding comments: the two HAS_XORQ short-circuits duplicated each other (now one points to the other), and the deferred-filter comment dropped the stale tracking-proxy aside. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
The integration tests load BSL query modules that import xorq directly, so the whole directory needs xorq. Move that gate into the test tree (collect_ignore_glob in the integration conftest) instead of a --ignore CLI flag, so both CI legs run a plain `pytest` and the condition lives with the tests that require it. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
Use the dominant 'xorq-vendored ibis' compound-adjective form (lowercase, per codebase convention) in the projection-pushdown test comments. Reword the no-xorq walk_nodes stub comment to explain why it exists (symbol-surface symmetry for the gated function-local imports) rather than just that it never runs. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com>
xorq 0.3.31 drops cityhash, dask, envyaml, geoarrow-types, git-annex, and pythran from its dependency tree and adds xorq-dasher, which slims the lockfile considerably. Update the optional-dependency error-message tests to assert the install extra (boring-semantic-layer[xorq]) and add a subprocess test that exercises the tagged APIs with xorq blocked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e3bb0ac to
e4cbff5
Compare
* test: prefer public ibis APIs in examples * fix: resolve YAML calculated measures against measures first --------- Co-authored-by: boringdata <boringdata@users.noreply.github.com>
Co-authored-by: boringdata <boringdata@users.noreply.github.com>
This was referenced Jun 30, 2026
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.
No description provided.