Repository navigation
Releases: s-layer/semolina
Releases · s-layer/semolina
Release list
v0.7.0
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...
v0.6.1
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
commandparameter - (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...
v0.6.0 Engine Architecture
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
- @anentropic made their first contribution in #33
Full Changelog: v0.4.0...v0.6.0