Skip to content

Releases: s-layer/semolina

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 19:12
e8bd868

Changelog

All notable changes to this project will be documented in this file.

[0.7.0] - 2026-10-16

🚀 Features

  • Codegen-dto emits no backend alias; drop Dialect.metric_result_column_name (53-05)
  • Databricks native decimals and bound filter values (driver >= 0.2.0)
  • (codegen) Implement D9 on both --check commands
  • Public Query, exported builder types, all in every module
  • SemolinaError base for every Semolina error (D5)
  • [breaking] CLI dependencies move to a [cli] extra; import semolina stays light (D6)
  • SQLDialect is the SQL-generation ABC; to_sql() follows .using() (D7)

🐛 Bug Fixes

  • Alias every selected column to its field name on Snowflake and Databricks (53-02)
  • DuckDB projects field names and filters before aggregation; refuse unselected order_by dimensions (53-03)
  • Say DuckDB has no query for an OR across a dimension and a metric (53-03)
  • Order a selected metric by its alias on Databricks (53-04)
  • Complete a short Snowflake view name from the session (53-04)
  • Pin the session database on the Snowflake record pool (53-04)
  • (54-01) == None is IS NULL, other None comparisons raise, .where() checks its arguments
  • (54-02) Escape LIKE wildcards in startswith, endswith and iexact
  • (54-04) To_sql() writes each value as the dialect's SQL literal
  • (54-05) Escape a pre-quoted view segment, refuse a dot inside one
  • (54-05) DuckDB introspect describes the schema-qualified view, quoted
  • (54-05) Snowflake introspect quotes each part of the view name
  • (54-05) Mark value slots where the compiler emits them
  • (54-05) Translate every ADBC introspection error, by type first
  • (54-03) Compile a metric filter to HAVING on the wrapped metric
  • (databricks) Quote the view name in introspect (FILT-05)
  • Render time, UUID and numpy filter values as SQL literals
  • Prefix a generated class name that is a Python keyword
  • Order by the alias when a select alias shadows the metric's measure
  • Report a DuckDB view in a foreign catalog as not found
  • Name an unbalanced view-name quote, catch it in codegen, keep Snowflake preview instants
  • (cli) Report a malformed view name under --check as an error line
  • Keep non-ASCII letters in class names; check between() bounds by identity
  • Render the values DuckDB used to bind into where_clause; refuse numpy datetimes
  • (codegen) The DTO reader keeps a described field and skips ClassVar and private names
  • Order a shadowed column by its own alias on every dialect
  • Four edge cases from review (DTO hint, DuckDB case, ZoneInfo time, Field(...))
  • Name a DTO view entry the way semolina codegen names the view
  • Read a doubled quote in a quoted view segment as the SQL escape
  • Quote the session database and schema introspect fills in on Snowflake
  • Read only a Field(...) call as leaving a DTO field bound
  • Report a view name codegen-dto cannot quote as an error line
  • Keep Snowflake's db..view default-schema shorthand unquoted
  • Name stray text outside a quoted view segment instead of a dot
  • Render_inline with no params returns the SQL unchanged; scope the quoting note per dialect
  • Read Field under an import alias, and a Field call inside Annotated
  • Match the DTO provenance docstring after a formatter reflows it
  • (codegen) Give non-identifier columns valid field names
  • (codegen) Treat type as a soft keyword on every Python version
  • (codegen) Settle field-name collisions ignoring case and reserve module names
  • (codegen) Refuse unusable class names and never emit unparseable source
  • (cli) Redact config errors; one exception-to-exit table for both commands
  • (codegen) Byte-identical stdout and --output, atomic writes, isolated ruff
  • (codegen) Expand ~ in DTO config, announce env override, honest --check
  • (codegen) Refuse import-shadowing class names; exit 6 only on a failed probe
  • (codegen) Derive class names clear of module imports; redact, exit 2, in-place fallback
  • (codegen) Exit 1 on any temporary-file error; write fd paths in place
  • (codegen) Databricks driver hint names dbc install; DUCKDB_DATABASE note only for duckdb
  • (codegen) Write only descriptor paths in place; document ruff defaults
  • (codegen) Read dotted file stems; keep warnings of DTO classes with no readable field
  • (codegen) Generic[T] and star-imported chain-ending bases are skipped without a warning
  • (codegen) NUL bytes on 3.11 and full-width keyword class names are clean errors
  • (codegen) Resolve class-body names in the module; a non-field rebinding removes an inherited field
  • (codegen) Follow re-exports to semolina; star-import exemption reads the base's file; skip method bodies
  • (codegen) A subclass named like its imported base extends the import, not itself
  • (codegen) Base-file warnings name the base's module; share compared_annotation; note namespace packages
  • (codegen) Follow re-exports in dotted annotations; skip methods in the model reader; Annotated[()] compares as text
  • (codegen) --check matches view names by the engine's identifier rules
  • (codegen) Fold quoted view names only on dialects that ignore their case
  • (query) Type the builder's parameters
  • (registry) Lock registry mutations
  • (packaging) Keep the doctest conftest in the package, out of the wheel
  • Introspect() without [cli]; refuse limit(bool); hint on a broken CLI install
  • Semolina.config stays reachable; CLI import bugs keep their traceback; lookups race-safe
  • Import duckdb lazily in the test install helper
  • A DuckDB fact query groups like Snowflake and Databricks (COR-1)
  • A view the warehouse cannot describe is not a connection failure (COR-2)
  • A connection that cannot be opened raises SemolinaConnectionError (ARCH-1)
  • Introspect()'s result types live in semolina.introspection (ARCH-8)
  • A DBAPI fetch after the result is drained returns an empty result
  • Codegen imports a --backend module from the working directory, and says "could not connect" once
  • Every error class lives in semolina.exceptions (ARCH-7)
  • Query reports what it selects through public read-only properties (ARCH-3)
  • Dialects name their backend, one backend table, to_sql takes a dialect (ARCH-5)
  • Name the extension when DuckDB cannot load it; export the two new errors
  • Require adbc-poolhouse 1.6.4, which stops async pools stalling past capacity

