Compare commits

...

55 Commits

Author SHA1 Message Date
Gerda Shank
9abe9da563 test setting macro_stack starting from materialization macro 2022-09-16 14:40:14 -04:00
Sam Debruyn
b98af4ce17 remove key as reserved keyword from test_bool_or (#5818) 2022-09-15 09:44:25 -05:00
Matthew McKnight
b0f8d3d2f1 [CT-1100] 021_test_concurrency test conversion (#5753)
* init push for 021_test_concurrency conversion

* ref to self, delete old integration tests, core passing locally

* creating base class to send setup to snowflake

* making changes to store all setup in core, todo: remove util changes after 1050 is merged

* swap sql seeds to csv

* white space removal

* rewriting seed to see if it fixes issue in snowflake

* attempt to rewrite file for test in snowflake

* update to main

* remove unneeded variable to seeds

* remove unneeded snowflake specific code
2022-09-14 15:49:36 -05:00
Emily Rockman
6c4577f44e Add config to disable metrics/exposures (#5815)
* first pass adding disabled functionality to metrics and exposures

* first pass at getting metrics disabled

* add unsaved file

* fix up comments

* Delete tmp.csv

* fix test

* add exposure logic, fix merge from main

* change when nodes are added to manifest, finish tests

* add changelog

* removed unused code

* minor cleanup
2022-09-14 14:35:38 -05:00
Matthew McKnight
89ee5962f5 [CT-1050] convert 020_ephemeral_test (#5699)
* init file creation for test_ephemeral conversion

* creating base class to run seed through and pass along to classes to test against

* laid out basic flow of tests, need to finish by figuring out how to handle the assertTrue sections and fix error thats occuring

* added creation and comparison of sql and expected result, seeing issue with extra appended test_ on some and issue with errorhandling regarding expect pass

* working on fixing view structure

* update to expected_sql file

* update to expected_sql file

* directory rename, close on all tests need to fix the test_test_ name change for first two tests and figure out why the new test is calling error instead of skipped in status

* renamed expected_sql to include the test_test_ephemeral style name, organized how models are imported into test classes

* move ephemeral functional test to adapter zone

* trying to include the BaseEphemeralMulti class to send to snowflake

* trying to fix snowflake test

* trying to fix snowflake test

* creation of second Base class to feed into others for testing purposes

* found way to check type of warehouse to make data type change for snowflake

* move seed into fixture, to be able to import it from core for adapter tests

* convert to csv and get test passing in core

* remove snowflake specific stuff from util

* remove whitespace

* update to main
2022-09-14 12:00:02 -05:00
Ian Knox
a096202b28 Complete CLI modeling for Click (#5789) 2022-09-14 10:27:47 -05:00
Stu Kilgore
7da7c2d692 Convert default selectors tests to pytest (#5820) 2022-09-13 11:47:13 -05:00
dependabot[bot]
1db48b3cca Bump python from 3.10.6-slim-bullseye to 3.10.7-slim-bullseye in /docker (#5805)
* Bump python from 3.10.6-slim-bullseye to 3.10.7-slim-bullseye in /docker

Bumps python from 3.10.6-slim-bullseye to 3.10.7-slim-bullseye.

---
updated-dependencies:
- dependency-name: python
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add automated changelog yaml from template for bot PR

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Github Build Bot <buildbot@fishtownanalytics.com>
2022-09-12 10:58:24 -07:00
Chenyu Li
567847a5b0 add a base python job helper class (#5802)
* add a base python job helper class

* fix comment, add changelog

* fix quote for adapters
2022-09-12 10:44:19 -07:00
Sam Debruyn
9894c04d38 fix dead anchor link in PR template (#5814)
* fix dead anchor link in PR template

The link did not go to the anchor directly, now it does

* changelog entry
2022-09-12 11:08:30 -04:00
Callum McCann
b26280d1cf Altering Window Metric Attribute To Match Freshness Tests (#5793)
* changing window spec

* more updates

* adding to v7 json?

* chenyu rules

* updating for formatting

* updating metric deferral test
2022-09-09 16:33:32 -07:00
Callum McCann
cfece2cf51 Renaming Attributes In Metric Spec (#5775)
* making updates - see what fails

* updating tests

* adding timestamp to ok_metric_no_model

* adding changie and fixing description error

* test fixes

* updating schema renderer

* fixing test_yaml_render

* file cleaning and window tests
2022-09-09 14:59:52 -04:00
Stu Kilgore
79da002c3c Fix warnings as errors during tests (#5800)
Added RunResultWarningMessage event to support this change.
2022-09-09 12:50:15 -05:00
Bertjan Broeksema
e3f827513f Remove tmp file after test passed (#5749)
* Remove tmp file after test passed

* Add changelog entry
2022-09-09 11:14:43 -04:00
Gerda Shank
10b2a7e7ff Convert test/integration/074_postgres_unlogged_table_tests (#5752)
* Convert test/integration//074_postgres_unlogged_table_tests

* Remove old test
2022-09-08 16:54:03 -04:00
jared-rimmer
82c8d6a7a8 Add invocation_args_dict to ProviderContext (#5782)
* Add invocation_args_to_dict to ProviderContext

* Change invocation_args_to_dict contextproperty to invocation_args_dict

* Fix invocation_args_dict builtin test

* Add CHANGELOG entry

* Fix formatting
2022-09-08 15:31:40 -04:00
Gerda Shank
c994717cbc Call build_flat_graph in merge_from_artifact (#5786) 2022-09-08 15:30:26 -04:00
Callum McCann
e3452b9a8f Add Window Attribute for Metrics (#5722)
* file changes

* changing to window

* adding test

* adding changie for feature

* fixing commits

* fixing tests

* adding timestamp

* fixing graph unparsed

* changing default value
2022-09-07 10:45:08 -04:00
Aram Panasenco
e95e36d63b Include py.typed in MANIFEST.in (#5703)
This enables packages that install dbt-core from pypi to use mypy.
2022-09-06 22:03:12 -04:00
jared-rimmer
74f7416144 Add extra rm command in make clean to remove all .coverage files (#5759)
* Add extra rm command in make clean to remove all .coverage files

* Add Changie entry
2022-09-06 21:36:35 -04:00
Mila Page
1feeb804f4 Update makefile to match our CI (#5763)
* Add structured logging test and provide CI env vars to integration conditionally.
* Add the crazy inline if make feature and ax unneeded variable

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-09-06 15:42:50 -07:00
Mila Page
0f6e4f0e32 Ct 866/migrate hook tests fixed (#5760)
* Finish converting first test file.
* Finish test conversion.
* Remove old integration hook tests.
* Move location of schema.yml to models directory.
* fix snapshot delete test that was failing
* Add the extra env var check for our CI.
* Add changelog
* Remove naive json flag check and instead force all integration tests to check for environment variables using flag routine.
* Revise the changelog to be more of an explanation.

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-09-06 12:22:29 -07:00
Emily Rockman
2b44c2b456 Convert experimental parser tests (#5772)
* WIP

* fixed up tests

* remove old test
2022-09-06 14:11:22 -05:00
leahwicz
2bb31ade39 Update release-branch-tests.yml (#5767) 2022-09-06 14:46:53 -04:00
Mila Page
0ce12405c0 Move docs in from Jinja. (#5762)
Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-09-06 10:05:05 -07:00
dependabot[bot]
b8c13e05db Bump black from 22.6.0 to 22.8.0 (#5750)
* Bump black from 22.6.0 to 22.8.0

Bumps [black](https://github.com/psf/black) from 22.6.0 to 22.8.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/22.6.0...22.8.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add automated changelog yaml from template for bot PR

* Remove newline

* Delete Dependency-20220901-154946.yaml

* Add automated changelog yaml from template for bot PR

* Delete Dependency-20220906-132643.yaml

* Add automated changelog yaml from template for bot PR

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Github Build Bot <buildbot@fishtownanalytics.com>
Co-authored-by: leahwicz <60146280+leahwicz@users.noreply.github.com>
Co-authored-by: Emily Rockman <emily.rockman@dbtlabs.com>
2022-09-06 11:31:13 -05:00
Emily Rockman
64268d2f9b Fix label selection syntax and trigger (#5754)
* Fix label selection syntax and trigger

* update version
2022-09-06 08:21:21 -05:00
Jeremy Cohen
8c8be68701 Roadmap update (Aug 2022) (#5748)
* Add dbt Core roadmap as of August 2022

* Cody intro

* Florian intro

* Lint my markdown

* add blurb on 1.5+ for Python next steps

* Revert "add blurb on 1.5+ for Python next steps"

This reverts commit 1659a5a727.

* PR feedback, self review

Co-authored-by: Cody Peterson <cody.dkdc2@gmail.com>
Co-authored-by: Florian Eiden <florian.eiden@dbtlabs.com>
2022-09-01 00:31:51 +02:00
Doug Beatty
1df713fee9 Test priority order of profiles directory configuration (#5715)
* Method for capturing standard out during testing (rather than logs)

* Allow dbt exit code assertion to be optional

* Verify priority order to search for profiles.yml configuration

* Updates after pre-commit checks

* Move `run_dbt_and_capture_stdout` into the test case
2022-08-30 17:18:17 -06:00
Gerda Shank
758afd4071 ADR for why we're using betterproto for protobuf (#5726) 2022-08-30 12:58:44 -04:00
Jeremy Cohen
0f9200d356 Update team ownership (#5694) 2022-08-30 15:24:34 +02:00
github-actions[bot]
5f59ff1254 Bumping version to 1.3.0b2 and generate changelog (#5724)
* Bumping version to 1.3.0b2 and generate CHANGELOG

* Remove newlines

* Remove newline

Co-authored-by: Github Build Bot <buildbot@fishtownanalytics.com>
Co-authored-by: leahwicz <60146280+leahwicz@users.noreply.github.com>
2022-08-29 11:11:35 -04:00
dependabot[bot]
49e7bdbef9 Bump mashumaro[msgpack] from 3.0.3 to 3.0.4 in /core (#5649)
* Bump mashumaro[msgpack] from 3.0.3 to 3.0.4 in /core

Bumps [mashumaro[msgpack]](https://github.com/Fatal1ty/mashumaro) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/Fatal1ty/mashumaro/releases)
- [Commits](https://github.com/Fatal1ty/mashumaro/compare/v3.0.3...v3.0.4)

---
updated-dependencies:
- dependency-name: mashumaro[msgpack]
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add automated changelog yaml from template for bot PR

* Remove newline

* Remove newline

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Github Build Bot <buildbot@fishtownanalytics.com>
Co-authored-by: leahwicz <60146280+leahwicz@users.noreply.github.com>
2022-08-25 09:00:46 -04:00
Stu Kilgore
5466fa5575 Add supported languages to materializations (#5695)
* Add supported languages to materializations

* Add changie entry

* Linting

* add more error and only get supported language for materialization macro, update schema

* fix test and add more check

Co-authored-by: Chenyu Li <chenyu.li@dbtlabs.com>
2022-08-24 12:08:16 -07:00
dependabot[bot]
f8f21ee707 Bump python from 3.10.5-slim-bullseye to 3.10.6-slim-bullseye in /docker (#5623)
* Bump python from 3.10.5-slim-bullseye to 3.10.6-slim-bullseye in /docker

Bumps python from 3.10.5-slim-bullseye to 3.10.6-slim-bullseye.

---
updated-dependencies:
- dependency-name: python
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add automated changelog yaml from template for bot PR

* Update Dependency-20220808-132327.yaml

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Github Build Bot <buildbot@fishtownanalytics.com>
Co-authored-by: Chenyu Li <chenyu.li@dbtlabs.com>
2022-08-24 11:20:00 -07:00
Chenyu Li
436737dde5 more complex visit_Call to parse chained command (#5677)
* more complex visit_Call

* add changelog

* traversing all of the tree
2022-08-24 08:02:19 -07:00
Jeremy Cohen
7f8d9a7af9 Check dbt-core version requirements when installing Hub packages (#5651)
* First cut at checking version compat for hub pkgs

* Account for field rename

* Add changelog entry

* Update error message

* Fix unit test

* PR feedback

* Try fixing test

* Edit exception msg

* Expand unit test to include pkg prerelease

* Update core/dbt/deps/registry.py

Co-authored-by: Doug Beatty <44704949+dbeatty10@users.noreply.github.com>

Co-authored-by: Doug Beatty <44704949+dbeatty10@users.noreply.github.com>
2022-08-19 23:13:03 +02:00
Doug Beatty
d80de82316 Update "Homepage" link for dbt-tests-adapter on PyPI (#5678) 2022-08-18 06:27:30 -06:00
Mila Page
0d02446e07 Change postgres name truncation logic to be overridable. (#5656)
* Change postgres name truncation logic to be overridable. Add exception with debugging instructions.

* Add changelog.

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-08-18 00:52:43 -07:00
Chenyu Li
a9e71b3907 fix multiple args for ref and source (#5635)
* fix multiple args for ref and source

* add test for support multi part ref and source
2022-08-17 14:13:32 -07:00
Nathaniel May
739fb98d0e Print more information on log line interop test failures (#5659)
Print more information on log line interop test failures
2022-08-16 21:30:10 +01:00
Elize Papineau
348769fa80 Fix/incremental column precision changes (#5395)
* Only consider schema change when column cannot be expanded

* Add test for column shortening

* Add changelog entry

* Move test from integration to adapter tests

* Remove print statement

* add on_schema_change
2022-08-12 14:54:29 -07:00
ilanbenb
7efb6ab62d Incremental model show reason for on_schema_change fail failures (#5505)
* show reason for schema change failures

When the incremental model fails, I do not get the context I need to easily fix my discrepency.
Adding more info

* Update on_schema_change.sql

Fix identation

* Added changie changes

Added changie changes

* Update on_schema_change.sql

Trim whitespaces

* Update on_schema_change.sql

Log message text  enhancement
2022-08-12 10:07:30 -07:00
Vyacheslav
a3b018fd3b Extended validations for the project names (#5620) 2022-08-10 16:45:42 -07:00
varun-dc
4d6208be64 Use sys.exit instead of exit (#5627)
* Use sys.exit instead of exit

* Add changelog
2022-08-09 10:22:36 -07:00
Gerda Shank
3aab9befcf CT-729 Include schema model config in unrendered config (#5344)
* Pass patch_config_dict to build_config_dict when creating
unrendered_config

* Add test case for unrendered_config

* Changie

* formatting, fix test

* Fix test so unrendered config includes docs config
2022-08-09 12:49:29 -04:00
Léon Stefani
e5ac9df069 Fix postgres handling for unlimited varchars (#5292)
* Fix postgres handling for unlimited varchars

* fix: correctly name varchar

* chore: added changelog entry

* Update .changes/unreleased/Fixes-20220523-103843.yaml

Co-authored-by: Emily Rockman <ebuschang@gmail.com>

Co-authored-by: Emily Rockman <ebuschang@gmail.com>
2022-08-09 09:59:58 -05:00
Emily Rockman
34960d8d61 link changelog to dbt-docs for Docs kind (#5628)
* first pass

* tweaks

* convert to use dbt-docs links in contributors section

* fix eq check

* fix format of contributos prs

* update docs changelog to point back to dbt-docs

* update beta 1.3 docs changelog

* remove optional param

* make issue inclusion conditional on being filled
2022-08-09 09:19:40 -05:00
Callum McCann
94a7cfa58d Adding Metric Helper Functions (#5607)
* Adding helper functions

* adding bad test

* use ResolvedMetricReference

* adding pytest

* adding changie updates

* adding pre-commit changes

Co-authored-by: Chenyu Li <chenyu.li@dbtlabs.com>
2022-08-08 08:37:09 -05:00
Gerda Shank
eb72dbf32a Do not render metrics description field when doing render_data (#5603) 2022-08-05 09:19:46 -04:00
Emily Rockman
9eb411f7b7 bring in new index and add changelog (#5614)
* bring in new index and add changelog

* Update Docs-20220804-134138.yaml
2022-08-04 14:07:18 -05:00
Benoit Perigaud
32415e3659 Add docs as a real node config and support node_color for coloring the DAG (#5397)
* add Optional node_color config in Docs dataclass

* Remove node_color from the original docs config

* Add docs config and input validation

* Handle when docs is both under docs and config.docs

* Add node_color to Docs

* Make docs a Dict to avoid parsing errors

* Make docs a dataclass instead of a Dict

* Fix error when using docs as dataclass

* Simplify generator for the default value

* skeleton for test fixtures

* bump manifest to v7

* + config hierarchy tests

* add show override tests

* update manifest

* Remove node_color from the original docs config

* Add node_color to Docs

* Make docs a Dict to avoid parsing errors

* Make docs a dataclass instead of a Dict

* Simplify generator for the default value

* + config hierarchy tests

* add show override tests

* Fix unit tests

* Add tests in case of incorrect input for node_color

* Rename tests and Fix typos

* Fix functional tests

* Fix issues with remote branch

* Add changie entry

* modify tests to meet standards (#5608)

Co-authored-by: Matt Winkler <matt.winkler@fishtownanalytics.com>
Co-authored-by: Emily Rockman <emily.rockman@dbtlabs.com>
2022-08-03 14:31:30 -05:00
Gerda Shank
7886924c07 Comment out line to generate new manifest in test_previous_version_state.py (#5604) 2022-08-03 14:18:48 -04:00
Emily Rockman
40b55ed65a convert to reusable action (#5565)
* convert to reusable action

* fix branch name

* reimplemented changelog

* update to use workflow

* fix typo

* move def

* inherit secrets

* send in comment/label

* specify GITHUB_TOKEN

* Add automated changelog yaml from template for bot PR

* Delete Dependency-20220801-193810.yaml

* Add automated changelog yaml from template for bot PR

* remove dummy changelog

* remove token

* rename file

* point to main

Co-authored-by: Github Build Bot <buildbot@fishtownanalytics.com>
2022-08-03 11:33:11 -05:00
Emily Rockman
4f5b9e686c Store when default env vars are used in manifest (#5589)
* WIP

* handle defauly env vars

* fix typo

* add changelog

* small fixes

* add constants.py file
2022-08-02 20:53:11 -05:00
238 changed files with 13259 additions and 2412 deletions

View File

@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.3.0b1
current_version = 1.3.0b2
parse = (?P<major>\d+)
\.(?P<minor>\d+)
\.(?P<patch>\d+)

49
.changes/1.3.0-b2.md Normal file
View File

@@ -0,0 +1,49 @@
## dbt-core 1.3.0-b2 - August 29, 2022
### Features
- Add `--defer` flag to dbt compile & dbt docs generate ([#4110](https://github.com/dbt-labs/dbt-core/issues/4110), [#4514](https://github.com/dbt-labs/dbt-core/pull/4514))
- use MethodName.File when value ends with .csv ([#5578](https://github.com/dbt-labs/dbt-core/issues/5578), [#5581](https://github.com/dbt-labs/dbt-core/pull/5581))
- Make `docs` configurable in `dbt_project.yml` and add a `node_color` attribute to change the color of nodes in the DAG ([#5333](https://github.com/dbt-labs/dbt-core/issues/5333), [#5397](https://github.com/dbt-labs/dbt-core/pull/5397))
- Adding ResolvedMetricReference helper functions and tests ([#5567](https://github.com/dbt-labs/dbt-core/issues/5567), [#5607](https://github.com/dbt-labs/dbt-core/pull/5607))
- Check dbt-core version requirements when installing Hub packages ([#5648](https://github.com/dbt-labs/dbt-core/issues/5648), [#5651](https://github.com/dbt-labs/dbt-core/pull/5651))
### Fixes
- Remove the default 256 characters limit on postgres character varying type when no limitation is set ([#5238](https://github.com/dbt-labs/dbt-core/issues/5238), [#5292](https://github.com/dbt-labs/dbt-core/pull/5292))
- Include schema file config in unrendered_config ([#5338](https://github.com/dbt-labs/dbt-core/issues/5338), [#5344](https://github.com/dbt-labs/dbt-core/pull/5344))
- Resolves #5351 - Do not consider shorter varchar cols as schema changes ([#5351](https://github.com/dbt-labs/dbt-core/issues/5351), [#5395](https://github.com/dbt-labs/dbt-core/pull/5395))
- on_shchma_change fail verbosity enhancement ([#5504](https://github.com/dbt-labs/dbt-core/issues/5504), [#5505](https://github.com/dbt-labs/dbt-core/pull/5505))
- Fix error rendering docs block in metrics description ([#5585](https://github.com/dbt-labs/dbt-core/issues/5585), [#5603](https://github.com/dbt-labs/dbt-core/pull/5603))
- Extended validations for the project names ([#5379](https://github.com/dbt-labs/dbt-core/issues/5379), [#5620](https://github.com/dbt-labs/dbt-core/pull/5620))
- Use sys.exit instead of exit ([#5621](https://github.com/dbt-labs/dbt-core/issues/5621), [#5627](https://github.com/dbt-labs/dbt-core/pull/5627))
- Finishing logic upgrade to Redshift for name truncation collisions. ([#5586](https://github.com/dbt-labs/dbt-core/issues/5586), [#5656](https://github.com/dbt-labs/dbt-core/pull/5656))
- multiple args for ref and source ([#5634](https://github.com/dbt-labs/dbt-core/issues/5634), [#5635](https://github.com/dbt-labs/dbt-core/pull/5635))
- Fix Unexpected behavior when chaining methods on dbt-ref'ed/sourced dataframes ([#5646](https://github.com/dbt-labs/dbt-core/issues/5646), [#5677](https://github.com/dbt-labs/dbt-core/pull/5677))
### Docs
- Leverages `docs.node_color` from `dbt-core` to color nodes in the DAG ([dbt-docs/#44](https://github.com/dbt-labs/dbt-docs/issues/44), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
### Under the Hood
- Save use of default env vars to manifest to enable partial parsing in those cases. ([#5155](https://github.com/dbt-labs/dbt-core/issues/5155), [#5589](https://github.com/dbt-labs/dbt-core/pull/5589))
- add more information to log line interop test failures ([#5658](https://github.com/dbt-labs/dbt-core/issues/5658), [#5659](https://github.com/dbt-labs/dbt-core/pull/5659))
- Add supported languages to materializations ([#5569](https://github.com/dbt-labs/dbt-core/issues/5569), [#5695](https://github.com/dbt-labs/dbt-core/pull/5695))
### Dependency
- Bump python from 3.10.5-slim-bullseye to 3.10.6-slim-bullseye in /docker ([#4904](https://github.com/dbt-labs/dbt-core/issues/4904), [#5623](https://github.com/dbt-labs/dbt-core/pull/5623))
- Bump mashumaro[msgpack] from 3.0.3 to 3.0.4 in /core ([#4904](https://github.com/dbt-labs/dbt-core/issues/4904), [#5649](https://github.com/dbt-labs/dbt-core/pull/5649))
### Contributors
- [@Goodkat](https://github.com/Goodkat) ([#5581](https://github.com/dbt-labs/dbt-core/pull/5581), [#5620](https://github.com/dbt-labs/dbt-core/pull/5620))
- [@Ilanbenb](https://github.com/Ilanbenb) ([#5505](https://github.com/dbt-labs/dbt-core/pull/5505))
- [@b-per](https://github.com/b-per) ([#5397](https://github.com/dbt-labs/dbt-core/pull/5397), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
- [@callum-mcdata](https://github.com/callum-mcdata) ([#5607](https://github.com/dbt-labs/dbt-core/pull/5607))
- [@epapineau](https://github.com/epapineau) ([#5395](https://github.com/dbt-labs/dbt-core/pull/5395))
- [@kadero](https://github.com/kadero) ([#4514](https://github.com/dbt-labs/dbt-core/pull/4514))
- [@matt-winkler](https://github.com/matt-winkler) ([#5397](https://github.com/dbt-labs/dbt-core/pull/5397), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
- [@shrodingers](https://github.com/shrodingers) ([#5292](https://github.com/dbt-labs/dbt-core/pull/5292))
- [@sungchun12](https://github.com/sungchun12) ([#5397](https://github.com/dbt-labs/dbt-core/pull/5397), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
- [@varun-dc](https://github.com/varun-dc) ([#5627](https://github.com/dbt-labs/dbt-core/pull/5627))

View File

@@ -0,0 +1,7 @@
kind: Dependency
body: "Bump python from 3.10.5-slim-bullseye to 3.10.6-slim-bullseye in /docker"
time: 2022-08-08T13:23:27.00000Z
custom:
Author: dependabot[bot]
Issue: 4904
PR: 5623

View File

@@ -0,0 +1,7 @@
kind: Dependency
body: "Bump mashumaro[msgpack] from 3.0.3 to 3.0.4 in /core"
time: 2022-08-15T18:27:31.00000Z
custom:
Author: dependabot[bot]
Issue: 4904
PR: 5649

View File

@@ -3,5 +3,5 @@ body: Update dependency inline-source from ^6.1.5 to ^7.2.0
time: 2022-07-28T14:02:58.441963-07:00
custom:
Author: emmyoop
Issue: "5574"
PR: "5577"
Issue: "299"
PR: "291"

View File

@@ -3,5 +3,5 @@ body: Update dependency jest from ^26.2.2 to ^28.1.3
time: 2022-07-28T14:03:29.837274-07:00
custom:
Author: emmyoop
Issue: "5574"
PR: "5577"
Issue: "299"
PR: "291"

View File

@@ -3,5 +3,5 @@ body: Update dependency underscore from ^1.9.0 to ^1.13.4
time: 2022-07-28T14:03:51.123441-07:00
custom:
Author: emmyoop
Issue: "5574"
PR: "5577"
Issue: "299"
PR: "291"

View File

@@ -3,5 +3,5 @@ body: Update dependency webpack-cli from ^3.3.12 to ^4.7.0
time: 2022-07-28T14:04:25.629638-07:00
custom:
Author: emmyoop
Issue: "5574"
PR: "5577"
Issue: "299"
PR: "291"

View File

@@ -3,5 +3,5 @@ body: Update dependency webpack-dev-server from ^3.1.11 to ^4.9.3
time: 2022-07-28T14:04:49.637369-07:00
custom:
Author: emmyoop
Issue: "5574"
PR: "5577"
Issue: "299"
PR: "291"

View File

@@ -4,5 +4,5 @@ body: Searches no longer require perfect matches, and instead consider each word
time: 2022-07-28T14:06:20.371364-07:00
custom:
Author: joellabes
Issue: "5574"
PR: "5577"
Issue: "143"
PR: "145"

View File

@@ -3,5 +3,5 @@ body: Support the renaming of SQL to code happening in dbt-core
time: 2022-07-28T14:08:06.184934-07:00
custom:
Author: jtcohen6 stu-k drewbanin ChenyuLInx
Issue: "5574"
PR: "5577"
Issue: "299"
PR: "292"

View File

@@ -0,0 +1,7 @@
kind: Docs
body: Leverages `docs.node_color` from `dbt-core` to color nodes in the DAG
time: 2022-08-04T13:41:38.669987-05:00
custom:
Author: matt-winkler sungchun12 b-per
Issue: "44"
PR: "281"

View File

@@ -0,0 +1,8 @@
kind: Features
body: Make `docs` configurable in `dbt_project.yml` and add a `node_color` attribute
to change the color of nodes in the DAG
time: 2022-08-03T10:42:30.60624+02:00
custom:
Author: matt-winkler sungchun12 b-per
Issue: "5333"
PR: "5397"

View File

@@ -0,0 +1,7 @@
kind: Features
body: Adding ResolvedMetricReference helper functions and tests
time: 2022-08-04T12:09:36.202919-04:00
custom:
Author: callum-mcdata
Issue: "5567"
PR: "5607"

View File

@@ -0,0 +1,7 @@
kind: Features
body: Check dbt-core version requirements when installing Hub packages
time: 2022-08-15T13:43:12.965143+01:00
custom:
Author: jtcohen6
Issue: "5648"
PR: "5651"

View File

@@ -0,0 +1,8 @@
kind: Fixes
body: Remove the default 256 characters limit on postgres character varying type when
no limitation is set
time: 2022-05-23T10:38:43.392232+02:00
custom:
Author: shrodingers
Issue: "5238"
PR: "5292"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Include schema file config in unrendered_config
time: 2022-06-07T12:30:58.535207-04:00
custom:
Author: gshank
Issue: "5338"
PR: "5344"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: 'Resolves #5351 - Do not consider shorter varchar cols as schema changes'
time: 2022-06-17T19:37:31.885484-07:00
custom:
Author: epapineau
Issue: "5351"
PR: "5395"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: on_shchma_change fail verbosity enhancement
time: 2022-07-20T21:37:46.474241+03:00
custom:
Author: Ilanbenb
Issue: "5504"
PR: "5505"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Fix error rendering docs block in metrics description
time: 2022-08-03T14:42:21.386265-04:00
custom:
Author: gshank
Issue: "5585"
PR: "5603"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Extended validations for the project names
time: 2022-08-05T22:10:22.746830854+02:00
custom:
Author: Goodkat
Issue: "5379"
PR: "5620"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Use sys.exit instead of exit
time: 2022-08-08T11:20:01.838171926-04:00
custom:
Author: varun-dc
Issue: "5621"
PR: "5627"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Finishing logic upgrade to Redshift for name truncation collisions.
time: 2022-08-15T23:04:09.173645-07:00
custom:
Author: versusfacit
Issue: "5586"
PR: "5656"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: multiple args for ref and source
time: 2022-08-16T15:34:01.348339-07:00
custom:
Author: ChenyuLInx
Issue: "5634"
PR: "5635"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Fix Unexpected behavior when chaining methods on dbt-ref'ed/sourced dataframes
time: 2022-08-17T16:36:42.678275-07:00
custom:
Author: ChenyuLInx
Issue: "5646"
PR: "5677"

View File

@@ -0,0 +1,8 @@
kind: Under the Hood
body: Save use of default env vars to manifest to enable partial parsing in those
cases.
time: 2022-08-02T11:29:36.417589-05:00
custom:
Author: emmyoop
Issue: "5155"
PR: "5589"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: add more information to log line interop test failures
time: 2022-08-16T12:20:32.119588+01:00
custom:
Author: nathaniel-may
Issue: "5658"
PR: "5659"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: Add supported languages to materializations
time: 2022-08-22T10:37:39.50743-05:00
custom:
Author: stu-k
Issue: "5569"
PR: "5695"

View File

@@ -0,0 +1,7 @@
kind: Breaking Changes
body: Renaming Metric Spec Attributes
time: 2022-09-06T15:45:21.2769-05:00
custom:
Author: callum-mcdata
Issue: "5774"
PR: "5775"

View File

@@ -0,0 +1,7 @@
kind: "Dependency"
body: "Bump black from 22.6.0 to 22.8.0"
time: 2022-09-06T13:48:58.00000Z
custom:
Author: dependabot[bot]
Issue: 4904
PR: 5750

View File

@@ -0,0 +1,7 @@
kind: "Dependency"
body: "Bump python from 3.10.6-slim-bullseye to 3.10.7-slim-bullseye in /docker"
time: 2022-09-12T00:22:53.00000Z
custom:
Author: dependabot[bot]
Issue: 4904
PR: 5805

View File

@@ -0,0 +1,7 @@
kind: Features
body: Adding the `window` parameter to the metric spec.
time: 2022-08-31T12:13:19.48356-05:00
custom:
Author: callum-mcdata
Issue: "5721"
PR: "5722"

View File

@@ -0,0 +1,7 @@
kind: Features
body: Add invocation args dict to ProviderContext class
time: 2022-09-08T08:13:15.17337+01:00
custom:
Author: jared-rimmer
Issue: "5524"
PR: "5782"

View File

@@ -0,0 +1,7 @@
kind: Features
body: Adds new cli framework
time: 2022-09-08T10:41:49.375734-05:00
custom:
Author: iknox-fa
Issue: "5526"
PR: "5647"

View File

@@ -0,0 +1,7 @@
kind: Features
body: Add enabled config to exposures and metrics
time: 2022-09-13T09:59:24.445918-05:00
custom:
Author: emmyoop
Issue: "5422"
PR: "5815"

View File

@@ -0,0 +1,8 @@
kind: Fixes
body: Include py.typed in MANIFEST.in. This enables packages that install dbt-core
from pypi to use mypy.
time: 2022-08-23T11:26:33.8415455-07:00
custom:
Author: panasenco
Issue: "5703"
PR: "5703"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Removal of all .coverage files when using make clean command
time: 2022-09-03T15:54:09.741554082+01:00
custom:
Author: jared-rimmer
Issue: "5633"
PR: "5759"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Remove temp files generated by unit tests
time: 2022-09-09T09:28:32.590208+02:00
custom:
Author: bbroeksema
Issue: "5631"
PR: "5749"

View File

@@ -0,0 +1,7 @@
kind: Fixes
body: Fix warnings as errors during tests
time: 2022-09-09T09:56:27.90654-05:00
custom:
Author: stu-k
Issue: "5424"
PR: "5800"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: Migrate integration test 014 but also fix the snapshot hard delete test's timezone logic and force all integration tests to run flags.set_from_args to force environment variables are accessible to all integration test threads.
time: 2022-09-05T00:17:49.564534-07:00
custom:
Author: versusfacit
Issue: "5760"
PR: "5760"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: Support dbt-metrics compilation by rebuilding flat_graph
time: 2022-09-08T14:56:44.173322-04:00
custom:
Author: gshank
Issue: "5525"
PR: "5786"

View File

@@ -0,0 +1,8 @@
kind: Under the Hood
body: Reworking the way we define the window attribute of metrics to match freshness
tests
time: 2022-09-08T18:07:31.532608-05:00
custom:
Author: callum-mcdata
Issue: "5722"
PR: "5793"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: Add PythonJobHelper base class in core and add more type checking
time: 2022-09-09T11:52:20.419364-07:00
custom:
Author: ChenyuLInx
Issue: "5802"
PR: "5802"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: Convert default selector tests to pytest
time: 2022-09-12T13:40:00.625912-05:00
custom:
Author: stu-k
Issue: "5728"
PR: "5820"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: The link did not go to the anchor directly, now it does
time: 2022-09-12T14:00:35.899828+02:00
custom:
Author: sdebruyn
Issue: "5813"
PR: "5814"

View File

@@ -0,0 +1,7 @@
kind: Under the Hood
body: remove key as reserved keyword from test_bool_or
time: 2022-09-12T19:03:41.481601+02:00
custom:
Author: sdebruyn
Issue: "5817"
PR: "5818"

View File

@@ -7,14 +7,26 @@ versionExt: md
versionFormat: '## dbt-core {{.Version}} - {{.Time.Format "January 02, 2006"}}'
kindFormat: '### {{.Kind}}'
changeFormat: '- {{.Body}} ([#{{.Custom.Issue}}](https://github.com/dbt-labs/dbt-core/issues/{{.Custom.Issue}}), [#{{.Custom.PR}}](https://github.com/dbt-labs/dbt-core/pull/{{.Custom.PR}}))'
kinds:
- label: Breaking Changes
- label: Features
- label: Fixes
- label: Docs
- label: Under the Hood
- label: Dependencies
- label: Security
- label: Breaking Changes
- label: Features
- label: Fixes
- label: Docs
changeFormat: '- {{.Body}} ([dbt-docs/#{{.Custom.Issue}}](https://github.com/dbt-labs/dbt-docs/issues/{{.Custom.Issue}}), [dbt-docs/#{{.Custom.PR}}](https://github.com/dbt-labs/dbt-docs/pull/{{.Custom.PR}}))'
- label: Under the Hood
- label: Dependencies
changeFormat: '- {{.Body}} ({{if ne .Custom.Issue ""}}[#{{.Custom.Issue}}](https://github.com/dbt-labs/dbt-core/issues/{{.Custom.Issue}}), {{end}}[#{{.Custom.PR}}](https://github.com/dbt-labs/dbt-core/pull/{{.Custom.PR}}))'
- label: Security
changeFormat: '- {{.Body}} ({{if ne .Custom.Issue ""}}[#{{.Custom.Issue}}](https://github.com/dbt-labs/dbt-core/issues/{{.Custom.Issue}}), {{end}}[#{{.Custom.PR}}](https://github.com/dbt-labs/dbt-core/pull/{{.Custom.PR}}))'
newlines:
afterChangelogHeader: 1
afterKind: 1
afterChangelogVersion: 1
beforeKind: 1
endOfVersion: 1
custom:
- key: Author
label: GitHub Username(s) (separated by a single space if multiple)
@@ -23,11 +35,12 @@ custom:
- key: Issue
label: GitHub Issue Number
type: int
minLength: 4
minInt: 1
- key: PR
label: GitHub Pull Request Number
type: int
minLength: 4
minInt: 1
footerFormat: |
{{- $contributorDict := dict }}
{{- /* any names added to this list should be all lowercase for later matching purposes */}}
@@ -39,14 +52,20 @@ footerFormat: |
{{- $authorLower := lower $author }}
{{- /* we only want to include non-core team contributors */}}
{{- if not (has $authorLower $core_team)}}
{{- $pr := $change.Custom.PR }}
{{- /* Docs kind link back to dbt-docs instead of dbt-core PRs */}}
{{- $prLink := $change.Kind }}
{{- if eq $change.Kind "Docs" }}
{{- $prLink = "[dbt-docs/#pr](https://github.com/dbt-labs/dbt-docs/pull/pr)" | replace "pr" $change.Custom.PR }}
{{- else }}
{{- $prLink = "[#pr](https://github.com/dbt-labs/dbt-core/pull/pr)" | replace "pr" $change.Custom.PR }}
{{- end }}
{{- /* check if this contributor has other PRs associated with them already */}}
{{- if hasKey $contributorDict $author }}
{{- $prList := get $contributorDict $author }}
{{- $prList = append $prList $pr }}
{{- $prList = append $prList $prLink }}
{{- $contributorDict := set $contributorDict $author $prList }}
{{- else }}
{{- $prList := list $change.Custom.PR }}
{{- $prList := list $prLink }}
{{- $contributorDict := set $contributorDict $author $prList }}
{{- end }}
{{- end}}
@@ -56,6 +75,6 @@ footerFormat: |
{{- if $contributorDict}}
### Contributors
{{- range $k,$v := $contributorDict }}
- [@{{$k}}](https://github.com/{{$k}}) ({{ range $index, $element := $v }}{{if $index}}, {{end}}[#{{$element}}](https://github.com/dbt-labs/dbt-core/pull/{{$element}}){{end}})
- [@{{$k}}](https://github.com/{{$k}}) ({{ range $index, $element := $v }}{{if $index}}, {{end}}{{$element}}{{end}})
{{- end }}
{{- end }}

60
.github/CODEOWNERS vendored
View File

@@ -16,25 +16,57 @@
# Changes to GitHub configurations including Actions
/.github/ @leahwicz
### LANGUAGE
# Language core modules
/core/dbt/config/ @dbt-labs/core-language
/core/dbt/context/ @dbt-labs/core-language
/core/dbt/contracts/ @dbt-labs/core-language
/core/dbt/deps/ @dbt-labs/core-language
/core/dbt/parser/ @dbt-labs/core-language
/core/dbt/config/ @dbt-labs/core-language
/core/dbt/context/ @dbt-labs/core-language
/core/dbt/contracts/ @dbt-labs/core-language
/core/dbt/deps/ @dbt-labs/core-language
/core/dbt/events/ @dbt-labs/core-language # structured logging
/core/dbt/parser/ @dbt-labs/core-language
# Language misc files
/core/dbt/dataclass_schema.py @dbt-labs/core-language
/core/dbt/hooks.py @dbt-labs/core-language
/core/dbt/node_types.py @dbt-labs/core-language
/core/dbt/semver.py @dbt-labs/core-language
### EXECUTION
# Execution core modules
/core/dbt/events/ @dbt-labs/core-execution @dbt-labs/core-language # eventually remove language but they have knowledge here now
/core/dbt/graph/ @dbt-labs/core-execution
/core/dbt/task/ @dbt-labs/core-execution
/core/dbt/graph/ @dbt-labs/core-execution
/core/dbt/task/ @dbt-labs/core-execution
# Adapter interface, scaffold, Postgres plugin
/core/dbt/adapters @dbt-labs/core-adapters
/core/scripts/create_adapter_plugin.py @dbt-labs/core-adapters
/plugins/ @dbt-labs/core-adapters
# Execution misc files
/core/dbt/compilation.py @dbt-labs/core-execution
/core/dbt/flags.py @dbt-labs/core-execution
/core/dbt/lib.py @dbt-labs/core-execution
/core/dbt/main.py @dbt-labs/core-execution
/core/dbt/profiler.py @dbt-labs/core-execution
/core/dbt/selected_resources.py @dbt-labs/core-execution
/core/dbt/tracking.py @dbt-labs/core-execution
/core/dbt/version.py @dbt-labs/core-execution
# Global project: default macros, including generic tests + materializations
/core/dbt/include/global_project @dbt-labs/core-execution @dbt-labs/core-adapters
### ADAPTERS
# Adapter interface ("base" + "sql" adapter defaults, cache)
/core/dbt/adapters @dbt-labs/core-adapters
# Global project (default macros + materializations), starter project
/core/dbt/include @dbt-labs/core-adapters
# Postgres plugin
/plugins/ @dbt-labs/core-adapters
# Functional tests for adapter plugins
/tests/adapter @dbt-labs/core-adapters
### TESTS
# Overlapping ownership for vast majority of unit + functional tests
# Perf regression testing framework
# This excludes the test project files itself since those aren't specific

20
.github/_README.md vendored
View File

@@ -143,19 +143,21 @@ Some triggers of note that we use:
- Print out all variables you will reference as the first step of a job. This allows for easier debugging. The first job should log all inputs. Subsequent jobs should reference outputs of other jobs, if present.
When possible, generate variables at the top of your workflow in a single place to reference later. This is not always strictly possible since you may generate a value to be used lated mid-workflow.
When possible, generate variables at the top of your workflow in a single place to reference later. This is not always strictly possible since you may generate a value to be used later mid-workflow.
Be sure to use quotes around these logs so special characters are not interpreted.
```yaml
job1:
- name: [DEBUG] Print Variables
- name: "[DEBUG] Print Variables"
run: |
echo "all variables defined as inputs"
echo The last commit sha in the release: ${{ inputs.sha }}
echo The release version number: ${{ inputs.version_number }}
echo The changelog_path: ${{ inputs.changelog_path }}
echo The build_script_path: ${{ inputs.build_script_path }}
echo The s3_bucket_name: ${{ inputs.s3_bucket_name }}
echo The package_test_command: ${{ inputs.package_test_command }}
echo "The last commit sha in the release: ${{ inputs.sha }}"
echo "The release version number: ${{ inputs.version_number }}"
echo "The changelog_path: ${{ inputs.changelog_path }}"
echo "The build_script_path: ${{ inputs.build_script_path }}"
echo "The s3_bucket_name: ${{ inputs.s3_bucket_name }}"
echo "The package_test_command: ${{ inputs.package_test_command }}"
# collect all the variables that need to be used in subsequent jobs
- name: Set Variables
@@ -167,7 +169,7 @@ Some triggers of note that we use:
job2:
needs: [job1]
- name: '[DEBUG] Print Variables'
- name: "[DEBUG] Print Variables"
run: |
echo "all variables defined in job1 > Set Variables > outputs"
echo "important_path: ${{ needs.job1.outputs.important_path }}"

View File

@@ -20,4 +20,4 @@ resolves #
- [ ] I have run this code in development and it appears to resolve the stated issue
- [ ] This PR includes tests, or tests are not required/relevant for this PR
- [ ] I have [opened an issue to add/update docs](https://github.com/dbt-labs/docs.getdbt.com/issues/new/choose), or docs changes are not required/relevant for this PR
- [ ] I have run `changie new` to [create a changelog entry](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#Adding-CHANGELOG-Entry)
- [ ] I have run `changie new` to [create a changelog entry](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#adding-a-changelog-entry)

View File

@@ -28,7 +28,7 @@ name: Bot Changelog
on:
pull_request:
# catch when the PR is opened with the label or when the label is added
types: [opened, labeled]
types: [labeled]
permissions:
contents: write
@@ -48,9 +48,9 @@ jobs:
steps:
- name: Create and commit changelog on bot PR
if: "contains(github.event.pull_request.labels.*.name, ${{ matrix.label }})"
if: ${{ contains(github.event.pull_request.labels.*.name, matrix.label) }}
id: bot_changelog
uses: emmyoop/changie_bot@v1.0
uses: emmyoop/changie_bot@v1.0.1
with:
GITHUB_TOKEN: ${{ secrets.FISHTOWN_BOT_PAT }}
commit_author_name: "Github Build Bot"
@@ -58,4 +58,4 @@ jobs:
commit_message: "Add automated changelog yaml from template for bot PR"
changie_kind: ${{ matrix.changie_kind }}
label: ${{ matrix.label }}
custom_changelog_string: "custom:\n Author: ${{ github.event.pull_request.user.login }}\n Issue: 4904\n PR: ${{ github.event.pull_request.number }}\n"
custom_changelog_string: "custom:\n Author: ${{ github.event.pull_request.user.login }}\n Issue: 4904\n PR: ${{ github.event.pull_request.number }}"

View File

@@ -1,78 +0,0 @@
# **what?**
# Checks that a file has been committed under the /.changes directory
# as a new CHANGELOG entry. Cannot check for a specific filename as
# it is dynamically generated by change type and timestamp.
# This workflow should not require any secrets since it runs for PRs
# from forked repos.
# By default, secrets are not passed to workflows running from
# a forked repo.
# **why?**
# Ensure code change gets reflected in the CHANGELOG.
# **when?**
# This will run for all PRs going into main and *.latest. It will
# run when they are opened, reopened, when any label is added or removed
# and when new code is pushed to the branch. The action will then get
# skipped if the 'Skip Changelog' label is present is any of the labels.
name: Check Changelog Entry
on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
workflow_dispatch:
defaults:
run:
shell: bash
permissions:
contents: read
pull-requests: write
env:
changelog_comment: 'Thank you for your pull request! We could not find a changelog entry for this change. For details on how to document a change, see [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#adding-changelog-entry).'
jobs:
changelog:
name: changelog
if: "!contains(github.event.pull_request.labels.*.name, 'Skip Changelog')"
runs-on: ubuntu-latest
steps:
- name: Check if changelog file was added
# https://github.com/marketplace/actions/paths-changes-filter
# For each filter, it sets output variable named by the filter to the text:
# 'true' - if any of changed files matches any of filter rules
# 'false' - if none of changed files matches any of filter rules
# also, returns:
# `changes` - JSON array with names of all filters matching any of the changed files
uses: dorny/paths-filter@v2
id: filter
with:
token: ${{ secrets.GITHUB_TOKEN }}
filters: |
changelog:
- added: '.changes/unreleased/**.yaml'
- name: Check if comment already exists
uses: peter-evans/find-comment@v1
id: changelog_comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: ${{ env.changelog_comment }}
- name: Create PR comment if changelog entry is missing, required, and does not exist
if: |
steps.filter.outputs.changelog == 'false' &&
steps.changelog_comment.outputs.comment-body == ''
uses: peter-evans/create-or-update-comment@v1
with:
issue-number: ${{ github.event.pull_request.number }}
body: ${{ env.changelog_comment }}
- name: Fail job if changelog entry is missing and required
if: steps.filter.outputs.changelog == 'false'
uses: actions/github-script@v6
with:
script: core.setFailed('Changelog entry required to merge.')

View File

@@ -0,0 +1,40 @@
# **what?**
# Checks that a file has been committed under the /.changes directory
# as a new CHANGELOG entry. Cannot check for a specific filename as
# it is dynamically generated by change type and timestamp.
# This workflow should not require any secrets since it runs for PRs
# from forked repos.
# By default, secrets are not passed to workflows running from
# a forked repo.
# **why?**
# Ensure code change gets reflected in the CHANGELOG.
# **when?**
# This will run for all PRs going into main and *.latest. It will
# run when they are opened, reopened, when any label is added or removed
# and when new code is pushed to the branch. The action will then get
# skipped if the 'Skip Changelog' label is present is any of the labels.
name: Check Changelog Entry
on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
workflow_dispatch:
defaults:
run:
shell: bash
permissions:
contents: read
pull-requests: write
jobs:
changelog:
uses: dbt-labs/actions/.github/workflows/changelog-existence.yml@main
with:
changelog_comment: 'Thank you for your pull request! We could not find a changelog entry for this change. For details on how to document a change, see [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#adding-changelog-entry).'
skip_label: 'Skip Changelog'
secrets: inherit

View File

@@ -39,7 +39,7 @@ jobs:
max-parallel: 1
fail-fast: false
matrix:
branch: [1.0.latest, 1.1.latest, main]
branch: [1.0.latest, 1.1.latest, 1.2.latest, main]
steps:
- name: Call CI workflow for ${{ matrix.branch }} branch

4
.gitignore vendored
View File

@@ -95,3 +95,7 @@ venv/
# vscode
.vscode/
# poetry
pyproject.toml
poetry.lock

View File

@@ -6,7 +6,7 @@ exclude: ^test/
# Force all unspecified python hooks to run python 3.8
default_language_version:
python: python3.8
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks

View File

@@ -4,6 +4,58 @@
- Changes are listed under the (pre)release in which they first appear. Subsequent releases include changes from previous releases.
- "Breaking changes" listed under a version may require action from end users or external maintainers when upgrading to that version.
- Do not edit this file directly. This file is auto-generated using [changie](https://github.com/miniscruff/changie). For details on how to document a change, see [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#adding-changelog-entry)
## dbt-core 1.3.0-b2 - August 29, 2022
### Features
- Add `--defer` flag to dbt compile & dbt docs generate ([#4110](https://github.com/dbt-labs/dbt-core/issues/4110), [#4514](https://github.com/dbt-labs/dbt-core/pull/4514))
- use MethodName.File when value ends with .csv ([#5578](https://github.com/dbt-labs/dbt-core/issues/5578), [#5581](https://github.com/dbt-labs/dbt-core/pull/5581))
- Make `docs` configurable in `dbt_project.yml` and add a `node_color` attribute to change the color of nodes in the DAG ([#5333](https://github.com/dbt-labs/dbt-core/issues/5333), [#5397](https://github.com/dbt-labs/dbt-core/pull/5397))
- Adding ResolvedMetricReference helper functions and tests ([#5567](https://github.com/dbt-labs/dbt-core/issues/5567), [#5607](https://github.com/dbt-labs/dbt-core/pull/5607))
- Check dbt-core version requirements when installing Hub packages ([#5648](https://github.com/dbt-labs/dbt-core/issues/5648), [#5651](https://github.com/dbt-labs/dbt-core/pull/5651))
### Fixes
- Remove the default 256 characters limit on postgres character varying type when no limitation is set ([#5238](https://github.com/dbt-labs/dbt-core/issues/5238), [#5292](https://github.com/dbt-labs/dbt-core/pull/5292))
- Include schema file config in unrendered_config ([#5338](https://github.com/dbt-labs/dbt-core/issues/5338), [#5344](https://github.com/dbt-labs/dbt-core/pull/5344))
- Resolves #5351 - Do not consider shorter varchar cols as schema changes ([#5351](https://github.com/dbt-labs/dbt-core/issues/5351), [#5395](https://github.com/dbt-labs/dbt-core/pull/5395))
- on_shchma_change fail verbosity enhancement ([#5504](https://github.com/dbt-labs/dbt-core/issues/5504), [#5505](https://github.com/dbt-labs/dbt-core/pull/5505))
- Fix error rendering docs block in metrics description ([#5585](https://github.com/dbt-labs/dbt-core/issues/5585), [#5603](https://github.com/dbt-labs/dbt-core/pull/5603))
- Extended validations for the project names ([#5379](https://github.com/dbt-labs/dbt-core/issues/5379), [#5620](https://github.com/dbt-labs/dbt-core/pull/5620))
- Use sys.exit instead of exit ([#5621](https://github.com/dbt-labs/dbt-core/issues/5621), [#5627](https://github.com/dbt-labs/dbt-core/pull/5627))
- Finishing logic upgrade to Redshift for name truncation collisions. ([#5586](https://github.com/dbt-labs/dbt-core/issues/5586), [#5656](https://github.com/dbt-labs/dbt-core/pull/5656))
- multiple args for ref and source ([#5634](https://github.com/dbt-labs/dbt-core/issues/5634), [#5635](https://github.com/dbt-labs/dbt-core/pull/5635))
- Fix Unexpected behavior when chaining methods on dbt-ref'ed/sourced dataframes ([#5646](https://github.com/dbt-labs/dbt-core/issues/5646), [#5677](https://github.com/dbt-labs/dbt-core/pull/5677))
### Docs
- Leverages `docs.node_color` from `dbt-core` to color nodes in the DAG ([dbt-docs/#44](https://github.com/dbt-labs/dbt-docs/issues/44), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
### Under the Hood
- Save use of default env vars to manifest to enable partial parsing in those cases. ([#5155](https://github.com/dbt-labs/dbt-core/issues/5155), [#5589](https://github.com/dbt-labs/dbt-core/pull/5589))
- add more information to log line interop test failures ([#5658](https://github.com/dbt-labs/dbt-core/issues/5658), [#5659](https://github.com/dbt-labs/dbt-core/pull/5659))
- Add supported languages to materializations ([#5569](https://github.com/dbt-labs/dbt-core/issues/5569), [#5695](https://github.com/dbt-labs/dbt-core/pull/5695))
### Dependency
- Bump python from 3.10.5-slim-bullseye to 3.10.6-slim-bullseye in /docker ([#4904](https://github.com/dbt-labs/dbt-core/issues/4904), [#5623](https://github.com/dbt-labs/dbt-core/pull/5623))
- Bump mashumaro[msgpack] from 3.0.3 to 3.0.4 in /core ([#4904](https://github.com/dbt-labs/dbt-core/issues/4904), [#5649](https://github.com/dbt-labs/dbt-core/pull/5649))
### Contributors
- [@Goodkat](https://github.com/Goodkat) ([#5581](https://github.com/dbt-labs/dbt-core/pull/5581), [#5620](https://github.com/dbt-labs/dbt-core/pull/5620))
- [@Ilanbenb](https://github.com/Ilanbenb) ([#5505](https://github.com/dbt-labs/dbt-core/pull/5505))
- [@b-per](https://github.com/b-per) ([#5397](https://github.com/dbt-labs/dbt-core/pull/5397), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
- [@callum-mcdata](https://github.com/callum-mcdata) ([#5607](https://github.com/dbt-labs/dbt-core/pull/5607))
- [@epapineau](https://github.com/epapineau) ([#5395](https://github.com/dbt-labs/dbt-core/pull/5395))
- [@kadero](https://github.com/kadero) ([#4514](https://github.com/dbt-labs/dbt-core/pull/4514))
- [@matt-winkler](https://github.com/matt-winkler) ([#5397](https://github.com/dbt-labs/dbt-core/pull/5397), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
- [@shrodingers](https://github.com/shrodingers) ([#5292](https://github.com/dbt-labs/dbt-core/pull/5292))
- [@sungchun12](https://github.com/sungchun12) ([#5397](https://github.com/dbt-labs/dbt-core/pull/5397), [dbt-docs/#281](https://github.com/dbt-labs/dbt-docs/pull/281))
- [@varun-dc](https://github.com/varun-dc) ([#5627](https://github.com/dbt-labs/dbt-core/pull/5627))
## dbt-core 1.3.0-b1 - July 29, 2022
### Features
- Python model inital version ([#5261](https://github.com/dbt-labs/dbt-core/issues/5261), [#5421](https://github.com/dbt-labs/dbt-core/pull/5421))
@@ -42,6 +94,7 @@
- [@leoebfolsom](https://github.com/leoebfolsom) ([#5295](https://github.com/dbt-labs/dbt-core/pull/5295))
- [@nicholasyager](https://github.com/nicholasyager) ([#5393](https://github.com/dbt-labs/dbt-core/pull/5393))
- [@tomasfarias](https://github.com/tomasfarias) ([#5432](https://github.com/dbt-labs/dbt-core/pull/5432))
## Previous Releases
For information on prior major and minor releases, see their changelogs:

View File

@@ -7,7 +7,9 @@
3. [Setting up an environment](#setting-up-an-environment)
4. [Running `dbt` in development](#running-dbt-core-in-development)
5. [Testing dbt-core](#testing)
6. [Submitting a Pull Request](#submitting-a-pull-request)
6. [Debugging](#debugging)
7. [Adding a changelog entry](#adding-a-changelog-entry)
8. [Submitting a Pull Request](#submitting-a-pull-request)
## About this document
@@ -21,7 +23,8 @@ If you get stuck, we're happy to help! Drop us a line in the `#dbt-core-developm
- **Adapters:** Is your issue or proposed code change related to a specific [database adapter](https://docs.getdbt.com/docs/available-adapters)? If so, please open issues, PRs, and discussions in that adapter's repository instead. The sole exception is Postgres; the `dbt-postgres` plugin lives in this repository (`dbt-core`).
- **CLA:** Please note that anyone contributing code to `dbt-core` must sign the [Contributor License Agreement](https://docs.getdbt.com/docs/contributor-license-agreements). If you are unable to sign the CLA, the `dbt-core` maintainers will unfortunately be unable to merge any of your Pull Requests. We welcome you to participate in discussions, open issues, and comment on existing ones.
- **Branches:** All pull requests from community contributors should target the `main` branch (default). If the change is needed as a patch for a minor version of dbt that has already been released (or is already a release candidate), a maintainer will backport the changes in your PR to the relevant "latest" release branch (`1.0.latest`, `1.1.latest`, ...)
- **Branches:** All pull requests from community contributors should target the `main` branch (default). If the change is needed as a patch for a minor version of dbt that has already been released (or is already a release candidate), a maintainer will backport the changes in your PR to the relevant "latest" release branch (`1.0.latest`, `1.1.latest`, ...). If an issue fix applies to a release branch, that fix should be first committed to the development branch and then to the release branch (rarely release-branch fixes may not apply to `main`).
- **Releases**: Before releasing a new minor version of Core, we prepare a series of alphas and release candidates to allow users (especially employees of dbt Labs!) to test the new version in live environments. This is an important quality assurance step, as it exposes the new code to a wide variety of complicated deployments and can surface bugs before official release. Releases are accessible via pip, homebrew, and dbt Cloud.
## Getting the code
@@ -41,7 +44,9 @@ If you are not a member of the `dbt-labs` GitHub organization, you can contribut
### dbt Labs contributors
If you are a member of the `dbt-labs` GitHub organization, you will have push access to the `dbt-core` repo. Rather than forking `dbt-core` to make your changes, just clone the repository, check out a new branch, and push directly to that branch.
If you are a member of the `dbt-labs` GitHub organization, you will have push access to the `dbt-core` repo. Rather than forking `dbt-core` to make your changes, just clone the repository, check out a new branch, and push directly to that branch. Branch names should be fixed by `CT-XXX/` where:
* CT stands for 'core team'
* XXX stands for a JIRA ticket number
## Setting up an environment
@@ -151,7 +156,7 @@ Check out the other targets in the Makefile to see other commonly used test
suites.
#### `pre-commit`
[`pre-commit`](https://pre-commit.com) takes care of running all code-checks for formatting and linting. Run `make dev` to install `pre-commit` in your local environment. Once this is done you can use any of the linter-based make targets as well as a git pre-commit hook that will ensure proper formatting and linting.
[`pre-commit`](https://pre-commit.com) takes care of running all code-checks for formatting and linting. Run `make dev` to install `pre-commit` in your local environment (we recommend running this command with a python virtual environment active). This command installs several pip executables including black, mypy, and flake8. Once this is done you can use any of the linter-based make targets as well as a git pre-commit hook that will ensure proper formatting and linting.
#### `tox`
@@ -174,7 +179,29 @@ python3 -m pytest tests/functional/sources
> See [pytest usage docs](https://docs.pytest.org/en/6.2.x/usage.html) for an overview of useful command-line options.
## Adding CHANGELOG Entry
### Unit, Integration, Functional?
Here are some general rules for adding tests:
* unit tests (`test/unit` & `tests/unit`) dont need to access a database; "pure Python" tests should be written as unit tests
* functional tests (`test/integration` & `tests/functional`) cover anything that interacts with a database, namely adapter
* *everything in* `test/*` *is being steadily migrated to* `tests/*`
## Debugging
1. The logs for a `dbt run` have stack traces and other information for debugging errors (in `logs/dbt.log` in your project directory).
2. Try using a debugger, like `ipdb`. For pytest: `--pdb --pdbcls=IPython.terminal.debugger:pdb`
3. Sometimes, its easier to debug on a single thread: `dbt --single-threaded run`
4. To make print statements from Jinja macros: `{{ log(msg, info=true) }}`
5. You can also add `{{ debug() }}` statements, which will drop you into some auto-generated code that the macro wrote.
6. The dbt “artifacts” are written out to the target directory of your dbt project. They are in unformatted json, which can be hard to read. Format them with:
> python -m json.tool target/run_results.json > run_results.json
### Assorted development tips
* Append `# type: ignore` to the end of a line if you need to disable `mypy` on that line.
* Sometimes flake8 complains about lines that are actually fine, in which case you can put a comment on the line such as: # noqa or # noqa: ANNN, where ANNN is the error code that flake8 issues.
* To collect output for `CProfile`, run dbt with the `-r` option and the name of an output file, i.e. `dbt -r dbt.cprof run`. If you just want to profile parsing, you can do: `dbt -r dbt.cprof parse`. `pip` install `snakeviz` to view the output. Run `snakeviz dbt.cprof` and output will be rendered in a browser window.
## Adding a CHANGELOG Entry
We use [changie](https://changie.dev) to generate `CHANGELOG` entries. **Note:** Do not edit the `CHANGELOG.md` directly. Your modifications will be lost.
@@ -186,8 +213,10 @@ You don't need to worry about which `dbt-core` version your change will go into.
## Submitting a Pull Request
A `dbt-core` maintainer will review your PR. They may suggest code revision for style or clarity, or request that you add unit or integration test(s). These are good things! We believe that, with a little bit of help, anyone can contribute high-quality code.
Code can be merged into the current development branch `main` by opening a pull request. A `dbt-core` maintainer will review your PR. They may suggest code revision for style or clarity, or request that you add unit or integration test(s). These are good things! We believe that, with a little bit of help, anyone can contribute high-quality code.
Automated tests run via GitHub Actions. If you're a first-time contributor, all tests (including code checks and unit tests) will require a maintainer to approve. Changes in the `dbt-core` repository trigger integration tests against Postgres. dbt Labs also provides CI environments in which to test changes to other adapters, triggered by PRs in those adapters' repositories, as well as periodic maintenance checks of each adapter in concert with the latest `dbt-core` code changes.
Once all tests are passing and your PR has been approved, a `dbt-core` maintainer will merge your changes into the active development branch. And that's it! Happy developing :tada:
Sometimes, the content license agreement auto-check bot doesn't find a user's entry in its roster. If you need to force a rerun, add `@cla-bot check` in a comment on the pull request.

View File

@@ -6,6 +6,19 @@ ifeq ($(USE_DOCKER),true)
DOCKER_CMD := docker-compose run --rm test
endif
LOGS_DIR := ./logs
# Optional flag to invoke tests using our CI env.
# But we always want these active for structured
# log testing.
CI_FLAGS =\
DBT_TEST_USER_1=dbt_test_user_1\
DBT_TEST_USER_2=dbt_test_user_2\
DBT_TEST_USER_3=dbt_test_user_3\
RUSTFLAGS="-D warnings"\
LOG_DIR=./logs\
DBT_LOG_FORMAT=json
.PHONY: dev
dev: ## Installs dbt-* packages in develop mode along with development dependencies.
@\
@@ -48,13 +61,20 @@ test: .env ## Runs unit tests with py and code checks against staged changes.
.PHONY: integration
integration: .env ## Runs postgres integration tests with py-integration
@\
$(DOCKER_CMD) tox -e py-integration -- -nauto
$(if $(USE_CI_FLAGS), $(CI_FLAGS)) $(DOCKER_CMD) tox -e py-integration -- -nauto
.PHONY: integration-fail-fast
integration-fail-fast: .env ## Runs postgres integration tests with py-integration in "fail fast" mode.
@\
$(DOCKER_CMD) tox -e py-integration -- -x -nauto
.PHONY: interop
interop: clean
@\
mkdir $(LOGS_DIR) && \
$(CI_FLAGS) $(DOCKER_CMD) tox -e py-integration -- -nauto && \
LOG_DIR=$(LOGS_DIR) cargo run --manifest-path test/interop/log_parsing/Cargo.toml
.PHONY: setup-db
setup-db: ## Setup Postgres database with docker-compose for system testing.
@\
@@ -76,6 +96,7 @@ endif
clean: ## Resets development environment.
@echo 'cleaning repo...'
@rm -f .coverage
@rm -f .coverage.*
@rm -rf .eggs/
@rm -f .env
@rm -rf .tox/

View File

@@ -1 +1,2 @@
recursive-include dbt/include *.py *.sql *.yml *.html *.md .gitkeep .gitignore
include dbt/py.typed

View File

@@ -0,0 +1,10 @@
## Base adapters
### impl.py
The class `SQLAdapter` in [base/imply.py](https://github.com/dbt-labs/dbt-core/blob/main/core/dbt/adapters/base/impl.py) is a (mostly) abstract object that adapter objects inherit from. The base class scaffolds out methods that every adapter project usually should implement for smooth communication between dbt and database.
Some target databases require more or fewer methods--it all depends on what the warehouse's featureset is.
Look into the class for function-level comments.

View File

@@ -10,5 +10,5 @@ from dbt.adapters.base.relation import ( # noqa
SchemaSearchMap,
)
from dbt.adapters.base.column import Column # noqa
from dbt.adapters.base.impl import AdapterConfig, BaseAdapter # noqa
from dbt.adapters.base.impl import AdapterConfig, BaseAdapter, PythonJobHelper # noqa
from dbt.adapters.base.plugin import AdapterPlugin # noqa

View File

@@ -60,6 +60,7 @@ from dbt.adapters.base.relation import (
SchemaSearchMap,
)
from dbt.adapters.base import Column as BaseColumn
from dbt.adapters.base import Credentials
from dbt.adapters.cache import RelationsCache, _make_key
@@ -127,6 +128,35 @@ def _relation_name(rel: Optional[BaseRelation]) -> str:
return str(rel)
def log_code_execution(code_execution_function):
# decorator to log code and execution time
if code_execution_function.__name__ != "submit_python_job":
raise ValueError("this should be only used to log submit_python_job now")
def execution_with_log(*args):
self = args[0]
connection_name = self.connections.get_thread_connection().name
fire_event(CodeExecution(conn_name=connection_name, code_content=args[2]))
start_time = time.time()
response = code_execution_function(*args)
fire_event(
CodeExecutionStatus(
status=response._message, elapsed=round((time.time() - start_time), 2)
)
)
return response
return execution_with_log
class PythonJobHelper:
def __init__(self, parsed_model: Dict, credential: Credentials) -> None:
raise NotImplementedError("PythonJobHelper is not implemented yet")
def submit(self, compiled_code: str) -> Any:
raise NotImplementedError("PythonJobHelper submit function is not implemented yet")
class BaseAdapter(metaclass=AdapterMeta):
"""The BaseAdapter provides an abstract base class for adapters.
@@ -1182,9 +1212,37 @@ class BaseAdapter(metaclass=AdapterMeta):
return sql
@property
def python_submission_helpers(self) -> Dict[str, Type[PythonJobHelper]]:
raise NotImplementedError("python_submission_helpers is not specified")
@property
def default_python_submission_method(self) -> str:
raise NotImplementedError("default_python_submission_method is not specified")
@available.parse_none
def submit_python_job(self, parsed_model: dict, compiled_code: str):
raise NotImplementedException("`submit_python_job` is not implemented for this adapter!")
@log_code_execution
def submit_python_job(self, parsed_model: dict, compiled_code: str) -> AdapterResponse:
submission_method = parsed_model["config"].get(
"submission_method", self.default_python_submission_method
)
if submission_method not in self.python_submission_helpers:
raise NotImplementedError(
"Submission method {} is not supported for current adapter".format(
submission_method
)
)
job_helper = self.python_submission_helpers[submission_method](
parsed_model, self.connections.profile.credentials
)
submission_result = job_helper.submit(compiled_code)
# process submission result to generate adapter response
return self.generate_python_submission_response(submission_result)
def generate_python_submission_response(self, submission_result: Any) -> AdapterResponse:
raise NotImplementedException(
"Your adapter need to implement generate_python_submission_response"
)
def valid_incremental_strategies(self):
"""The set of standard builtin strategies which this adapter supports out-of-the-box.
@@ -1274,24 +1332,3 @@ def catch_as_completed(
# exc is not None, derives from Exception, and isn't ctrl+c
exceptions.append(exc)
return merge_tables(tables), exceptions
def log_code_execution(code_execution_function):
# decorator to log code and execution time
if code_execution_function.__name__ != "submit_python_job":
raise ValueError("this should be only used to log submit_python_job now")
def execution_with_log(*args):
self = args[0]
connection_name = self.connections.get_thread_connection().name
fire_event(CodeExecution(conn_name=connection_name, code_content=args[2]))
start_time = time.time()
response = code_execution_function(*args)
fire_event(
CodeExecutionStatus(
status=response._message, elapsed=round((time.time() - start_time), 2)
)
)
return response
return execution_with_log

View File

@@ -1,3 +1,4 @@
import re
import threading
from copy import deepcopy
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple
@@ -413,9 +414,24 @@ class RelationsCache:
:raises InternalError: If the new key is already present.
"""
if new_key in self.relations:
# Tell user when collision caused by model names truncated during
# materialization.
match = re.search("__dbt_backup|__dbt_tmp$", new_key.identifier)
if match:
truncated_model_name_prefix = new_key.identifier[: match.start()]
message_addendum = (
"\n\nName collisions can occur when the length of two "
"models' names approach your database's builtin limit. "
"Try restructuring your project such that no two models "
"share the prefix '{}'.".format(truncated_model_name_prefix)
+ " Then, clean your warehouse of any removed models."
)
else:
message_addendum = ""
dbt.exceptions.raise_cache_inconsistent(
"in rename, new key {} already in cache: {}".format(
new_key, list(self.relations.keys())
"in rename, new key {} already in cache: {}{}".format(
new_key, list(self.relations.keys()), message_addendum
)
)

1
core/dbt/cli/README.md Normal file
View File

@@ -0,0 +1 @@
TODO

0
core/dbt/cli/__init__.py Normal file
View File

384
core/dbt/cli/main.py Normal file
View File

@@ -0,0 +1,384 @@
import click
from dbt.cli import params as p
import sys
# This is temporary for RAT-ing
import inspect
from pprint import pformat as pf
# dbt
@click.group(
invoke_without_command=True,
no_args_is_help=True,
epilog="Specify one of these sub-commands and you can find more help from there.",
)
@click.pass_context
@p.version
@p.cache_selected_only
@p.debug
@p.fail_fast
@p.log_format
@p.partial_parse
@p.print
@p.printer_width
@p.quiet
@p.send_anonymous_usage_stats
@p.static_parser
@p.use_colors
@p.use_experimental_parser
@p.version_check
@p.warn_error
@p.write_json
@p.event_buffer_size
@p.record_timing
def cli(ctx, **kwargs):
"""An ELT tool for managing your SQL transformations and data models.
For more documentation on these commands, visit: docs.getdbt.com
"""
if kwargs.get("version", False):
click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}")
sys.exit()
else:
del ctx.params["version"]
# dbt build
@cli.command("build")
@click.pass_context
def build(ctx, **kwargs):
"""Run all Seeds, Models, Snapshots, and tests in DAG order"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt clean
@cli.command("clean")
@click.pass_context
@p.project_dir
@p.profiles_dir
@p.profile
@p.target
@p.vars
def clean(ctx, **kwargs):
"""Delete all folders in the clean-targets list (usually the dbt_packages and target directories.)"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt docs
@cli.group()
@click.pass_context
def docs(ctx, **kwargs):
"""Generate or serve the documentation website for your project"""
# dbt docs generate
@docs.command("generate")
@click.pass_context
@p.version_check
@p.project_dir
@p.profiles_dir
@p.profile
@p.target
@p.vars
@p.compile_docs
@p.defer
@p.threads
@p.target_path
@p.log_path
@p.models
@p.exclude
@p.selector
@p.state
def docs_generate(ctx, **kwargs):
"""Generate the documentation website for your project"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.parent.params)}"
)
# dbt docs serve
@docs.command("serve")
@click.pass_context
@p.project_dir
@p.profiles_dir
@p.profile
@p.target
@p.vars
@p.port
@p.browser
def docs_serve(ctx, **kwargs):
"""Serve the documentation website for your project"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.parent.params)}"
)
# dbt compile
@cli.command("compile")
@click.pass_context
@p.version_check
@p.project_dir
@p.profiles_dir
@p.profile
@p.target
@p.vars
@p.parse_only
@p.threads
@p.target_path
@p.log_path
@p.models
@p.exclude
@p.selector
@p.state
@p.defer
@p.full_refresh
def compile(ctx, **kwargs):
"""Generates executable SQL from source, model, test, and analysis files. Compiled SQL files are written to the target/ directory."""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt debug
@cli.command("debug")
@click.pass_context
@p.version_check
@p.project_dir
@p.profiles_dir
@p.profile
@p.target
@p.vars
@p.config_dir
def debug(ctx, **kwargs):
"""Show some helpful information about dbt for debugging. Not to be confused with the --debug option which increases verbosity."""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt deps
@cli.command("deps")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
def deps(ctx, **kwargs):
"""Pull the most recent version of the dependencies listed in packages.yml"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt init
@cli.command("init")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.skip_profile_setup
def init(ctx, **kwargs):
"""Initialize a new DBT project."""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt list
# dbt TODO: Figure out aliasing for ls (or just c/p?)
@cli.command("list")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.output
@p.ouptut_keys
@p.resource_type
@p.models
@p.indirect_selection
@p.exclude
@p.selector
@p.state
def list(ctx, **kwargs):
"""List the resources in your project"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt parse
@cli.command("parse")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.write_manifest
@p.compile_parse
@p.threads
@p.target_path
@p.log_path
@p.version_check
def parse(ctx, **kwargs):
"""Parses the project and provides information on performance"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt run
@cli.command("run")
@click.pass_context
@p.fail_fast
@p.version_check
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.log_path
@p.target_path
@p.threads
@p.models
@p.exclude
@p.selector
@p.state
@p.defer
@p.full_refresh
def run(ctx, **kwargs):
"""Compile SQL and execute against the current target database."""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt run operation
@cli.command("run-operation")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.args
def run_operation(ctx, **kwargs):
"""Run the named macro with any supplied arguments."""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt seed
@cli.command("seed")
@click.pass_context
@p.version_check
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.full_refresh
@p.log_path
@p.target_path
@p.threads
@p.models
@p.exclude
@p.selector
@p.state
@p.show
def seed(ctx, **kwargs):
"""Load data from csv files into your data warehouse."""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt snapshot
@cli.command("snapshot")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.threads
@p.models
@p.exclude
@p.selector
@p.state
@p.defer
def snapshot(ctx, **kwargs):
"""Execute snapshots defined in your project"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# dbt source
@cli.group()
@click.pass_context
def source(ctx, **kwargs):
"""Manage your project's sources"""
# dbt source freshness
@source.command("freshness")
@click.pass_context
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.threads
@p.models
@p.exclude
@p.selector
@p.state
@p.output_path # TODO: Is this ok to re-use? We have three different output params, how much can we consolidate?
def freshness(ctx, **kwargs):
"""Snapshots the current freshness of the project's sources"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.parent.params)}"
)
# dbt test
@cli.command("test")
@click.pass_context
@p.fail_fast
@p.version_check
@p.store_failures
@p.profile
@p.profiles_dir
@p.project_dir
@p.target
@p.vars
@p.indirect_selection
@p.log_path
@p.target_path
@p.threads
@p.models
@p.exclude
@p.selector
@p.state
@p.defer
def test(ctx, **kwargs):
"""Runs tests on data in deployed models. Run this after `dbt run`"""
click.echo(
f"`{inspect.stack()[0][3]}` called\n kwargs: {kwargs}\n ctx: {pf(ctx.parent.params)}"
)
# Support running as a module
if __name__ == "__main__":
cli()

304
core/dbt/cli/params.py Normal file
View File

@@ -0,0 +1,304 @@
import click
import yaml
from pathlib import Path, PurePath
from click import ParamType
class YAML(ParamType):
"""The Click YAML type. Converts YAML strings into objects."""
name = "YAML"
def convert(self, value, param, ctx):
# assume non-string values are a problem
if not isinstance(value, str):
self.fail(f"Cannot load YAML from type {type(value)}", param, ctx)
try:
return yaml.load(value, Loader=yaml.Loader)
except yaml.parser.ParserError:
self.fail(f"String '{value}' is not valid YAML", param, ctx)
args = click.option(
"--args",
help="Supply arguments to the macro. This dictionary will be mapped to the keyword arguments defined in the selected macro. This argument should be a YAML string, eg. '{my_variable: my_value}'",
type=YAML(),
)
browser = click.option(
"--browser/--no-browser",
help="Wether or not to open a local web browser after starting the server",
default=True,
)
cache_selected_only = click.option(
"--cache-selected-only/--no-cache-selected-only",
help="Pre cache database objects relevant to selected resource only.",
default=False,
)
compile_docs = click.option(
"--compile/--no-compile",
help="Wether or not to run 'dbt compile' as part of docs generation",
default=True,
)
compile_parse = click.option(
"--compile/--no-compile",
help="TODO: No help text currently available",
default=True,
)
config_dir = click.option(
"--config-dir",
help="If specified, DBT will show path information for this project",
type=click.STRING,
)
debug = click.option(
"--debug/--no-debug",
"-d/ ",
help="Display debug logging during dbt execution. Useful for debugging and making bug reports.",
default=False,
)
defer = click.option(
"--defer/--no-defer",
help="If set, defer to the state variable for resolving unselected nodes.",
default=True,
)
event_buffer_size = click.option(
"--event-buffer-size",
help="Sets the max number of events to buffer in EVENT_HISTORY.",
default=100000,
type=click.INT,
)
exclude = click.option("--exclude", help="Specify the nodes to exclude.")
fail_fast = click.option(
"--fail-fast/--no-fail-fast", "-x/ ", help="Stop execution on first failure.", default=False
)
full_refresh = click.option(
"--full-refresh",
help="If specified, dbt will drop incremental models and fully-recalculate the incremental table from the model definition.",
is_flag=True,
)
indirect_selection = click.option(
"--indirect_selection",
help="Select all tests that are adjacent to selected resources, even if they those resources have been explicitly selected.",
type=click.Choice(["eager", "cautious"], case_sensitive=False),
default="eager",
)
log_format = click.option(
"--log-format",
help="Specify the log format, overriding the command's default.",
type=click.Choice(["text", "json", "default"], case_sensitive=False),
default="default",
)
log_path = click.option(
"--log-path",
help="Configure the 'log-path'. Only applies this setting for the current run. Overrides the 'DBT_LOG_PATH' if it is set.",
type=click.Path(),
)
models = click.option("-m", "-s", help="Specify the nodes to include.", multiple=True)
output = click.option(
"--output",
help="TODO: No current help text",
type=click.Choice(["json", "name", "path", "selector"], case_sensitive=False),
default="name",
)
ouptut_keys = click.option(
"--output-keys",
help="TODO: No current help text",
default=False,
)
output_path = click.option(
"--output",
"-o",
help="Specify the output path for the json report. By default, outputs to 'target/sources.json'",
type=click.Path(file_okay=True, dir_okay=False, writable=True),
default=PurePath.joinpath(Path.cwd(), "target/sources.json"),
)
parse_only = click.option(
"--parse-only",
help="TODO: No help text currently available",
is_flag=True,
)
partial_parse = click.option(
"--partial-parse/--no-partial-parse",
help="Allow for partial parsing by looking for and writing to a pickle file in the target directory. This overrides the user configuration file.",
default=True,
)
port = click.option(
"--port", help="Specify the port number for the docs server", default=8080, type=click.INT
)
print = click.option(
"--print/--no-print", help="Output all {{ print() }} macro calls.", default=True
)
printer_width = click.option(
"--printer_width", help="Sets the width of terminal output", type=click.INT, default=80
)
profile = click.option(
"--profile",
help="Which profile to load. Overrides setting in dbt_project.yml.",
)
profiles_dir = click.option(
"--profiles-dir",
help=f"Which directory to look in for the profiles.yml file. Default = {PurePath.joinpath(Path.home(), '.dbt')}",
default=PurePath.joinpath(Path.home(), ".dbt"),
type=click.Path(
exists=True,
),
)
project_dir = click.option(
"--project-dir",
help="Which directory to look in for the dbt_project.yml file. Default is the current working directory and its parents.",
default=Path.cwd(),
type=click.Path(exists=True),
)
quiet = click.option(
"--quiet/--no-quiet",
help="Suppress all non-error logging to stdout. Does not affect {{ print() }} macro calls.",
default=False,
)
record_timing = click.option(
"-r",
"--record-timing-info",
help="When this option is passed, dbt will output low-level timing stats to the specified file. Example: `--record-timing-info output.profile`",
is_flag=True,
default=False,
)
resource_type = click.option(
"--resource-type",
help="TODO: No current help text",
type=click.Choice(
[
"metric",
"source",
"analysis",
"model",
"test",
"exposure",
"snapshot",
"seed",
"default",
"all",
],
case_sensitive=False,
),
default="default",
)
selector = click.option("--selector", help="The selector name to use, as defined in selectors.yml")
send_anonymous_usage_stats = click.option(
"--anonymous-usage-stats/--no-anonymous-usage-stats",
help="Send anonymous usage stats to dbt Labs.",
default=True,
)
show = click.option(
"--show",
help="Show a sample of the loaded data in the terminal",
default=False,
)
skip_profile_setup = click.option(
"--skip-profile-setup",
"-s",
help="Skip interative profile setup.",
default=False,
)
state = click.option(
"--state",
help="If set, use the given directory as the source for json files to compare with this project.",
)
static_parser = click.option(
"--static-parser/--no-static-parser", help="Use the static parser.", default=True
)
store_failures = click.option(
"--store-failures", help="Store test results (failing rows) in the database", default=False
)
target = click.option("-t", "--target", help="Which target to load for the given profile")
target_path = click.option(
"--target-path",
help="Configure the 'target-path'. Only applies this setting for the current run. Overrides the 'DBT_TARGET_PATH' if it is set.",
type=click.Path(),
)
threads = click.option(
"--threads",
help="Specify number of threads to use while executing models. Overrides settings in profiles.yml.",
default=1,
type=click.INT,
)
use_colors = click.option(
"--use-colors/--no-use-colors",
help="Output is colorized by default and may also be set in a profile or at the command line.",
default=True,
)
use_experimental_parser = click.option(
"--use-experimental-parser/--no-use-experimental-parser",
help="Enable experimental parsing features.",
default=False,
)
vars = click.option(
"--vars",
help="Supply variables to the project. This argument overrides variables defined in your dbt_project.yml file. This argument should be a YAML string, eg. '{my_variable: my_value}'",
type=YAML(),
)
version = click.option("--version", help="Show version information", is_flag=True, default=False)
version_check = click.option(
"--version-check/--no-version-check",
help="Ensure dbt's version matches the one specified in the dbt_project.yml file ('require-dbt-version')",
default=True,
)
warn_error = click.option(
"--warn-error/--no-warn-error",
help="If dbt would normally warn, instead raise an exception. Examples include --models that selects nothing, deprecations, configurations with no associated models, invalid test configurations, and missing sources/refs in tests.",
default=False,
)
write_json = click.option(
"--write-json/--no-write-json",
help="Writing the manifest and run_results.json files to disk",
default=True,
)
write_manifest = click.option(
"--write-manifest/--no-write-manifest",
help="TODO: No help text currently available",
default=True,
)

View File

@@ -1 +1,19 @@
# Clients README
### Jinja
#### How are materializations defined
Model materializations are kept in `core/dbt/include/global_project/macros/materializations/models/`. Materializations are defined using syntax that isn't part of the Jinja standard library. These tags are referenced internally, and materializations can be overridden in user projects when users have specific needs.
```
-- Pseudocode for arguments
{% materialization <name>, <target name := one_of{default, adapter}> %}'
{% endmaterialization %}
```
These blocks are referred to Jinja extensions. Extensions are defined as part of the accepted Jinja code encapsulated within a dbt project. This includes system code used internally by dbt and user space (i.e. user-defined) macros. Extensions exist to help Jinja users create reusable code blocks or abstract objects--for us, materializations are a great use-case since we pass these around as arguments within dbt system code.
The code that defines this extension is a class `MaterializationExtension` and a `parse` routine. That code lives in [clients/jinja.py](https://github.com/dbt-labs/dbt-core/blob/main/core/dbt/clients/jinja.py). The routine
enables Jinja to parse (i.e. recognize) the unique comma separated arg structure our `materialization` tags exhibit (the `table, default` as seen above).

View File

@@ -37,6 +37,10 @@ from dbt.exceptions import (
UndefinedMacroException,
)
from dbt import flags
from dbt.node_types import ModelLanguage
SUPPORTED_LANG_ARG = jinja2.nodes.Name("supported_languages", "param")
def _linecache_inject(source, write):
@@ -307,7 +311,7 @@ class MacroGenerator(BaseMacroGenerator):
unique_id = self.macro.unique_id
depth = self.stack.depth
# only mark depth=0 as a dependency
if depth == 0:
if depth == 1:
self.node.depends_on.add_macro(unique_id)
self.stack.push(unique_id)
try:
@@ -364,9 +368,20 @@ class MaterializationExtension(jinja2.ext.Extension):
value = parser.parse_expression()
adapter_name = value.value
elif target.name == "supported_languages":
target.set_ctx("param")
node.args.append(target)
parser.stream.expect("assign")
languages = parser.parse_expression()
node.defaults.append(languages)
else:
invalid_materialization_argument(materialization_name, target.name)
if SUPPORTED_LANG_ARG not in node.args:
node.args.append(SUPPORTED_LANG_ARG)
node.defaults.append(jinja2.nodes.List([jinja2.nodes.Const("sql")]))
node.name = get_materialization_macro_name(materialization_name, adapter_name)
node.body = parser.parse_statements(("name:endmaterialization",), drop_needle=True)
@@ -632,3 +647,21 @@ def add_rendered_test_kwargs(
# when the test node was created in _parse_generic_test.
kwargs = deep_map_render(_convert_function, node.test_metadata.kwargs)
context[GENERIC_TEST_KWARGS_NAME] = kwargs
def get_supported_languages(node: jinja2.nodes.Macro) -> List[ModelLanguage]:
if "materialization" not in node.name:
raise_compiler_error("Only materialization macros can be used with this function")
no_kwargs = not node.defaults
no_langs_found = SUPPORTED_LANG_ARG not in node.args
if no_kwargs or no_langs_found:
raise_compiler_error(f"No supported_languages found in materialization macro {node.name}")
lang_idx = node.args.index(SUPPORTED_LANG_ARG)
# indexing defaults from the end
# since supported_languages is a kwarg, and kwargs are at always after args
return [
ModelLanguage[item.value] for item in node.defaults[-(len(node.args) - lang_idx)].items
]

View File

@@ -14,6 +14,7 @@ from dbt.events.types import (
)
from dbt.utils import memoized, _connection_exception_retry as connection_exception_retry
from dbt import deprecations
from dbt import semver
import os
if os.getenv("DBT_PACKAGE_HUB_URL"):
@@ -125,10 +126,37 @@ def package_version(package_name, version, registry_base_url=None) -> Dict[str,
return response[version]
def get_available_versions(package_name) -> List["str"]:
def is_compatible_version(package_spec, dbt_version) -> bool:
require_dbt_version = package_spec.get("require_dbt_version")
if not require_dbt_version:
# if version requirements are missing or empty, assume any version is compatible
return True
else:
# determine whether dbt_version satisfies this package's require-dbt-version config
if not isinstance(require_dbt_version, list):
require_dbt_version = [require_dbt_version]
supported_versions = [
semver.VersionSpecifier.from_version_string(v) for v in require_dbt_version
]
return semver.versions_compatible(dbt_version, *supported_versions)
def get_compatible_versions(package_name, dbt_version, should_version_check) -> List["str"]:
# returns a list of all available versions of a package
response = package(package_name)
return list(response)
# if the user doesn't care about installing compatible versions, just return them all
if not should_version_check:
return list(response)
# otherwise, only return versions that are compatible with the installed version of dbt-core
else:
compatible_versions = [
pkg_version
for pkg_version, info in response.items()
if is_compatible_version(info, dbt_version)
]
return compatible_versions
def _get_index(registry_base_url=None):

View File

@@ -380,6 +380,8 @@ class PartialProject(RenderComponents):
snapshots: Dict[str, Any]
sources: Dict[str, Any]
tests: Dict[str, Any]
metrics: Dict[str, Any]
exposures: Dict[str, Any]
vars_value: VarProvider
dispatch = cfg.dispatch
@@ -388,6 +390,8 @@ class PartialProject(RenderComponents):
snapshots = cfg.snapshots
sources = cfg.sources
tests = cfg.tests
metrics = cfg.metrics
exposures = cfg.exposures
if cfg.vars is None:
vars_dict: Dict[str, Any] = {}
else:
@@ -441,6 +445,8 @@ class PartialProject(RenderComponents):
query_comment=query_comment,
sources=sources,
tests=tests,
metrics=metrics,
exposures=exposures,
vars=vars_value,
config_version=cfg.config_version,
unrendered=unrendered,
@@ -543,6 +549,8 @@ class Project:
snapshots: Dict[str, Any]
sources: Dict[str, Any]
tests: Dict[str, Any]
metrics: Dict[str, Any]
exposures: Dict[str, Any]
vars: VarProvider
dbt_version: List[VersionSpecifier]
packages: Dict[str, Any]
@@ -615,6 +623,8 @@ class Project:
"snapshots": self.snapshots,
"sources": self.sources,
"tests": self.tests,
"metrics": self.metrics,
"exposures": self.exposures,
"vars": self.vars.to_dict(),
"require-dbt-version": [v.to_version_string() for v in self.dbt_version],
"config-version": self.config_version,

View File

@@ -3,13 +3,13 @@ import re
import os
from dbt.clients.jinja import get_rendered, catch_jinja
from dbt.constants import SECRET_ENV_PREFIX
from dbt.context.target import TargetContext
from dbt.context.secret import SecretContext, SECRET_PLACEHOLDER
from dbt.context.base import BaseContext
from dbt.contracts.connection import HasCredentials
from dbt.exceptions import DbtProjectError, CompilationException, RecursionException
from dbt.utils import deep_map_render
from dbt.logger import SECRET_ENV_PREFIX
Keypath = Tuple[Union[str, int], ...]

View File

@@ -105,6 +105,8 @@ class RuntimeConfig(Project, Profile, AdapterRequiredConfig):
query_comment=project.query_comment,
sources=project.sources,
tests=project.tests,
metrics=project.metrics,
exposures=project.exposures,
vars=project.vars,
config_version=project.config_version,
unrendered=project.unrendered,
@@ -274,6 +276,8 @@ class RuntimeConfig(Project, Profile, AdapterRequiredConfig):
"snapshots": self._get_config_paths(self.snapshots),
"sources": self._get_config_paths(self.sources),
"tests": self._get_config_paths(self.tests),
"metrics": self._get_config_paths(self.metrics),
"exposures": self._get_config_paths(self.exposures),
}
def get_unused_resource_config_paths(
@@ -477,6 +481,8 @@ class UnsetProfileConfig(RuntimeConfig):
"snapshots": self.snapshots,
"sources": self.sources,
"tests": self.tests,
"metrics": self.metrics,
"exposures": self.exposures,
"vars": self.vars.to_dict(),
"require-dbt-version": [v.to_version_string() for v in self.dbt_version],
"config-version": self.config_version,
@@ -537,6 +543,8 @@ class UnsetProfileConfig(RuntimeConfig):
query_comment=project.query_comment,
sources=project.sources,
tests=project.tests,
metrics=project.metrics,
exposures=project.exposures,
vars=project.vars,
config_version=project.config_version,
unrendered=project.unrendered,

2
core/dbt/constants.py Normal file
View File

@@ -0,0 +1,2 @@
SECRET_ENV_PREFIX = "DBT_ENV_SECRET_"
DEFAULT_ENV_PLACEHOLDER = "DBT_DEFAULT_PLACEHOLDER"

View File

@@ -2,7 +2,7 @@
Contexts are used for Jinja rendering. They include context methods, executable macros, and various settings that are available in Jinja.
The most common entrypoint to Jinja rendering in dbt is a method named `get_rendered`, which takes two arguments: templated code (string), and a context used to render it (dictionary).
The most common entrypoint to Jinja rendering in dbt is a method named `get_rendered`, which takes two arguments: templated code (string), and a context used to render it (dictionary).
The context is the bundle of information that is in "scope" when rendering Jinja-templated code. For instance, imagine a simple Jinja template:
```

View File

@@ -6,6 +6,7 @@ from dbt import flags
from dbt import tracking
from dbt.clients.jinja import get_rendered
from dbt.clients.yaml_helper import yaml, safe_load, SafeLoader, Loader, Dumper # noqa: F401
from dbt.constants import SECRET_ENV_PREFIX, DEFAULT_ENV_PLACEHOLDER
from dbt.contracts.graph.compiled import CompiledResource
from dbt.exceptions import (
CompilationException,
@@ -14,7 +15,6 @@ from dbt.exceptions import (
raise_parsing_error,
disallow_secret_env_var,
)
from dbt.logger import SECRET_ENV_PREFIX
from dbt.events.functions import fire_event, get_invocation_id
from dbt.events.types import MacroEventInfo, MacroEventDebug
from dbt.version import __version__ as dbt_version
@@ -305,7 +305,12 @@ class BaseContext(metaclass=ContextMeta):
return_value = default
if return_value is not None:
self.env_vars[var] = return_value
# If the environment variable is set from a default, store a string indicating
# that so we can skip partial parsing. Otherwise the file will be scheduled for
# reparsing. If the default changes, the file will have been updated and therefore
# will be scheduled for reparsing anyways.
self.env_vars[var] = return_value if var in os.environ else DEFAULT_ENV_PLACEHOLDER
return return_value
else:
msg = f"Env var required but not provided: '{var}'"

View File

@@ -1,8 +1,8 @@
import os
from typing import Any, Dict, Optional
from dbt.constants import SECRET_ENV_PREFIX, DEFAULT_ENV_PLACEHOLDER
from dbt.contracts.connection import AdapterRequiredConfig
from dbt.logger import SECRET_ENV_PREFIX
from dbt.node_types import NodeType
from dbt.utils import MultiDict
@@ -94,7 +94,14 @@ class SchemaYamlContext(ConfiguredContext):
if return_value is not None:
if self.schema_yaml_vars:
self.schema_yaml_vars.env_vars[var] = return_value
# If the environment variable is set from a default, store a string indicating
# that so we can skip partial parsing. Otherwise the file will be scheduled for
# reparsing. If the default changes, the file will have been updated and therefore
# will be scheduled for reparsing anyways.
self.schema_yaml_vars.env_vars[var] = (
return_value if var in os.environ else DEFAULT_ENV_PLACEHOLDER
)
return return_value
else:
msg = f"Env var required but not provided: '{var}'"

View File

@@ -43,9 +43,12 @@ class UnrenderedConfig(ConfigSource):
model_configs = unrendered.get("sources")
elif resource_type == NodeType.Test:
model_configs = unrendered.get("tests")
elif resource_type == NodeType.Metric:
model_configs = unrendered.get("metrics")
elif resource_type == NodeType.Exposure:
model_configs = unrendered.get("exposures")
else:
model_configs = unrendered.get("models")
if model_configs is None:
return {}
else:
@@ -65,6 +68,10 @@ class RenderedConfig(ConfigSource):
model_configs = self.project.sources
elif resource_type == NodeType.Test:
model_configs = self.project.tests
elif resource_type == NodeType.Metric:
model_configs = self.project.metrics
elif resource_type == NodeType.Exposure:
model_configs = self.project.exposures
else:
model_configs = self.project.models
return model_configs

View File

@@ -4,6 +4,7 @@ from dbt.clients.jinja import MacroStack
from dbt.contracts.connection import AdapterRequiredConfig
from dbt.contracts.graph.manifest import Manifest
from dbt.context.macro_resolver import TestMacroNamespace
from .base import contextproperty
from .configured import ConfiguredContext
@@ -66,6 +67,10 @@ class ManifestContext(ConfiguredContext):
dct.update(self.namespace)
return dct
@contextproperty
def context_macro_stack(self):
return self.macro_stack
class QueryHeaderContext(ManifestContext):
def __init__(self, config: AdapterRequiredConfig, manifest: Manifest) -> None:

View File

@@ -22,7 +22,7 @@ from dbt.config import RuntimeConfig, Project
from .base import contextmember, contextproperty, Var
from .configured import FQNLookup
from .context_config import ContextConfig
from dbt.logger import SECRET_ENV_PREFIX
from dbt.constants import SECRET_ENV_PREFIX, DEFAULT_ENV_PLACEHOLDER
from dbt.context.macro_resolver import MacroResolver, TestMacroNamespace
from .macros import MacroNamespaceBuilder, MacroNamespace
from .manifest import ManifestContext
@@ -63,7 +63,7 @@ from dbt.exceptions import (
from dbt.config import IsFQNResource
from dbt.node_types import NodeType, ModelLanguage
from dbt.utils import merge, AttrDict, MultiDict
from dbt.utils import merge, AttrDict, MultiDict, args_to_dict
from dbt import selected_resources
@@ -710,6 +710,10 @@ class ProviderContext(ManifestContext):
self.model,
)
@contextproperty
def invocation_args_dict(self):
return args_to_dict(self.config.args)
@contextproperty
def _sql_results(self) -> Dict[str, AttrDict]:
return self.sql_results
@@ -1211,7 +1215,14 @@ class ProviderContext(ManifestContext):
# Save the env_var value in the manifest and the var name in the source_file.
# If this is compiling, do not save because it's irrelevant to parsing.
if self.model and not hasattr(self.model, "compiled"):
self.manifest.env_vars[var] = return_value
# If the environment variable is set from a default, store a string indicating
# that so we can skip partial parsing. Otherwise the file will be scheduled for
# reparsing. If the default changes, the file will have been updated and therefore
# will be scheduled for reparsing anyways.
self.manifest.env_vars[var] = (
return_value if var in os.environ else DEFAULT_ENV_PLACEHOLDER
)
# hooks come from dbt_project.yml which doesn't have a real file_id
if self.model.file_id in self.manifest.files:
source_file = self.manifest.files[self.model.file_id]
@@ -1233,6 +1244,11 @@ class ProviderContext(ManifestContext):
"""
return selected_resources.SELECTED_RESOURCES
@contextmember
def submit_python_job(self):
# Check macro_stack and that the unique id is for a materialization macro
pass
class MacroContext(ProviderContext):
"""Internally, macros can be executed like nodes, with some restrictions:
@@ -1535,7 +1551,13 @@ class TestContext(ProviderContext):
if return_value is not None:
# Save the env_var value in the manifest and the var name in the source_file
if self.model:
self.manifest.env_vars[var] = return_value
# If the environment variable is set from a default, store a string indicating
# that so we can skip partial parsing. Otherwise the file will be scheduled for
# reparsing. If the default changes, the file will have been updated and therefore
# will be scheduled for reparsing anyways.
self.manifest.env_vars[var] = (
return_value if var in os.environ else DEFAULT_ENV_PLACEHOLDER
)
# the "model" should only be test nodes, but just in case, check
# TODO CT-211
if self.model.resource_type == NodeType.Test and self.model.file_key_name: # type: ignore[union-attr] # noqa

View File

@@ -3,8 +3,8 @@ from typing import Any, Dict, Optional
from .base import BaseContext, contextmember
from dbt.constants import SECRET_ENV_PREFIX, DEFAULT_ENV_PLACEHOLDER
from dbt.exceptions import raise_parsing_error
from dbt.logger import SECRET_ENV_PREFIX
SECRET_PLACEHOLDER = "$$$DBT_SECRET_START$$${}$$$DBT_SECRET_END$$$"
@@ -43,7 +43,11 @@ class SecretContext(BaseContext):
# if it's a 'secret' env var, we shouldn't even get here
# but just to be safe — don't save secrets
if not var.startswith(SECRET_ENV_PREFIX):
self.env_vars[var] = return_value
# If the environment variable is set from a default, store a string indicating
# that so we can skip partial parsing. Otherwise the file will be scheduled for
# reparsing. If the default changes, the file will have been updated and therefore
# will be scheduled for reparsing anyways.
self.env_vars[var] = return_value if var in os.environ else DEFAULT_ENV_PLACEHOLDER
return return_value
else:
msg = f"Env var required but not provided: '{var}'"

View File

@@ -216,7 +216,7 @@ class MetricLookup(dbtClassMixin):
return manifest.metrics[unique_id]
# This handles both models/seeds/snapshots and sources
# This handles both models/seeds/snapshots and sources/metrics/exposures
class DisabledLookup(dbtClassMixin):
def __init__(self, manifest: "Manifest"):
self.storage: Dict[str, Dict[PackageName, List[Any]]] = {}
@@ -464,7 +464,7 @@ class Disabled(Generic[D]):
target: D
MaybeMetricNode = Optional[ParsedMetric]
MaybeMetricNode = Optional[Union[ParsedMetric, Disabled[ParsedMetric]]]
MaybeDocumentation = Optional[ParsedDocumentation]
@@ -616,7 +616,7 @@ class Manifest(MacroMethods, DataClassMessagePackMixin, dbtClassMixin):
flat_graph: Dict[str, Any] = field(default_factory=dict)
state_check: ManifestStateCheck = field(default_factory=ManifestStateCheck)
source_patches: MutableMapping[SourceKey, SourcePatch] = field(default_factory=dict)
disabled: MutableMapping[str, List[CompileResultNode]] = field(default_factory=dict)
disabled: MutableMapping[str, List[GraphMemberNode]] = field(default_factory=dict)
env_vars: MutableMapping[str, str] = field(default_factory=dict)
_doc_lookup: Optional[DocLookup] = field(
@@ -964,13 +964,22 @@ class Manifest(MacroMethods, DataClassMessagePackMixin, dbtClassMixin):
current_project: str,
node_package: str,
) -> MaybeMetricNode:
metric: Optional[ParsedMetric] = None
disabled: Optional[List[ParsedMetric]] = None
candidates = _search_packages(current_project, node_package, target_metric_package)
for pkg in candidates:
metric = self.metric_lookup.find(target_metric_name, pkg, self)
if metric is not None:
if metric is not None and metric.config.enabled:
return metric
# it's possible that the node is disabled
if disabled is None:
disabled = self.disabled_lookup.find(f"{target_metric_name}", pkg)
if disabled:
return Disabled(disabled[0])
return None
# Called by DocsRuntimeContext.doc
@@ -1018,6 +1027,10 @@ class Manifest(MacroMethods, DataClassMessagePackMixin, dbtClassMixin):
merged.add(unique_id)
self.nodes[unique_id] = node.replace(deferred=True)
# Rebuild the flat_graph, which powers the 'graph' context variable,
# now that we've deferred some nodes
self.build_flat_graph()
# log up to 5 items
sample = list(islice(merged, 5))
fire_event(MergedFromState(nbr_merged=len(merged), sample=sample))
@@ -1089,7 +1102,7 @@ class Manifest(MacroMethods, DataClassMessagePackMixin, dbtClassMixin):
self.metrics[metric.unique_id] = metric
source_file.metrics.append(metric.unique_id)
def add_disabled_nofile(self, node: CompileResultNode):
def add_disabled_nofile(self, node: GraphMemberNode):
# There can be multiple disabled nodes for the same unique_id
if node.unique_id in self.disabled:
self.disabled[node.unique_id].append(node)

View File

@@ -38,33 +38,56 @@ class ResolvedMetricReference(MetricReference):
if node and node.resource_type == NodeType.Metric:
yield from cls.parent_metrics(node, manifest)
def parent_models(self):
@classmethod
def parent_metrics_names(cls, metric_node, manifest):
yield metric_node.name
for parent_unique_id in metric_node.depends_on.nodes:
node = manifest.metrics.get(parent_unique_id)
if node and node.resource_type == NodeType.Metric:
yield from cls.parent_metrics_names(node, manifest)
@classmethod
def reverse_dag_parsing(cls, metric_node, manifest, metric_depth_count):
if metric_node.calculation_method == "derived":
yield {metric_node.name: metric_depth_count}
metric_depth_count = metric_depth_count + 1
for parent_unique_id in metric_node.depends_on.nodes:
node = manifest.metrics.get(parent_unique_id)
if (
node
and node.resource_type == NodeType.Metric
and node.calculation_method == "derived"
):
yield from cls.reverse_dag_parsing(node, manifest, metric_depth_count)
def full_metric_dependency(self):
to_return = list(set(self.parent_metrics_names(self.node, self.manifest)))
return to_return
def base_metric_dependency(self):
in_scope_metrics = list(self.parent_metrics(self.node, self.manifest))
to_return = {
"base": [],
"derived": [],
}
to_return = []
for metric in in_scope_metrics:
if metric.type == "expression":
to_return["derived"].append(
{"metric_source": None, "metric": metric, "is_derived": True}
)
else:
for node_unique_id in metric.depends_on.nodes:
node = self.manifest.nodes.get(node_unique_id)
if node and node.resource_type in NodeType.refable():
to_return["base"].append(
{
"metric_relation_node": node,
"metric_relation": self.Relation.create(
database=node.database,
schema=node.schema,
identifier=node.alias,
),
"metric": metric,
"is_derived": False,
}
)
if metric.calculation_method != "derived" and metric.name not in to_return:
to_return.append(metric.name)
return to_return
def derived_metric_dependency(self):
in_scope_metrics = list(self.parent_metrics(self.node, self.manifest))
to_return = []
for metric in in_scope_metrics:
if metric.calculation_method == "derived" and metric.name not in to_return:
to_return.append(metric.name)
return to_return
def derived_metric_dependency_depth(self):
metric_depth_count = 1
to_return = list(self.reverse_dag_parsing(self.node, self.manifest, metric_depth_count))
return to_return

View File

@@ -7,7 +7,8 @@ from dbt.dataclass_schema import (
ValidationError,
register_pattern,
)
from dbt.contracts.graph.unparsed import AdditionalPropertiesAllowed
from dbt.contracts.graph.unparsed import AdditionalPropertiesAllowed, Docs
from dbt.contracts.graph.utils import validate_color
from dbt.exceptions import InternalException, CompilationException
from dbt.contracts.util import Replaceable, list_str
from dbt import hooks
@@ -285,7 +286,7 @@ class BaseConfig(AdditionalPropertiesAllowed, Replaceable):
# 'meta' moved here from node
mergebehavior = {
"append": ["pre-hook", "pre_hook", "post-hook", "post_hook", "tags"],
"update": ["quoting", "column_types", "meta"],
"update": ["quoting", "column_types", "meta", "docs"],
"dict_key_append": ["grants"],
}
@@ -362,6 +363,16 @@ class BaseConfig(AdditionalPropertiesAllowed, Replaceable):
return self.from_dict(dct)
@dataclass
class MetricConfig(BaseConfig):
enabled: bool = True
@dataclass
class ExposureConfig(BaseConfig):
enabled: bool = True
@dataclass
class SourceConfig(BaseConfig):
enabled: bool = True
@@ -465,6 +476,20 @@ class NodeConfig(NodeAndTestConfig):
default_factory=list,
metadata=MergeBehavior.Append.meta(),
)
docs: Docs = field(
default_factory=Docs,
metadata=MergeBehavior.Update.meta(),
)
# we validate that node_color has a suitable value to prevent dbt-docs from crashing
def __post_init__(self):
if self.docs.node_color:
node_color = self.docs.node_color
if not validate_color(node_color):
raise ValidationError(
f"Invalid color name for docs.node_color: {node_color}. "
"It is neither a valid HTML color name nor a valid HEX code."
)
@classmethod
def __pre_deserialize__(cls, data):
@@ -598,6 +623,8 @@ class SnapshotConfig(EmptySnapshotConfig):
RESOURCE_TYPES: Dict[NodeType, Type[BaseConfig]] = {
NodeType.Metric: MetricConfig,
NodeType.Exposure: ExposureConfig,
NodeType.Source: SourceConfig,
NodeType.Seed: SeedConfig,
NodeType.Test: TestConfig,

View File

@@ -37,11 +37,12 @@ from dbt.contracts.graph.unparsed import (
ExposureType,
MaturityType,
MetricFilter,
MetricTime,
)
from dbt.contracts.util import Replaceable, AdditionalPropertiesMixin
from dbt.exceptions import warn_or_error
from dbt import flags
from dbt.node_types import NodeType
from dbt.node_types import ModelLanguage, NodeType
from .model_config import (
@@ -49,6 +50,8 @@ from .model_config import (
SeedConfig,
TestConfig,
SourceConfig,
MetricConfig,
ExposureConfig,
EmptySnapshotConfig,
SnapshotConfig,
)
@@ -157,7 +160,6 @@ class ParsedNodeMixins(dbtClassMixin):
self.created_at = time.time()
self.description = patch.description
self.columns = patch.columns
self.docs = patch.docs
def get_materialization(self):
return self.config.materialized
@@ -517,6 +519,7 @@ class ParsedMacro(UnparsedBaseNode, HasUniqueID):
patch_path: Optional[str] = None
arguments: List[MacroArgument] = field(default_factory=list)
created_at: float = field(default_factory=lambda: time.time())
supported_languages: Optional[List[ModelLanguage]] = None
def patch(self, patch: ParsedMacroPatch):
self.patch_path: Optional[str] = patch.file_id
@@ -745,6 +748,8 @@ class ParsedExposure(UnparsedBaseNode, HasUniqueID, HasFqn):
maturity: Optional[MaturityType] = None
meta: Dict[str, Any] = field(default_factory=dict)
tags: List[str] = field(default_factory=list)
config: ExposureConfig = field(default_factory=ExposureConfig)
unrendered_config: Dict[str, Any] = field(default_factory=dict)
url: Optional[str] = None
depends_on: DependsOn = field(default_factory=DependsOn)
refs: List[List[str]] = field(default_factory=list)
@@ -777,6 +782,12 @@ class ParsedExposure(UnparsedBaseNode, HasUniqueID, HasFqn):
def same_url(self, old: "ParsedExposure") -> bool:
return self.url == old.url
def same_config(self, old: "ParsedExposure") -> bool:
return self.config.same_contents(
self.unrendered_config,
old.unrendered_config,
)
def same_contents(self, old: Optional["ParsedExposure"]) -> bool:
# existing when it didn't before is a change!
# metadata/tags changes are not "changes"
@@ -791,6 +802,7 @@ class ParsedExposure(UnparsedBaseNode, HasUniqueID, HasFqn):
and self.same_url(old)
and self.same_description(old)
and self.same_depends_on(old)
and self.same_config(old)
and True
)
@@ -806,17 +818,20 @@ class ParsedMetric(UnparsedBaseNode, HasUniqueID, HasFqn):
name: str
description: str
label: str
type: str
sql: str
calculation_method: str
expression: str
timestamp: Optional[str]
filters: List[MetricFilter]
time_grains: List[str]
dimensions: List[str]
window: Optional[MetricTime]
model: Optional[str] = None
model_unique_id: Optional[str] = None
resource_type: NodeType = NodeType.Metric
meta: Dict[str, Any] = field(default_factory=dict)
tags: List[str] = field(default_factory=list)
config: MetricConfig = field(default_factory=MetricConfig)
unrendered_config: Dict[str, Any] = field(default_factory=dict)
sources: List[List[str]] = field(default_factory=list)
depends_on: DependsOn = field(default_factory=DependsOn)
refs: List[List[str]] = field(default_factory=list)
@@ -834,6 +849,9 @@ class ParsedMetric(UnparsedBaseNode, HasUniqueID, HasFqn):
def same_model(self, old: "ParsedMetric") -> bool:
return self.model == old.model
def same_window(self, old: "ParsedMetric") -> bool:
return self.window == old.window
def same_dimensions(self, old: "ParsedMetric") -> bool:
return self.dimensions == old.dimensions
@@ -846,11 +864,11 @@ class ParsedMetric(UnparsedBaseNode, HasUniqueID, HasFqn):
def same_label(self, old: "ParsedMetric") -> bool:
return self.label == old.label
def same_type(self, old: "ParsedMetric") -> bool:
return self.type == old.type
def same_calculation_method(self, old: "ParsedMetric") -> bool:
return self.calculation_method == old.calculation_method
def same_sql(self, old: "ParsedMetric") -> bool:
return self.sql == old.sql
def same_expression(self, old: "ParsedMetric") -> bool:
return self.expression == old.expression
def same_timestamp(self, old: "ParsedMetric") -> bool:
return self.timestamp == old.timestamp
@@ -858,6 +876,12 @@ class ParsedMetric(UnparsedBaseNode, HasUniqueID, HasFqn):
def same_time_grains(self, old: "ParsedMetric") -> bool:
return self.time_grains == old.time_grains
def same_config(self, old: "ParsedMetric") -> bool:
return self.config.same_contents(
self.unrendered_config,
old.unrendered_config,
)
def same_contents(self, old: Optional["ParsedMetric"]) -> bool:
# existing when it didn't before is a change!
# metadata/tags changes are not "changes"
@@ -866,14 +890,16 @@ class ParsedMetric(UnparsedBaseNode, HasUniqueID, HasFqn):
return (
self.same_model(old)
and self.same_window(old)
and self.same_dimensions(old)
and self.same_filters(old)
and self.same_description(old)
and self.same_label(old)
and self.same_type(old)
and self.same_sql(old)
and self.same_calculation_method(old)
and self.same_expression(old)
and self.same_timestamp(old)
and self.same_time_grains(old)
and self.same_config(old)
and True
)

View File

@@ -77,6 +77,7 @@ class UnparsedRunHook(UnparsedNode):
@dataclass
class Docs(dbtClassMixin, Replaceable):
show: bool = True
node_color: Optional[str] = None
@dataclass
@@ -433,6 +434,7 @@ class UnparsedExposure(dbtClassMixin, Replaceable):
tags: List[str] = field(default_factory=list)
url: Optional[str] = None
depends_on: List[str] = field(default_factory=list)
config: Dict[str, Any] = field(default_factory=dict)
@dataclass
@@ -443,35 +445,55 @@ class MetricFilter(dbtClassMixin, Replaceable):
value: str
class MetricTimePeriod(StrEnum):
day = "day"
week = "week"
month = "month"
year = "year"
def plural(self) -> str:
return str(self) + "s"
@dataclass
class MetricTime(dbtClassMixin, Mergeable):
count: Optional[int] = None
period: Optional[MetricTimePeriod] = None
def __bool__(self):
return self.count is not None and self.period is not None
@dataclass
class UnparsedMetric(dbtClassMixin, Replaceable):
# TODO : verify that this disallows metric names with spaces
# TODO: fix validation that you broke :p
# name: Identifier
name: str
label: str
type: str
model: Optional[str] = None
calculation_method: str
timestamp: str
description: str = ""
sql: Union[str, int] = ""
timestamp: Optional[str] = None
expression: Union[str, int] = ""
time_grains: List[str] = field(default_factory=list)
dimensions: List[str] = field(default_factory=list)
window: Optional[MetricTime] = None
model: Optional[str] = None
filters: List[MetricFilter] = field(default_factory=list)
meta: Dict[str, Any] = field(default_factory=dict)
tags: List[str] = field(default_factory=list)
config: Dict[str, Any] = field(default_factory=dict)
@classmethod
def validate(cls, data):
# super().validate(data)
# TODO: putting this back for now to get tests passing. Do we want to implement name: Identifier?
super(UnparsedMetric, cls).validate(data)
if "name" in data and " " in data["name"]:
raise ParsingException(f"Metrics name '{data['name']}' cannot contain spaces")
# TODO: Expressions _cannot_ have `model` properties
if data.get("model") is None and data.get("type") != "expression":
raise ValidationError("Non-expression metrics require a 'model' property")
if data.get("calculation_method") == "expression":
raise ValidationError(
"The metric calculation method expression has been deprecated and renamed to derived. Please update"
)
if data.get("model") is not None and data.get("type") == "expression":
raise ValidationError("Expression metrics cannot have a 'model' property")
if data.get("model") is None and data.get("calculation_method") != "derived":
raise ValidationError("Non-derived metrics require a 'model' property")
if data.get("model") is not None and data.get("calculation_method") == "derived":
raise ValidationError("Derived metrics cannot have a 'model' property")

View File

@@ -0,0 +1,153 @@
import re
HTML_COLORS = [
"aliceblue",
"antiquewhite",
"aqua",
"aquamarine",
"azure",
"beige",
"bisque",
"black",
"blanchedalmond",
"blue",
"blueviolet",
"brown",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"coral",
"cornflowerblue",
"cornsilk",
"crimson",
"cyan",
"darkblue",
"darkcyan",
"darkgoldenrod",
"darkgray",
"darkgreen",
"darkkhaki",
"darkmagenta",
"darkolivegreen",
"darkorange",
"darkorchid",
"darkred",
"darksalmon",
"darkseagreen",
"darkslateblue",
"darkslategray",
"darkturquoise",
"darkviolet",
"deeppink",
"deepskyblue",
"dimgray",
"dodgerblue",
"firebrick",
"floralwhite",
"forestgreen",
"fuchsia",
"gainsboro",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"green",
"greenyellow",
"honeydew",
"hotpink",
"indianred",
"indigo",
"ivory",
"khaki",
"lavender",
"lavenderblush",
"lawngreen",
"lemonchiffon",
"lightblue",
"lightcoral",
"lightcyan",
"lightgoldenrodyellow",
"lightgray",
"lightgreen",
"lightpink",
"lightsalmon",
"lightsalmon",
"lightseagreen",
"lightskyblue",
"lightslategray",
"lightsteelblue",
"lightyellow",
"lime",
"limegreen",
"linen",
"magenta",
"maroon",
"mediumaquamarine",
"mediumblue",
"mediumorchid",
"mediumpurple",
"mediumseagreen",
"mediumslateblue",
"mediumslateblue",
"mediumspringgreen",
"mediumturquoise",
"mediumvioletred",
"midnightblue",
"mintcream",
"mistyrose",
"moccasin",
"navajowhite",
"navy",
"oldlace",
"olive",
"olivedrab",
"orange",
"orangered",
"orchid",
"palegoldenrod",
"palegreen",
"paleturquoise",
"palevioletred",
"papayawhip",
"peachpuff",
"peru",
"pink",
"plum",
"powderblue",
"purple",
"rebeccapurple",
"red",
"rosybrown",
"royalblue",
"saddlebrown",
"salmon",
"sandybrown",
"seagreen",
"seashell",
"sienna",
"silver",
"skyblue",
"slateblue",
"slategray",
"snow",
"springgreen",
"steelblue",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"wheat",
"white",
"whitesmoke",
"yellow",
"yellowgreen",
]
def validate_color(color: str) -> bool:
match_hex = re.search(r"^#(?:[0-9a-f]{3}){1,2}$", color.lower())
match_html_color_name = color.lower() in HTML_COLORS
return bool(match_hex or match_html_color_name)

View File

@@ -192,6 +192,8 @@ class Project(HyphenatedDbtClassMixin, Replaceable):
analyses: Dict[str, Any] = field(default_factory=dict)
sources: Dict[str, Any] = field(default_factory=dict)
tests: Dict[str, Any] = field(default_factory=dict)
metrics: Dict[str, Any] = field(default_factory=dict)
exposures: Dict[str, Any] = field(default_factory=dict)
vars: Optional[Dict[str, Any]] = field(
default=None,
metadata=dict(

View File

@@ -3,6 +3,8 @@ import functools
from typing import List
from dbt import semver
from dbt import flags
from dbt.version import get_installed_version
from dbt.clients import registry, system
from dbt.contracts.project import (
RegistryPackageMetadata,
@@ -125,20 +127,27 @@ class RegistryUnpinnedPackage(RegistryPackageMixin, UnpinnedPackage[RegistryPinn
new_msg = "Version error for package {}: {}".format(self.name, e)
raise DependencyException(new_msg) from e
available = registry.get_available_versions(self.package)
should_version_check = bool(flags.VERSION_CHECK)
dbt_version = get_installed_version()
compatible_versions = registry.get_compatible_versions(
self.package, dbt_version, should_version_check
)
prerelease_version_specified = any(bool(version.prerelease) for version in self.versions)
installable = semver.filter_installable(
available, self.install_prerelease or prerelease_version_specified
compatible_versions, self.install_prerelease or prerelease_version_specified
)
available_latest = installable[-1]
# for now, pick a version and then recurse. later on,
# we'll probably want to traverse multiple options
# so we can match packages. not going to make a difference
# right now.
target = semver.resolve_to_specific_version(range_, installable)
if installable:
# for now, pick a version and then recurse. later on,
# we'll probably want to traverse multiple options
# so we can match packages. not going to make a difference
# right now.
target = semver.resolve_to_specific_version(range_, installable)
else:
target = None
if not target:
package_version_not_found(self.package, range_, installable)
# raise an exception if no installable target version is found
package_version_not_found(self.package, range_, installable, should_version_check)
latest_compatible = installable[-1]
return RegistryPinnedPackage(
package=self.package, version=target, version_latest=available_latest
package=self.package, version=target, version_latest=latest_compatible
)

View File

@@ -120,7 +120,6 @@ def resolve_packages(
) -> List[PinnedPackage]:
pending = PackageListing.from_contracts(packages)
final = PackageListing()
renderer = DbtProjectYamlRenderer(config, config.cli_vars)
while pending:

View File

@@ -3,9 +3,10 @@ import dbt.events.functions as this # don't worry I hate it too.
from dbt.events.base_types import NoStdOut, Event, NoFile, ShowException, Cache
from dbt.events.types import EventBufferFull, T_Event, MainReportVersion, EmptyLine
import dbt.flags as flags
from dbt.constants import SECRET_ENV_PREFIX
# TODO this will need to move eventually
from dbt.logger import SECRET_ENV_PREFIX, make_log_dir_if_missing, GLOBAL_LOGGER
from dbt.logger import make_log_dir_if_missing, GLOBAL_LOGGER
from datetime import datetime
import json
import io
@@ -56,6 +57,7 @@ def setup_event_logger(log_path, level_override=None):
EVENT_HISTORY = deque(maxlen=flags.EVENT_BUFFER_SIZE) # type: ignore
make_log_dir_if_missing(log_path)
this.format_json = flags.LOG_FORMAT == "json"
# USE_COLORS can be None if the app just started and the cli flags
# havent been applied yet

View File

@@ -1640,6 +1640,15 @@ class RunResultWarning(WarnLevel):
return ui.yellow(f"{info} in {self.resource_type} {self.node_name} ({self.path})")
@dataclass
class RunResultWarningMessage(WarnLevel):
msg: str
code: str = "Z049"
def message(self) -> str:
return f" {self.msg}"
@dataclass
class RunResultFailure(ErrorLevel):
resource_type: str

View File

@@ -631,13 +631,13 @@ def ref_target_not_found(
raise_compiler_error(msg, model)
def get_source_not_found_or_disabled_msg(
model,
def get_not_found_or_disabled_msg(
node,
target_name: str,
target_table_name: str,
target_kind: str,
target_package: Optional[str] = None,
disabled: Optional[bool] = None,
) -> str:
full_name = f"{target_name}.{target_table_name}"
if disabled is None:
reason = "was not found or is disabled"
elif disabled is True:
@@ -645,34 +645,57 @@ def get_source_not_found_or_disabled_msg(
else:
reason = "was not found"
return _get_target_failure_msg(
model, full_name, None, include_path=True, reason=reason, target_kind="source"
node,
target_name,
target_package,
include_path=True,
reason=reason,
target_kind=target_kind,
)
def source_target_not_found(
model, target_name: str, target_table_name: str, disabled: Optional[bool] = None
) -> NoReturn:
msg = get_source_not_found_or_disabled_msg(model, target_name, target_table_name, disabled)
msg = get_not_found_or_disabled_msg(
node=model,
target_name=f"{target_name}.{target_table_name}",
target_kind="source",
disabled=disabled,
)
raise_compiler_error(msg, model)
def get_metric_not_found_msg(
model,
target_name: str,
target_package: Optional[str],
) -> str:
reason = "was not found"
return _get_target_failure_msg(
model, target_name, target_package, include_path=True, reason=reason, target_kind="metric"
def metric_target_not_found(
metric, target_name: str, target_package: Optional[str], disabled: Optional[bool] = None
) -> NoReturn:
msg = get_not_found_or_disabled_msg(
node=metric,
target_name=target_name,
target_kind="metric",
target_package=target_package,
disabled=disabled,
)
def metric_target_not_found(metric, target_name: str, target_package: Optional[str]) -> NoReturn:
msg = get_metric_not_found_msg(metric, target_name, target_package)
raise_compiler_error(msg, metric)
def exposure_target_not_found(
exposure, target_name: str, target_package: Optional[str], disabled: Optional[bool] = None
) -> NoReturn:
msg = get_not_found_or_disabled_msg(
node=exposure,
target_name=target_name,
target_kind="exposure",
target_package=target_package,
disabled=disabled,
)
raise_compiler_error(msg, exposure)
def dependency_not_found(model, target_model_name):
raise_compiler_error(
"'{}' depends on '{}' which is not in the graph!".format(
@@ -776,13 +799,25 @@ def package_not_found(package_name):
raise_dependency_error("Package {} was not found in the package index".format(package_name))
def package_version_not_found(package_name, version_range, available_versions):
def package_version_not_found(
package_name, version_range, available_versions, should_version_check
):
base_msg = (
"Could not find a matching version for package {}\n"
"Could not find a matching compatible version for package {}\n"
" Requested range: {}\n"
" Available versions: {}"
" Compatible versions: {}\n"
)
raise_dependency_error(base_msg.format(package_name, version_range, available_versions))
addendum = (
(
"\n"
" Not shown: package versions incompatible with installed version of dbt-core\n"
" To include them, run 'dbt --no-version-check deps'"
)
if should_version_check
else ""
)
msg = base_msg.format(package_name, version_range, available_versions) + addendum
raise_dependency_error(msg)
def invalid_materialization_argument(name, argument):

View File

@@ -165,7 +165,8 @@ class NodeSelector(MethodManager):
elif unique_id in self.manifest.exposures:
return True
elif unique_id in self.manifest.metrics:
return True
metric = self.manifest.metrics[unique_id]
return metric.config.enabled
node = self.manifest.nodes[unique_id]
return not node.empty and node.config.enabled

View File

@@ -1,15 +1,63 @@
# Include Module
The Include module is reponsible for housing default macro definitions, starter project scaffold, and the html file used to generate the docs page.
The Include module is responsible for housing default macro definitions, starter project scaffold, and the html file used to generate the docs page.
# Directories
## `global_project`
Defines the default implementations of jinja2 macros for `dbt-core` which can be overwritten in each adapter repo to work more in line with those adapter plugins. To view adapter specific jinja2 changes please check the relevant adapter repo [`adapter.sql` ](https://github.com/dbt-labs/dbt-bigquery/blob/main/dbt/include/bigquery/macros/adapters.sql) file in the `include` directory or in the [`impl.py`](https://github.com/dbt-labs/dbt-bigquery/blob/main/dbt/adapters/bigquery/impl.py) file for some ex. BigQuery (truncate_relation).
These directories contain the macros which wrap model code in DDL/DML. That code, in turn, “materializes” as a fully fledged database object in a warehouse pointed to by the current `target`. Herere the major steps of this process:
1. the SQL `select` query is compiled. In its current state, it could be run directly through a query editor to retrieve a dataset that will match 1:1 the database object materialized by `dbt`.
2. `dbt` embeds this SQL query into a materialization macro.
3. `dbt` executes this materialization macro which unravels a table into a DML/DDL statement that creates/truncate-and-replenishes/replaces a relation (e.g. view, table) in the `target`.
Note: `dbt compile` will not progress past step 1. It places the code produced in `target/compiled`.
### adapter.dispatch
Packages (e.g. `include` directories of adapters, any [hub](https://hub.getdbt.com/)-hosted package) can be interpreted as namespaces of functions a.k.a macros. In `dbt`'s macrospace, we take advantage of the multiple dispatch programming language concept. In short, multiple dispatch supports dynamic searching for a function across several namespaces—usually in a manually specified manner/order.
Adapters can have their own implementation of the same macro X. For example, a macro executed by `dbt-redshift` may need a specific implementation different from `dbt-snowflake`'s macro. We use multiple dispatch via `adapter.dispatch`, a Jinja function, which enables polymorphic macro invocations. The chosen implementation is selected according to what the `adapter` object is set to at runtime (it could be for redshift, postgres, and so on).
For more on this object, check out the dbt docs [here](https://docs.getdbt.com/reference/dbt-jinja-functions/adapter).
## `starter_project`
Produces the default project after running the `dbt init` command for the CLI. `dbt-cloud` initializes the project by using [dbt-starter-project](https://github.com/dbt-labs/dbt-starter-project).
# Files
- `index.html` a file generated from [dbt-docs](https://github.com/dbt-labs/dbt-docs) prior to new releases and replaced in the `dbt-core` directory. It is used to generate the docs page after using the `generate docs` command in dbt.
# dbt and database adapter python package interop
Lets say we have a fictional python app named `dbt-core` with this structure
```
dbt
├── adapters
│   └── base.py
├── cli.py
└── main.py
```
`pip install dbt-core` will install this application in my python environment, maintaining the same structure. Note that `dbt.adapters` only contains a `base.py`. In this example, we can assume that base.py includes an abstract class for creating connections. Lets say we wanted to create an postgres adapter that this app could use, and can be installed independently. We can create a python package with the following structure called `dbt-postgres`
```
dbt
└── adapters
└── postgres
└── impl.py
```
`pip install dbt-postgres` will install this package in the python environment, maintaining the same structure again. Lets say `impl.py` imports `dbt.adapters.base` and implements a concrete class inheriting from the abstract class in `base.py` from the `dbt-core` package. Since our top level package is named the same in both packages, `pip` will put this in the same place. We end up with this installed in our python environment.
```
dbt
├── adapters
│   ├── base.py
│   └── postgres
│   └── impl.py
├── cli.py
└── main.py
```
`dbt.adapters` now has a postgres module that dbt can easily find and call directly. dbt and its adapters follows the same type of file structure convention. This is the magic that allows you to import `dbt.*` in database adapters, and using a factory pattern in dbt-core, we can create instances of concrete classes defined in the database adapter packages (for creating connections, defining database configuration, defining credentials, etc.)

View File

@@ -41,7 +41,7 @@
{% for sc in source_columns %}
{% set tc = target_columns | selectattr("name", "equalto", sc.name) | list | first %}
{% if tc %}
{% if sc.data_type != tc.data_type %}
{% if sc.data_type != tc.data_type and not sc.can_expand_to(other_column=tc) %}
{{ result.append( { 'column_name': tc.name, 'new_type': sc.data_type } ) }}
{% endif %}
{% endif %}

View File

@@ -119,6 +119,11 @@
- set the `on_schema_change` config to either append_new_columns or sync_all_columns, depending on your situation.
- Re-run the incremental model with `full_refresh: True` to update the target schema.
- update the schema manually and re-run the process.
Additional troubleshooting context:
Source columns not in target: {{ schema_changes_dict['source_not_in_target'] }}
Target columns not in source: {{ schema_changes_dict['target_not_in_source'] }}
New column types: {{ schema_changes_dict['new_target_types'] }}
{% endset %}
{% do exceptions.raise_compiler_error(fail_msg) %}

Some files were not shown because too many files have changed in this diff Show More