Conversation
PolarsDatabaseReader and PolarsDatabaseWriter described database I/O with file metadata only (get_file_and_dataframe_metadata on the query or table name), so OpenLineageAdapter(sql_dataset_identity="datasource") could not identify the database and emitted fake FileSystem datasets. Post-1.0 classes now add get_sql_metadata alongside file_metadata, so legacy output is unchanged and datasource mode names the SQLite/Postgres table. The writer unpacks table_name the way Polars does (quote-aware, [[catalog.]schema.]table) so a write resolves to the same dataset as a query reading that table. The pre-1.0 classes keep file metadata and add a connection-less sql_metadata whose note asks datasource users to upgrade to polars>=1.0. Adds the spec under writeups/specs/ and documents the behaviour on the OpenLineageAdapter reference page. Release note: Polars database I/O now also records `sql_metadata`; default-mode OpenLineage users may see the identity `FutureWarning`, silenced by `sql_dataset_identity="legacy"`. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
polars_pre_1_0_0_extension.py falls back to `CsvEncoding = type` when polars.type_aliases lacks it, but never defined `SchemaDefinition`, which PolarsJSONReader annotates its fields with. Python 3.10 to 3.13 evaluate that annotation at import, so importing the module under Polars 1.0 or later raised NameError; Python 3.14's lazy annotations hid it. The new pre-1.0 row-count test imports the module, so CI failed on 3.10 to 3.13 only. Define the same `type` fallback for SchemaDefinition. Make the test fixture that resolves polars' TYPE_CHECKING-only connection names version-independent, since polars 1.44 names them differently from 1.41. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Python 3.14 job resolved fonttools 4.66.1 in the minute it was being uploaded, when only its cp311 and cp312 wheels existed, and failed at `uv sync` before running any test. The wheels are complete now. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…n OpenLineage Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
PolarsDatabaseReaderandPolarsDatabaseWriterdescribed database I/O with file metadata only, soOpenLineageAdapter(sql_dataset_identity="datasource")could not identify the database and emitted fake FileSystem datasets .This PR adds
sql_metadatanext tofile_metadata: legacy mode emits exactly what it did before, and datasource mode names the real table (for examplesqlite://<file>+orders).This does not fully fix #1740, since recognizing more connection types in
get_sql_source(ADBC, connectorx URIs, cursors, Sessions) is not handled.Changes
Detailed changes
Post-1.0 classes (
hamilton/plugins/polars_post_1_0_0_extensions.py)load_dataandsave_datareturn{**get_file_and_dataframe_metadata(...), **get_sql_metadata(..., db_connection=self.connection, operation="read"|"write")}. The adapter checksfile_metadatabeforesql_metadata, so legacy output is unchanged.len(df)only for apl.DataFrame;iter_batches=Truereturns a generator, sorowsisNone. Write row count is theintwrite_databasereturns.get_sql_metadata's row counting is not broadened.table_namethe way Polars does (csv.readerwith.as the delimiter): the last component is the table, the one before it the schema, and a leading catalog is dropped because the connection identifies it.main.orders,"my-tbl"and"a.b"therefore resolve to the same dataset as a query reading that table.file_metadata["path"]keeps the name as given.get_sql_source, which catches errors, and where the new parsing could fail Polars raises first.Pre-1.0 classes (
hamilton/plugins/polars_pre_1_0_0_extension.py)file_metadataand add a connection-lesssql_metadata(sourceisNone) whosenotesreads "Datasource lineage for Polars database I/O requires polars>=1.0; upgrade polars". In datasource mode the adapter emits no dataset and logs the note as a warning.Docs (
docs/reference/lifecycle-hooks/OpenLineageAdapter.rst)dataSourceURI and nosqljob facet, and the write is named after the table.polars>=1.0; older Polars logs an upgrade note and emits no dataset.Tests
tests/plugins/test_h_openlineage.py: a driver run withOpenLineageAdapterin datasource mode asserts the SQLite namespace and name for the write and the read, thesqljob facet, and nostoragefacet. A default-mode run pins the exact legacy namespace, names and facet keys, and fails if the adapter'sfile_metadata/sql_metadatabranches are reordered. The pre-1.0 classes are checked forsource is None, no dataset and the upgrade warning. Qualified and quoted table names are checked for write/read identity agreement. A fixture supplies the names Polars only imports for type checking, because@load_from.databaseand@save_to.databasecannot resolve the class type hints otherwise (this fails onmaintoo).tests/plugins/test_polars_extensions.py: row counts for the plain read, the write and theiter_batches=Trueread, for both the post-1.0 and pre-1.0 classes;file_metadatais still returned; the table and schema the writer records for unqualified, qualified and quoted names.Spec
writeups/specs/2609-01-polars-sql-metadata.mdis the manifest this change was built and verified against.How I tested this
pre-commitis clean.pytest tests/plugins/test_polars_extensions.py tests/plugins/test_polars_lazyframe_extensions.py tests/plugins/test_h_openlineage.py tests/io/test_utils.pygives 122 passed, 1 skipped (the Postgres test that needsHAMILTON_TEST_POSTGRES_URL, skipped onmaintoo).file_metadatafor every Polars database reader and writer were compared againstmainand are identical.Notes
sql_metadata. Default-mode OpenLineage users may see the identityFutureWarning, silenced bysql_dataset_identity="legacy".Follow-up work
Neither item below is needed for this change, and neither is a regression: legacy output is unchanged.
1. Tell the converter when a write target is a literal table name.
sql_datasetscannot tell a table calledINSERT INTO orders SELECT * FROM customersfrom a statement, becauseget_sql_metadataalso accepts statements from custom savers and files them under either key. A write to such a quoted name in datasource mode emitsorders(or nothing forSELECT * FROM orders) instead of the table written, so the write and read identities disagree. The pandasto_sqlwriter behaves the same onmain. The fix belongs at the shared boundary: an explicit marker from the writers that the target is an identifier, honored bysql_datasets, with a metadata version bump and write/read identity regressions for these names. It needs a maintainer's view on the metadata schema, since orchestrator providers reusesql_datasets. Until then the OpenLineage reference page says to give such tables plain names.2. Recognize more connection types in
get_sql_source. ADBC connections, connectorx URIs, Polars cursors and SQLAlchemy sessions are not recognized, so Polars database I/O through them records no datasource and emits no dataset in datasource mode. This is the part of #1740 this PR leaves open.Checklist