Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-versions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<table>
<tr><th>Version</th><th style="min-width:130px">Dates</th><th>Commits</th><th>Highlights</th></tr>
<tr><td valign="top"><b>v2.22.0</b></td><td valign="top">'26 Jul 15</td><td valign="top" align="right">3</td><td valign="top"><ul><li><b>Python 3.14 support</b>. All three Docker images (API, UI, Flight) build on python:3.14-slim and 3.14 joined the CI matrix; snowflake-connector-python and pyarrow were raised to versions that ship cp314 wheels, since the locked ones had none and the slim image failed building them from source.</li><li><b>sqlglot 30</b>. Constraint moved >=26,&lt;27 to >=30,&lt;31. sqlglot 30 renamed the Select args colliding with Python keywords and made exp.Expr the common base class; the OBSQL translator and pgwire subquery flattening were updated to match. No behavior change, but installs pinning sqlglot 26 must move. pyarrow widened to &lt;26 and structlog to &lt;27.</li><li><b>OSI converter roundtrip fidelity</b> (osi-orionbelt 0.1.1). Metrics whose SQL referenced physical codes rather than display names were dropped on the return trip; colliding dimension names silently overwrote each other; fields with spaces in the display name emitted invalid OBML with no LOSSY warning; and validate_osi crashed on malformed input instead of reporting schema errors.</li></ul></td></tr>
<tr><td valign="top"><b>v2.21.1</b></td><td valign="top">'26 Jul 13</td><td valign="top" align="right">1</td><td valign="top"><ul><li><b>Arrow Flight SQL result cache restored</b>. Flight's cache read/write called a result-codec API removed in 2.20.0, so every Flight query silently missed the cache and never stored a result; Flight now uses the current data-only codec and shares one entry per compiled query with REST and pgwire.</li><li><b>Flight cache hits keep the advertised schema</b>. Empty / all-null results no longer stream null-typed columns on a hit: Flight preserves the exact Arrow schema on write and casts a hit back to the schema advertised in FlightInfo.</li><li><b>Cache key + TTL derivation shared across surfaces</b> via a single layer-clean service module, replacing three copies that could drift (internal refactor, no behavior change).</li></ul></td></tr>
<tr><td valign="top"><b>v2.21.0</b></td><td valign="top">'26 Jul 07</td><td valign="top" align="right">3</td><td valign="top"><ul><li><b>Cross-session content-addressed model cache</b>. Identical OBML loaded into different sessions now compiles once and is shared under a stable content-derived model_id, instead of each session recompiling its own copy under a random id. In admin-curated mode the curated model is compiled once for the process and every user session references it; shared models are refcounted and evicted once no session uses them. Because model_id is part of the result-cache key, identical model plus SQL now shares result-cache entries across sessions too.</li><li><b>Single-model shortcut resolution scoped to protected sessions</b>. In admin-curated single-model mode the top-level shortcut endpoints ignore transient user sessions, so a duplicated per-session copy of the curated model no longer triggers a spurious "multiple models loaded across sessions" error.</li></ul></td></tr>
<tr><td valign="top"><b>v2.20.0</b></td><td valign="top">'26 Jul 06</td><td valign="top" align="right">3</td><td valign="top"><ul><li><b>Ontology Graph rendered from the OBSL ontology</b>. The UI graph is now a rendering of the exported RDF (single source of truth), so it and the ontology can't drift; synthesized row-count measures appear in it, and an Export Onto button downloads the Turtle. New toolbar: rotate-left/right controls and a clearer PNG export.</li><li><b>New ontology predicates</b>. obsl:anchoredTo (grain-anchored counts, a new measure source form) and obsl:referencesColumn (columns an expression measure reads, distinct from declared-columns[] obsl:sourceColumn). Ontology, SHACL, and spec updated together; exported graphs stay SHACL-valid.</li><li><b>Cache stores row data + column schema only</b>. The response envelope (sql, explain, timing, cached, columns) is rebuilt fresh per request, so a cache hit reports the cache read time (not the stale DB time) on every surface and empty/all-null column types survive. format=arrow now returns a length-prefixed frame (JSON envelope + gzip'd Arrow data); JSON/TSV unchanged.</li></ul></td></tr>
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

All notable changes to OrionBelt Semantic Layer are documented here.

## [2.22.0] - 2026-07-15

### Added

- **Python 3.14 support.** All three Docker images (API, UI, Flight) now build on `python:3.14-slim`, and 3.14 joined the CI test matrix alongside 3.12 and 3.13. Reaching it required `snowflake-connector-python` 4.3.0 -> 4.6.0 and `pyarrow` 19.0.1 -> 25.0.0: the previously locked versions had no cp314 wheels, so the slim image tried to build them from source and failed.

### Changed

- **sqlglot 30.** The constraint moved from `>=26.0,<27.0` to `>=30.0,<31.0`. sqlglot 30 renamed the `Select` args that collide with Python keywords (`from` -> `from_`, `with` -> `with_`) and made `exp.Expr` the common base class, so the OBSQL translator (`compiler/sql_translator.py`) and the pgwire federation-subquery flattening (`pgwire/router.py`) were updated to match. No behavior change, but installs pinning sqlglot 26 will need to move.
- **Dependency constraints widened**: `pyarrow` `>=16.0,<20.0` -> `>=16.0,<26.0` (the old cap had no version-specific rationale and blocked the cp314 wheels the 3.14 images need) and `structlog` `>=25.1,<26.0` -> `>=25.1,<27.0`.

### Fixed

- **OSI converter dropped metrics whose SQL referenced physical codes** (`osi-orionbelt` 0.1.1). `OBMLtoOSI` emits metric SQL against the physical code (e.g. `SUM(fact_orders.amount)`), but `OSItoOBML` resolved references by OSI dataset/field name only, so any metric over a data object whose code differed from its display name was dropped on the return trip. References now resolve by both name and physical code, including quoted physical identifiers (a Snowflake/Databricks `"net_amount"` field expression or a `WH.PUBLIC."fact_orders"` source table) that previously fell through to a LOSSY unconverted metric.
- **OSI converter silently overwrote colliding dimension names** (`osi-orionbelt` 0.1.1). `_extract_dimensions` keyed dimensions by bare field name, so the same field name in two datasets (`Orders.date`, `Invoices.date`) meant the second silently replaced the first. The later one is now qualified with its data object and a warning is recorded.
- **OSI converter emitted invalid OBML for fields with spaces in the display name** (`osi-orionbelt` 0.1.1). Resolving a physical code to a display name containing a space spliced `Orders.Net Amount` into the intermediate SQL, which the downstream parsers split on the space, emitting `{[Orders].[Net]} Amount` with no LOSSY warning. Resolved names that are not bare SQL words are now bracket-quoted, and the `dataset.column` parsers accept and unquote bracketed identifiers.
- **`validate_osi` raised `AttributeError` on malformed input** (`osi-orionbelt` 0.1.1). Its semantic loops now guard against datasets and fields that are not lists of dicts, returning schema errors instead of crashing.

## [2.21.1] - 2026-07-13

### Fixed
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ralforion/orionbelt-semantic-layer/blob/main/examples/quickstart_colab.ipynb)

