Compare commits

..

50 Commits

Author SHA1 Message Date
Callum McCann
fb8b161351 adding entity inheritence 2022-12-06 16:20:12 -06:00
Callum McCann
7ecb431278 making dimensions possible! 2022-12-06 13:54:28 -06:00
Callum McCann
792150ff6a let there be entity 2022-12-05 16:02:14 -06:00
leahwicz
85d0b5afc7 Reverting back to older ubuntu image (#6363)
* Reverting back to older ubuntu image

* Updating the structured logging workflow as well
2022-12-02 12:09:46 -05:00
Matthew McKnight
1fbcaa4484 reformatting of test after some spike investigation (#6314)
* reformatting of test after some spike investigation

* reformat code to pull tests back into base class definition, move a test to more appropriate spot
2022-12-01 16:54:58 -06:00
justbldwn
481235a943 clarify error log for number of allowed models in a Python file (#6251) 2022-12-01 14:43:36 -05:00
Michelle Ark
2289e45571 Exposures support metrics (#6342)
* exposures support metrics
2022-12-01 11:01:16 -05:00
dependabot[bot]
b5d303f12a Bump mashumaro[msgpack] from 3.0.4 to 3.1 in /core (#6108)
* Bump mashumaro[msgpack] from 3.0.4 to 3.1.1 in /core

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

---
updated-dependencies:
- dependency-name: mashumaro[msgpack]
  dependency-type: direct:production
  update-type: version-update:semver-minor
...
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: Michelle Ark <michelle.ark@dbtlabs.com>
2022-11-30 17:32:47 -05:00
Mila Page
c3be975783 Ct 288/convert 070 incremental test (#6330)
* Convert incremental schema tests.

* Drop the old test.

* Bad git add. My disappoint is immeasurable and my day has been ruined.

* Adjustments for flake8.

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-11-29 12:47:20 -08:00
Mila Page
47c2edb42a Ct 1518/convert 063 relation names tests (#6304)
* Convert old test.

Add documentation. Adapt and reenable previously skipped test.

* Convert test and adapt and comment for current standards.

* Remove old versions of tests.

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-11-29 12:25:36 -08:00
Stu Kilgore
b3440417ad Add GHA workflow to build CLI API docs (#6187) 2022-11-29 13:30:47 -06:00
leahwicz
020f639c7a Update stale.yml (#6258) 2022-11-29 09:40:59 -05:00
Mila Page
55db15aba8 Convert test 067. (#6305)
* Convert test 067. One bug outstanding.

* Test now working! Schema needed renaming to avoid 63 char max problems

* Remove old test.

* Add some docs and rewrite.

* Add exception for when audit tables' schema runs over the db limit.

* Code cleanup.

* Revert exception.

* Round out comments.

* Rename what shouldn't be a base class.

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-11-29 00:06:07 -08:00
Itamar Hartstein
bce0e7c096 BaseContext: expose md5 function in context (#6247)
* BaseContext: expose md5 function in context

* BaseContext: add return value type

* Add changie entry

* rename "md5" to "local_md5"

* fix test_context.py
2022-11-28 10:23:40 -05:00
Gerda Shank
7d7066466d CT 1537 fix event test and rename a couple of fields (#6293)
* Rename MacroEvent to JinjaLog

* Rename ConnectionClosed/2

* Fix LogSeedResult

* Rename ConnectionLeftOpen events, fix test_events.py

* Update events README.md, add "category" to EventInfo

* Rename GeneralMacroWarning to JinjaLogWarning
2022-11-22 14:54:20 -05:00
Emily Rockman
517576c088 add back in conditional node length check (#6298) 2022-11-21 21:20:55 -08:00
leahwicz
987764858b Revert "Bump python from 3.10.7-slim-bullseye to 3.11.0-slim-bullseye in /docker (#6180)" (#6281)
This reverts commit 8e28f5906e.
2022-11-17 09:14:22 -05:00
FishtownBuildBot
a235abd176 Add new index.html and changelog yaml files from dbt-docs (#6265) 2022-11-16 17:00:33 +01:00
dependabot[bot]
9297e4d55c Update pathspec requirement from ~=0.9.0 to >=0.9,<0.11 in /core (#5917)
* Update pathspec requirement from ~=0.9.0 to >=0.9,<0.11 in /core

Updates the requirements on [pathspec](https://github.com/cpburnz/python-pathspec) to permit the latest version.
- [Release notes](https://github.com/cpburnz/python-pathspec/releases)
- [Changelog](https://github.com/cpburnz/python-pathspec/blob/master/CHANGES.rst)
- [Commits](https://github.com/cpburnz/python-pathspec/compare/v0.9.0...v0.10.1)

---
updated-dependencies:
- dependency-name: pathspec
  dependency-type: direct:production
...

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-11-15 22:02:37 -05:00
Michelle Ark
eae98677b9 s/gitlab/github for flake8 precommit repo (#6252) 2022-11-15 10:30:00 -05:00
Matthew McKnight
66ac107409 [CT-1262] Convert dbt_debug (#6125)
* init pr for dbt_debug test conversion

* removal of old test

* minor test format change

* add new Base class and Test classes

* reformatting test, new method for capsys and error messgae to check, todo fix badproject

* refomatting tests, ready for review

* checking yaml file, and small reformat

* modifying since update wasn't working in ci/cd
2022-11-14 14:22:48 -06:00
Michelle Ark
39c5c42215 converting 044_test_run_operations (#6122)
* converting 044_test_run_operations
2022-11-14 10:39:57 -05:00
dependabot[bot]
9f280a8469 Update colorama requirement from <0.4.6,>=0.3.9 to >=0.3.9,<0.4.7 in /core (#6144)
* Update colorama requirement in /core

Updates the requirements on [colorama](https://github.com/tartley/colorama) to permit the latest version.
- [Release notes](https://github.com/tartley/colorama/releases)
- [Changelog](https://github.com/tartley/colorama/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tartley/colorama/compare/0.3.9...0.4.6)

---
updated-dependencies:
- dependency-name: colorama
  dependency-type: direct:production
...

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-11-13 09:57:33 -05:00
Joe Berni
73116fb816 feature/favor-state-node (#5859) 2022-11-09 10:58:01 -06:00
Stu Kilgore
f02243506d Convert postgres index tests (#6228) 2022-11-08 15:30:29 -06:00
Stu Kilgore
d5e9ce1797 Convert color tests to pytest (#6230) 2022-11-08 15:25:57 -06:00
Stu Kilgore
4e786184d2 Convert threading tests to pytest (#6226) 2022-11-08 08:56:10 -06:00
Chenyu Li
930bd3541e properly track hook running (#6059) 2022-11-07 10:44:29 -06:00
Gerda Shank
6c76137da4 CT 1443 remove root path (#6172)
* Remove root_path

* Bump manifest schema to 8

* Update tests and compability utility for v8, root_path removal
2022-11-04 16:38:26 -04:00
Gerda Shank
68d06d8a9c Combine various print result log events with different levels (#6174)
* Combine various print result log events with different levels

* Changie

* more merge cleanup

* Specify DynamicLevel for event classes that must specify level
2022-11-04 14:26:37 -04:00
Rachel
d0543c9242 Updates lib to use new profile name functionality (#6202)
* Updates lib to use new profile name functionality

* Adds changie entry

* Fixes formatting
2022-11-04 10:05:24 -07:00
Michelle Ark
cfad27f963 add typing to DepsTask.run (#6192) 2022-11-03 17:35:16 -04:00
Emily Rockman
c3ccbe3357 add python version and upgrade action (#6204) 2022-11-03 09:13:00 -05:00
dependabot[bot]
8e28f5906e Bump python from 3.10.7-slim-bullseye to 3.11.0-slim-bullseye in /docker (#6180)
* Bump python from 3.10.7-slim-bullseye to 3.11.0-slim-bullseye in /docker

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

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

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-11-02 08:40:51 -07:00
FishtownBuildBot
d23285b4ba Add new index.html and changelog yaml files from dbt-docs (#6112) 2022-11-02 08:36:56 -07:00
Michelle Ark
a42748433d converting 023_exit_codes_tests (#6105)
* converting 023_exit_codes_tests

* use packages fixture, clean up test names
2022-11-01 16:26:12 -04:00
Emily Rockman
be4a91a0fe Convert messages to struct logs (#6064)
* Initial structured logging changes

* remove "this" from core/dbt/events/functions.py

* CT-1047: Fix execution_time definitions to use float

* CT-1047: Revert unintended checking of changes to functions.py

* WIP

* first pass to resolve circular deps

* more circular dep resolution

* remove a bunch of duplication

* move message into log line

* update comments

* fix field that wen missing during rebase

* remove double import

* remove some comments and extra code

* fix pre-commit

* rework deprecations

* WIP converting messages

* WIP converting messages

* remove stray comment

* WIP more message conversion

* WIP more message conversion

* tweak the messages

* convert last message

* rename

* remove warn_or_raise as never used

* add fake calls to all new events

* fix some tests

* put back deprecation

* restore deprecation fully

* fix unit test

* fix log levels

* remove some skipped ids

* fix macro log function

* fix how messages are built to match expected outcome

* fix expected test message

* small fixes from reviews

* fix conflict resolution in UI

Co-authored-by: Gerda Shank <gerda@dbtlabs.com>
Co-authored-by: Peter Allen Webb <peter.webb@dbtlabs.com>
2022-10-31 12:04:56 -05:00
Emily Rockman
8145eed603 revert to community action (#6163) 2022-10-27 16:10:58 -05:00
Emily Rockman
fc00239f36 point to correct workflow (#6161)
* point to correct workflow

* add inputs
2022-10-27 14:05:09 -05:00
Ian Knox
77dfec7214 more ergonomic profile name handling (#6157) 2022-10-27 10:49:27 -05:00
Emily Rockman
7b73264ec8 switch out to use internal action for triage labels (#6120)
* switch out to use our action

* point to main
2022-10-27 08:33:15 -05:00
Mila Page
1916784287 Ct 1167/030 statement tests conversion (#6109)
* Convert test to functional set.

* Remove old statement tests from integration test set.

* Nix whitespace

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-10-26 03:37:44 -07:00
Ian Knox
c2856017a1 [BUGFIX] Force tox to update pip (fixes psycopg2-binary @ 2.9.5) (#6134) 2022-10-25 13:01:38 -05:00
Michelle Ark
17b82661d2 convert 027 cycle test (#6094)
* convert 027 cycle test

* remove no-op expect_pass=False

* remove postgres from test names
2022-10-21 11:41:51 -04:00
Michelle Ark
6c8609499a Add 'michelleark' to changie's core_team list (#6084) 2022-10-20 14:41:41 -04:00
Peter Webb
53ae325576 CT-1099: Migrate test 071_commented_yaml_regression_3568_tests (#6106) 2022-10-20 12:43:30 -04:00
Mila Page
a7670a3ab9 Add unit tests for recent stringifier functors added to events library. (#6095)
Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-10-19 22:52:32 -07:00
Mila Page
ff2f1f42c3 Working solution serialization bug. (#5874)
* Create functors to initialize event types with str-type member attributes. Before this change, the spec of various classes expected base_msg and msg params to be str's. This assumption did not always hold true. post_init hooks ensures the spec is obeyed.
* Add new changelog.
* Add msg type change functor to a few other events that could use it.

Co-authored-by: Mila Page <versusfacit@users.noreply.github.com>
2022-10-18 12:20:30 -07:00
Luke Bassett
35f7975d8f Updated string formatting on non-f-strings. (#6086)
* Updated string formatting on non-f-strings.

Found all cases of strings separated by white space on a single line and
removed white space separation. EX: "hello " "world" -> "hello world".

* add changelog entry
2022-10-17 15:58:31 -05:00
Eve Johns
a9c8bc0e0a f-string cleanup #6068 (#6082)
* fix f string issue

* removed one space

* Add changelog

* fixed return format

Co-authored-by: Leah Antkiewicz <leah.antkiewicz@fishtownanalytics.com>
2022-10-17 16:58:04 -04:00
259 changed files with 8303 additions and 7859 deletions

View File

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

View File

@@ -1,89 +0,0 @@
## dbt-core 1.4.0-b1 - December 15, 2022
### Features
- Added favor-state flag to optionally favor state nodes even if unselected node exists ([#2968](https://github.com/dbt-labs/dbt-core/issues/2968))
- Update structured logging. Convert to using protobuf messages. Ensure events are enriched with node_info. ([#5610](https://github.com/dbt-labs/dbt-core/issues/5610))
- Friendlier error messages when packages.yml is malformed ([#5486](https://github.com/dbt-labs/dbt-core/issues/5486))
- Migrate dbt-utils current_timestamp macros into core + adapters ([#5521](https://github.com/dbt-labs/dbt-core/issues/5521))
- Allow partitions in external tables to be supplied as a list ([#5929](https://github.com/dbt-labs/dbt-core/issues/5929))
- extend -f flag shorthand for seed command ([#5990](https://github.com/dbt-labs/dbt-core/issues/5990))
- This pulls the profile name from args when constructing a RuntimeConfig in lib.py, enabling the dbt-server to override the value that's in the dbt_project.yml ([#6201](https://github.com/dbt-labs/dbt-core/issues/6201))
- Adding tarball install method for packages. Allowing package tarball to be specified via url in the packages.yaml. ([#4205](https://github.com/dbt-labs/dbt-core/issues/4205))
- Added an md5 function to the base context ([#6246](https://github.com/dbt-labs/dbt-core/issues/6246))
- Exposures support metrics in lineage ([#6057](https://github.com/dbt-labs/dbt-core/issues/6057))
- Add support for Python 3.11 ([#6147](https://github.com/dbt-labs/dbt-core/issues/6147))
- incremental predicates ([#5680](https://github.com/dbt-labs/dbt-core/issues/5680))
### Fixes
- Account for disabled flags on models in schema files more completely ([#3992](https://github.com/dbt-labs/dbt-core/issues/3992))
- Add validation of enabled config for metrics, exposures and sources ([#6030](https://github.com/dbt-labs/dbt-core/issues/6030))
- check length of args of python model function before accessing it ([#6041](https://github.com/dbt-labs/dbt-core/issues/6041))
- Add functors to ensure event types with str-type attributes are initialized to spec, even when provided non-str type params. ([#5436](https://github.com/dbt-labs/dbt-core/issues/5436))
- Allow hooks to fail without halting execution flow ([#5625](https://github.com/dbt-labs/dbt-core/issues/5625))
- Clarify Error Message for how many models are allowed in a Python file ([#6245](https://github.com/dbt-labs/dbt-core/issues/6245))
- After this, will be possible to use default values for dbt.config.get ([#6309](https://github.com/dbt-labs/dbt-core/issues/6309))
- Use full path for writing manifest ([#6055](https://github.com/dbt-labs/dbt-core/issues/6055))
- [CT-1284] Change Python model default materialization to table ([#6345](https://github.com/dbt-labs/dbt-core/issues/6345))
- Repair a regression which prevented basic logging before the logging subsystem is completely configured. ([#6434](https://github.com/dbt-labs/dbt-core/issues/6434))
### Docs
- minor doc correction ([dbt-docs/#5791](https://github.com/dbt-labs/dbt-docs/issues/5791))
- Generate API docs for new CLI interface ([dbt-docs/#5528](https://github.com/dbt-labs/dbt-docs/issues/5528))
- ([dbt-docs/#5880](https://github.com/dbt-labs/dbt-docs/issues/5880))
- Fix rendering of sample code for metrics ([dbt-docs/#323](https://github.com/dbt-labs/dbt-docs/issues/323))
- Alphabetize `core/dbt/README.md` ([dbt-docs/#6368](https://github.com/dbt-labs/dbt-docs/issues/6368))
### Under the Hood
- Put black config in explicit config ([#5946](https://github.com/dbt-labs/dbt-core/issues/5946))
- Added flat_graph attribute the Manifest class's deepcopy() coverage ([#5809](https://github.com/dbt-labs/dbt-core/issues/5809))
- Add mypy configs so `mypy` passes from CLI ([#5983](https://github.com/dbt-labs/dbt-core/issues/5983))
- Exception message cleanup. ([#6023](https://github.com/dbt-labs/dbt-core/issues/6023))
- Add dmypy cache to gitignore ([#6028](https://github.com/dbt-labs/dbt-core/issues/6028))
- Provide useful errors when the value of 'materialized' is invalid ([#5229](https://github.com/dbt-labs/dbt-core/issues/5229))
- Clean up string formatting ([#6068](https://github.com/dbt-labs/dbt-core/issues/6068))
- Fixed extra whitespace in strings introduced by black. ([#1350](https://github.com/dbt-labs/dbt-core/issues/1350))
- Remove the 'root_path' field from most nodes ([#6171](https://github.com/dbt-labs/dbt-core/issues/6171))
- Combine certain logging events with different levels ([#6173](https://github.com/dbt-labs/dbt-core/issues/6173))
- Convert threading tests to pytest ([#5942](https://github.com/dbt-labs/dbt-core/issues/5942))
- Convert postgres index tests to pytest ([#5770](https://github.com/dbt-labs/dbt-core/issues/5770))
- Convert use color tests to pytest ([#5771](https://github.com/dbt-labs/dbt-core/issues/5771))
- Add github actions workflow to generate high level CLI API docs ([#5942](https://github.com/dbt-labs/dbt-core/issues/5942))
- Functionality-neutral refactor of event logging system to improve encapsulation and modularity. ([#6139](https://github.com/dbt-labs/dbt-core/issues/6139))
- Consolidate ParsedNode and CompiledNode classes ([#6383](https://github.com/dbt-labs/dbt-core/issues/6383))
- Prevent doc gen workflow from running on forks ([#6386](https://github.com/dbt-labs/dbt-core/issues/6386))
- Fix intermittent database connection failure in Windows CI test ([#6394](https://github.com/dbt-labs/dbt-core/issues/6394))
- Refactor and clean up manifest nodes ([#6426](https://github.com/dbt-labs/dbt-core/issues/6426))
- Restore important legacy logging behaviors, following refactor which removed them ([#6437](https://github.com/dbt-labs/dbt-core/issues/6437))
### Dependencies
- Update pathspec requirement from ~=0.9.0 to >=0.9,<0.11 in /core ([#5917](https://github.com/dbt-labs/dbt-core/pull/5917))
- Bump black from 22.8.0 to 22.10.0 ([#6019](https://github.com/dbt-labs/dbt-core/pull/6019))
- Bump mashumaro[msgpack] from 3.0.4 to 3.1.1 in /core ([#6108](https://github.com/dbt-labs/dbt-core/pull/6108))
- Update colorama requirement from <0.4.6,>=0.3.9 to >=0.3.9,<0.4.7 in /core ([#6144](https://github.com/dbt-labs/dbt-core/pull/6144))
- Bump mashumaro[msgpack] from 3.1.1 to 3.2 in /core ([#4904](https://github.com/dbt-labs/dbt-core/issues/4904))
### Contributors
- [@andy-clapson](https://github.com/andy-clapson) ([dbt-docs/#5791](https://github.com/dbt-labs/dbt-docs/issues/5791))
- [@chamini2](https://github.com/chamini2) ([#6041](https://github.com/dbt-labs/dbt-core/issues/6041))
- [@daniel-murray](https://github.com/daniel-murray) ([#2968](https://github.com/dbt-labs/dbt-core/issues/2968))
- [@dave-connors-3](https://github.com/dave-connors-3) ([#5990](https://github.com/dbt-labs/dbt-core/issues/5990))
- [@dbeatty10](https://github.com/dbeatty10) ([dbt-docs/#6368](https://github.com/dbt-labs/dbt-docs/issues/6368), [#6394](https://github.com/dbt-labs/dbt-core/issues/6394))
- [@devmessias](https://github.com/devmessias) ([#6309](https://github.com/dbt-labs/dbt-core/issues/6309))
- [@eve-johns](https://github.com/eve-johns) ([#6068](https://github.com/dbt-labs/dbt-core/issues/6068))
- [@haritamar](https://github.com/haritamar) ([#6246](https://github.com/dbt-labs/dbt-core/issues/6246))
- [@jared-rimmer](https://github.com/jared-rimmer) ([#5486](https://github.com/dbt-labs/dbt-core/issues/5486))
- [@josephberni](https://github.com/josephberni) ([#2968](https://github.com/dbt-labs/dbt-core/issues/2968))
- [@joshuataylor](https://github.com/joshuataylor) ([#6147](https://github.com/dbt-labs/dbt-core/issues/6147))
- [@justbldwn](https://github.com/justbldwn) ([#6245](https://github.com/dbt-labs/dbt-core/issues/6245))
- [@luke-bassett](https://github.com/luke-bassett) ([#1350](https://github.com/dbt-labs/dbt-core/issues/1350))
- [@max-sixty](https://github.com/max-sixty) ([#5946](https://github.com/dbt-labs/dbt-core/issues/5946), [#5983](https://github.com/dbt-labs/dbt-core/issues/5983), [#6028](https://github.com/dbt-labs/dbt-core/issues/6028))
- [@paulbenschmidt](https://github.com/paulbenschmidt) ([dbt-docs/#5880](https://github.com/dbt-labs/dbt-docs/issues/5880))
- [@pgoslatara](https://github.com/pgoslatara) ([#5929](https://github.com/dbt-labs/dbt-core/issues/5929))
- [@racheldaniel](https://github.com/racheldaniel) ([#6201](https://github.com/dbt-labs/dbt-core/issues/6201))
- [@timle2](https://github.com/timle2) ([#4205](https://github.com/dbt-labs/dbt-core/issues/4205))
- [@dave-connors-3](https://github.com/dave-connors-3) ([#5680](https://github.com/dbt-labs/dbt-core/issues/5680))

View File

@@ -1,7 +0,0 @@
kind: "Dependencies"
body: "Bump mashumaro[msgpack] from 3.1.1 to 3.2 in /core"
time: 2022-12-05T00:21:18.00000Z
custom:
Author: dependabot[bot]
Issue: 4904
PR: 6375

View File

@@ -1,6 +0,0 @@
kind: Docs
body: Alphabetize `core/dbt/README.md`
time: 2022-12-02T15:05:23.695333-07:00
custom:
Author: dbeatty10
Issue: "6368"

View File

@@ -1,6 +0,0 @@
kind: Features
body: Update structured logging. Convert to using protobuf messages. Ensure events are enriched with node_info.
time: 2022-08-17T15:48:57.225267-04:00
custom:
Author: gshank
Issue: "5610"

View File

@@ -1,7 +0,0 @@
kind: Features
body: incremental predicates
time: 2022-08-23T08:57:27.640804-05:00
custom:
Author: dave-connors-3
Issue: "5680"
PR: "5702"

View File

@@ -1,8 +0,0 @@
kind: Features
body: Adding tarball install method for packages. Allowing package tarball to be specified
via url in the packages.yaml.
time: 2022-11-07T10:50:18.464545-05:00
custom:
Author: timle2
Issue: "4205"
PR: "4689"

View File

@@ -1,7 +0,0 @@
kind: Features
body: Add support for Python 3.11
time: 2022-12-06T15:07:04.753127+01:00
custom:
Author: joshuataylor MichelleArk jtcohen6
Issue: "6147"
PR: "6326"

View File

@@ -1,7 +0,0 @@
kind: Fixes
body: Add functors to ensure event types with str-type attributes are initialized
to spec, even when provided non-str type params.
time: 2022-10-16T17:37:42.846683-07:00
custom:
Author: versusfacit
Issue: "5436"

View File

@@ -1,7 +0,0 @@
kind: Fixes
body: After this, will be possible to use default values for dbt.config.get
time: 2022-11-24T16:34:19.039512764-03:00
custom:
Author: devmessias
Issue: "6309"
PR: "6317"

View File

@@ -1,6 +0,0 @@
kind: Fixes
body: Use full path for writing manifest
time: 2022-12-02T16:48:59.029519-05:00
custom:
Author: gshank
Issue: "6055"

View File

@@ -1,6 +0,0 @@
kind: Fixes
body: '[CT-1284] Change Python model default materialization to table'
time: 2022-12-13T11:26:20.550017-08:00
custom:
Author: aranke
Issue: "6345"

View File

@@ -1,7 +0,0 @@
kind: Fixes
body: Repair a regression which prevented basic logging before the logging subsystem
is completely configured.
time: 2022-12-14T15:53:07.396512-05:00
custom:
Author: peterallenwebb
Issue: "6434"

View File

@@ -1,6 +0,0 @@
kind: Under the Hood
body: Fixed extra whitespace in strings introduced by black.
time: 2022-10-17T15:15:11.499246-05:00
custom:
Author: luke-bassett
Issue: "1350"

View File

@@ -1,6 +0,0 @@
kind: Under the Hood
body: Clean up string formatting
time: 2022-10-17T15:58:44.676549-04:00
custom:
Author: eve-johns
Issue: "6068"

View File

@@ -1,8 +0,0 @@
kind: Under the Hood
body: Functionality-neutral refactor of event logging system to improve encapsulation
and modularity.
time: 2022-11-18T14:57:17.792622-05:00
custom:
Author: peterallenwebb
Issue: "6139"
PR: "6291"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Consolidate ParsedNode and CompiledNode classes
time: 2022-12-05T16:49:48.563583-05:00
custom:
Author: gshank
Issue: "6383"
PR: "6384"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Prevent doc gen workflow from running on forks
time: 2022-12-06T09:40:15.301984-06:00
custom:
Author: stu-k
Issue: "6386"
PR: "6390"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Fix intermittent database connection failure in Windows CI test
time: 2022-12-06T11:30:53.166009-07:00
custom:
Author: MichelleArk dbeatty10
Issue: "6394"
PR: "6395"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Refactor and clean up manifest nodes
time: 2022-12-11T21:42:40.560074-05:00
custom:
Author: gshank
Issue: "6426"
PR: "6427"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Restore important legacy logging behaviors, following refactor which removed
them
time: 2022-12-13T21:41:06.815133-05:00
custom:
Author: peterallenwebb
Issue: "6437"

View File

@@ -1,9 +0,0 @@
kind: Breaking Changes
body: Cleaned up exceptions to directly raise in code. Removed use of all exception
functions in the code base and marked them all as deprecated to be removed next
minor release.
time: 2022-12-05T14:19:37.863032-06:00
custom:
Author: emmyoop
Issue: "6339"
PR: "6347"

View File

@@ -1,6 +1,7 @@
kind: "Dependencies" kind: "Dependency"
body: "Update pathspec requirement from ~=0.9.0 to >=0.9,<0.11 in /core" body: "Update pathspec requirement from ~=0.9.0 to >=0.9,<0.11 in /core"
time: 2022-09-23T00:06:46.00000Z time: 2022-09-23T00:06:46.00000Z
custom: custom:
Author: dependabot[bot] Author: dependabot[bot]
PR: "5917" Issue: 4904
PR: 5917

View File

@@ -1,6 +1,7 @@
kind: "Dependencies" kind: "Dependency"
body: "Bump black from 22.8.0 to 22.10.0" body: "Bump black from 22.8.0 to 22.10.0"
time: 2022-10-07T00:08:48.00000Z time: 2022-10-07T00:08:48.00000Z
custom: custom:
Author: dependabot[bot] Author: dependabot[bot]
PR: "6019" Issue: 4904
PR: 6019

View File

@@ -1,6 +1,7 @@
kind: "Dependencies" kind: "Dependency"
body: "Bump mashumaro[msgpack] from 3.0.4 to 3.1.1 in /core" body: "Bump mashumaro[msgpack] from 3.0.4 to 3.1.1 in /core"
time: 2022-10-20T00:07:53.00000Z time: 2022-10-20T00:07:53.00000Z
custom: custom:
Author: dependabot[bot] Author: dependabot[bot]
PR: "6108" Issue: 4904
PR: 6108

View File

@@ -1,6 +1,7 @@
kind: "Dependencies" kind: "Dependency"
body: "Update colorama requirement from <0.4.6,>=0.3.9 to >=0.3.9,<0.4.7 in /core" body: "Update colorama requirement from <0.4.6,>=0.3.9 to >=0.3.9,<0.4.7 in /core"
time: 2022-10-26T00:09:10.00000Z time: 2022-10-26T00:09:10.00000Z
custom: custom:
Author: dependabot[bot] Author: dependabot[bot]
PR: "6144" Issue: 4904
PR: 6144

View File

@@ -4,3 +4,4 @@ time: 2022-09-08T15:41:57.689162-04:00
custom: custom:
Author: andy-clapson Author: andy-clapson
Issue: "5791" Issue: "5791"
PR: "5684"

View File

@@ -4,3 +4,4 @@ time: 2022-10-07T09:06:56.446078-05:00
custom: custom:
Author: stu-k Author: stu-k
Issue: "5528" Issue: "5528"
PR: "6022"

View File

@@ -3,3 +3,4 @@ time: 2022-10-17T17:14:11.715348-05:00
custom: custom:
Author: paulbenschmidt Author: paulbenschmidt
Issue: "5880" Issue: "5880"
PR: "324"

View File

@@ -4,3 +4,4 @@ time: 2022-11-16T15:57:43.204201+01:00
custom: custom:
Author: jtcohen6 Author: jtcohen6
Issue: "323" Issue: "323"
PR: "346"

View File

@@ -5,3 +5,4 @@ time: 2022-04-08T16:54:59.696564+01:00
custom: custom:
Author: daniel-murray josephberni Author: daniel-murray josephberni
Issue: "2968" Issue: "2968"
PR: "5859"

View File

@@ -0,0 +1,7 @@
kind: Features
body: Proto logging messages
time: 2022-08-17T15:48:57.225267-04:00
custom:
Author: gshank
Issue: "5610"
PR: "5643"

View File

@@ -4,3 +4,4 @@ time: 2022-09-12T12:59:35.121188+01:00
custom: custom:
Author: jared-rimmer Author: jared-rimmer
Issue: "5486" Issue: "5486"
PR: "5812"

View File

@@ -4,3 +4,4 @@ time: 2022-09-14T09:56:25.97818-07:00
custom: custom:
Author: colin-rogers-dbt Author: colin-rogers-dbt
Issue: "5521" Issue: "5521"
PR: "5838"

View File

@@ -4,3 +4,4 @@ time: 2022-09-25T21:16:51.051239654+02:00
custom: custom:
Author: pgoslatara Author: pgoslatara
Issue: "5929" Issue: "5929"
PR: "5930"

View File

@@ -4,3 +4,4 @@ time: 2022-10-03T11:07:05.381632-05:00
custom: custom:
Author: dave-connors-3 Author: dave-connors-3
Issue: "5990" Issue: "5990"
PR: "5991"

View File

@@ -5,3 +5,4 @@ time: 2022-11-02T15:00:03.000805-05:00
custom: custom:
Author: racheldaniel Author: racheldaniel
Issue: "6201" Issue: "6201"
PR: "6202"

View File

@@ -4,3 +4,4 @@ time: 2022-11-14T18:52:07.788593+02:00
custom: custom:
Author: haritamar Author: haritamar
Issue: "6246" Issue: "6246"
PR: "6247"

View File

@@ -1,7 +0,0 @@
kind: Features
body: Click CLI Flags work with UserConfig
time: 2022-11-29T18:32:39.068035-05:00
custom:
Author: michelleark
Issue: "6327"
PR: "6266"

View File

@@ -4,3 +4,4 @@ time: 2022-11-30T11:29:13.256034-05:00
custom: custom:
Author: michelleark Author: michelleark
Issue: "6057" Issue: "6057"
PR: "6342"

View File

@@ -4,3 +4,4 @@ time: 2022-09-16T10:48:54.162273-05:00
custom: custom:
Author: emmyoop Author: emmyoop
Issue: "3992" Issue: "3992"
PR: "5868"

View File

@@ -4,3 +4,4 @@ time: 2022-10-10T11:32:18.752322-05:00
custom: custom:
Author: emmyoop Author: emmyoop
Issue: "6030" Issue: "6030"
PR: "6038"

View File

@@ -4,3 +4,4 @@ time: 2022-10-11T16:07:15.464093-04:00
custom: custom:
Author: chamini2 Author: chamini2
Issue: "6041" Issue: "6041"
PR: "6042"

View File

@@ -4,3 +4,4 @@ time: 2022-11-07T09:53:14.340257-06:00
custom: custom:
Author: ChenyuLInx Author: ChenyuLInx
Issue: "5625" Issue: "5625"
PR: "6059"

View File

@@ -4,3 +4,4 @@ time: 2022-11-15T08:10:21.527884-05:00
custom: custom:
Author: justbldwn Author: justbldwn
Issue: "6245" Issue: "6245"
PR: "6251"

View File

@@ -1,7 +0,0 @@
kind: Fixes
body: Fix typo in util.py
time: 2022-11-17T22:03:20.4836855+09:00
custom:
Author: eltociear
Issue: "4904"
PR: "6037"

View File

@@ -1,6 +0,0 @@
kind: Fixes
body: '[CT-1591] Don''t parse empty Python files'
time: 2022-12-13T11:39:15.818464-08:00
custom:
Author: aranke
Issue: "6345"

View File

@@ -4,3 +4,4 @@ time: 2022-09-27T19:42:59.241433-07:00
custom: custom:
Author: max-sixty Author: max-sixty
Issue: "5946" Issue: "5946"
PR: "5947"

View File

@@ -4,3 +4,4 @@ time: 2022-09-29T13:44:06.275941-04:00
custom: custom:
Author: peterallenwebb Author: peterallenwebb
Issue: "5809" Issue: "5809"
PR: "5975"

View File

@@ -4,3 +4,4 @@ time: 2022-10-05T12:03:10.061263-07:00
custom: custom:
Author: max-sixty Author: max-sixty
Issue: "5983" Issue: "5983"
PR: "5983"

View File

@@ -4,3 +4,4 @@ time: 2022-10-07T09:46:27.682872-05:00
custom: custom:
Author: emmyoop Author: emmyoop
Issue: "6023" Issue: "6023"
PR: "6024"

View File

@@ -4,3 +4,4 @@ time: 2022-10-07T14:00:44.227644-07:00
custom: custom:
Author: max-sixty Author: max-sixty
Issue: "6028" Issue: "6028"
PR: "5978"

View File

@@ -4,3 +4,4 @@ time: 2022-10-13T18:19:12.167548-04:00
custom: custom:
Author: peterallenwebb Author: peterallenwebb
Issue: "5229" Issue: "5229"
PR: "6025"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Click CLI supports logging
time: 2022-10-17T17:05:00.478948-05:00
custom:
Author: iknox-fa
Issue: "5530"
PR: "6088"

View File

@@ -4,3 +4,4 @@ time: 2022-10-28T10:48:37.687886-04:00
custom: custom:
Author: gshank Author: gshank
Issue: "6171" Issue: "6171"
PR: "6172"

View File

@@ -4,3 +4,4 @@ time: 2022-10-28T11:03:44.887836-04:00
custom: custom:
Author: gshank Author: gshank
Issue: "6173" Issue: "6173"
PR: "6174"

View File

@@ -4,3 +4,4 @@ time: 2022-11-08T07:45:50.589147-06:00
custom: custom:
Author: stu-k Author: stu-k
Issue: "5942" Issue: "5942"
PR: "6226"

View File

@@ -4,3 +4,4 @@ time: 2022-11-08T11:56:33.743042-06:00
custom: custom:
Author: stu-k Author: stu-k
Issue: "5770" Issue: "5770"
PR: "6228"

View File

@@ -4,3 +4,4 @@ time: 2022-11-08T13:31:04.788547-06:00
custom: custom:
Author: stu-k Author: stu-k
Issue: "5771" Issue: "5771"
PR: "6230"

View File

@@ -4,3 +4,4 @@ time: 2022-11-16T13:00:37.916202-06:00
custom: custom:
Author: stu-k Author: stu-k
Issue: "5942" Issue: "5942"
PR: "6187"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: '`dbt clean` works with click cli'
time: 2022-12-02T12:30:46.711184-06:00
custom:
Author: stu-k
Issue: "5542"
PR: "6369"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Adds Profile support to the new Click CLI
time: 2022-12-04T16:11:10.417872-06:00
custom:
Author: iknox-fa ChenyuLInx
Issue: "5536"
PR: "6336"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Pin ubuntu at 20.04 for some workflows
time: 2022-12-05T09:22:17.614875-06:00
custom:
Author: stu-k
Issue: "9999"
PR: "6380"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: '`dbt run` works with Click cli'
time: 2022-12-06T15:17:59.765623-06:00
custom:
Author: iknox-fa
Issue: "5551"
PR: "6396"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Cherry pick tox fix
time: 2022-12-12T11:08:59.440276-06:00
custom:
Author: stu-k
Issue: "9999"
PR: "6430"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: functional tests run using click cli through dbtRunner
time: 2022-12-14T11:20:48.521869-05:00
custom:
Author: MichelleArk
Issue: "6096"
PR: "6387"

View File

@@ -1,6 +0,0 @@
kind: Under the Hood
body: Treat dense text blobs as binary for `git grep`
time: 2022-12-19T19:34:35.890275-07:00
custom:
Author: dbeatty10
Issue: "6294"

View File

@@ -1,7 +0,0 @@
kind: Under the Hood
body: Remove UnsetProfileConfig
time: 2023-01-05T10:47:48.707656-05:00
custom:
Author: MichelleArk
Issue: "5539"
PR: "6504"

View File

@@ -6,67 +6,19 @@ changelogPath: CHANGELOG.md
versionExt: md versionExt: md
versionFormat: '## dbt-core {{.Version}} - {{.Time.Format "January 02, 2006"}}' versionFormat: '## dbt-core {{.Version}} - {{.Time.Format "January 02, 2006"}}'
kindFormat: '### {{.Kind}}' kindFormat: '### {{.Kind}}'
changeFormat: |- 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}}))'
{{- $IssueList := list }}
{{- $changes := splitList " " $.Custom.Issue }}
{{- range $issueNbr := $changes }}
{{- $changeLink := "[#nbr](https://github.com/dbt-labs/dbt-core/issues/nbr)" | replace "nbr" $issueNbr }}
{{- $IssueList = append $IssueList $changeLink }}
{{- end -}}
- {{.Body}} ({{ range $index, $element := $IssueList }}{{if $index}}, {{end}}{{$element}}{{end}})
kinds: kinds:
- label: Breaking Changes - label: Breaking Changes
- label: Features - label: Features
- label: Fixes - label: Fixes
- label: Docs - label: Docs
changeFormat: |- 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}}))'
{{- $IssueList := list }}
{{- $changes := splitList " " $.Custom.Issue }}
{{- range $issueNbr := $changes }}
{{- $changeLink := "[dbt-docs/#nbr](https://github.com/dbt-labs/dbt-docs/issues/nbr)" | replace "nbr" $issueNbr }}
{{- $IssueList = append $IssueList $changeLink }}
{{- end -}}
- {{.Body}} ({{ range $index, $element := $IssueList }}{{if $index}}, {{end}}{{$element}}{{end}})
- label: Under the Hood - label: Under the Hood
- label: Dependencies - label: Dependencies
changeFormat: |- 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}}))'
{{- $PRList := list }}
{{- $changes := splitList " " $.Custom.PR }}
{{- range $pullrequest := $changes }}
{{- $changeLink := "[#nbr](https://github.com/dbt-labs/dbt-core/pull/nbr)" | replace "nbr" $pullrequest }}
{{- $PRList = append $PRList $changeLink }}
{{- end -}}
- {{.Body}} ({{ range $index, $element := $PRList }}{{if $index}}, {{end}}{{$element}}{{end}})
skipGlobalChoices: true
additionalChoices:
- key: Author
label: GitHub Username(s) (separated by a single space if multiple)
type: string
minLength: 3
- key: PR
label: GitHub Pull Request Number (separated by a single space if multiple)
type: string
minLength: 1
- label: Security - label: Security
changeFormat: |- 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}}))'
{{- $PRList := list }}
{{- $changes := splitList " " $.Custom.PR }}
{{- range $pullrequest := $changes }}
{{- $changeLink := "[#nbr](https://github.com/dbt-labs/dbt-core/pull/nbr)" | replace "nbr" $pullrequest }}
{{- $PRList = append $PRList $changeLink }}
{{- end -}}
- {{.Body}} ({{ range $index, $element := $PRList }}{{if $index}}, {{end}}{{$element}}{{end}})
skipGlobalChoices: true
additionalChoices:
- key: Author
label: GitHub Username(s) (separated by a single space if multiple)
type: string
minLength: 3
- key: PR
label: GitHub Pull Request Number (separated by a single space if multiple)
type: string
minLength: 1
newlines: newlines:
afterChangelogHeader: 1 afterChangelogHeader: 1
@@ -81,41 +33,42 @@ custom:
type: string type: string
minLength: 3 minLength: 3
- key: Issue - key: Issue
label: GitHub Issue Number (separated by a single space if multiple) label: GitHub Issue Number
type: string type: int
minLength: 1 minInt: 1
- key: PR
label: GitHub Pull Request Number
type: int
minInt: 1
footerFormat: | footerFormat: |
{{- $contributorDict := dict }} {{- $contributorDict := dict }}
{{- /* any names added to this list should be all lowercase for later matching purposes */}} {{- /* any names added to this list should be all lowercase for later matching purposes */}}
{{- $core_team := list "michelleark" "peterallenwebb" "emmyoop" "nathaniel-may" "gshank" "leahwicz" "chenyulinx" "stu-k" "iknox-fa" "versusfacit" "mcknight-42" "jtcohen6" "aranke" "dependabot[bot]" "snyk-bot" "colin-rogers-dbt" }} {{- $core_team := list "michelleark" "peterallenwebb" "emmyoop" "nathaniel-may" "gshank" "leahwicz" "chenyulinx" "stu-k" "iknox-fa" "versusfacit" "mcknight-42" "jtcohen6" "dependabot[bot]" "snyk-bot" "colin-rogers-dbt" }}
{{- range $change := .Changes }} {{- range $change := .Changes }}
{{- $authorList := splitList " " $change.Custom.Author }} {{- $authorList := splitList " " $change.Custom.Author }}
{{- /* loop through all authors for a single changelog */}} {{- /* loop through all authors for a PR */}}
{{- range $author := $authorList }} {{- range $author := $authorList }}
{{- $authorLower := lower $author }} {{- $authorLower := lower $author }}
{{- /* we only want to include non-core team contributors */}} {{- /* we only want to include non-core team contributors */}}
{{- if not (has $authorLower $core_team)}} {{- if not (has $authorLower $core_team)}}
{{- $changeList := splitList " " $change.Custom.Author }} {{- /* Docs kind link back to dbt-docs instead of dbt-core PRs */}}
{{- /* Docs kind link back to dbt-docs instead of dbt-core issues */}} {{- $prLink := $change.Kind }}
{{- $changeLink := $change.Kind }} {{- if eq $change.Kind "Docs" }}
{{- if or (eq $change.Kind "Dependencies") (eq $change.Kind "Security") }} {{- $prLink = "[dbt-docs/#pr](https://github.com/dbt-labs/dbt-docs/pull/pr)" | replace "pr" $change.Custom.PR }}
{{- $changeLink = "[#nbr](https://github.com/dbt-labs/dbt-core/pull/nbr)" | replace "nbr" $change.Custom.PR }} {{- else }}
{{- else if eq $change.Kind "Docs"}} {{- $prLink = "[#pr](https://github.com/dbt-labs/dbt-core/pull/pr)" | replace "pr" $change.Custom.PR }}
{{- $changeLink = "[dbt-docs/#nbr](https://github.com/dbt-labs/dbt-docs/issues/nbr)" | replace "nbr" $change.Custom.Issue }} {{- end }}
{{- else }} {{- /* check if this contributor has other PRs associated with them already */}}
{{- $changeLink = "[#nbr](https://github.com/dbt-labs/dbt-core/issues/nbr)" | replace "nbr" $change.Custom.Issue }} {{- if hasKey $contributorDict $author }}
{{- end }} {{- $prList := get $contributorDict $author }}
{{- /* check if this contributor has other changes associated with them already */}} {{- $prList = append $prList $prLink }}
{{- if hasKey $contributorDict $author }} {{- $contributorDict := set $contributorDict $author $prList }}
{{- $contributionList := get $contributorDict $author }} {{- else }}
{{- $contributionList = append $contributionList $changeLink }} {{- $prList := list $prLink }}
{{- $contributorDict := set $contributorDict $author $contributionList }} {{- $contributorDict := set $contributorDict $author $prList }}
{{- else }} {{- end }}
{{- $contributionList := list $changeLink }} {{- end}}
{{- $contributorDict := set $contributorDict $author $contributionList }}
{{- end }}
{{- end}}
{{- end}} {{- end}}
{{- end }} {{- end }}
{{- /* no indentation here for formatting so the final markdown doesn't have unneeded indentations */}} {{- /* no indentation here for formatting so the final markdown doesn't have unneeded indentations */}}

2
.gitattributes vendored
View File

@@ -1,2 +0,0 @@
core/dbt/include/index.html binary
tests/functional/artifacts/data/state/*/manifest.json binary

View File

@@ -40,7 +40,7 @@ jobs:
matrix: matrix:
include: include:
- label: "dependencies" - label: "dependencies"
changie_kind: "Dependencies" changie_kind: "Dependency"
- label: "snyk" - label: "snyk"
changie_kind: "Security" changie_kind: "Security"
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -58,4 +58,4 @@ jobs:
commit_message: "Add automated changelog yaml from template for bot PR" commit_message: "Add automated changelog yaml from template for bot PR"
changie_kind: ${{ matrix.changie_kind }} changie_kind: ${{ matrix.changie_kind }}
label: ${{ matrix.label }} label: ${{ matrix.label }}
custom_changelog_string: "custom:\n Author: ${{ github.event.pull_request.user.login }}\n PR: ${{ github.event.pull_request.number }}" custom_changelog_string: "custom:\n Author: ${{ github.event.pull_request.user.login }}\n Issue: 4904\n PR: ${{ github.event.pull_request.number }}"

View File

@@ -34,7 +34,6 @@ jobs:
check_gen: check_gen:
name: check if generation needed name: check if generation needed
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.event.pull_request.head.repo.fork == false }}
outputs: outputs:
cli_dir_changed: ${{ steps.check_cli.outputs.cli_dir_changed }} cli_dir_changed: ${{ steps.check_cli.outputs.cli_dir_changed }}
docs_dir_changed: ${{ steps.check_docs.outputs.docs_dir_changed }} docs_dir_changed: ${{ steps.check_docs.outputs.docs_dir_changed }}
@@ -45,6 +44,8 @@ jobs:
echo "env.CLI_DIR: ${{ env.CLI_DIR }}" echo "env.CLI_DIR: ${{ env.CLI_DIR }}"
echo "env.DOCS_BUILD_DIR: ${{ env.DOCS_BUILD_DIR }}" echo "env.DOCS_BUILD_DIR: ${{ env.DOCS_BUILD_DIR }}"
echo "env.DOCS_DIR: ${{ env.DOCS_DIR }}" echo "env.DOCS_DIR: ${{ env.DOCS_DIR }}"
echo ">>>>> git log"
git log --pretty=oneline | head -5
- name: git checkout - name: git checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -145,7 +146,6 @@ jobs:
echo "creating docs" echo "creating docs"
make html make html
make markdown
- name: debug - name: debug
run: | run: |

View File

@@ -73,7 +73,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] python-version: ["3.7", "3.8", "3.9", "3.10"]
env: env:
TOXENV: "unit" TOXENV: "unit"
@@ -118,7 +118,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] python-version: ["3.7", "3.8", "3.9", "3.10"]
os: [ubuntu-20.04] os: [ubuntu-20.04]
include: include:
- python-version: 3.8 - python-version: 3.8

View File

@@ -5,96 +5,6 @@
- "Breaking changes" listed under a version may require action from end users or external maintainers when upgrading to that version. - "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) - 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.4.0-b1 - December 15, 2022
### Features
- Added favor-state flag to optionally favor state nodes even if unselected node exists ([#2968](https://github.com/dbt-labs/dbt-core/issues/2968))
- Update structured logging. Convert to using protobuf messages. Ensure events are enriched with node_info. ([#5610](https://github.com/dbt-labs/dbt-core/issues/5610))
- Friendlier error messages when packages.yml is malformed ([#5486](https://github.com/dbt-labs/dbt-core/issues/5486))
- Migrate dbt-utils current_timestamp macros into core + adapters ([#5521](https://github.com/dbt-labs/dbt-core/issues/5521))
- Allow partitions in external tables to be supplied as a list ([#5929](https://github.com/dbt-labs/dbt-core/issues/5929))
- extend -f flag shorthand for seed command ([#5990](https://github.com/dbt-labs/dbt-core/issues/5990))
- This pulls the profile name from args when constructing a RuntimeConfig in lib.py, enabling the dbt-server to override the value that's in the dbt_project.yml ([#6201](https://github.com/dbt-labs/dbt-core/issues/6201))
- Adding tarball install method for packages. Allowing package tarball to be specified via url in the packages.yaml. ([#4205](https://github.com/dbt-labs/dbt-core/issues/4205))
- Added an md5 function to the base context ([#6246](https://github.com/dbt-labs/dbt-core/issues/6246))
- Exposures support metrics in lineage ([#6057](https://github.com/dbt-labs/dbt-core/issues/6057))
- Add support for Python 3.11 ([#6147](https://github.com/dbt-labs/dbt-core/issues/6147))
- incremental predicates ([#5680](https://github.com/dbt-labs/dbt-core/issues/5680))
### Fixes
- Account for disabled flags on models in schema files more completely ([#3992](https://github.com/dbt-labs/dbt-core/issues/3992))
- Add validation of enabled config for metrics, exposures and sources ([#6030](https://github.com/dbt-labs/dbt-core/issues/6030))
- check length of args of python model function before accessing it ([#6041](https://github.com/dbt-labs/dbt-core/issues/6041))
- Add functors to ensure event types with str-type attributes are initialized to spec, even when provided non-str type params. ([#5436](https://github.com/dbt-labs/dbt-core/issues/5436))
- Allow hooks to fail without halting execution flow ([#5625](https://github.com/dbt-labs/dbt-core/issues/5625))
- Clarify Error Message for how many models are allowed in a Python file ([#6245](https://github.com/dbt-labs/dbt-core/issues/6245))
- After this, will be possible to use default values for dbt.config.get ([#6309](https://github.com/dbt-labs/dbt-core/issues/6309))
- Use full path for writing manifest ([#6055](https://github.com/dbt-labs/dbt-core/issues/6055))
- [CT-1284] Change Python model default materialization to table ([#6345](https://github.com/dbt-labs/dbt-core/issues/6345))
- Repair a regression which prevented basic logging before the logging subsystem is completely configured. ([#6434](https://github.com/dbt-labs/dbt-core/issues/6434))
### Docs
- minor doc correction ([dbt-docs/#5791](https://github.com/dbt-labs/dbt-docs/issues/5791))
- Generate API docs for new CLI interface ([dbt-docs/#5528](https://github.com/dbt-labs/dbt-docs/issues/5528))
- ([dbt-docs/#5880](https://github.com/dbt-labs/dbt-docs/issues/5880))
- Fix rendering of sample code for metrics ([dbt-docs/#323](https://github.com/dbt-labs/dbt-docs/issues/323))
- Alphabetize `core/dbt/README.md` ([dbt-docs/#6368](https://github.com/dbt-labs/dbt-docs/issues/6368))
### Under the Hood
- Put black config in explicit config ([#5946](https://github.com/dbt-labs/dbt-core/issues/5946))
- Added flat_graph attribute the Manifest class's deepcopy() coverage ([#5809](https://github.com/dbt-labs/dbt-core/issues/5809))
- Add mypy configs so `mypy` passes from CLI ([#5983](https://github.com/dbt-labs/dbt-core/issues/5983))
- Exception message cleanup. ([#6023](https://github.com/dbt-labs/dbt-core/issues/6023))
- Add dmypy cache to gitignore ([#6028](https://github.com/dbt-labs/dbt-core/issues/6028))
- Provide useful errors when the value of 'materialized' is invalid ([#5229](https://github.com/dbt-labs/dbt-core/issues/5229))
- Clean up string formatting ([#6068](https://github.com/dbt-labs/dbt-core/issues/6068))
- Fixed extra whitespace in strings introduced by black. ([#1350](https://github.com/dbt-labs/dbt-core/issues/1350))
- Remove the 'root_path' field from most nodes ([#6171](https://github.com/dbt-labs/dbt-core/issues/6171))
- Combine certain logging events with different levels ([#6173](https://github.com/dbt-labs/dbt-core/issues/6173))
- Convert threading tests to pytest ([#5942](https://github.com/dbt-labs/dbt-core/issues/5942))
- Convert postgres index tests to pytest ([#5770](https://github.com/dbt-labs/dbt-core/issues/5770))
- Convert use color tests to pytest ([#5771](https://github.com/dbt-labs/dbt-core/issues/5771))
- Add github actions workflow to generate high level CLI API docs ([#5942](https://github.com/dbt-labs/dbt-core/issues/5942))
- Functionality-neutral refactor of event logging system to improve encapsulation and modularity. ([#6139](https://github.com/dbt-labs/dbt-core/issues/6139))
- Consolidate ParsedNode and CompiledNode classes ([#6383](https://github.com/dbt-labs/dbt-core/issues/6383))
- Prevent doc gen workflow from running on forks ([#6386](https://github.com/dbt-labs/dbt-core/issues/6386))
- Fix intermittent database connection failure in Windows CI test ([#6394](https://github.com/dbt-labs/dbt-core/issues/6394))
- Refactor and clean up manifest nodes ([#6426](https://github.com/dbt-labs/dbt-core/issues/6426))
- Restore important legacy logging behaviors, following refactor which removed them ([#6437](https://github.com/dbt-labs/dbt-core/issues/6437))
### Dependencies
- Update pathspec requirement from ~=0.9.0 to >=0.9,<0.11 in /core ([#5917](https://github.com/dbt-labs/dbt-core/pull/5917))
- Bump black from 22.8.0 to 22.10.0 ([#6019](https://github.com/dbt-labs/dbt-core/pull/6019))
- Bump mashumaro[msgpack] from 3.0.4 to 3.1.1 in /core ([#6108](https://github.com/dbt-labs/dbt-core/pull/6108))
- Update colorama requirement from <0.4.6,>=0.3.9 to >=0.3.9,<0.4.7 in /core ([#6144](https://github.com/dbt-labs/dbt-core/pull/6144))
- Bump mashumaro[msgpack] from 3.1.1 to 3.2 in /core ([#4904](https://github.com/dbt-labs/dbt-core/issues/4904))
### Contributors
- [@andy-clapson](https://github.com/andy-clapson) ([dbt-docs/#5791](https://github.com/dbt-labs/dbt-docs/issues/5791))
- [@chamini2](https://github.com/chamini2) ([#6041](https://github.com/dbt-labs/dbt-core/issues/6041))
- [@daniel-murray](https://github.com/daniel-murray) ([#2968](https://github.com/dbt-labs/dbt-core/issues/2968))
- [@dave-connors-3](https://github.com/dave-connors-3) ([#5990](https://github.com/dbt-labs/dbt-core/issues/5990))
- [@dbeatty10](https://github.com/dbeatty10) ([dbt-docs/#6368](https://github.com/dbt-labs/dbt-docs/issues/6368), [#6394](https://github.com/dbt-labs/dbt-core/issues/6394))
- [@devmessias](https://github.com/devmessias) ([#6309](https://github.com/dbt-labs/dbt-core/issues/6309))
- [@eve-johns](https://github.com/eve-johns) ([#6068](https://github.com/dbt-labs/dbt-core/issues/6068))
- [@haritamar](https://github.com/haritamar) ([#6246](https://github.com/dbt-labs/dbt-core/issues/6246))
- [@jared-rimmer](https://github.com/jared-rimmer) ([#5486](https://github.com/dbt-labs/dbt-core/issues/5486))
- [@josephberni](https://github.com/josephberni) ([#2968](https://github.com/dbt-labs/dbt-core/issues/2968))
- [@joshuataylor](https://github.com/joshuataylor) ([#6147](https://github.com/dbt-labs/dbt-core/issues/6147))
- [@justbldwn](https://github.com/justbldwn) ([#6245](https://github.com/dbt-labs/dbt-core/issues/6245))
- [@luke-bassett](https://github.com/luke-bassett) ([#1350](https://github.com/dbt-labs/dbt-core/issues/1350))
- [@max-sixty](https://github.com/max-sixty) ([#5946](https://github.com/dbt-labs/dbt-core/issues/5946), [#5983](https://github.com/dbt-labs/dbt-core/issues/5983), [#6028](https://github.com/dbt-labs/dbt-core/issues/6028))
- [@paulbenschmidt](https://github.com/paulbenschmidt) ([dbt-docs/#5880](https://github.com/dbt-labs/dbt-docs/issues/5880))
- [@pgoslatara](https://github.com/pgoslatara) ([#5929](https://github.com/dbt-labs/dbt-core/issues/5929))
- [@racheldaniel](https://github.com/racheldaniel) ([#6201](https://github.com/dbt-labs/dbt-core/issues/6201))
- [@timle2](https://github.com/timle2) ([#4205](https://github.com/dbt-labs/dbt-core/issues/4205))
- [@dave-connors-3](https://github.com/dave-connors-3) ([#5680](https://github.com/dbt-labs/dbt-core/issues/5680))
## Previous Releases ## Previous Releases

View File

@@ -56,7 +56,7 @@ There are some tools that will be helpful to you in developing locally. While th
These are the tools used in `dbt-core` development and testing: These are the tools used in `dbt-core` development and testing:
- [`tox`](https://tox.readthedocs.io/en/latest/) to manage virtualenvs across python versions. We currently target the latest patch releases for Python 3.7, 3.8, 3.9, 3.10 and 3.11 - [`tox`](https://tox.readthedocs.io/en/latest/) to manage virtualenvs across python versions. We currently target the latest patch releases for Python 3.7, 3.8, 3.9, and 3.10
- [`pytest`](https://docs.pytest.org/en/latest/) to define, discover, and run tests - [`pytest`](https://docs.pytest.org/en/latest/) to define, discover, and run tests
- [`flake8`](https://flake8.pycqa.org/en/latest/) for code linting - [`flake8`](https://flake8.pycqa.org/en/latest/) for code linting
- [`black`](https://github.com/psf/black) for code formatting - [`black`](https://github.com/psf/black) for code formatting
@@ -160,7 +160,7 @@ suites.
#### `tox` #### `tox`
[`tox`](https://tox.readthedocs.io/en/latest/) takes care of managing virtualenvs and install dependencies in order to run tests. You can also run tests in parallel, for example, you can run unit tests for Python 3.7, Python 3.8, Python 3.9, Python 3.10 and Python 3.11 checks in parallel with `tox -p`. Also, you can run unit tests for specific python versions with `tox -e py37`. The configuration for these tests in located in `tox.ini`. [`tox`](https://tox.readthedocs.io/en/latest/) takes care of managing virtualenvs and install dependencies in order to run tests. You can also run tests in parallel, for example, you can run unit tests for Python 3.7, Python 3.8, Python 3.9, and Python 3.10 checks in parallel with `tox -p`. Also, you can run unit tests for specific python versions with `tox -e py37`. The configuration for these tests in located in `tox.ini`.
#### `pytest` #### `pytest`
@@ -201,21 +201,13 @@ Here are some general rules for adding tests:
* 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. * 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. * 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 or modifying a CHANGELOG Entry ## 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. We use [changie](https://changie.dev) to generate `CHANGELOG` entries. **Note:** Do not edit the `CHANGELOG.md` directly. Your modifications will be lost.
Follow the steps to [install `changie`](https://changie.dev/guide/installation/) for your system. Follow the steps to [install `changie`](https://changie.dev/guide/installation/) for your system.
Once changie is installed and your PR is created for a new feature, simply run the following command and changie will walk you through the process of creating a changelog entry: Once changie is installed and your PR is created, simply run `changie new` and changie will walk you through the process of creating a changelog entry. Commit the file that's created and your changelog entry is complete!
```shell
changie new
```
Commit the file that's created and your changelog entry is complete!
If you are contributing to a feature already in progress, you will modify the changie yaml file in dbt/.changes/unreleased/ related to your change. If you need help finding this file, please ask within the discussion for the pull request!
You don't need to worry about which `dbt-core` version your change will go into. Just create the changelog entry with `changie`, and open your PR against the `main` branch. All merged changes will be included in the next minor version of `dbt-core`. The Core maintainers _may_ choose to "backport" specific changes in order to patch older minor versions. In that case, a maintainer will take care of that backport after merging your PR, before releasing the new version of `dbt-core`. You don't need to worry about which `dbt-core` version your change will go into. Just create the changelog entry with `changie`, and open your PR against the `main` branch. All merged changes will be included in the next minor version of `dbt-core`. The Core maintainers _may_ choose to "backport" specific changes in order to patch older minor versions. In that case, a maintainer will take care of that backport after merging your PR, before releasing the new version of `dbt-core`.

View File

@@ -49,9 +49,6 @@ RUN apt-get update \
python3.10 \ python3.10 \
python3.10-dev \ python3.10-dev \
python3.10-venv \ python3.10-venv \
python3.11 \
python3.11-dev \
python3.11-venv \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

View File

@@ -2,59 +2,50 @@
## The following are individual files in this directory. ## The following are individual files in this directory.
### compilation.py
### constants.py
### dataclass_schema.py
### deprecations.py ### deprecations.py
### exceptions.py
### flags.py ### flags.py
### helper_types.py
### hooks.py
### lib.py
### links.py
### logger.py
### main.py ### main.py
### node_types.py
### profiler.py
### selected_resources.py
### semver.py
### tracking.py ### tracking.py
### version.py
### lib.py
### node_types.py
### helper_types.py
### links.py
### semver.py
### ui.py ### ui.py
### compilation.py
### dataclass_schema.py
### exceptions.py
### hooks.py
### logger.py
### profiler.py
### utils.py ### utils.py
### version.py
## The subdirectories will be documented in a README in the subdirectory ## The subdirectories will be documented in a README in the subdirectory
* adapters
* cli
* clients
* config * config
* context
* contracts
* deps
* docs
* events
* graph
* include * include
* parser * adapters
* context
* deps
* graph
* task * task
* tests * clients
* events

View File

@@ -48,7 +48,6 @@ from dbt.events.types import (
Rollback, Rollback,
RollbackFailed, RollbackFailed,
) )
from dbt.events.contextvars import get_node_info
from dbt import flags from dbt import flags
from dbt.utils import cast_to_str from dbt.utils import cast_to_str
@@ -170,9 +169,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
if conn.name == conn_name and conn.state == "open": if conn.name == conn_name and conn.state == "open":
return conn return conn
fire_event( fire_event(NewConnection(conn_name=conn_name, conn_type=self.TYPE))
NewConnection(conn_name=conn_name, conn_type=self.TYPE, node_info=get_node_info())
)
if conn.state == "open": if conn.state == "open":
fire_event(ConnectionReused(conn_name=conn_name)) fire_event(ConnectionReused(conn_name=conn_name))
@@ -339,9 +336,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
except Exception: except Exception:
fire_event( fire_event(
RollbackFailed( RollbackFailed(
conn_name=cast_to_str(connection.name), conn_name=cast_to_str(connection.name), exc_info=traceback.format_exc()
exc_info=traceback.format_exc(),
node_info=get_node_info(),
) )
) )
@@ -350,16 +345,10 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
"""Perform the actual close operation.""" """Perform the actual close operation."""
# On windows, sometimes connection handles don't have a close() attr. # On windows, sometimes connection handles don't have a close() attr.
if hasattr(connection.handle, "close"): if hasattr(connection.handle, "close"):
fire_event( fire_event(ConnectionClosed(conn_name=cast_to_str(connection.name)))
ConnectionClosed(conn_name=cast_to_str(connection.name), node_info=get_node_info())
)
connection.handle.close() connection.handle.close()
else: else:
fire_event( fire_event(ConnectionLeftOpen(conn_name=cast_to_str(connection.name)))
ConnectionLeftOpen(
conn_name=cast_to_str(connection.name), node_info=get_node_info()
)
)
@classmethod @classmethod
def _rollback(cls, connection: Connection) -> None: def _rollback(cls, connection: Connection) -> None:
@@ -370,7 +359,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
f'"{connection.name}", but it does not have one open!' f'"{connection.name}", but it does not have one open!'
) )
fire_event(Rollback(conn_name=cast_to_str(connection.name), node_info=get_node_info())) fire_event(Rollback(conn_name=cast_to_str(connection.name)))
cls._rollback_handle(connection) cls._rollback_handle(connection)
connection.transaction_open = False connection.transaction_open = False
@@ -382,7 +371,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
return connection return connection
if connection.transaction_open and connection.handle: if connection.transaction_open and connection.handle:
fire_event(Rollback(conn_name=cast_to_str(connection.name), node_info=get_node_info())) fire_event(Rollback(conn_name=cast_to_str(connection.name)))
cls._rollback_handle(connection) cls._rollback_handle(connection)
connection.transaction_open = False connection.transaction_open = False

View File

@@ -15,6 +15,7 @@ from typing import (
List, List,
Mapping, Mapping,
Iterator, Iterator,
Union,
Set, Set,
) )
@@ -22,20 +23,13 @@ import agate
import pytz import pytz
from dbt.exceptions import ( from dbt.exceptions import (
raise_database_error,
raise_compiler_error,
invalid_type_error,
get_relation_returned_multiple_results,
InternalException, InternalException,
InvalidMacroArgType,
InvalidMacroResult,
InvalidQuoteConfigType,
NotImplementedException, NotImplementedException,
NullRelationCacheAttempted,
NullRelationDropAttempted,
RelationReturnedMultipleResults,
RenameToNoneAttempted,
RuntimeException, RuntimeException,
SnapshotTargetIncomplete,
SnapshotTargetNotSnapshotTable,
UnexpectedNull,
UnexpectedNonTimestamp,
) )
from dbt.adapters.protocol import ( from dbt.adapters.protocol import (
@@ -44,8 +38,9 @@ from dbt.adapters.protocol import (
) )
from dbt.clients.agate_helper import empty_table, merge_tables, table_from_rows from dbt.clients.agate_helper import empty_table, merge_tables, table_from_rows
from dbt.clients.jinja import MacroGenerator from dbt.clients.jinja import MacroGenerator
from dbt.contracts.graph.compiled import CompileResultNode, CompiledSeedNode
from dbt.contracts.graph.manifest import Manifest, MacroManifest from dbt.contracts.graph.manifest import Manifest, MacroManifest
from dbt.contracts.graph.nodes import ResultNode from dbt.contracts.graph.parsed import ParsedSeedNode
from dbt.events.functions import fire_event, warn_or_error from dbt.events.functions import fire_event, warn_or_error
from dbt.events.types import ( from dbt.events.types import (
CacheMiss, CacheMiss,
@@ -69,6 +64,9 @@ from dbt.adapters.base import Credentials
from dbt.adapters.cache import RelationsCache, _make_ref_key_msg from dbt.adapters.cache import RelationsCache, _make_ref_key_msg
SeedModel = Union[ParsedSeedNode, CompiledSeedNode]
GET_CATALOG_MACRO_NAME = "get_catalog" GET_CATALOG_MACRO_NAME = "get_catalog"
FRESHNESS_MACRO_NAME = "collect_freshness" FRESHNESS_MACRO_NAME = "collect_freshness"
@@ -104,10 +102,18 @@ def _utc(dt: Optional[datetime], source: BaseRelation, field_name: str) -> datet
assume the datetime is already for UTC and add the timezone. assume the datetime is already for UTC and add the timezone.
""" """
if dt is None: if dt is None:
raise UnexpectedNull(field_name, source) raise raise_database_error(
"Expected a non-null value when querying field '{}' of table "
" {} but received value 'null' instead".format(field_name, source)
)
elif not hasattr(dt, "tzinfo"): elif not hasattr(dt, "tzinfo"):
raise UnexpectedNonTimestamp(field_name, source, dt) raise raise_database_error(
"Expected a timestamp value when querying field '{}' of table "
"{} but received value of type '{}' instead".format(
field_name, source, type(dt).__name__
)
)
elif dt.tzinfo: elif dt.tzinfo:
return dt.astimezone(pytz.UTC) return dt.astimezone(pytz.UTC)
@@ -237,7 +243,9 @@ class BaseAdapter(metaclass=AdapterMeta):
return conn.name return conn.name
@contextmanager @contextmanager
def connection_named(self, name: str, node: Optional[ResultNode] = None) -> Iterator[None]: def connection_named(
self, name: str, node: Optional[CompileResultNode] = None
) -> Iterator[None]:
try: try:
if self.connections.query_header is not None: if self.connections.query_header is not None:
self.connections.query_header.set(name, node) self.connections.query_header.set(name, node)
@@ -249,7 +257,7 @@ class BaseAdapter(metaclass=AdapterMeta):
self.connections.query_header.reset() self.connections.query_header.reset()
@contextmanager @contextmanager
def connection_for(self, node: ResultNode) -> Iterator[None]: def connection_for(self, node: CompileResultNode) -> Iterator[None]:
with self.connection_named(node.unique_id, node): with self.connection_named(node.unique_id, node):
yield yield
@@ -364,7 +372,7 @@ class BaseAdapter(metaclass=AdapterMeta):
lowercase strings. lowercase strings.
""" """
info_schema_name_map = SchemaSearchMap() info_schema_name_map = SchemaSearchMap()
nodes: Iterator[ResultNode] = chain( nodes: Iterator[CompileResultNode] = chain(
[ [
node node
for node in manifest.nodes.values() for node in manifest.nodes.values()
@@ -433,7 +441,7 @@ class BaseAdapter(metaclass=AdapterMeta):
"""Cache a new relation in dbt. It will show up in `list relations`.""" """Cache a new relation in dbt. It will show up in `list relations`."""
if relation is None: if relation is None:
name = self.nice_connection_name() name = self.nice_connection_name()
raise NullRelationCacheAttempted(name) raise_compiler_error("Attempted to cache a null relation for {}".format(name))
self.cache.add(relation) self.cache.add(relation)
# so jinja doesn't render things # so jinja doesn't render things
return "" return ""
@@ -445,7 +453,7 @@ class BaseAdapter(metaclass=AdapterMeta):
""" """
if relation is None: if relation is None:
name = self.nice_connection_name() name = self.nice_connection_name()
raise NullRelationDropAttempted(name) raise_compiler_error("Attempted to drop a null relation for {}".format(name))
self.cache.drop(relation) self.cache.drop(relation)
return "" return ""
@@ -462,7 +470,9 @@ class BaseAdapter(metaclass=AdapterMeta):
name = self.nice_connection_name() name = self.nice_connection_name()
src_name = _relation_name(from_relation) src_name = _relation_name(from_relation)
dst_name = _relation_name(to_relation) dst_name = _relation_name(to_relation)
raise RenameToNoneAttempted(src_name, dst_name, name) raise_compiler_error(
"Attempted to rename {} to {} for {}".format(src_name, dst_name, name)
)
self.cache.rename(from_relation, to_relation) self.cache.rename(from_relation, to_relation)
return "" return ""
@@ -612,7 +622,7 @@ class BaseAdapter(metaclass=AdapterMeta):
to_relation. to_relation.
""" """
if not isinstance(from_relation, self.Relation): if not isinstance(from_relation, self.Relation):
raise InvalidMacroArgType( invalid_type_error(
method_name="get_missing_columns", method_name="get_missing_columns",
arg_name="from_relation", arg_name="from_relation",
got_value=from_relation, got_value=from_relation,
@@ -620,7 +630,7 @@ class BaseAdapter(metaclass=AdapterMeta):
) )
if not isinstance(to_relation, self.Relation): if not isinstance(to_relation, self.Relation):
raise InvalidMacroArgType( invalid_type_error(
method_name="get_missing_columns", method_name="get_missing_columns",
arg_name="to_relation", arg_name="to_relation",
got_value=to_relation, got_value=to_relation,
@@ -645,7 +655,7 @@ class BaseAdapter(metaclass=AdapterMeta):
incorrect. incorrect.
""" """
if not isinstance(relation, self.Relation): if not isinstance(relation, self.Relation):
raise InvalidMacroArgType( invalid_type_error(
method_name="valid_snapshot_target", method_name="valid_snapshot_target",
arg_name="relation", arg_name="relation",
got_value=relation, got_value=relation,
@@ -666,16 +676,24 @@ class BaseAdapter(metaclass=AdapterMeta):
if missing: if missing:
if extra: if extra:
raise SnapshotTargetIncomplete(extra, missing) msg = (
'Snapshot target has ("{}") but not ("{}") - is it an '
"unmigrated previous version archive?".format(
'", "'.join(extra), '", "'.join(missing)
)
)
else: else:
raise SnapshotTargetNotSnapshotTable(missing) msg = 'Snapshot target is not a snapshot table (missing "{}")'.format(
'", "'.join(missing)
)
raise_compiler_error(msg)
@available.parse_none @available.parse_none
def expand_target_column_types( def expand_target_column_types(
self, from_relation: BaseRelation, to_relation: BaseRelation self, from_relation: BaseRelation, to_relation: BaseRelation
) -> None: ) -> None:
if not isinstance(from_relation, self.Relation): if not isinstance(from_relation, self.Relation):
raise InvalidMacroArgType( invalid_type_error(
method_name="expand_target_column_types", method_name="expand_target_column_types",
arg_name="from_relation", arg_name="from_relation",
got_value=from_relation, got_value=from_relation,
@@ -683,7 +701,7 @@ class BaseAdapter(metaclass=AdapterMeta):
) )
if not isinstance(to_relation, self.Relation): if not isinstance(to_relation, self.Relation):
raise InvalidMacroArgType( invalid_type_error(
method_name="expand_target_column_types", method_name="expand_target_column_types",
arg_name="to_relation", arg_name="to_relation",
got_value=to_relation, got_value=to_relation,
@@ -765,7 +783,7 @@ class BaseAdapter(metaclass=AdapterMeta):
"schema": schema, "schema": schema,
"database": database, "database": database,
} }
raise RelationReturnedMultipleResults(kwargs, matches) get_relation_returned_multiple_results(kwargs, matches)
elif matches: elif matches:
return matches[0] return matches[0]
@@ -829,7 +847,10 @@ class BaseAdapter(metaclass=AdapterMeta):
elif quote_config is None: elif quote_config is None:
pass pass
else: else:
raise InvalidQuoteConfigType(quote_config) raise_compiler_error(
f'The seed configuration value of "quote_columns" has an '
f"invalid type {type(quote_config)}"
)
if quote_columns: if quote_columns:
return self.quote(column) return self.quote(column)
@@ -1079,7 +1100,11 @@ class BaseAdapter(metaclass=AdapterMeta):
# now we have a 1-row table of the maximum `loaded_at_field` value and # now we have a 1-row table of the maximum `loaded_at_field` value and
# the current time according to the db. # the current time according to the db.
if len(table) != 1 or len(table[0]) != 2: if len(table) != 1 or len(table[0]) != 2:
raise InvalidMacroResult(FRESHNESS_MACRO_NAME, table) raise_compiler_error(
'Got an invalid result from "{}" macro: {}'.format(
FRESHNESS_MACRO_NAME, [tuple(r) for r in table]
)
)
if table[0][0] is None: if table[0][0] is None:
# no records in the table, so really the max_loaded_at was # no records in the table, so really the max_loaded_at was
# infinitely long ago. Just call it 0:00 January 1 year UTC # infinitely long ago. Just call it 0:00 January 1 year UTC

View File

@@ -7,9 +7,9 @@ from dbt.adapters.protocol import AdapterProtocol
def project_name_from_path(include_path: str) -> str: def project_name_from_path(include_path: str) -> str:
# avoid an import cycle # avoid an import cycle
from dbt.config.project import PartialProject from dbt.config.project import Project
partial = PartialProject.from_project_root(include_path) partial = Project.partial_load(include_path)
if partial.project_name is None: if partial.project_name is None:
raise CompilationException(f"Invalid project at {include_path}: name not set!") raise CompilationException(f"Invalid project at {include_path}: name not set!")
return partial.project_name return partial.project_name

View File

@@ -5,7 +5,7 @@ from dbt.clients.jinja import QueryStringGenerator
from dbt.context.manifest import generate_query_header_context from dbt.context.manifest import generate_query_header_context
from dbt.contracts.connection import AdapterRequiredConfig, QueryComment from dbt.contracts.connection import AdapterRequiredConfig, QueryComment
from dbt.contracts.graph.nodes import ResultNode from dbt.contracts.graph.compiled import CompileResultNode
from dbt.contracts.graph.manifest import Manifest from dbt.contracts.graph.manifest import Manifest
from dbt.exceptions import RuntimeException from dbt.exceptions import RuntimeException
@@ -90,7 +90,7 @@ class MacroQueryStringSetter:
def reset(self): def reset(self):
self.set("master", None) self.set("master", None)
def set(self, name: str, node: Optional[ResultNode]): def set(self, name: str, node: Optional[CompileResultNode]):
wrapped: Optional[NodeWrapper] = None wrapped: Optional[NodeWrapper] = None
if node is not None: if node is not None:
wrapped = NodeWrapper(node) wrapped = NodeWrapper(node)

View File

@@ -1,8 +1,9 @@
from collections.abc import Hashable from collections.abc import Hashable
from dataclasses import dataclass, field from dataclasses import dataclass
from typing import Optional, TypeVar, Any, Type, Dict, Iterator, Tuple, Set from typing import Optional, TypeVar, Any, Type, Dict, Union, Iterator, Tuple, Set
from dbt.contracts.graph.nodes import SourceDefinition, ManifestNode, ResultNode, ParsedNode from dbt.contracts.graph.compiled import CompiledNode
from dbt.contracts.graph.parsed import ParsedSourceDefinition, ParsedNode
from dbt.contracts.relation import ( from dbt.contracts.relation import (
RelationType, RelationType,
ComponentName, ComponentName,
@@ -11,7 +12,7 @@ from dbt.contracts.relation import (
Policy, Policy,
Path, Path,
) )
from dbt.exceptions import ApproximateMatch, InternalException, MultipleDatabasesNotAllowed from dbt.exceptions import InternalException
from dbt.node_types import NodeType from dbt.node_types import NodeType
from dbt.utils import filter_null_values, deep_merge, classproperty from dbt.utils import filter_null_values, deep_merge, classproperty
@@ -26,10 +27,8 @@ class BaseRelation(FakeAPIObject, Hashable):
path: Path path: Path
type: Optional[RelationType] = None type: Optional[RelationType] = None
quote_character: str = '"' quote_character: str = '"'
# Python 3.11 requires that these use default_factory instead of simple default include_policy: Policy = Policy()
# ValueError: mutable default <class 'dbt.contracts.relation.Policy'> for field include_policy is not allowed: use default_factory quote_policy: Policy = Policy()
include_policy: Policy = field(default_factory=lambda: Policy())
quote_policy: Policy = field(default_factory=lambda: Policy())
dbt_created: bool = False dbt_created: bool = False
def _is_exactish_match(self, field: ComponentName, value: str) -> bool: def _is_exactish_match(self, field: ComponentName, value: str) -> bool:
@@ -40,9 +39,9 @@ class BaseRelation(FakeAPIObject, Hashable):
@classmethod @classmethod
def _get_field_named(cls, field_name): def _get_field_named(cls, field_name):
for f, _ in cls._get_fields(): for field, _ in cls._get_fields():
if f.name == field_name: if field.name == field_name:
return f return field
# this should be unreachable # this should be unreachable
raise ValueError(f"BaseRelation has no {field_name} field!") raise ValueError(f"BaseRelation has no {field_name} field!")
@@ -53,11 +52,11 @@ class BaseRelation(FakeAPIObject, Hashable):
@classmethod @classmethod
def get_default_quote_policy(cls) -> Policy: def get_default_quote_policy(cls) -> Policy:
return cls._get_field_named("quote_policy").default_factory() return cls._get_field_named("quote_policy").default
@classmethod @classmethod
def get_default_include_policy(cls) -> Policy: def get_default_include_policy(cls) -> Policy:
return cls._get_field_named("include_policy").default_factory() return cls._get_field_named("include_policy").default
def get(self, key, default=None): def get(self, key, default=None):
"""Override `.get` to return a metadata object so we don't break """Override `.get` to return a metadata object so we don't break
@@ -100,7 +99,7 @@ class BaseRelation(FakeAPIObject, Hashable):
if approximate_match and not exact_match: if approximate_match and not exact_match:
target = self.create(database=database, schema=schema, identifier=identifier) target = self.create(database=database, schema=schema, identifier=identifier)
raise ApproximateMatch(target, self) dbt.exceptions.approximate_relation_match(target, self)
return exact_match return exact_match
@@ -185,7 +184,7 @@ class BaseRelation(FakeAPIObject, Hashable):
) )
@classmethod @classmethod
def create_from_source(cls: Type[Self], source: SourceDefinition, **kwargs: Any) -> Self: def create_from_source(cls: Type[Self], source: ParsedSourceDefinition, **kwargs: Any) -> Self:
source_quoting = source.quoting.to_dict(omit_none=True) source_quoting = source.quoting.to_dict(omit_none=True)
source_quoting.pop("column", None) source_quoting.pop("column", None)
quote_policy = deep_merge( quote_policy = deep_merge(
@@ -210,7 +209,7 @@ class BaseRelation(FakeAPIObject, Hashable):
def create_ephemeral_from_node( def create_ephemeral_from_node(
cls: Type[Self], cls: Type[Self],
config: HasQuoting, config: HasQuoting,
node: ManifestNode, node: Union[ParsedNode, CompiledNode],
) -> Self: ) -> Self:
# Note that ephemeral models are based on the name. # Note that ephemeral models are based on the name.
identifier = cls.add_ephemeral_prefix(node.name) identifier = cls.add_ephemeral_prefix(node.name)
@@ -223,7 +222,7 @@ class BaseRelation(FakeAPIObject, Hashable):
def create_from_node( def create_from_node(
cls: Type[Self], cls: Type[Self],
config: HasQuoting, config: HasQuoting,
node: ManifestNode, node: Union[ParsedNode, CompiledNode],
quote_policy: Optional[Dict[str, bool]] = None, quote_policy: Optional[Dict[str, bool]] = None,
**kwargs: Any, **kwargs: Any,
) -> Self: ) -> Self:
@@ -244,20 +243,20 @@ class BaseRelation(FakeAPIObject, Hashable):
def create_from( def create_from(
cls: Type[Self], cls: Type[Self],
config: HasQuoting, config: HasQuoting,
node: ResultNode, node: Union[CompiledNode, ParsedNode, ParsedSourceDefinition],
**kwargs: Any, **kwargs: Any,
) -> Self: ) -> Self:
if node.resource_type == NodeType.Source: if node.resource_type == NodeType.Source:
if not isinstance(node, SourceDefinition): if not isinstance(node, ParsedSourceDefinition):
raise InternalException( raise InternalException(
"type mismatch, expected SourceDefinition but got {}".format(type(node)) "type mismatch, expected ParsedSourceDefinition but got {}".format(type(node))
) )
return cls.create_from_source(node, **kwargs) return cls.create_from_source(node, **kwargs)
else: else:
# Can't use ManifestNode here because of parameterized generics if not isinstance(node, (ParsedNode, CompiledNode)):
if not isinstance(node, (ParsedNode)):
raise InternalException( raise InternalException(
f"type mismatch, expected ManifestNode but got {type(node)}" "type mismatch, expected ParsedNode or CompiledNode but "
"got {}".format(type(node))
) )
return cls.create_from_node(config, node, **kwargs) return cls.create_from_node(config, node, **kwargs)
@@ -438,7 +437,7 @@ class SchemaSearchMap(Dict[InformationSchema, Set[Optional[str]]]):
if not allow_multiple_databases: if not allow_multiple_databases:
seen = {r.database.lower() for r in self if r.database} seen = {r.database.lower() for r in self if r.database}
if len(seen) > 1: if len(seen) > 1:
raise MultipleDatabasesNotAllowed(seen) dbt.exceptions.raise_compiler_error(str(seen))
for information_schema_name, schema in self.search(): for information_schema_name, schema in self.search():
path = {"database": information_schema_name.database, "schema": schema} path = {"database": information_schema_name.database, "schema": schema}

View File

@@ -1,3 +1,4 @@
import re
import threading import threading
from copy import deepcopy from copy import deepcopy
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple from typing import Any, Dict, Iterable, List, Optional, Set, Tuple
@@ -8,13 +9,7 @@ from dbt.adapters.reference_keys import (
_make_msg_from_ref_key, _make_msg_from_ref_key,
_ReferenceKey, _ReferenceKey,
) )
from dbt.exceptions import ( import dbt.exceptions
DependentLinkNotCached,
NewNameAlreadyInCache,
NoneRelationFound,
ReferencedLinkNotCached,
TruncatedModelNameCausedCollision,
)
from dbt.events.functions import fire_event, fire_event_if from dbt.events.functions import fire_event, fire_event_if
from dbt.events.types import ( from dbt.events.types import (
AddLink, AddLink,
@@ -155,7 +150,11 @@ class _CachedRelation:
:raises InternalError: If the new key already exists. :raises InternalError: If the new key already exists.
""" """
if new_key in self.referenced_by: if new_key in self.referenced_by:
raise NewNameAlreadyInCache(old_key, new_key) dbt.exceptions.raise_cache_inconsistent(
'in rename of "{}" -> "{}", new name is in the cache already'.format(
old_key, new_key
)
)
if old_key not in self.referenced_by: if old_key not in self.referenced_by:
return return
@@ -271,11 +270,15 @@ class RelationsCache:
if referenced is None: if referenced is None:
return return
if referenced is None: if referenced is None:
raise ReferencedLinkNotCached(referenced_key) dbt.exceptions.raise_cache_inconsistent(
"in add_link, referenced link key {} not in cache!".format(referenced_key)
)
dependent = self.relations.get(dependent_key) dependent = self.relations.get(dependent_key)
if dependent is None: if dependent is None:
raise DependentLinkNotCached(dependent_key) dbt.exceptions.raise_cache_inconsistent(
"in add_link, dependent link key {} not in cache!".format(dependent_key)
)
assert dependent is not None # we just raised! assert dependent is not None # we just raised!
@@ -427,7 +430,24 @@ class RelationsCache:
if new_key in self.relations: if new_key in self.relations:
# Tell user when collision caused by model names truncated during # Tell user when collision caused by model names truncated during
# materialization. # materialization.
raise TruncatedModelNameCausedCollision(new_key, self.relations) 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()), message_addendum
)
)
if old_key not in self.relations: if old_key not in self.relations:
fire_event(TemporaryRelation(key=_make_msg_from_ref_key(old_key))) fire_event(TemporaryRelation(key=_make_msg_from_ref_key(old_key)))
@@ -485,7 +505,9 @@ class RelationsCache:
] ]
if None in results: if None in results:
raise NoneRelationFound() dbt.exceptions.raise_cache_inconsistent(
"in get_relations, a None relation was found in the cache!"
)
return results return results
def clear(self): def clear(self):

View File

@@ -8,6 +8,7 @@ from typing import (
Generic, Generic,
TypeVar, TypeVar,
Tuple, Tuple,
Union,
Dict, Dict,
Any, Any,
) )
@@ -16,7 +17,8 @@ from typing_extensions import Protocol
import agate import agate
from dbt.contracts.connection import Connection, AdapterRequiredConfig, AdapterResponse from dbt.contracts.connection import Connection, AdapterRequiredConfig, AdapterResponse
from dbt.contracts.graph.nodes import ResultNode, ManifestNode from dbt.contracts.graph.compiled import CompiledNode, ManifestNode, NonSourceCompiledNode
from dbt.contracts.graph.parsed import ParsedNode, ParsedSourceDefinition
from dbt.contracts.graph.model_config import BaseConfig from dbt.contracts.graph.model_config import BaseConfig
from dbt.contracts.graph.manifest import Manifest from dbt.contracts.graph.manifest import Manifest
from dbt.contracts.relation import Policy, HasQuoting from dbt.contracts.relation import Policy, HasQuoting
@@ -46,7 +48,11 @@ class RelationProtocol(Protocol):
... ...
@classmethod @classmethod
def create_from(cls: Type[Self], config: HasQuoting, node: ResultNode) -> Self: def create_from(
cls: Type[Self],
config: HasQuoting,
node: Union[CompiledNode, ParsedNode, ParsedSourceDefinition],
) -> Self:
... ...
@@ -59,7 +65,7 @@ class CompilerProtocol(Protocol):
node: ManifestNode, node: ManifestNode,
manifest: Manifest, manifest: Manifest,
extra_context: Optional[Dict[str, Any]] = None, extra_context: Optional[Dict[str, Any]] = None,
) -> ManifestNode: ) -> NonSourceCompiledNode:
... ...

View File

@@ -10,7 +10,6 @@ from dbt.adapters.base import BaseConnectionManager
from dbt.contracts.connection import Connection, ConnectionState, AdapterResponse from dbt.contracts.connection import Connection, ConnectionState, AdapterResponse
from dbt.events.functions import fire_event from dbt.events.functions import fire_event
from dbt.events.types import ConnectionUsed, SQLQuery, SQLCommit, SQLQueryStatus from dbt.events.types import ConnectionUsed, SQLQuery, SQLCommit, SQLQueryStatus
from dbt.events.contextvars import get_node_info
from dbt.utils import cast_to_str from dbt.utils import cast_to_str
@@ -57,13 +56,7 @@ class SQLConnectionManager(BaseConnectionManager):
connection = self.get_thread_connection() connection = self.get_thread_connection()
if auto_begin and connection.transaction_open is False: if auto_begin and connection.transaction_open is False:
self.begin() self.begin()
fire_event( fire_event(ConnectionUsed(conn_type=self.TYPE, conn_name=cast_to_str(connection.name)))
ConnectionUsed(
conn_type=self.TYPE,
conn_name=cast_to_str(connection.name),
node_info=get_node_info(),
)
)
with self.exception_handler(sql): with self.exception_handler(sql):
if abridge_sql_log: if abridge_sql_log:
@@ -71,11 +64,7 @@ class SQLConnectionManager(BaseConnectionManager):
else: else:
log_sql = sql log_sql = sql
fire_event( fire_event(SQLQuery(conn_name=cast_to_str(connection.name), sql=log_sql))
SQLQuery(
conn_name=cast_to_str(connection.name), sql=log_sql, node_info=get_node_info()
)
)
pre = time.time() pre = time.time()
cursor = connection.handle.cursor() cursor = connection.handle.cursor()
@@ -83,9 +72,7 @@ class SQLConnectionManager(BaseConnectionManager):
fire_event( fire_event(
SQLQueryStatus( SQLQueryStatus(
status=str(self.get_response(cursor)), status=str(self.get_response(cursor)), elapsed=round((time.time() - pre), 2)
elapsed=round((time.time() - pre)),
node_info=get_node_info(),
) )
) )
@@ -169,7 +156,7 @@ class SQLConnectionManager(BaseConnectionManager):
"it does not have one open!".format(connection.name) "it does not have one open!".format(connection.name)
) )
fire_event(SQLCommit(conn_name=connection.name, node_info=get_node_info())) fire_event(SQLCommit(conn_name=connection.name))
self.add_commit_query() self.add_commit_query()
connection.transaction_open = False connection.transaction_open = False

View File

@@ -1,8 +1,9 @@
import agate import agate
from typing import Any, Optional, Tuple, Type, List from typing import Any, Optional, Tuple, Type, List
import dbt.clients.agate_helper
from dbt.contracts.connection import Connection from dbt.contracts.connection import Connection
from dbt.exceptions import RelationTypeNull import dbt.exceptions
from dbt.adapters.base import BaseAdapter, available from dbt.adapters.base import BaseAdapter, available
from dbt.adapters.cache import _make_ref_key_msg from dbt.adapters.cache import _make_ref_key_msg
from dbt.adapters.sql import SQLConnectionManager from dbt.adapters.sql import SQLConnectionManager
@@ -131,7 +132,9 @@ class SQLAdapter(BaseAdapter):
def drop_relation(self, relation): def drop_relation(self, relation):
if relation.type is None: if relation.type is None:
raise RelationTypeNull(relation) dbt.exceptions.raise_compiler_error(
"Tried to drop relation {}, but its type is null.".format(relation)
)
self.cache_dropped(relation) self.cache_dropped(relation)
self.execute_macro(DROP_RELATION_MACRO_NAME, kwargs={"relation": relation}) self.execute_macro(DROP_RELATION_MACRO_NAME, kwargs={"relation": relation})

View File

@@ -1 +0,0 @@
from .main import cli as dbt_cli # noqa

View File

@@ -1,16 +0,0 @@
import click
from typing import Optional
from dbt.cli.main import cli as dbt
def make_context(args, command=dbt) -> Optional[click.Context]:
try:
ctx = command.make_context(command.name, args)
except click.exceptions.Exit:
return None
ctx.invoked_subcommand = ctx.protected_args[0] if ctx.protected_args else None
ctx.obj = {}
return ctx

View File

@@ -1,20 +0,0 @@
from dbt.cli.main import dbtRunner
from dbt.config.runtime import load_profile, load_project
if __name__ == "__main__":
project_dir = "/Users/chenyuli/git/jaffle_shop"
cli_args = ["run", "--project-dir", project_dir]
# initialize the dbt runner
dbt = dbtRunner()
# run the command
res, success = dbt.invoke(cli_args)
# preload profile and project
profile = load_profile(project_dir, {}, "testing-postgres")
project = load_project(project_dir, False, profile, {})
# initialize the runner with pre-loaded profile and project, you can also pass in a preloaded manifest
dbt = dbtRunner(profile=profile, project=project)
# run the command, this will use the pre-loaded profile and project instead of loading
res, success = dbt.invoke(cli_args)

View File

@@ -1,17 +1,10 @@
# TODO Move this to /core/dbt/flags.py when we're ready to break things # TODO Move this to /core/dbt/flags.py when we're ready to break things
import os import os
import sys
from dataclasses import dataclass from dataclasses import dataclass
from importlib import import_module
from multiprocessing import get_context from multiprocessing import get_context
from pprint import pformat as pf from pprint import pformat as pf
from typing import Set
from click import Context, get_current_context from click import get_current_context
from click.core import ParameterSource
from dbt.config.profile import read_user_config
from dbt.contracts.project import UserConfig
if os.name != "nt": if os.name != "nt":
# https://bugs.python.org/issue41567 # https://bugs.python.org/issue41567
@@ -20,12 +13,12 @@ if os.name != "nt":
@dataclass(frozen=True) @dataclass(frozen=True)
class Flags: class Flags:
def __init__(self, ctx: Context = None, user_config: UserConfig = None) -> None: def __init__(self, ctx=None) -> None:
if ctx is None: if ctx is None:
ctx = get_current_context() ctx = get_current_context()
def assign_params(ctx, params_assigned_from_default): def assign_params(ctx):
"""Recursively adds all click params to flag object""" """Recursively adds all click params to flag object"""
for param_name, param_value in ctx.params.items(): for param_name, param_value in ctx.params.items():
# N.B. You have to use the base MRO method (object.__setattr__) to set attributes # N.B. You have to use the base MRO method (object.__setattr__) to set attributes
@@ -34,57 +27,18 @@ class Flags:
if hasattr(self, param_name): if hasattr(self, param_name):
raise Exception(f"Duplicate flag names found in click command: {param_name}") raise Exception(f"Duplicate flag names found in click command: {param_name}")
object.__setattr__(self, param_name.upper(), param_value) object.__setattr__(self, param_name.upper(), param_value)
if ctx.get_parameter_source(param_name) == ParameterSource.DEFAULT:
params_assigned_from_default.add(param_name)
if ctx.parent: if ctx.parent:
assign_params(ctx.parent, params_assigned_from_default) assign_params(ctx.parent)
params_assigned_from_default = set() # type: Set[str] assign_params(ctx)
assign_params(ctx, params_assigned_from_default)
# Get the invoked command flags
invoked_subcommand_name = (
ctx.invoked_subcommand if hasattr(ctx, "invoked_subcommand") else None
)
if invoked_subcommand_name is not None:
invoked_subcommand = getattr(import_module("dbt.cli.main"), invoked_subcommand_name)
invoked_subcommand.allow_extra_args = True
invoked_subcommand.ignore_unknown_options = True
invoked_subcommand_ctx = invoked_subcommand.make_context(None, sys.argv)
assign_params(invoked_subcommand_ctx, params_assigned_from_default)
if not user_config:
profiles_dir = getattr(self, "PROFILES_DIR", None)
user_config = read_user_config(profiles_dir) if profiles_dir else None
# Overwrite default assignments with user config if available
if user_config:
for param_assigned_from_default in params_assigned_from_default:
user_config_param_value = getattr(user_config, param_assigned_from_default, None)
if user_config_param_value is not None:
object.__setattr__(
self, param_assigned_from_default.upper(), user_config_param_value
)
# Hard coded flags # Hard coded flags
object.__setattr__(self, "WHICH", invoked_subcommand_name or ctx.info_name) object.__setattr__(self, "WHICH", ctx.info_name)
object.__setattr__(self, "MP_CONTEXT", get_context("spawn")) object.__setattr__(self, "MP_CONTEXT", get_context("spawn"))
# Support console DO NOT TRACK initiave # Support console DO NOT TRACK initiave
object.__setattr__( if os.getenv("DO_NOT_TRACK", "").lower() in (1, "t", "true", "y", "yes"):
self, object.__setattr__(self, "ANONYMOUS_USAGE_STATS", False)
"ANONYMOUS_USAGE_STATS",
False
if os.getenv("DO_NOT_TRACK", "").lower() in ("1", "t", "true", "y", "yes")
else True,
)
# Support lower cased access for legacy code
params = set(
x for x in dir(self) if not callable(getattr(self, x)) and not x.startswith("__")
)
for param in params:
object.__setattr__(self, param.lower(), getattr(self, param))
def __str__(self) -> str: def __str__(self) -> str:
return str(pf(self.__dict__)) return str(pf(self.__dict__))

View File

@@ -1,20 +1,14 @@
import inspect # This is temporary for RAT-ing import inspect # This is temporary for RAT-ing
from copy import copy from copy import copy
from pprint import pformat as pf # This is temporary for RAT-ing from pprint import pformat as pf # This is temporary for RAT-ing
from typing import List, Tuple, Optional
import click import click
from dbt.cli import requires, params as p from dbt.adapters.factory import adapter_management
from dbt.config import RuntimeConfig from dbt.cli import params as p
from dbt.config.project import Project from dbt.cli.flags import Flags
from dbt.config.profile import Profile from dbt.profiler import profiler
from dbt.contracts.graph.manifest import Manifest
from dbt.task.clean import CleanTask
from dbt.task.deps import DepsTask
from dbt.task.run import RunTask
# CLI invocation
def cli_runner(): def cli_runner():
# Alias "list" to "ls" # Alias "list" to "ls"
ls = copy(cli.commands["list"]) ls = copy(cli.commands["list"])
@@ -25,31 +19,6 @@ def cli_runner():
cli() cli()
class dbtUsageException(Exception):
pass
# Programmatic invocation
class dbtRunner:
def __init__(
self, project: Project = None, profile: Profile = None, manifest: Manifest = None
):
self.project = project
self.profile = profile
self.manifest = manifest
def invoke(self, args: List[str]) -> Tuple[Optional[List], bool]:
try:
dbt_ctx = cli.make_context(cli.name, args)
dbt_ctx.obj = {}
dbt_ctx.obj["project"] = self.project
dbt_ctx.obj["profile"] = self.profile
dbt_ctx.obj["manifest"] = self.manifest
return cli.invoke(dbt_ctx)
except (click.NoSuchOption, click.UsageError) as e:
raise dbtUsageException(e.message)
# dbt # dbt
@click.group( @click.group(
context_settings={"help_option_names": ["-h", "--help"]}, context_settings={"help_option_names": ["-h", "--help"]},
@@ -62,17 +31,16 @@ class dbtRunner:
@p.cache_selected_only @p.cache_selected_only
@p.debug @p.debug
@p.enable_legacy_logger @p.enable_legacy_logger
@p.event_buffer_size
@p.fail_fast @p.fail_fast
@p.log_cache_events @p.log_cache_events
@p.log_format @p.log_format
@p.log_path
@p.macro_debugging @p.macro_debugging
@p.partial_parse @p.partial_parse
@p.print @p.print
@p.printer_width @p.printer_width
@p.quiet @p.quiet
@p.record_timing_info @p.record_timing_info
@p.single_threaded
@p.static_parser @p.static_parser
@p.use_colors @p.use_colors
@p.use_experimental_parser @p.use_experimental_parser
@@ -84,10 +52,21 @@ def cli(ctx, **kwargs):
"""An ELT tool for managing your SQL transformations and data models. """An ELT tool for managing your SQL transformations and data models.
For more documentation on these commands, visit: docs.getdbt.com For more documentation on these commands, visit: docs.getdbt.com
""" """
incomplete_flags = Flags()
# Profiling
if incomplete_flags.RECORD_TIMING_INFO:
ctx.with_resource(profiler(enable=True, outfile=incomplete_flags.RECORD_TIMING_INFO))
# Adapter management
ctx.with_resource(adapter_management())
# Version info # Version info
if ctx.params["version"]: if incomplete_flags.VERSION:
click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}") click.echo(f"`version` called\n ctx.params: {pf(ctx.params)}")
return return
else:
del ctx.params["version"]
# dbt build # dbt build
@@ -98,10 +77,11 @@ def cli(ctx, **kwargs):
@p.fail_fast @p.fail_fast
@p.full_refresh @p.full_refresh
@p.indirect_selection @p.indirect_selection
@p.log_path
@p.models
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.show @p.show
@p.state @p.state
@@ -111,11 +91,10 @@ def cli(ctx, **kwargs):
@p.threads @p.threads
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
def build(ctx, **kwargs): def build(ctx, **kwargs):
"""Run all Seeds, Models, Snapshots, and tests in DAG order""" """Run all Seeds, Models, Snapshots, and tests in DAG order"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt clean # dbt clean
@@ -126,16 +105,10 @@ def build(ctx, **kwargs):
@p.project_dir @p.project_dir
@p.target @p.target
@p.vars @p.vars
@requires.preflight
@requires.profile
@requires.project
def clean(ctx, **kwargs): def clean(ctx, **kwargs):
"""Delete all folders in the clean-targets list (usually the dbt_packages and target directories.)""" """Delete all folders in the clean-targets list (usually the dbt_packages and target directories.)"""
task = CleanTask(ctx.obj["flags"], ctx.obj["project"]) flags = Flags()
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
results = task.run()
success = task.interpret_results(results)
return results, success
# dbt docs # dbt docs
@@ -151,10 +124,11 @@ def docs(ctx, **kwargs):
@p.compile_docs @p.compile_docs
@p.defer @p.defer
@p.exclude @p.exclude
@p.log_path
@p.models
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.state @p.state
@p.target @p.target
@@ -162,11 +136,10 @@ def docs(ctx, **kwargs):
@p.threads @p.threads
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
def docs_generate(ctx, **kwargs): def docs_generate(ctx, **kwargs):
"""Generate the documentation website for your project""" """Generate the documentation website for your project"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt docs serve # dbt docs serve
@@ -179,11 +152,10 @@ def docs_generate(ctx, **kwargs):
@p.project_dir @p.project_dir
@p.target @p.target
@p.vars @p.vars
@requires.preflight
def docs_serve(ctx, **kwargs): def docs_serve(ctx, **kwargs):
"""Serve the documentation website for your project""" """Serve the documentation website for your project"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt compile # dbt compile
@@ -192,11 +164,12 @@ def docs_serve(ctx, **kwargs):
@p.defer @p.defer
@p.exclude @p.exclude
@p.full_refresh @p.full_refresh
@p.log_path
@p.models
@p.parse_only @p.parse_only
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.state @p.state
@p.target @p.target
@@ -204,11 +177,10 @@ def docs_serve(ctx, **kwargs):
@p.threads @p.threads
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
def compile(ctx, **kwargs): def compile(ctx, **kwargs):
"""Generates executable SQL from source, model, test, and analysis files. Compiled SQL files are written to the target/ directory.""" """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 flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt debug # dbt debug
@@ -221,11 +193,10 @@ def compile(ctx, **kwargs):
@p.target @p.target
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
def debug(ctx, **kwargs): def debug(ctx, **kwargs):
"""Show some helpful information about dbt for debugging. Not to be confused with the --debug option which increases verbosity.""" """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 flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt deps # dbt deps
@@ -236,16 +207,10 @@ def debug(ctx, **kwargs):
@p.project_dir @p.project_dir
@p.target @p.target
@p.vars @p.vars
@requires.preflight
@requires.profile
@requires.project
def deps(ctx, **kwargs): def deps(ctx, **kwargs):
"""Pull the most recent version of the dependencies listed in packages.yml""" """Pull the most recent version of the dependencies listed in packages.yml"""
task = DepsTask(ctx.obj["flags"], ctx.obj["project"]) flags = Flags()
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
results = task.run()
success = task.interpret_results(results)
return results, success
# dbt init # dbt init
@@ -257,11 +222,10 @@ def deps(ctx, **kwargs):
@p.skip_profile_setup @p.skip_profile_setup
@p.target @p.target
@p.vars @p.vars
@requires.preflight
def init(ctx, **kwargs): def init(ctx, **kwargs):
"""Initialize a new DBT project.""" """Initialize a new DBT project."""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt list # dbt list
@@ -269,28 +233,28 @@ def init(ctx, **kwargs):
@click.pass_context @click.pass_context
@p.exclude @p.exclude
@p.indirect_selection @p.indirect_selection
@p.models
@p.output @p.output
@p.output_keys @p.output_keys
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.resource_type @p.resource_type
@p.select
@p.selector @p.selector
@p.state @p.state
@p.target @p.target
@p.vars @p.vars
@requires.preflight
def list(ctx, **kwargs): def list(ctx, **kwargs):
"""List the resources in your project""" """List the resources in your project"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt parse # dbt parse
@cli.command("parse") @cli.command("parse")
@click.pass_context @click.pass_context
@p.compile_parse @p.compile_parse
@p.log_path
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@@ -300,11 +264,10 @@ def list(ctx, **kwargs):
@p.vars @p.vars
@p.version_check @p.version_check
@p.write_manifest @p.write_manifest
@requires.preflight
def parse(ctx, **kwargs): def parse(ctx, **kwargs):
"""Parses the project and provides information on performance""" """Parses the project and provides information on performance"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt run # dbt run
@@ -314,10 +277,11 @@ def parse(ctx, **kwargs):
@p.exclude @p.exclude
@p.fail_fast @p.fail_fast
@p.full_refresh @p.full_refresh
@p.log_path
@p.models
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.state @p.state
@p.target @p.target
@@ -325,17 +289,10 @@ def parse(ctx, **kwargs):
@p.threads @p.threads
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
@requires.profile
@requires.project
def run(ctx, **kwargs): def run(ctx, **kwargs):
"""Compile SQL and execute against the current target database.""" """Compile SQL and execute against the current target database."""
config = RuntimeConfig.from_parts(ctx.obj["project"], ctx.obj["profile"], ctx.obj["flags"]) flags = Flags()
task = RunTask(ctx.obj["flags"], config) click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
results = task.run()
success = task.interpret_results(results)
return results, success
# dbt run operation # dbt run operation
@@ -347,11 +304,10 @@ def run(ctx, **kwargs):
@p.project_dir @p.project_dir
@p.target @p.target
@p.vars @p.vars
@requires.preflight
def run_operation(ctx, **kwargs): def run_operation(ctx, **kwargs):
"""Run the named macro with any supplied arguments.""" """Run the named macro with any supplied arguments."""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt seed # dbt seed
@@ -359,10 +315,11 @@ def run_operation(ctx, **kwargs):
@click.pass_context @click.pass_context
@p.exclude @p.exclude
@p.full_refresh @p.full_refresh
@p.log_path
@p.models
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.show @p.show
@p.state @p.state
@@ -371,11 +328,10 @@ def run_operation(ctx, **kwargs):
@p.threads @p.threads
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
def seed(ctx, **kwargs): def seed(ctx, **kwargs):
"""Load data from csv files into your data warehouse.""" """Load data from csv files into your data warehouse."""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt snapshot # dbt snapshot
@@ -383,20 +339,19 @@ def seed(ctx, **kwargs):
@click.pass_context @click.pass_context
@p.defer @p.defer
@p.exclude @p.exclude
@p.models
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.state @p.state
@p.target @p.target
@p.threads @p.threads
@p.vars @p.vars
@requires.preflight
def snapshot(ctx, **kwargs): def snapshot(ctx, **kwargs):
"""Execute snapshots defined in your project""" """Execute snapshots defined in your project"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt source # dbt source
@@ -410,21 +365,20 @@ def source(ctx, **kwargs):
@source.command("freshness") @source.command("freshness")
@click.pass_context @click.pass_context
@p.exclude @p.exclude
@p.models
@p.output_path # TODO: Is this ok to re-use? We have three different output params, how much can we consolidate? @p.output_path # TODO: Is this ok to re-use? We have three different output params, how much can we consolidate?
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.state @p.state
@p.target @p.target
@p.threads @p.threads
@p.vars @p.vars
@requires.preflight
def freshness(ctx, **kwargs): def freshness(ctx, **kwargs):
"""Snapshots the current freshness of the project's sources""" """Snapshots the current freshness of the project's sources"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# dbt test # dbt test
@@ -434,10 +388,11 @@ def freshness(ctx, **kwargs):
@p.exclude @p.exclude
@p.fail_fast @p.fail_fast
@p.indirect_selection @p.indirect_selection
@p.log_path
@p.models
@p.profile @p.profile
@p.profiles_dir @p.profiles_dir
@p.project_dir @p.project_dir
@p.select
@p.selector @p.selector
@p.state @p.state
@p.store_failures @p.store_failures
@@ -446,11 +401,10 @@ def freshness(ctx, **kwargs):
@p.threads @p.threads
@p.vars @p.vars
@p.version_check @p.version_check
@requires.preflight
def test(ctx, **kwargs): def test(ctx, **kwargs):
"""Runs tests on data in deployed models. Run this after `dbt run`""" """Runs tests on data in deployed models. Run this after `dbt run`"""
click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {ctx.obj['flags']}") flags = Flags()
return None, True click.echo(f"`{inspect.stack()[0][3]}` called\n flags: {flags}")
# Support running as a module # Support running as a module

View File

@@ -1,7 +1,5 @@
from click import ParamType from click import ParamType
import yaml
from dbt.config.utils import parse_cli_vars
from dbt.exceptions import ValidationException
class YAML(ParamType): class YAML(ParamType):
@@ -14,8 +12,8 @@ class YAML(ParamType):
if not isinstance(value, str): if not isinstance(value, str):
self.fail(f"Cannot load YAML from type {type(value)}", param, ctx) self.fail(f"Cannot load YAML from type {type(value)}", param, ctx)
try: try:
return parse_cli_vars(value) return yaml.load(value, Loader=yaml.Loader)
except ValidationException: except yaml.parser.ParserError:
self.fail(f"String '{value}' is not valid YAML", param, ctx) self.fail(f"String '{value}' is not valid YAML", param, ctx)

View File

@@ -80,6 +80,14 @@ enable_legacy_logger = click.option(
hidden=True, hidden=True,
) )
event_buffer_size = click.option(
"--event-buffer-size",
envvar="DBT_EVENT_BUFFER_SIZE",
help="Sets the max number of events to buffer in EVENT_HISTORY.",
default=100000,
type=click.INT,
)
exclude = click.option("--exclude", envvar=None, help="Specify the nodes to exclude.") exclude = click.option("--exclude", envvar=None, help="Specify the nodes to exclude.")
fail_fast = click.option( fail_fast = click.option(
@@ -123,8 +131,7 @@ log_path = click.option(
"--log-path", "--log-path",
envvar="DBT_LOG_PATH", envvar="DBT_LOG_PATH",
help="Configure the 'log-path'. Only applies this setting for the current run. Overrides the 'DBT_LOG_PATH' if it is set.", help="Configure the 'log-path'. Only applies this setting for the current run. Overrides the 'DBT_LOG_PATH' if it is set.",
default=lambda: Path.cwd() / "logs", type=click.Path(),
type=click.Path(resolve_path=True, path_type=Path),
) )
macro_debugging = click.option( macro_debugging = click.option(
@@ -133,6 +140,14 @@ macro_debugging = click.option(
hidden=True, hidden=True,
) )
models = click.option(
"-m",
"-s",
"models",
envvar=None,
help="Specify the nodes to include.",
multiple=True,
)
output = click.option( output = click.option(
"--output", "--output",
@@ -206,7 +221,7 @@ profiles_dir = click.option(
"--profiles-dir", "--profiles-dir",
envvar="DBT_PROFILES_DIR", envvar="DBT_PROFILES_DIR",
help="Which directory to look in for the profiles.yml file. If not set, dbt will look in the current working directory first, then HOME/.dbt/", help="Which directory to look in for the profiles.yml file. If not set, dbt will look in the current working directory first, then HOME/.dbt/",
default=default_profiles_dir, default=default_profiles_dir(),
type=click.Path(exists=True), type=click.Path(exists=True),
) )
@@ -214,7 +229,7 @@ project_dir = click.option(
"--project-dir", "--project-dir",
envvar=None, envvar=None,
help="Which directory to look in for the dbt_project.yml file. Default is the current working directory and its parents.", help="Which directory to look in for the dbt_project.yml file. Default is the current working directory and its parents.",
default=default_project_dir, default=default_project_dir(),
type=click.Path(exists=True), type=click.Path(exists=True),
) )
@@ -254,15 +269,6 @@ resource_type = click.option(
default="default", default="default",
) )
select = click.option(
"-m",
"-s",
"select",
envvar=None,
help="Specify the nodes to include.",
multiple=True,
)
selector = click.option( selector = click.option(
"--selector", envvar=None, help="The selector name to use, as defined in selectors.yml" "--selector", envvar=None, help="The selector name to use, as defined in selectors.yml"
) )
@@ -271,19 +277,6 @@ show = click.option(
"--show", envvar=None, help="Show a sample of the loaded data in the terminal", is_flag=True "--show", envvar=None, help="Show a sample of the loaded data in the terminal", is_flag=True
) )
# TODO: The env var is a correction!
# The original env var was `DBT_TEST_SINGLE_THREADED`.
# This broke the existing naming convention.
# This will need to be communicated as a change to the community!
#
# N.B. This flag is only used for testing, hence it's hidden from help text.
single_threaded = click.option(
"--single-threaded/--no-single-threaded",
envvar="DBT_SINGLE_THREADED",
default=False,
hidden=True,
)
skip_profile_setup = click.option( skip_profile_setup = click.option(
"--skip-profile-setup", "-s", envvar=None, help="Skip interative profile setup.", is_flag=True "--skip-profile-setup", "-s", envvar=None, help="Skip interative profile setup.", is_flag=True
) )
@@ -356,7 +349,6 @@ vars = click.option(
envvar=None, envvar=None,
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}'", 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(), type=YAML(),
default="{}",
) )
version = click.option( version = click.option(

View File

@@ -1,87 +0,0 @@
from dbt.adapters.factory import adapter_management
from dbt.cli.flags import Flags
from dbt.config.runtime import load_project, load_profile
from dbt.events.functions import setup_event_logger
from dbt.exceptions import DbtProjectError
from dbt.profiler import profiler
from dbt.tracking import initialize_from_flags, track_run
from click import Context
from functools import update_wrapper
def preflight(func):
def wrapper(*args, **kwargs):
ctx = args[0]
assert isinstance(ctx, Context)
ctx.obj = ctx.obj or {}
# Flags
flags = Flags(ctx)
ctx.obj["flags"] = flags
# Tracking
initialize_from_flags(flags.ANONYMOUS_USAGE_STATS, flags.PROFILES_DIR)
ctx.with_resource(track_run(run_command=flags.WHICH))
# Logging
# N.B. Legacy logger is not supported
setup_event_logger(
flags.LOG_PATH,
flags.LOG_FORMAT,
flags.USE_COLORS,
flags.DEBUG,
)
# Profiling
if flags.RECORD_TIMING_INFO:
ctx.with_resource(profiler(enable=True, outfile=flags.RECORD_TIMING_INFO))
# Adapter management
ctx.with_resource(adapter_management())
return func(*args, **kwargs)
return update_wrapper(wrapper, func)
def profile(func):
def wrapper(*args, **kwargs):
ctx = args[0]
assert isinstance(ctx, Context)
if ctx.obj.get("profile") is None:
flags = ctx.obj["flags"]
# TODO: Generalize safe access to flags.THREADS:
# https://github.com/dbt-labs/dbt-core/issues/6259
threads = getattr(flags, "THREADS", None)
profile = load_profile(
flags.PROJECT_DIR, flags.VARS, flags.PROFILE, flags.TARGET, threads
)
ctx.obj["profile"] = profile
return func(*args, **kwargs)
return update_wrapper(wrapper, func)
def project(func):
def wrapper(*args, **kwargs):
ctx = args[0]
assert isinstance(ctx, Context)
if ctx.obj.get("project") is None:
# TODO: Decouple target from profile, and remove the need for profile here:
# https://github.com/dbt-labs/dbt-core/issues/6257
if not ctx.obj.get("profile"):
raise DbtProjectError("profile required for project")
flags = ctx.obj["flags"]
project = load_project(
flags.PROJECT_DIR, flags.VERSION_CHECK, ctx.obj["profile"], flags.VARS
)
ctx.obj["project"] = project
return func(*args, **kwargs)
return update_wrapper(wrapper, func)

View File

@@ -1,15 +1,7 @@
import re import re
from collections import namedtuple from collections import namedtuple
from dbt.exceptions import ( import dbt.exceptions
BlockDefinitionNotAtTop,
InternalException,
MissingCloseTag,
MissingControlFlowStartTag,
NestedTags,
UnexpectedControlFlowEndTag,
UnexpectedMacroEOF,
)
def regex(pat): def regex(pat):
@@ -147,7 +139,10 @@ class TagIterator:
def _expect_match(self, expected_name, *patterns, **kwargs): def _expect_match(self, expected_name, *patterns, **kwargs):
match = self._first_match(*patterns, **kwargs) match = self._first_match(*patterns, **kwargs)
if match is None: if match is None:
raise UnexpectedMacroEOF(expected_name, self.data[self.pos :]) msg = 'unexpected EOF, expected {}, got "{}"'.format(
expected_name, self.data[self.pos :]
)
dbt.exceptions.raise_compiler_error(msg)
return match return match
def handle_expr(self, match): def handle_expr(self, match):
@@ -261,7 +256,7 @@ class TagIterator:
elif block_type_name is not None: elif block_type_name is not None:
yield self.handle_tag(match) yield self.handle_tag(match)
else: else:
raise InternalException( raise dbt.exceptions.InternalException(
"Invalid regex match in next_block, expected block start, " "Invalid regex match in next_block, expected block start, "
"expr start, or comment start" "expr start, or comment start"
) )
@@ -270,6 +265,13 @@ class TagIterator:
return self.find_tags() return self.find_tags()
duplicate_tags = (
"Got nested tags: {outer.block_type_name} (started at {outer.start}) did "
"not have a matching {{% end{outer.block_type_name} %}} before a "
"subsequent {inner.block_type_name} was found (started at {inner.start})"
)
_CONTROL_FLOW_TAGS = { _CONTROL_FLOW_TAGS = {
"if": "endif", "if": "endif",
"for": "endfor", "for": "endfor",
@@ -317,16 +319,33 @@ class BlockIterator:
found = self.stack.pop() found = self.stack.pop()
else: else:
expected = _CONTROL_FLOW_END_TAGS[tag.block_type_name] expected = _CONTROL_FLOW_END_TAGS[tag.block_type_name]
raise UnexpectedControlFlowEndTag(tag, expected, self.tag_parser) dbt.exceptions.raise_compiler_error(
(
"Got an unexpected control flow end tag, got {} but "
"never saw a preceeding {} (@ {})"
).format(tag.block_type_name, expected, self.tag_parser.linepos(tag.start))
)
expected = _CONTROL_FLOW_TAGS[found] expected = _CONTROL_FLOW_TAGS[found]
if expected != tag.block_type_name: if expected != tag.block_type_name:
raise MissingControlFlowStartTag(tag, expected, self.tag_parser) dbt.exceptions.raise_compiler_error(
(
"Got an unexpected control flow end tag, got {} but "
"expected {} next (@ {})"
).format(tag.block_type_name, expected, self.tag_parser.linepos(tag.start))
)
if tag.block_type_name in allowed_blocks: if tag.block_type_name in allowed_blocks:
if self.stack: if self.stack:
raise BlockDefinitionNotAtTop(self.tag_parser, tag.start) dbt.exceptions.raise_compiler_error(
(
"Got a block definition inside control flow at {}. "
"All dbt block definitions must be at the top level"
).format(self.tag_parser.linepos(tag.start))
)
if self.current is not None: if self.current is not None:
raise NestedTags(outer=self.current, inner=tag) dbt.exceptions.raise_compiler_error(
duplicate_tags.format(outer=self.current, inner=tag)
)
if collect_raw_data: if collect_raw_data:
raw_data = self.data[self.last_position : tag.start] raw_data = self.data[self.last_position : tag.start]
self.last_position = tag.start self.last_position = tag.start
@@ -347,7 +366,11 @@ class BlockIterator:
if self.current: if self.current:
linecount = self.data[: self.current.end].count("\n") + 1 linecount = self.data[: self.current.end].count("\n") + 1
raise MissingCloseTag(self.current.block_type_name, linecount) dbt.exceptions.raise_compiler_error(
("Reached EOF without finding a close tag for {} (searched from line {})").format(
self.current.block_type_name, linecount
)
)
if collect_raw_data: if collect_raw_data:
raw_data = self.data[self.last_position :] raw_data = self.data[self.last_position :]

View File

@@ -14,10 +14,10 @@ from dbt.events.types import (
) )
from dbt.exceptions import ( from dbt.exceptions import (
CommandResultError, CommandResultError,
GitCheckoutError,
GitCloningError,
GitCloningProblem,
RuntimeException, RuntimeException,
bad_package_spec,
raise_git_cloning_error,
raise_git_cloning_problem,
) )
from packaging import version from packaging import version
@@ -27,6 +27,16 @@ def _is_commit(revision: str) -> bool:
return bool(re.match(r"\b[0-9a-f]{40}\b", revision)) return bool(re.match(r"\b[0-9a-f]{40}\b", revision))
def _raise_git_cloning_error(repo, revision, error):
stderr = error.stderr.strip()
if "usage: git" in stderr:
stderr = stderr.split("\nusage: git")[0]
if re.match("fatal: destination path '(.+)' already exists", stderr):
raise_git_cloning_error(error)
bad_package_spec(repo, revision, stderr)
def clone(repo, cwd, dirname=None, remove_git_dir=False, revision=None, subdirectory=None): def clone(repo, cwd, dirname=None, remove_git_dir=False, revision=None, subdirectory=None):
has_revision = revision is not None has_revision = revision is not None
is_commit = _is_commit(revision or "") is_commit = _is_commit(revision or "")
@@ -54,7 +64,7 @@ def clone(repo, cwd, dirname=None, remove_git_dir=False, revision=None, subdirec
try: try:
result = run_cmd(cwd, clone_cmd, env={"LC_ALL": "C"}) result = run_cmd(cwd, clone_cmd, env={"LC_ALL": "C"})
except CommandResultError as exc: except CommandResultError as exc:
raise GitCloningError(repo, revision, exc) _raise_git_cloning_error(repo, revision, exc)
if subdirectory: if subdirectory:
cwd_subdir = os.path.join(cwd, dirname or "") cwd_subdir = os.path.join(cwd, dirname or "")
@@ -62,7 +72,7 @@ def clone(repo, cwd, dirname=None, remove_git_dir=False, revision=None, subdirec
try: try:
run_cmd(cwd_subdir, clone_cmd_subdir) run_cmd(cwd_subdir, clone_cmd_subdir)
except CommandResultError as exc: except CommandResultError as exc:
raise GitCloningError(repo, revision, exc) _raise_git_cloning_error(repo, revision, exc)
if remove_git_dir: if remove_git_dir:
rmdir(os.path.join(dirname, ".git")) rmdir(os.path.join(dirname, ".git"))
@@ -105,7 +115,8 @@ def checkout(cwd, repo, revision=None):
try: try:
return _checkout(cwd, repo, revision) return _checkout(cwd, repo, revision)
except CommandResultError as exc: except CommandResultError as exc:
raise GitCheckoutError(repo=repo, revision=revision, error=exc) stderr = exc.stderr.strip()
bad_package_spec(repo, revision, stderr)
def get_current_sha(cwd): def get_current_sha(cwd):
@@ -134,7 +145,7 @@ def clone_and_checkout(
err = exc.stderr err = exc.stderr
exists = re.match("fatal: destination path '(.+)' already exists", err) exists = re.match("fatal: destination path '(.+)' already exists", err)
if not exists: if not exists:
raise GitCloningProblem(repo) raise_git_cloning_problem(repo)
directory = None directory = None
start_sha = None start_sha = None

View File

@@ -25,19 +25,16 @@ from dbt.utils import (
) )
from dbt.clients._jinja_blocks import BlockIterator, BlockData, BlockTag from dbt.clients._jinja_blocks import BlockIterator, BlockData, BlockTag
from dbt.contracts.graph.nodes import GenericTestNode from dbt.contracts.graph.compiled import CompiledGenericTestNode
from dbt.contracts.graph.parsed import ParsedGenericTestNode
from dbt.exceptions import ( from dbt.exceptions import (
CaughtMacroException,
CaughtMacroExceptionWithNode,
CompilationException,
InternalException, InternalException,
InvalidMaterializationArg, raise_compiler_error,
JinjaRenderingException, CompilationException,
invalid_materialization_argument,
MacroReturn, MacroReturn,
MaterializtionMacroNotUsed, JinjaRenderingException,
NoSupportedLanguagesFound,
UndefinedCompilation,
UndefinedMacroException, UndefinedMacroException,
) )
from dbt import flags from dbt import flags
@@ -241,7 +238,7 @@ class BaseMacroGenerator:
try: try:
yield yield
except (TypeError, jinja2.exceptions.TemplateRuntimeError) as e: except (TypeError, jinja2.exceptions.TemplateRuntimeError) as e:
raise CaughtMacroException(e) raise_compiler_error(str(e))
def call_macro(self, *args, **kwargs): def call_macro(self, *args, **kwargs):
# called from __call__ methods # called from __call__ methods
@@ -300,7 +297,7 @@ class MacroGenerator(BaseMacroGenerator):
try: try:
yield yield
except (TypeError, jinja2.exceptions.TemplateRuntimeError) as e: except (TypeError, jinja2.exceptions.TemplateRuntimeError) as e:
raise CaughtMacroExceptionWithNode(exc=e, node=self.macro) raise_compiler_error(str(e), self.macro)
except CompilationException as e: except CompilationException as e:
e.stack.append(self.macro) e.stack.append(self.macro)
raise e raise e
@@ -380,7 +377,7 @@ class MaterializationExtension(jinja2.ext.Extension):
node.defaults.append(languages) node.defaults.append(languages)
else: else:
raise InvalidMaterializationArg(materialization_name, target.name) invalid_materialization_argument(materialization_name, target.name)
if SUPPORTED_LANG_ARG not in node.args: if SUPPORTED_LANG_ARG not in node.args:
node.args.append(SUPPORTED_LANG_ARG) node.args.append(SUPPORTED_LANG_ARG)
@@ -455,7 +452,7 @@ def create_undefined(node=None):
return self return self
def __reduce__(self): def __reduce__(self):
raise UndefinedCompilation(name=self.name, node=node) raise_compiler_error(f"{self.name} is undefined", node=node)
return Undefined return Undefined
@@ -623,7 +620,7 @@ GENERIC_TEST_KWARGS_NAME = "_dbt_generic_test_kwargs"
def add_rendered_test_kwargs( def add_rendered_test_kwargs(
context: Dict[str, Any], context: Dict[str, Any],
node: GenericTestNode, node: Union[ParsedGenericTestNode, CompiledGenericTestNode],
capture_macros: bool = False, capture_macros: bool = False,
) -> None: ) -> None:
"""Render each of the test kwargs in the given context using the native """Render each of the test kwargs in the given context using the native
@@ -655,13 +652,13 @@ def add_rendered_test_kwargs(
def get_supported_languages(node: jinja2.nodes.Macro) -> List[ModelLanguage]: def get_supported_languages(node: jinja2.nodes.Macro) -> List[ModelLanguage]:
if "materialization" not in node.name: if "materialization" not in node.name:
raise MaterializtionMacroNotUsed(node=node) raise_compiler_error("Only materialization macros can be used with this function")
no_kwargs = not node.defaults no_kwargs = not node.defaults
no_langs_found = SUPPORTED_LANG_ARG not in node.args no_langs_found = SUPPORTED_LANG_ARG not in node.args
if no_kwargs or no_langs_found: if no_kwargs or no_langs_found:
raise NoSupportedLanguagesFound(node=node) raise_compiler_error(f"No supported_languages found in materialization macro {node.name}")
lang_idx = node.args.index(SUPPORTED_LANG_ARG) lang_idx = node.args.index(SUPPORTED_LANG_ARG)
# indexing defaults from the end # indexing defaults from the end

View File

@@ -1,6 +1,6 @@
import jinja2 import jinja2
from dbt.clients.jinja import get_environment from dbt.clients.jinja import get_environment
from dbt.exceptions import MacroNamespaceNotString, MacroNameNotString from dbt.exceptions import raise_compiler_error
def statically_extract_macro_calls(string, ctx, db_wrapper=None): def statically_extract_macro_calls(string, ctx, db_wrapper=None):
@@ -117,14 +117,20 @@ def statically_parse_adapter_dispatch(func_call, ctx, db_wrapper):
func_name = kwarg.value.value func_name = kwarg.value.value
possible_macro_calls.append(func_name) possible_macro_calls.append(func_name)
else: else:
raise MacroNameNotString(kwarg_value=kwarg.value.value) raise_compiler_error(
f"The macro_name parameter ({kwarg.value.value}) "
"to adapter.dispatch was not a string"
)
elif kwarg.key == "macro_namespace": elif kwarg.key == "macro_namespace":
# This will remain to enable static resolution # This will remain to enable static resolution
kwarg_type = type(kwarg.value).__name__ kwarg_type = type(kwarg.value).__name__
if kwarg_type == "Const": if kwarg_type == "Const":
macro_namespace = kwarg.value.value macro_namespace = kwarg.value.value
else: else:
raise MacroNamespaceNotString(kwarg_type) raise_compiler_error(
"The macro_namespace parameter to adapter.dispatch "
f"is a {kwarg_type}, not a string"
)
# positional arguments # positional arguments
if packages_arg: if packages_arg:

View File

@@ -1,32 +1,30 @@
import errno import errno
import fnmatch
import functools import functools
import fnmatch
import json import json
import os import os
import os.path import os.path
import re import re
import shutil import shutil
import stat
import subprocess import subprocess
import sys import sys
import tarfile import tarfile
from pathlib import Path
from typing import Any, Callable, Dict, List, NoReturn, Optional, Tuple, Type, Union
import dbt.exceptions
import requests import requests
import stat
from typing import Type, NoReturn, List, Optional, Dict, Any, Tuple, Callable, Union
from pathspec import PathSpec # type: ignore
from dbt.events.functions import fire_event from dbt.events.functions import fire_event
from dbt.events.types import ( from dbt.events.types import (
SystemCouldNotWrite,
SystemErrorRetrievingModTime, SystemErrorRetrievingModTime,
SystemCouldNotWrite,
SystemExecutingCmd, SystemExecutingCmd,
SystemReportReturnCode,
SystemStdErrMsg,
SystemStdOutMsg, SystemStdOutMsg,
SystemStdErrMsg,
SystemReportReturnCode,
) )
from dbt.exceptions import InternalException import dbt.exceptions
from dbt.utils import _connection_exception_retry as connection_exception_retry from dbt.utils import _connection_exception_retry as connection_exception_retry
from pathspec import PathSpec # type: ignore
if sys.platform == "win32": if sys.platform == "win32":
from ctypes import WinDLL, c_bool from ctypes import WinDLL, c_bool
@@ -108,18 +106,12 @@ def load_file_contents(path: str, strip: bool = True) -> str:
return to_return return to_return
@functools.singledispatch def make_directory(path: str) -> None:
def make_directory(path=None) -> None:
""" """
Make a directory and any intermediate directories that don't already Make a directory and any intermediate directories that don't already
exist. This function handles the case where two threads try to create exist. This function handles the case where two threads try to create
a directory at once. a directory at once.
""" """
raise InternalException(f"Can not create directory from {type(path)} ")
@make_directory.register
def _(path: str) -> None:
path = convert_path(path) path = convert_path(path)
if not os.path.exists(path): if not os.path.exists(path):
# concurrent writes that try to create the same dir can fail # concurrent writes that try to create the same dir can fail
@@ -133,11 +125,6 @@ def _(path: str) -> None:
raise e raise e
@make_directory.register
def _(path: Path) -> None:
path.mkdir(parents=True, exist_ok=True)
def make_file(path: str, contents: str = "", overwrite: bool = False) -> bool: def make_file(path: str, contents: str = "", overwrite: bool = False) -> bool:
""" """
Make a file at `path` assuming that the directory it resides in already Make a file at `path` assuming that the directory it resides in already
@@ -157,8 +144,7 @@ def make_symlink(source: str, link_path: str) -> None:
Create a symlink at `link_path` referring to `source`. Create a symlink at `link_path` referring to `source`.
""" """
if not supports_symlinks(): if not supports_symlinks():
# TODO: why not import these at top? dbt.exceptions.system_error("create a symbolic link")
raise dbt.exceptions.SymbolicLinkError()
os.symlink(source, link_path) os.symlink(source, link_path)

View File

@@ -1,6 +1,6 @@
import os import os
from collections import defaultdict from collections import defaultdict
from typing import List, Dict, Any, Tuple, Optional from typing import List, Dict, Any, Tuple, cast, Optional
import networkx as nx # type: ignore import networkx as nx # type: ignore
import pickle import pickle
@@ -12,23 +12,23 @@ from dbt.clients import jinja
from dbt.clients.system import make_directory from dbt.clients.system import make_directory
from dbt.context.providers import generate_runtime_model_context from dbt.context.providers import generate_runtime_model_context
from dbt.contracts.graph.manifest import Manifest, UniqueID from dbt.contracts.graph.manifest import Manifest, UniqueID
from dbt.contracts.graph.nodes import ( from dbt.contracts.graph.compiled import (
ManifestNode, COMPILED_TYPES,
ManifestSQLNode, CompiledGenericTestNode,
GenericTestNode,
GraphMemberNode, GraphMemberNode,
InjectedCTE, InjectedCTE,
SeedNode, ManifestNode,
NonSourceCompiledNode,
) )
from dbt.contracts.graph.parsed import ParsedNode
from dbt.exceptions import ( from dbt.exceptions import (
GraphDependencyNotFound, dependency_not_found,
InternalException, InternalException,
RuntimeException, RuntimeException,
) )
from dbt.graph import Graph from dbt.graph import Graph
from dbt.events.functions import fire_event from dbt.events.functions import fire_event
from dbt.events.types import FoundStats, WritingInjectedSQLForNode from dbt.events.types import FoundStats, CompilingNode, WritingInjectedSQLForNode
from dbt.events.contextvars import get_node_info
from dbt.node_types import NodeType, ModelLanguage from dbt.node_types import NodeType, ModelLanguage
from dbt.events.format import pluralize from dbt.events.format import pluralize
import dbt.tracking import dbt.tracking
@@ -36,6 +36,14 @@ import dbt.tracking
graph_file_name = "graph.gpickle" graph_file_name = "graph.gpickle"
def _compiled_type_for(model: ParsedNode):
if type(model) not in COMPILED_TYPES:
raise InternalException(
f"Asked to compile {type(model)} node, but it has no compiled form"
)
return COMPILED_TYPES[type(model)]
def print_compile_stats(stats): def print_compile_stats(stats):
names = { names = {
NodeType.Model: "model", NodeType.Model: "model",
@@ -48,6 +56,7 @@ def print_compile_stats(stats):
NodeType.Source: "source", NodeType.Source: "source",
NodeType.Exposure: "exposure", NodeType.Exposure: "exposure",
NodeType.Metric: "metric", NodeType.Metric: "metric",
NodeType.Entity: "entity",
} }
results = {k: 0 for k in names.keys()} results = {k: 0 for k in names.keys()}
@@ -83,6 +92,8 @@ def _generate_stats(manifest: Manifest):
stats[exposure.resource_type] += 1 stats[exposure.resource_type] += 1
for metric in manifest.metrics.values(): for metric in manifest.metrics.values():
stats[metric.resource_type] += 1 stats[metric.resource_type] += 1
for entity in manifest.entities.values():
stats[entity.resource_type] += 1
for macro in manifest.macros.values(): for macro in manifest.macros.values():
stats[macro.resource_type] += 1 stats[macro.resource_type] += 1
return stats return stats
@@ -168,7 +179,7 @@ class Compiler:
# a dict for jinja rendering of SQL # a dict for jinja rendering of SQL
def _create_node_context( def _create_node_context(
self, self,
node: ManifestSQLNode, node: NonSourceCompiledNode,
manifest: Manifest, manifest: Manifest,
extra_context: Dict[str, Any], extra_context: Dict[str, Any],
) -> Dict[str, Any]: ) -> Dict[str, Any]:
@@ -176,7 +187,7 @@ class Compiler:
context = generate_runtime_model_context(node, self.config, manifest) context = generate_runtime_model_context(node, self.config, manifest)
context.update(extra_context) context.update(extra_context)
if isinstance(node, GenericTestNode): if isinstance(node, CompiledGenericTestNode):
# for test nodes, add a special keyword args value to the context # for test nodes, add a special keyword args value to the context
jinja.add_rendered_test_kwargs(context, node) jinja.add_rendered_test_kwargs(context, node)
@@ -187,6 +198,14 @@ class Compiler:
relation_cls = adapter.Relation relation_cls = adapter.Relation
return relation_cls.add_ephemeral_prefix(name) return relation_cls.add_ephemeral_prefix(name)
def _get_relation_name(self, node: ParsedNode):
relation_name = None
if node.is_relational and not node.is_ephemeral_model:
adapter = get_adapter(self.config)
relation_cls = adapter.Relation
relation_name = str(relation_cls.create_from(self.config, node))
return relation_name
def _inject_ctes_into_sql(self, sql: str, ctes: List[InjectedCTE]) -> str: def _inject_ctes_into_sql(self, sql: str, ctes: List[InjectedCTE]) -> str:
""" """
`ctes` is a list of InjectedCTEs like: `ctes` is a list of InjectedCTEs like:
@@ -245,10 +264,10 @@ class Compiler:
def _recursively_prepend_ctes( def _recursively_prepend_ctes(
self, self,
model: ManifestSQLNode, model: NonSourceCompiledNode,
manifest: Manifest, manifest: Manifest,
extra_context: Optional[Dict[str, Any]], extra_context: Optional[Dict[str, Any]],
) -> Tuple[ManifestSQLNode, List[InjectedCTE]]: ) -> Tuple[NonSourceCompiledNode, List[InjectedCTE]]:
"""This method is called by the 'compile_node' method. Starting """This method is called by the 'compile_node' method. Starting
from the node that it is passed in, it will recursively call from the node that it is passed in, it will recursively call
itself using the 'extra_ctes'. The 'ephemeral' models do itself using the 'extra_ctes'. The 'ephemeral' models do
@@ -263,8 +282,7 @@ class Compiler:
# Just to make it plain that nothing is actually injected for this case # Just to make it plain that nothing is actually injected for this case
if not model.extra_ctes: if not model.extra_ctes:
if not isinstance(model, SeedNode): model.extra_ctes_injected = True
model.extra_ctes_injected = True
manifest.update_node(model) manifest.update_node(model)
return (model, model.extra_ctes) return (model, model.extra_ctes)
@@ -283,7 +301,6 @@ class Compiler:
f"could not be resolved: {cte.id}" f"could not be resolved: {cte.id}"
) )
cte_model = manifest.nodes[cte.id] cte_model = manifest.nodes[cte.id]
assert not isinstance(cte_model, SeedNode)
if not cte_model.is_ephemeral_model: if not cte_model.is_ephemeral_model:
raise InternalException(f"{cte.id} is not ephemeral") raise InternalException(f"{cte.id} is not ephemeral")
@@ -291,6 +308,8 @@ class Compiler:
# This model has already been compiled, so it's been # This model has already been compiled, so it's been
# through here before # through here before
if getattr(cte_model, "compiled", False): if getattr(cte_model, "compiled", False):
assert isinstance(cte_model, tuple(COMPILED_TYPES.values()))
cte_model = cast(NonSourceCompiledNode, cte_model)
new_prepended_ctes = cte_model.extra_ctes new_prepended_ctes = cte_model.extra_ctes
# if the cte_model isn't compiled, i.e. first time here # if the cte_model isn't compiled, i.e. first time here
@@ -327,19 +346,21 @@ class Compiler:
return model, prepended_ctes return model, prepended_ctes
# Sets compiled fields in the ManifestSQLNode passed in, # creates a compiled_node from the ManifestNode passed in,
# creates a "context" dictionary for jinja rendering, # creates a "context" dictionary for jinja rendering,
# and then renders the "compiled_code" using the node, the # and then renders the "compiled_code" using the node, the
# raw_code and the context. # raw_code and the context.
def _compile_node( def _compile_node(
self, self,
node: ManifestSQLNode, node: ManifestNode,
manifest: Manifest, manifest: Manifest,
extra_context: Optional[Dict[str, Any]] = None, extra_context: Optional[Dict[str, Any]] = None,
) -> ManifestSQLNode: ) -> NonSourceCompiledNode:
if extra_context is None: if extra_context is None:
extra_context = {} extra_context = {}
fire_event(CompilingNode(unique_id=node.unique_id))
data = node.to_dict(omit_none=True) data = node.to_dict(omit_none=True)
data.update( data.update(
{ {
@@ -349,8 +370,9 @@ class Compiler:
"extra_ctes": [], "extra_ctes": [],
} }
) )
compiled_node = _compiled_type_for(node).from_dict(data)
if node.language == ModelLanguage.python: if compiled_node.language == ModelLanguage.python:
# TODO could we also 'minify' this code at all? just aesthetic, not functional # TODO could we also 'minify' this code at all? just aesthetic, not functional
# quoating seems like something very specific to sql so far # quoating seems like something very specific to sql so far
@@ -358,7 +380,7 @@ class Compiler:
# TODO try to find better way to do this, given that # TODO try to find better way to do this, given that
original_quoting = self.config.quoting original_quoting = self.config.quoting
self.config.quoting = {key: False for key in original_quoting.keys()} self.config.quoting = {key: False for key in original_quoting.keys()}
context = self._create_node_context(node, manifest, extra_context) context = self._create_node_context(compiled_node, manifest, extra_context)
postfix = jinja.get_rendered( postfix = jinja.get_rendered(
"{{ py_script_postfix(model) }}", "{{ py_script_postfix(model) }}",
@@ -366,21 +388,23 @@ class Compiler:
node, node,
) )
# we should NOT jinja render the python model's 'raw code' # we should NOT jinja render the python model's 'raw code'
node.compiled_code = f"{node.raw_code}\n\n{postfix}" compiled_node.compiled_code = f"{node.raw_code}\n\n{postfix}"
# restore quoting settings in the end since context is lazy evaluated # restore quoting settings in the end since context is lazy evaluated
self.config.quoting = original_quoting self.config.quoting = original_quoting
else: else:
context = self._create_node_context(node, manifest, extra_context) context = self._create_node_context(compiled_node, manifest, extra_context)
node.compiled_code = jinja.get_rendered( compiled_node.compiled_code = jinja.get_rendered(
node.raw_code, node.raw_code,
context, context,
node, node,
) )
node.compiled = True compiled_node.relation_name = self._get_relation_name(node)
return node compiled_node.compiled = True
return compiled_node
def write_graph_file(self, linker: Linker, manifest: Manifest): def write_graph_file(self, linker: Linker, manifest: Manifest):
filename = graph_file_name filename = graph_file_name
@@ -399,7 +423,7 @@ class Compiler:
elif dependency in manifest.metrics: elif dependency in manifest.metrics:
linker.dependency(node.unique_id, (manifest.metrics[dependency].unique_id)) linker.dependency(node.unique_id, (manifest.metrics[dependency].unique_id))
else: else:
raise GraphDependencyNotFound(node, dependency) dependency_not_found(node, dependency)
def link_graph(self, linker: Linker, manifest: Manifest, add_test_edges: bool = False): def link_graph(self, linker: Linker, manifest: Manifest, add_test_edges: bool = False):
for source in manifest.sources.values(): for source in manifest.sources.values():
@@ -487,13 +511,10 @@ class Compiler:
return Graph(linker.graph) return Graph(linker.graph)
# writes the "compiled_code" into the target/compiled directory # writes the "compiled_code" into the target/compiled directory
def _write_node(self, node: ManifestSQLNode) -> ManifestSQLNode: def _write_node(self, node: NonSourceCompiledNode) -> ManifestNode:
if not node.extra_ctes_injected or node.resource_type in ( if not node.extra_ctes_injected or node.resource_type == NodeType.Snapshot:
NodeType.Snapshot,
NodeType.Seed,
):
return node return node
fire_event(WritingInjectedSQLForNode(node_info=get_node_info())) fire_event(WritingInjectedSQLForNode(unique_id=node.unique_id))
if node.compiled_code: if node.compiled_code:
node.compiled_path = node.write_node( node.compiled_path = node.write_node(
@@ -503,11 +524,11 @@ class Compiler:
def compile_node( def compile_node(
self, self,
node: ManifestSQLNode, node: ManifestNode,
manifest: Manifest, manifest: Manifest,
extra_context: Optional[Dict[str, Any]] = None, extra_context: Optional[Dict[str, Any]] = None,
write: bool = True, write: bool = True,
) -> ManifestSQLNode: ) -> NonSourceCompiledNode:
"""This is the main entry point into this code. It's called by """This is the main entry point into this code. It's called by
CompileRunner.compile, GenericRPCRunner.compile, and CompileRunner.compile, GenericRPCRunner.compile, and
RunTask.get_hook_sql. It calls '_compile_node' to convert RunTask.get_hook_sql. It calls '_compile_node' to convert

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