💼 Other

  • (ruff) Exclude .planning, as prek already does
  • (deps) Add griffelib for reading committed files in --check

🚜 Refactor

  • Delete the unused WHERE helpers that bypassed the HAVING split
  • (cli) Remove dead cli/utils.py and its tests
  • ARCH-4 shares engine state on a base and lifts introspection out of the methods
  • ARCH-7 imports the engine errors from semolina.exceptions
  • Share the cursors' non-I/O half through a private base (ARCH-2)
  • Snowflake and Databricks share one introspection error translation; engines exports SemolinaIntrospectionError

📚 Documentation

  • (planning) Propose D2, portable result column names (53-01)
  • (planning) Record D2 review answers and the Snowflake/DuckDB comparison
  • (planning) D2 decided as option A; sharpen the where_clause binding gap
  • (planning) 53-01 complete; D2 decided
  • (planning) 53-02 complete; 53-04 lists the integration tests to update
  • DuckDB filter routing, the where_clause binding, and the order_by refusal (53-03)
  • (planning) 53-03 complete; 53-05 also sweeps the warehouse SQL previews
  • (planning) 53-04 live results; regenerate the type-fidelity artifact
  • (planning) D4 live probe for metric filters on both warehouses (53-04)
  • (planning) D4 decided by live measurement: metric filters compile to HAVING (53-04)
  • (planning) Close 53-04; ALIAS-01 met; jaffle-shop live run moves to 54-03
  • Show aliased warehouse SQL and field-name row keys (53-05)
  • (planning) Close 53-05; ALIAS-02..04 met; ALIAS-05 waits on 54-03
  • (54-02) Use a field the guide's model has in the escaping example
  • (54-03) Metric filters are HAVING; the tutorial's OR example runs
  • (planning) Record Phase 54 progress and the recording session it still needs
  • Show the aliased SQL in the SQLBuilder docstring examples
  • Fix the operator-precedence example that now raises
  • [breaking] Say that a quoted view-name segment is written unescaped
  • Describe NULL comparisons and literal LIKE lookups in the Field docstrings
  • Fix the Snowflake render_literal backslash example and merge in_()'s Raises
  • Note that Snowflake and Databricks reject a metric filter in WHERE for now
  • --check no longer drifts across backends for column names alone
  • Say which values to_sql() can't preview, and place the OR/NOT mix note
  • Update pre-53 alias docstrings; warn off QUOTED_IDENTIFIERS_IGNORE_CASE
  • DuckDBSQLBuilder overrides _build_template, not build_select_with_params
  • Say where render_literal is used; drop jaffle-shop's removed Snowflake tests
  • Codegen-dto fields are bare and portable; DuckDB inlines a dimension filter
  • Databricks decimals are Decimal in the tutorials; old-driver symptom; untested bound types
  • (codegen) Describe how codegen names awkward columns
  • (codegen) Note case-insensitive collisions and reserved module names
  • (planning) Start Phase 55; reword GEN-01 after the codegen naming rule
  • (planning) 55-01 done
  • (planning) 55-02 done
  • (planning) 55-03 done
  • (codegen) Document --output, --check reading it, and the new exit 6
  • (planning) 55-04 done; Phase 55 summary for 55-01 to 55-04
  • (planning) Bring D9 to its checkpoint with measured prototypes
  • (codegen) List codegen-dto's exit 1 and 2 cases; "committed file" wording
  • (planning) Phase 55 summary notes the PR #56 review fixes
  • (codegen) Class naming, missing --check file exits 2, in-place write fallback
  • (planning) Phase 55 summary notes the PR #56 round-2 fixes
  • (codegen) What --check reads since D9, and what it accepts
  • (planning) D9 decided (griffe) and 55-06 done; Phase 55 complete
  • (codegen) Note that --check reads field...
