Repository navigation
fix: [AI-9453] parse dbt-core 1.11+ manifests and stop downgrading dbt deps - #120
Conversation
…t deps - Add `javascript` to manifest v12 `SupportedLanguage`; dbt-core 1.11+ ships `materialization_function_default` with it, so every 1.11+ manifest failed - `disabled` fallback now nulls the field instead of dropping it; v11/v12 declare it required, so the retry always failed and masked the real error - Relax `click` and `python-dotenv` pins to `<9.0` / `<2.0`; the old `~=` pins downgraded packages dbt-core 1.11+ requires - Add manifest v12 regression tests Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (5 files)
Previous Review Summaries (2 snapshots, latest commit 40f62c3)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 40f62c3)Status: No Issues Found | Recommendation: Merge Files Reviewed (5 files)
Previous review (commit 8b20353)Status: No Issues Found | Recommendation: Merge Files Reviewed (4 files)
Reviewed by gpt-6-sol · Input: 16 · Output: 2.9K · Cached: 293.3K |
`AltimateSupportedLanguage` aliased the manifest v11 enum (python/sql only), so `ManifestV12Wrapper._get_macro` still raised `ValueError` for any project-owned macro supporting JavaScript (e.g. a custom UDF materialization). Alias the v12 enum, a superset of v11, and add a wrapper-level test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sahrizvi
left a comment
There was a problem hiding this comment.
Review summary
Verdict: changes requested. One blocking regression (see the inline comment on schemas/manifest.py). Everything else below is non-blocking.
The dbt 1.11+ fix itself works. The full suite (161 tests) passes on this branch with click 8.5.0, python-dotenv 1.2.4 and pydantic 2.13.5.
Minor
1. Test coverage gaps (tests/test_vendor/test_manifest_v12.py)
- Nothing tests the v10/v11
get_macros()paths. That's how the inline regression got through. - The 1.11 case clones a macro inside an older v12 fixture. A trimmed manifest from a real dbt-core 1.11+/1.12 project, with top-level
functionsanddepends_on.functions, would cover that release's artifact shape. Optional. test_unrelated_errors_still_raisecan't detect error masking. Both parse attempts fail with the samesupported_languageserror, and pydantic reports every error, so the test passes whichever exception_try_parse_manifestraises.
2. Fallback error handling is fragile and silent (src/vendor/dbt_artifacts_parser/parser.py:98-106; this predates the PR, so treat it as a follow-up)
Setting disabled to None fixes the masking failure described in this PR. Two older problems remain. When the retry fails, the retry's error is the one raised; the original survives only as __context__, and except Exception: raise does nothing. When the retry succeeds, an unparseable disabled section is discarded with no log line. Suggested:
except Exception as original:
logger.debug("Manifest parse failed; retrying with %s nulled", _UNUSED_STRICT_FIELDS, exc_info=True)
try:
return model_class(**_strip_unused_fields(manifest))
except Exception:
raise originalNits / optional
setup.py: the newclick>=8.1.7,<9.0andpython-dotenv>=1.0.0,<2.0ranges are correct. A CI job against the lower bounds would be a nice-to-have. Don't tighten the upper bound, because dbt-core 1.11+ needs click>=8.3.schemas/manifest.py:425:Optional[Optional[List[AltimateSupportedLanguage]]]is redundant. This predates the PR._strip_unused_fields: the function now nulls fields instead of stripping them, so_null_unused_fieldswould describe it better.
What's good
- The root-cause write-up is accurate, and the docstring is right: v11/v12 declare
disabledas required but nullable, while v1–v10 default it toNone. Setting it toNoneis safe for every version. - The v12 enum is a strict superset of v11's, and the v12 wrapper already converts by value.
- The change is small and focused, the tests use GIVEN/WHEN/THEN and fail on
main, and relaxing the pins fixes the real dbt env breakage.
| from vendor.dbt_artifacts_parser.parsers.manifest.manifest_v11 import ManifestV11 | ||
| from vendor.dbt_artifacts_parser.parsers.manifest.manifest_v11 import SupportedLanguage | ||
| from vendor.dbt_artifacts_parser.parsers.manifest.manifest_v12 import ManifestV12 | ||
| from vendor.dbt_artifacts_parser.parsers.manifest.manifest_v12 import SupportedLanguage |
There was a problem hiding this comment.
MAJOR: regression for dbt 1.7 (manifest v11) projects with custom materializations
Pointing AltimateSupportedLanguage at the v12 enum breaks the v11 wrapper. ManifestV11Wrapper._get_macro (wrappers/manifest/v11/wrapper.py:184) passes macro.supported_languages (v11 SupportedLanguage members) straight into AltimateManifestMacroNode.supported_languages, whose type is now List[v12.SupportedLanguage]. Pydantic v2 rejects a member of a different Enum class even when the value matches.
Repro: load tests/data/manifest_v11.json, make a macro that has supported_languages project-owned, then call DBTFactory.get_manifest_wrapper(parse_manifest(m)).get_macros().
main: OK,[SupportedLanguage.sql]- this branch:
ValidationError: Input should be 'python', 'sql' or 'javascript' [type=enum, input_value=<SupportedLanguage.sql: 'sql'>, input_type=SupportedLanguage]
DBTInsightGenerator.__init__ (executor.py:63) always calls get_macros(). Project health / governance therefore crashes for any v11 project with a project-owned macro that declares supported_languages, which in practice means any custom materialization. 0.3.7 doesn't have this problem. The failure only needs "sql"; JavaScript plays no part. The v10 wrapper (v10/wrapper.py:184) uses the same pattern and already fails on main, and the same fix covers it.
Suggested fix: in the v10 and v11 wrappers, convert by value as the v12 wrapper already does:
supported_languages=[AltimateSupportedLanguage(lang.value) for lang in macro.supported_languages]
if macro.supported_languages
else None,Add v10 and v11 counterparts of test_wraps_project_macro_supporting_javascript that use ["sql"]. Optionally, make AltimateSupportedLanguage a standalone enum here (python, sql, javascript) so a future vendor bump can't silently change it again.
There was a problem hiding this comment.
Good catch, thanks. I reproduced it on the branch with your steps; both v10 and v11 failed with the same ValidationError (input_value=<SupportedLanguage.sql: 'sql'>).
Fixed in e7d2163: the v10 and v11 wrappers now convert by value (AltimateSupportedLanguage(lang.value)), the same way the v12 wrapper does. Added tests/core/platform/dbt/test_manifest_wrapper_macros.py, parametrized over the v10 and v11 fixtures with a project-owned macro using ["sql"]. Both cases fail on 40f62c3 and pass now.
I kept AltimateSupportedLanguage as an alias of the v12 enum for now. Making it a standalone enum is a reasonable hardening step, and I'm happy to do it here if you'd prefer.
There was a problem hiding this comment.
Verified the fix in e7d2163. Both wrappers now convert by value, and the new parametrized test fails for v10 and v11 when the old wrappers are restored. Resolved. Keeping the alias is fine; the standalone enum can be a follow-up.
- v10/v11 wrappers passed vendored `SupportedLanguage` members straight into `AltimateManifestMacroNode`, now typed with the v12 enum; Pydantic v2 rejects members of another Enum class, so `get_macros()` raised `ValidationError` for any v10/v11 project-owned macro declaring `supported_languages` (v11 regressed in this PR, v10 already failed on `main`) - `_try_parse_manifest` raises the original error when the `disabled`-nulled retry also fails, and logs the retry at debug level - Rename `_strip_unused_fields` to `_null_unused_fields` - Add v10/v11 wrapper tests and replace the masking test with one that can detect masking Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thanks for the thorough review. All changes are in e7d2163:
Full suite: 163 passed. pre-commit (ruff, black, whitespace, EOF, debug-statements) all passed. |
sahrizvi
left a comment
There was a problem hiding this comment.
Re-review (e7d2163)
No blocking issues left. This looks ready to merge. Every finding from the previous round is resolved:
- v10/v11
supported_languagesValidationError: fixed. Both wrappers convert by value, the same way v12 does. Nothing else insrc/datapilotconsumesSupportedLanguage/supported_languages, and v10, v11 and v12 are the only manifest wrappers. - Fallback error handling: fixed. The first failure is logged at debug level, and if the retry also fails the original error is raised.
- Rename to
_null_unused_fields: done, with no stale callers.
Verified: the full suite passes (163 tests). I mutation-checked both new regression tests:
- Restoring the 40f62c3 v10/v11 wrappers makes
test_wraps_project_macro_with_supported_languagesfail for both fixtures. - Changing
raise originalback toraisemakestest_failed_fallback_raises_the_original_errorfail.
Both tests prove what they claim.
The two inline comments are optional nits. Follow-ups are fine for the items you deferred (standalone enum, CI job for the lower bounds, real dbt 1.12 fixture, Optional[Optional[...]]).
| return model_class(**_null_unused_fields(manifest)) | ||
| except Exception: | ||
| raise | ||
| raise original |
There was a problem hiding this comment.
Nit (optional): raising original inside the nested except attaches the retry error as __context__. The traceback prints the retry failure first, then "During handling of the above exception, another exception occurred", and only then the original. It's harmless, and the retry error can be useful context. If you'd prefer a cleaner traceback:
raise original from None| assert parsed.disabled is None | ||
|
|
||
|
|
||
| def test_failed_fallback_raises_the_original_error(): |
There was a problem hiding this comment.
Nit (optional): the stub Model is the right way to prove the "original error wins" contract. Replacing test_unrelated_errors_still_raise did drop the end-to-end check that a real non-disabled validation error (the cobol case) still comes out of parse_manifest, though. Keeping both would cost only a few lines.
Jira: AI-9453
Problem
dbt Power User's Project Governance fails for every project on dbt-core 1.11+, with any datapilot version up to and including 0.3.7.
materialization_function_defaultwithsupported_languages: [sql, python, javascript]. Manifest v12SupportedLanguageonly allowedpython/sql, so parsing failed.disabledfallback dropped the key, but v11/v12 declaredisabledrequired (nullable). The retry therefore always failed withdisabled: Field required, which hid the real error.click~=8.1.7andpython-dotenv~=1.0.0downgrade packages dbt-core 1.11+ requires (click>=8.3,python-dotenv>=1.2), so installing datapilot breaks the user's dbt env.Fix
javascriptto v12SupportedLanguage.AltimateSupportedLanguage(schemas/manifest.py) at the v12 enum instead of v11. OtherwiseManifestV12Wrapper._get_macrostill raisedValueErrorfor any project-owned macro supporting JavaScript, e.g. a custom UDF materialization. v12's enum is a superset of v11's.supported_languagesby value, like v12. Passing vendored enum members to the v12-typed field raisedValidationError(from review).disabledtoNoneinstead of removing it (_null_unused_fields). If the retry also fails, the original error is raised, and the retry is logged at debug level.click>=8.1.7,<9.0andpython-dotenv>=1.0.0,<2.0.tests/test_vendor/test_manifest_v12.pyandtests/core/platform/dbt/test_manifest_wrapper_macros.py(v10/v11).Version bump to 0.3.8 is left to the usual bump PR. Companion PRs pin it: AltimateAI/altimate-backend#7000 (
REQUIRED_VERSION) and AltimateAI/vscode-dbt-power-user#2085 (version check). Publish 0.3.8 to PyPI before the backend PR deploys.Verification
Tests (
python:3.10, latestclick8.5.0 /python-dotenv1.2.4)pre-commit (ruff, black, whitespace, EOF, debug-statements): all passed.
Manifest from dbt-core 1.12.5 (jaffle_shop)
After installing into a dbt-core 1.12.5 venv:
pip check→No broken requirements found, anddbt parseOK.End-to-end in dbt Power User (code-server, dbt-core 1.12.5, local 0.3.8 wheel)
Re-verified after review fixes (damaged env + project JS materialization)
A dbt-core 1.12.5 venv already damaged by 0.3.7 (
click 8.1.8,python-dotenv 1.0.1), with a project macro{% materialization ai9453_js_udf, default, supported_languages=['sql', 'javascript'] %}. Upgrading to 0.3.8 from the extension completed governance, including the JS macro file, with noValueError.🤖 Generated with Claude Code