[![GitHub stars](https://img.shields.io/github/stars/ralforion/orionbelt-semantic-layer?style=social)](https://github.com/ralforion/orionbelt-semantic-layer)
[![Version 2.21.1](https://img.shields.io/badge/version-2.21.1-purple.svg)](https://github.com/ralforion/orionbelt-semantic-layer/releases)
[![Version 2.22.0](https://img.shields.io/badge/version-2.22.0-purple.svg)](https://github.com/ralforion/orionbelt-semantic-layer/releases)
[![PyPI](https://img.shields.io/pypi/v/orionbelt-semantic-layer?logo=pypi&logoColor=white)](https://pypi.org/project/orionbelt-semantic-layer/)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: BSL 1.1](https://img.shields.io/badge/License-BSL_1.1-orange.svg)](https://github.com/ralforion/orionbelt-semantic-layer/blob/main/LICENSE)
Expand Down Expand Up @@ -242,7 +242,7 @@ Open [http://localhost:8080/docs](http://localhost:8080/docs) to explore the API
# docker-compose.yml
services:
api:
image: ralforion/orionbelt-semantic-layer-api:2.21.1
image: ralforion/orionbelt-semantic-layer-api:2.22.0
ports: ["8080:8080"]
env_file: .env
volumes:
Expand All @@ -251,7 +251,7 @@ services:
MODEL_FILES: /app/models/my-model.obml.yml

ui:
image: ralforion/orionbelt-semantic-layer-ui:2.21.1
image: ralforion/orionbelt-semantic-layer-ui:2.22.0
ports: ["7860:7860"]
environment:
API_BASE_URL: http://api:8080
Expand All @@ -267,7 +267,7 @@ See [`.env.template`](.env.template) for the full environment variable reference
> - `API_SERVER_HOST` is already `0.0.0.0` inside the container — no override needed.
> - MCP via stdio does not work in Docker. Use the [MCP HTTP client](https://github.com/ralforion/orionbelt-semantic-layer-mcp) for containerized deployments.
> - Mount models to `/app/models` (or any path) and set `MODEL_FILES` (comma-separated paths) to pre-load on startup.
> - For production, pin a version tag (`:2.21.1`) rather than `:latest`.
> - For production, pin a version tag (`:2.22.0`) rather than `:latest`.

### Claude Desktop / MCP

Expand Down
2 changes: 1 addition & 1 deletion integrations/chatgpt-custom-gpt/openapi-gpt-action.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: OrionBelt Semantic Layer
version: 2.21.1
version: 2.22.0
description: >
Compile YAML semantic models (OBML) as analytical SQL across 8 database dialects.
This API runs in single-model mode with a pre-loaded semantic model.
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dev_addr: 127.0.0.1:8080

extra:
obml_version: "1.0"
project_version: "2.21.1"
project_version: "2.22.0"
analytics:
provider: google
property: G-X19K4GX3EX
Expand Down
2 changes: 1 addition & 1 deletion packages/osi-orionbelt/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "osi-orionbelt"
version = "0.1.0"
version = "0.1.1"
description = "Bidirectional OBML <-> OSI (Open Semantic Interchange) converter for OrionBelt semantic models"
license = { text = "Apache-2.0" }
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion packages/osi-orionbelt/src/osi_orionbelt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
validate_osi_ontology,
)

__version__ = "0.1.0"
__version__ = "0.1.1"

__all__ = [
"OBMLtoOSI",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "orionbelt-semantic-layer"
version = "2.21.1"
version = "2.22.0"
description = "OrionBelt Semantic Layer - Compiles and executes YAML semantic models as analytical SQL"
license = {text = "BSL-1.1"}
authors = [{name = "Ralf Becher, RALFORION d.o.o.", email = "info@ralforion.com"}]
Expand Down
2 changes: 1 addition & 1 deletion src/orionbelt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""OrionBelt Semantic Layer — Compiles and executes YAML semantic models as analytical SQL."""

__version__ = "2.21.1"
__version__ = "2.22.0"
40 changes: 40 additions & 0 deletions tests/unit/test_version_consistency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Every package's exported ``__version__`` must match its pyproject version.

A published wheel self-reports through ``<pkg>.__version__``, so a version bump
that updates pyproject.toml but not the module constant ships a wheel whose
metadata and exported version disagree. This has happened: osi-orionbelt 0.1.1
was tagged while the module still exported 0.1.0.

Both packages are checked, because osi-orionbelt is versioned independently of
orionbelt-semantic-layer and is easy to miss when grepping for the main
package's version.
"""

from __future__ import annotations

import tomllib
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).parents[2]

PACKAGES = [
("orionbelt", REPO_ROOT / "pyproject.toml"),
("osi_orionbelt", REPO_ROOT / "packages" / "osi-orionbelt" / "pyproject.toml"),
]


def _pyproject_version(pyproject: Path) -> str:
with pyproject.open("rb") as fh:
return str(tomllib.load(fh)["project"]["version"])


@pytest.mark.parametrize(("module_name", "pyproject"), PACKAGES)
def test_exported_version_matches_pyproject(module_name: str, pyproject: Path) -> None:
module = pytest.importorskip(module_name)
assert module.__version__ == _pyproject_version(pyproject), (
f"{module_name}.__version__ is {module.__version__!r} but "
f"{pyproject.relative_to(REPO_ROOT)} declares "
f"{_pyproject_version(pyproject)!r}. Bump both."
)
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.