Read more

v0.6.1

Choose a tag to compare

@github-actions github-actions released this 14 Oct 13:59
9fd28ad

Changelog

All notable changes to this project will be documented in this file.

[0.6.1] - 2026-10-14

🚀 Features

  • (46-02) Async query path end to end — AsyncEngine, AsyncSemolinaCursor, create_async_engine
  • (46-02) Complete the async cursor result surface and cover close ordering
  • (46-04) Add separate async engine registry with async-aware reset
  • (46-04) Add _Query.aexecute and export the async surface (ASYNC-02)
  • (47-01) Measure one DuckDB decimal metric end to end
  • (47-02) Widen the DuckDB probe to every field and name the disagreements
  • (47-02) Measure the downstream Decimal consumers instead of assuming them
  • (47-03) Probe Snowflake and Databricks result schemas from copied cassettes
  • (47-03) Add the Snowflake and Databricks rows, driver capability, and evidence limits
  • (48-01) DuckDB DECIMAL maps to decimal.Decimal; metrics annotate T | None
  • (48-01) Preserve the raw warehouse type in generated source (D-03)
  • (48-03) Apply the Decimal policy to Snowflake and Databricks (TYPE-03)
  • (48-03) Concrete types for every category-1 map gap (TYPE-05)
  • (48-03) Add the public semolina.JsonValue type alias (TYPE-06)
  • (48-03) Map VARIANT to the JsonValue union (TYPE-06)
  • (48-04) Promote probe_schema and ProbeResult into src/semolina/codegen/probe.py
  • (48-04) Arrow_type_to_python — the Arrow-to-annotation mapper (TYPE-07)
  • (48-05) Read a committed model's annotations without importing it
  • (48-05) Compare committed annotations against the probed result schema
  • (48-05) Wire semolina codegen --check --model with exit code 5
  • (49-01) .into(DTO) on the sync cursor with a structural schema pre-check
  • (49-02) Iter_into — check at the call, produce lazily
  • (49-05) Fetch_df and fetch_polars, guarded for what each actually imports
  • (49-06) Async into and iter_into on AsyncSemolinaCursor
  • (49-06) Async fetch_df / fetch_polars, and the four async guards
  • (49) Respect hand-authored coercions — gate the type check on validate=False
  • (50-02) Generate a typed Pydantic DTO from a query's probed result schema
  • (50-03) Per-class provenance and deferred annotations in generated DTOs
  • (50-06) Add the codegen-dto command and its exit-code epilog
  • (codegen-dto) Generate a DTO from a view, or from pyproject.toml
  • (codegen-dto) Add --check, so a committed DTO can be verified in CI
  • (config) Build, register and scope an engine in one call
  • Support model inheritance and abstract=True bases (52-06)

