Skip to content

v0.7.0

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Oct 19:12
· 14 commits to main since this release
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 fields bound to an existing field object as non-fields
  • (planning) Add Phase 58, a Fable code review and doc-writer docs pass before the v0.7.0 tag
  • (planning) Record D5, D6 and D7 (56-01)
  • (planning) D7 covers .using() only
  • (query) Resolvable refs now that Query is documented
  • State the sync/async naming rule and guard it (API-05)
  • To_sql() follows .using(); name the not-registered error (56-06)
  • (planning) Phase 56 done
  • A changelog page with the 0.7.0 notes for 0.6 users (API-11)
  • (planning) Phase 57 plans 01-04 done
  • Changelog warns that every filter now refuses None
  • (58) Pre-release review findings (REV-01)
  • Docstrings and pages that described a different design (ARCH-3, 4, 6, 9, COR-3)
  • (planning) Phase 58 progress, REV-01 done
  • Check every page changed since 0.6.1 against the code (REV-03, research and author)
  • Codegen docstrings name SemolinaGeneratedSourceError (ARCH-7)
  • Apply the doc-writer editor and user-tester findings (REV-03)
  • Read a query back through its properties; changelog for ARCH-3 and ARCH-7
  • (planning) Phase 58 done; 0.7.0 waits on adbc-poolhouse 1.6.4
  • (planning) The poolhouse hold is lifted; 57-05 waits on PR #63

馃帹 Styling

  • (databricks) Sort the introspect imports
  • Ruff format the new literal tests
  • Ruff format

