fix(ingest/powerbi): recover Databricks lineage lost to three M-Query shapes - #19364
fix(ingest/powerbi): recover Databricks lineage lost to three M-Query shapes#19364puneetagarwal-datahub wants to merge 5 commits into
Conversation
… steps
Redundant parentheses around a navigation step are valid M and refresh
without complaint in Power BI, but the M-Query resolver had no
ParenthesizedExpression case. The walk hit the unhandled-node fallback
and returned, so every table written that way produced no lineage at
all -- silently, since the fallback only logs at debug level.
Unwrap the node and continue the walk, which covers both a bare
`(Source{[Name=..]}[Data])` step and the `then (...)` / `else (...)`
form inside a conditional.
…is absent
A navigation step may omit Kind (`Schema{[Name="t"]}[Data]`), which is
valid M that Power BI refreshes without complaint. Indexing items["Kind"]
raised a bare KeyError that the caller's broad except turned into an
"Unknown M-Query Pattern" warning, so the table lost its lineage and the
report pointed at the pattern rather than the missing key.
Databricks chains are ordered catalog -> schema -> table, so take the
first level the chain has not filled yet. A step with neither Kind nor a
resolvable Name is genuinely unusable: report it as such instead of
raising.
…nnector Value.NativeQuery was recognised for DatabricksMultiCloud.Catalogs but not for plain Databricks.Catalogs, so Azure Databricks native queries bailed out at the is_native_parsing_supported gate with only a debug log. Register the connector and, in the same change, widen get_db_name to accept it. Both connectors take (host, http path, [Database=..., Catalog=...]), so the database resolves the same way -- without that half, the catalog would come back empty and the emitted URN would silently point at a dataset that does not exist. Covers the inline and single-hop source-argument forms. A source argument reached through more than one navigation step is a separate limitation in _get_data_source_tokens and is not addressed here.
… lineage The focused parser test asserts the upstream URN but nothing exercises the emitted MCPs, so a wrong URN shape, a wrong lineage type, or a dropped aspect would pass CI. Use a dedicated mock response and golden rather than extending default_mock_response.json. That fixture is loaded by 34 test invocations, so adding a table there regenerates 13 goldens for roughly 3400 lines of churn -- and it would assert nothing, because test_extract_lineage narrows dataset_type_mapping to four platforms and powerbi.py drops upstreams for any platform outside it. The per-platform fixture and golden pair follows the three existing mysql and ODBC pairs. Verified the golden guards the change: removing Databricks.Catalogs from SUPPORTED_NATIVE_QUERY_DATA_PLATFORM makes it fail.
|
Linear: ING-3347 Thanks for your contribution! We have created an internal ticket to track this PR. A member of the core DataHub team will be assigned to review it within the next few business days - you will get a follow-up comment once a reviewer is assigned. |
PR SummaryOverview The M-Query walker now continues through
Reviewed by Cursor Bugbot for commit 2e9c885. Bugbot is set up for automated code reviews on this repo. Configure here. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Connector Tests ResultsAll connector tests passed for commit To skip connector tests, add the Autogenerated by the connector-tests CI pipeline. |
The leaf-step test does not constrain which level a step in the middle of the chain takes -- it passes even with the catalog/schema/table ordering reversed. Assert the schema step directly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary
Three shapes of valid M-Query silently produced no lineage. Each is a separate defect; all three were reproduced against the real M-Query bridge before fixing.
1. Redundant parentheses around a navigation step
_walkhad noParenthesizedExpressioncase, so it hit the unhandled-node fallback and returned. The parse itself succeeded — only the walk gave up.2. A navigation step written without
Kind=table_detail[items["Kind"]]raised a bareKeyError, which the caller's broadexceptturned into an "Unknown M-Query Pattern" warning — so the report named the pattern rather than the missing key. Databricks chains are ordered catalog → schema → table, so the level now follows from position. A step with neitherKindnor a resolvableNameis genuinely unusable and is reported as such instead of raising.3. Native SQL on the
Databricks.CatalogsconnectorValue.NativeQuerywas registered forDatabricksMultiCloud.Catalogsbut not for plainDatabricks.Catalogs, so Azure Databricks native queries bailed at theis_native_parsing_supportedgate.get_db_nameneeded widening in the same change — both connectors take(host, http path, [Database=…, Catalog=…]), and without that half the catalog comes back empty and the emitted URN points at a dataset that does not exist.Scope
Covers the inline and single-hop source-argument forms of (3). A source argument reached through more than one navigation step is a separate limitation in
_get_data_source_tokens— that one is platform-agnostic (it affects Snowflake identically) and is left to its own PR.Testing
Every fix has a test that was watched failing first, plus a golden integration test asserting the emitted MCPs — table-level upstream and column-level lineage. Verified the golden fails if the
Databricks.Catalogsregistration is removed, so it genuinely guards the change.The golden uses a dedicated mock response rather than extending
default_mock_response.json. That fixture is loaded by 34 test invocations, so adding a table there regenerates 13 goldens for ~3,400 lines of churn — and would assert nothing, becausetest_extract_lineagenarrowsdataset_type_mappingto four platforms andpowerbi.pydrops upstreams for any platform outside it. The per-platform fixture/golden pair follows the three existing mysql and ODBC pairs.363 passed, 1 xfailed· ruff, format and mypy clean · no existing goldens touched.Note for reviewers
This and #19365 both touch
resolver.py— this PR adds theParenthesizedExpressioncase, the other renames the walk's accumulator. Whichever merges second needs a one-block rebase with no logic overlap. Either order is fine.Checklist
Summary by cubic
Recovers Power BI lineage lost to three valid M-Query shapes and enables native SQL lineage on Azure Databricks. Previously: parenthesized navigation steps aborted the walk; Databricks steps without Kind raised and were masked as “Unknown M-Query Pattern”;
Value.NativeQueryonDatabricks.Catalogswas unsupported. Now: the walk unwraps parentheses, Databricks levels are inferred by position (catalog → schema → table), unusable steps warn and skip, and native queries on both Databricks connectors emit correct 3-part URNs.ParenthesizedExpressionhandling in the resolver walk (covers bare(Source{...}[Data])andthen (...)/else (...)).Kindis missing; warns (does not raise) if bothKindandNameare missing.Databricks.Catalogsfor native-query parsing and widens database resolution to handle both connectors; fixes URN catalog resolution.Databricks.Catalogsnative queries, and an added check pinning mid-chain level inference; no existing goldens changed.resolver.py; expect a trivial one-block rebase if concurrent changes land first.Written for commit 2e9c885. Summary will update on new commits.