🐛 Bug Fixes

  • (46) Let aclose() own the reader fetch_record_batch() hands out
  • (46) Stop async iteration cleanly on an already-drained stream
  • (46) Report a failed check-in as a ResourceWarning (WR-01)
  • (46) Guard the undocumented AsyncPool inner-pool access (WR-05)
  • (46) Clear both registries in a finally so reset() cannot strand them (WR-04)
  • (46) Bump duckdb to 1.5.5 for semantic_views 0.12.0, closing the ASYNC-06 gap
  • (47) WR-01 resolve the type-fidelity artifact through milestone archival
  • (47) WR-02 escape table cells so a pipe cannot misalign the circularity guard
  • (47) WR-03 refuse an empty field request instead of emitting a trailing comma
  • (48-01) Refuse DuckDB container types before stripping type parameters
  • (48-02) Render date, datetime and Decimal SQL literals (DBX-04)
  • (48) CR-01 render drift-report cells as Text so rich cannot parse them as markup
  • (48) CR-02 route every semantic_view() name through one shared SQL escaper
  • (48) CR-03 emit warehouse metadata as pre-quoted Python literals in generated models
  • (48) WR-01 compare the field role and the resolved column, not the annotation alone
  • (48) WR-02 guard fetch_record_batch by proxying its reader, not refusing the call
  • (48) WR-03 move probe setup inside the try that promises a fallback, not a crash
  • (48) WR-04 pair each probed schema with its own route and label unprobed rows
  • (48) WR-06 tell a duplicated result column apart from an absent one
  • (48) IN-01 resolve run-end-encoded columns through their value type
  • (48) IN-02 anchor the Snowflake cassette path on the test file, not the cwd
  • (49-07) Make [arrowmodel] extra compose semolina[pyarrow]
  • (49) Make [pandas] extra compose semolina[pyarrow]
  • (50-01) Derive a metric's result-column name from the dialect
  • (50-02) A provenance header can no longer name a backend that did not answer
  • (50-06) Unbreak just docs-build on the dto_codegen module docstring
  • (50) CR-01 validate the generated class name as a Python identifier
  • (50) Upper-case inside the quotes in SnowflakeDialect.metric_result_column_name
  • (50) Map a driver connection failure onto exit 4 in both codegen commands
  • (48) Annotate Databricks decimal and interval as the driver returns (GREEN)
  • (49) CR-01 accept every column key arrowmodel would, not just the first
  • (49) WR-01 refuse AliasChoices / AliasPath at the pre-check
  • (49) WR-02 refuse alias_generator by name, and document all three constructs
  • (49) WR-03 normalise a creation-time OSError in sync iter_into
  • (49) WR-04 close the three holes in the narrowed content fence
  • (49) WR-05 make the path fence runnable, and fatal, in CI
  • (49) IN-01 give the missing-column line its own sentence
  • (49) IN-02 treat a duplicated result column as unresolvable, as the converter does
  • (49) IN-04 list the arrowmodel and pydantic errors, and close the None-description hole
  • (49) IN-06 spell DEFAULT_BASE_REF as the full 40-character SHA
  • (codegen) Let a generated DTO be built from its field names
  • (engines) Drop the registry name only while it still points at this engine
  • (codegen) Refuse a leading-underscore field name with the way out
  • (scope-fence) Skip the base-ref premise check outside CI, fail it inside
  • (release) Compare the wheel's version to the tag as PEP 440, not as a string
  • (results) Make Row copyable, hashable and a real Mapping
  • (query) Compare OrderTerm and query by field identity, not by predicate
  • In_() owns its values, engines validate, no duplicate columns (52-03)
  • Cursor parity — safe close, one read per cursor, pyarrow guards (52-04)
  • Refuse a timestamp column into a date field on the fast path (52-05)
  • Keep a removed field removed down an inheritance chain (52-06)
  • (release) Grant the CI call the permissions ci.yml requests

🚜 Refactor

  • (47) IN-01 delete the unused collect_rows() aggregator
  • (48) WR-01 give FieldCheckRow a detail column for non-annotation drift
  • (50) WR-02 drop render_dtos' unreachable command parameter
  • (codegen) Derive the Arrow annotation from the runtime type