馃И Testing

  • Expect every Snowflake/Databricks column aliased to its field name (53-02, red)
  • Expect DuckDB's aliased projection, where_clause routing and order_by refusal (53-03, red)
  • Expect Databricks to order a selected metric by its alias (53-04, red)
  • Re-record Snowflake and Databricks cassettes with aliased columns (53-04)
  • Qualify a bare Snowflake view name from the session (53-04, red)
  • Expect the Snowflake record pool to pin the session database (53-04, red)
  • Record Snowflake introspection of a bare view name (53-04)
  • A plain-field DTO converts on Snowflake and Databricks (53-05, ALIAS-02)
  • Expect codegen-dto to emit no backend alias and metric_result_column_name gone (53-05, red)
  • DuckDB-backed codegen tests expect bare DTO fields (53-05)
  • Read the tracer's nullability claim off the parsed annotations (53-05)
  • (54-01) None in a filter, and .where() refusing a non-predicate
  • (54-02) Lookup values match their wildcards literally
  • (54-04) To_sql() renders each dialect's literals
  • (54-05) Pre-quoted view segments are escaped; a dot inside one raises
  • (54-05) DuckDB introspect honours the schema and quotes the name
  • (54-05) Snowflake introspect quotes each part of the view name
  • (54-05) A ? in a view or column name is not a placeholder
  • (54-05) Every ADBC error is translated, by type before message
  • (54-03) A metric filter compiles to HAVING on the wrapped metric
  • (databricks) Introspect must quote the view name (FILT-05)
  • (integration) HAVING, boolean, NULL and NULLS LAST checks awaiting recording (54-03)
  • (integration) Record HAVING, boolean, NULL and NULLS LAST cassettes (54-03)
  • (jaffle-shop) Delete the live warehouse test now its checks are recorded (54-03)
  • DuckDB where_clause rejects time, UUID and numpy filter values (red)
  • A view named none/true/false generates an invalid class name (red)
  • ORDER BY a metric whose measure name is a select alias (red)
  • DuckDB introspect of a mistyped catalog reads as a connection failure (red)
  • Unbalanced-quote message, CLI ValueError and Snowflake aware-datetime preview (red)
  • --check on a malformed view name exits 1 with an error line
  • Non-ASCII view names keep their letters; between() checks None by identity
  • Values DuckDB used to bind still reach where_clause; numpy datetimes refuse
  • The DTO reader keeps a described field and skips ClassVar and private names
  • A field whose column another select alias shadows orders by its own alias
  • Call the standard rendering directly now DuckDB writes TIMESTAMPTZ
  • DTO underscore hint names the real column; DuckDB shadows ignore case; ZoneInfo times and Field(...) fields
  • DTO codegen names a view the way semolina codegen does (red)
  • A pre-quoted view segment escaped the SQL way is not escaped twice (red)
  • Introspect quotes the session database and schema it fills in (red)
  • A default built by a call other than Field is not read as a DTO field (red)
  • Codegen-dto reports a view name it cannot quote without a traceback (red)
  • Snowflake introspect keeps the db..view default-schema shorthand (red)
  • Text outside a quoted view segment is named as such, not as a dot (red)
  • Render_inline with no params leaves a question mark alone (red)
  • DTO reader follows Field import aliases and Field inside Annotated (red)
  • A reformatted provenance docstring still marks a generated DTO (red)
  • Wrap the reformatted-docstring test under the line limit
  • Expect native Databricks decimals and bound filter values
  • (integration) Record startswith/endswith LIKE ESCAPE filters live
  • (integration) Record HAVING on a quoted lower-case Snowflake measure
  • Name East as well as West in the endswith wildcard docstring
  • East does not end in est, so only West leaks without the escape
  • (integration) Re-record Databricks filter cassettes with bound params
  • (integration) Record Databricks DECIMAL, DATE and bound-parameter checks
  • Cite FILT-07 for the ? in a column name test
  • (codegen) Reproduce non-identifier column names in generated models
  • (codegen) Reproduce case-only collisions and import-shadowing field names
  • (codegen) Failing tests for the validity gate and a loud ruff failure
  • (cli) Failing tests for credential redaction and one exit-code table
  • (codegen) Failing tests for output plumbing
  • (codegen) Failing tests for config paths, env override note, check accuracy
  • (codegen) Turn the --check accuracy corpus into tests
  • (codegen) Failing tests for PR #56 review findings
  • (codegen) Failing tests for PR #56 second-round review findings
  • (codegen) Make the FIFO --output test unable to hang
  • (codegen) Failing tests for temporary-file errors and fd paths in --output
  • (codegen) Databricks driver hint and DUCKDB_DATABASE note for other backends (red)
  • (codegen) Name probed drift when another view's failed probe exits 6 (red)
  • (codegen) Only descriptor paths under /dev and /proc are written in place (red)
  • (codegen) Failing tests for D9 behaviour beyond the corpus
  • (codegen) Dotted file stems and fieldless DTO classes keep their warnings (red)
  • (codegen) Rename tie-breaks; Generic[T] and star-imported bases end the chain (red)
  • (codegen) A parser ValueError and full-width keyword names are refused (red)
  • (codegen) Class-body names resolve in the module; removed inherited fields stay removed (red)
  • (codegen) Base-file star imports, re-exported field classes, method locals (red)
  • (codegen) A subclass named like its imported base; DTO bases in other modules (red)
  • (codegen) Relative same-name base; base-file warnings name the base's module (red)
  • (codegen) Failing tests for Annotated[()], dotted re-exports and field calls in methods
  • (codegen) Failing tests for view-name matching by each engine's identifier rules
  • (codegen) --check on Snowflake checks each spelling of a view against its own class
  • (codegen) Failing test for view-name folding on a dialect with case-sensitive quoting
  • (query) Failing basedpyright tests for builder misuse
  • Failing tests for the public names and all in every module
  • Mark deliberate builder misuse for the type checker
  • Failing tests for a SemolinaError base (D5)
  • Failing tests for the [cli] extra and a light import semolina (D6)
  • Failing tests for SQLDialect and to_sql() following .using() (D7)
  • Failing concurrency tests for the registry
  • Failing tests for introspect without [cli], limit(bool), a broken CLI install
  • Failing tests for semolina.config access, an import bug in the CLI, and a lookup racing unregister
  • Failing check that copied cassettes say so (TEST-02)
  • Copied cassettes and their tests say copied in their names (TEST-02)
  • Failing tests for a retried semantic_views install (TEST-04)
  • Retry the extension install once; run timing tests outside -n auto (TEST-04)
  • The suite collects without duckdb installed (red)
  • A fact query keeps duplicate rows on DuckDB (red, COR-1)
  • A view that does not bind is reported as a connection failure (red, COR-2)
  • Connection failures outside introspect() surface as driver errors (red, ARCH-1)
  • Introspect() returns types defined in the codegen package (red, ARCH-8)
  • Sync and async cursors guard and claim each read identically (ARCH-2)
  • Codegen --check on an unparseable models file (TST-1)
  • Create_async_engine by connection name and without anyio (TST-2)
  • Run each DuckDB where_clause typed literal against the extension (TST-3)
  • Pin the precedence of the exported resolve_column_key (TST-4)
  • CLI output, write and config error paths (TST-5)
  • Typer Exit/Abort and unlisted setup errors in the exit table (TST-6)
  • Static reader robustness on cycles, bad MROs and odd constants (TST-7)
  • DUCKDB_DATABASE naming the committed path prints no note (TST-8)
  • A DBAPI fetch after the result is drained raises (red)
  • A connection failure says "could not connect" twice in the CLI (red)
  • A --backend module in the working directory cannot be imported (red)
  • Every error lives in semolina.exceptions, duplicate columns raise a SemolinaError (red, ARCH-7)
  • Query has no public way to read what it selects (red, ARCH-3)
  • A dialect cannot name its backend, and to_sql() refuses a dialect object (red, ARCH-5)
  • A DuckDB extension-load failure reads as a connection failure, two errors are not exported (red)
  • More concurrent aexecute() calls than pool slots stall until the checkout timeout (red)
  • Snowflake and Databricks keep separate copies of one error mapping; engines lacks SemolinaIntrospectionError (red)

鈿欙笍 Miscellaneous Tasks

  • Auto-merge Dependabot PRs once every check passes
  • Open and merge bot PRs as the GitHub App
  • (duckdb-check) Find the bump target from PyPI and the published binaries
  • (duckdb-check) Defer the bump on probe errors, label the manifest version
  • Bump duckdb pin 1.5.5 -> 1.5.6
  • Remove dead type-ignores; fail on unnecessary ones (API-09)
  • Restore uv.lock revision 5; SemolinaError docs name the classes Semolina defines
  • Type-check the jaffle-shop example; start CI on the duckdb-bump PR (TEST-03, TEST-05)
  • Review nits on the phase 57 changes
  • Review round 2 nits, held for a decision
  • (release) 0.7.0