📚 Documentation

  • (planning) Backlog todo — reduce register()/create_engine() redundancy
  • (planning) Refresh async todo with ADBC GIL-release findings
  • (planning) Async machinery belongs in adbc-poolhouse, not Semolina
  • (planning) Anyio posture for Semolina async layer
  • (planning) Async unblocked — adbc-poolhouse 1.5.0 ships the async stack
  • (planning) Backlog todo — arrowmodel typed-DTO integration + scrutiny
  • (planning) Research todo — warehouse type fidelity for field typing
  • (planning) Record untyped-fallback policy on type-fidelity todo
  • (planning) Untypeable-case taxonomy + VARIANT->JsonValue decision
  • (planning) Probe mechanics + timing model on type-fidelity todo
  • Start milestone v0.7 Async & Typed Results
  • Define milestone v0.7 requirements
  • Create milestone v0.7 roadmap (5 phases)
  • Tag 5 pending todos with resolves_phase after milestone v0.7 roadmap
  • Archive v0.5/v0.6 phase directories to milestones/v0.6-phases
  • (planning) Phase 46 context — async engine architecture decisions
  • (46) Research async query surface domain
  • (46) Add validation strategy
  • (46) Create phase plan — 7 plans, 5 waves, tracer-first async query surface
  • (46) Add pattern map
  • (46) Create phase plan
  • (46-01) Complete async packaging and Posture A lint plan
  • (46-02) Complete async engine and cursor plan
  • (46-03) Complete async cassette replay spike plan
  • (46-04) Complete async registry & query entry point plan
  • (46-06) Document async endpoints and async row streaming
  • (46-06) Document the async extra and the async engine surface
  • (46-06) Complete async documentation plan
  • (46-05) Complete cancellation proof and loop-matrix gate plan
  • (46-07) Record the phase gate result and close phase 46
  • (46) Correct the claim that a pre-cancelled aexecute proves check-in
  • (46) Tear the test fixture down with engine.dispose()
  • (46) Name the real adbc-poolhouse floor, 1.6.2
  • (46) Correct STATE.md — phase 46 is executed, not complete
  • (46) Plan 46-08 — gap closure for the unwritten cancellation docs
  • (46) Record gap-closure planning and correct stale STATE.md narrative
  • (46-08) Document timing out a slow query on the async path
  • (46-08) Document client disconnects and cancelling a stream mid-iteration
  • (46-08) Complete cancellation-docs gap-closure plan
  • (phase-46) Complete phase execution
  • (phase-46) Close resolved todos and evolve PROJECT.md
  • (phase-46) Correct plan count on the ROADMAP checkbox line
  • (47) Create phase plan
  • (47) Record planning completion and pattern map
  • (47-01) Complete type-fidelity probe tracer plan
  • (47-02) Complete named-disagreements plan
  • (47-03) Complete the Snowflake, Databricks, and driver-capability plan
  • (47-04) Explain warehouse type fidelity and why money is a Decimal
  • (47-04) Complete the type-mapping decision doc plan
  • (phase-47) Complete phase execution
  • (48) Create phase plan — 6 plans across 4 waves
  • (48) Create phase plan
  • (48-01) Complete type map tracer & renderer seams plan
  • (48-02) Complete databricks date/datetime/Decimal literals plan
  • (48-03) Complete type map implementation plan
  • (48-04) Complete probe promotion and arrow map plan
  • (48-05) Complete the codegen --check plan
  • (48-06) Replace th...
Read more

v0.6.0 Engine Architecture

Choose a tag to compare

@anentropic anentropic released this 25 Jun 20:18

What's Changed

  • chore(deps-dev): bump the dev-dependencies group with 7 updates by @dependabot[bot] in #15
  • chore(deps): bump pyarrow from 23.0.1 to 24.0.0 by @dependabot[bot] in #16
  • chore(deps): bump rich from 14.3.2 to 15.0.0 by @dependabot[bot] in #17
  • chore(deps): bump requests from 2.32.5 to 2.34.0 by @dependabot[bot] in #18
  • chore(deps): bump snowflake-connector-python from 4.4.0 to 4.5.0 by @dependabot[bot] in #19
  • chore(deps): bump requests from 2.32.5 to 2.34.2 by @dependabot[bot] in #21
  • chore(deps): bump typer from 0.24.0 to 0.25.1 by @dependabot[bot] in #22
  • chore(deps): bump adbc-poolhouse from 1.2.0 to 1.3.0 by @dependabot[bot] in #24
  • chore(deps): bump actions/checkout from 6 to 7 in the github-actions group across 1 directory by @dependabot[bot] in #29
  • Gsd/v0.6 milestone by @anentropic in #33
  • v0.5: streaming arrow, codegen polish by @anentropic in #27

New Contributors

Full Changelog: v0.4.0...v0.6.0