Skip to content

Commit 52280d2

Browse files
authored
Improve YAML string creation cross-platform (Issue #3) (#4)
1 parent dc909cb commit 52280d2

File tree

9 files changed

+106
-45
lines changed

9 files changed

+106
-45
lines changed

.github/workflows/test.yml

+19-3
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ jobs:
2525
black dbt_invoke tests setup.py --check --diff --color -S -l 79
2626
test:
2727
needs: lint
28-
runs-on: ubuntu-latest
28+
runs-on: ${{ matrix.os }}
2929
strategy:
3030
matrix:
31-
python-version: [3.6, 3.7, 3.8]
31+
os: [ubuntu-latest, macos-latest, windows-latest]
32+
python-version: [3.7, 3.x]
3233
dbt-version: [0.18.x, 0.19.x]
34+
exclude:
35+
- python-version: 3.x
36+
dbt-version: 0.18.x
3337
steps:
3438
- uses: actions/checkout@v2
3539
- name: Set up Python ${{ matrix.python-version }}
@@ -40,6 +44,18 @@ jobs:
4044
run: |
4145
python -m pip install --upgrade pip
4246
pip install -r requirements/requirements_dbt_${{ matrix.dbt-version }}.txt
43-
- name: Run tests
47+
# There is more than one target in profiles.yml because
48+
# dbt-sqlite for dbt~=0.18.x uses a different format than other
49+
# versions.
50+
- name: Run tests for dbt~=0.18.x
51+
if: ${{ matrix.dbt-version == '0.18.x' }}
52+
env:
53+
TARGET: ${{ matrix.dbt-version }}
54+
run: |
55+
python tests/test.py
56+
- name: Run tests for other dbt versions
57+
if: ${{ matrix.dbt-version != '0.18.x' }}
58+
env:
59+
TARGET: default
4460
run: |
4561
python tests/test.py

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -189,5 +189,8 @@ dbt-invoke properties.delete <options>
189189
ephemeral materializations.
190190
- This may be partially remedied by increasing the value of the `--threads`
191191
option in `dbt-invoke properties.update`.
192-
- dbt-invoke was developed with Python 3.6 to 3.8 and dbt 0.18 to 0.19 in mind.
193-
It has not been tested across different types of data warehouses.
192+
- dbt-invoke is tested against:
193+
- Python 3.7 as well as the latest version Python 3.x at the time of merge
194+
- dbt 0.18 and 0.19
195+
- macos-latest, windows-latest, ubuntu-latest
196+
- dbt-invoke has not been tested across different types of data warehouses.

dbt_invoke/internal/_utils.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
from pathlib import Path
44
import sys
5+
import platform
56

67
import yaml
78

@@ -236,9 +237,20 @@ def dbt_run_operation(
236237
}
237238
dbt_cli_kwargs = get_cli_kwargs(**dbt_kwargs)
238239
macro_kwargs = json.dumps(kwargs, sort_keys=False)
240+
if platform.system().lower().startswith('win'):
241+
# Format YAML string for Windows Command Prompt
242+
macro_kwargs = macro_kwargs.replace('"', '\\"')
243+
macro_kwargs = macro_kwargs.replace('\\\\"', '"')
244+
macro_kwargs = macro_kwargs.replace('>', '^>')
245+
macro_kwargs = macro_kwargs.replace('<', '^<')
246+
macro_kwargs = f'"{macro_kwargs}"'
247+
else:
248+
# Format YAML string for Mac/Linux (bash)
249+
macro_kwargs = macro_kwargs.replace("'", """'"'"'""")
250+
macro_kwargs = f"'{macro_kwargs}'"
239251
command = (
240252
f"dbt run-operation {dbt_cli_kwargs}"
241-
f" {macro_name} --args '{macro_kwargs}'"
253+
f" {macro_name} --args {macro_kwargs}"
242254
)
243255
logger.debug(f'Running command: {command}')
244256
result = ctx.run(command, hide=hide)

requirements/requirements_dbt_0.18.x.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
agate<1.6.2
22
cryptography<3
3-
dbt~=0.18.0
3+
dbt-core~=0.18.0
44
dbt-sqlite~=0.0.4
55
invoke>=1.4.1
66
PyYAML

requirements/requirements_dbt_0.19.x.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
agate<1.6.2
2-
dbt~=0.19.0
2+
dbt-core~=0.19.0
33
dbt-sqlite~=0.1.0
44
invoke>=1.4.1
55
pytz<2021.0

tests/test_config.yml

+34-20
Original file line numberDiff line numberDiff line change
@@ -69,37 +69,51 @@ expected_properties:
6969
expected_dbt_ls_results:
7070
resource_type:
7171
model:
72-
- models/marts/core/customers.sql
73-
- models/marts/core/orders.sql
72+
- &customers
73+
- models
74+
- marts
75+
- core
76+
- customers.sql
77+
- &orders
78+
- models
79+
- marts
80+
- core
81+
- orders.sql
7482
seed:
75-
- data/items.csv
83+
- &items
84+
- data
85+
- items.csv
7686
snapshot:
77-
- snapshots/items_snapshot.sql
87+
- &items_snapshot
88+
- snapshots
89+
- items_snapshot.sql
7890
analysis:
79-
- analyses/revenue_by_daily_cohort.sql
91+
- &revenue_by_daily_cohort
92+
- analyses
93+
- revenue_by_daily_cohort.sql
8094
select:
8195
marts.core:
82-
- models/marts/core/customers.sql
83-
- models/marts/core/orders.sql
96+
- *customers
97+
- *orders
8498
models:
8599
customers:
86-
- models/marts/core/customers.sql
100+
- *customers
87101
customers,orders:
88-
- models/marts/core/customers.sql
89-
- models/marts/core/orders.sql
102+
- *customers
103+
- *orders
90104
exclude:
91105
customers:
92-
- models/marts/core/orders.sql
93-
- data/items.csv
94-
- snapshots/items_snapshot.sql
106+
- *orders
107+
- *items
108+
- *items_snapshot
95109
selector:
96110
test_selector:
97-
- models/marts/core/orders.sql
98-
- snapshots/items_snapshot.sql
111+
- *orders
112+
- *items_snapshot
99113
'':
100114
'':
101-
- models/marts/core/customers.sql
102-
- models/marts/core/orders.sql
103-
- data/items.csv
104-
- snapshots/items_snapshot.sql
105-
- analyses/revenue_by_daily_cohort.sql
115+
- *customers
116+
- *orders
117+
- *items
118+
- *items_snapshot
119+
- *revenue_by_daily_cohort

tests/test_dbt_project/analyses/revenue_by_daily_cohort.sql

+2
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ LEFT JOIN
1111
ON o.item_id = i.item_id
1212
AND o.order_at >= i.dbt_valid_from
1313
AND o.order_at < COALESCE(i.dbt_valid_to, CURRENT_TIMESTAMP)
14+
WHERE
15+
o.order_at >= '1970-01-01 00:00:00'
1416
GROUP BY
1517
CAST(c.created_at AS DATE)

tests/test_dbt_project/profiles.yml

+26-15
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,31 @@ config:
33

44
# Credit to https://github.com/codeforkjeff/dbt-sqlite
55
dbt-sqlite:
6-
target: dev
6+
target: "{{ env_var('TARGET', 'default') }}"
77
outputs:
8-
dev:
9-
type: sqlite
8+
# There is more than one target because dbt-sqlite for dbt~=0.18.x
9+
# uses a different format for schemas_and_paths
10+
0.18.x:
11+
type: &type sqlite
1012
# sqlite locks the whole db on writes so anything > 1 won't help
11-
threads: 1
12-
# value is arbitrary
13-
database: "database"
14-
# value of 'schema' must be defined in schema_paths below. in most cases,
15-
# this should be 'main'
16-
schema: 'main'
17-
# connect schemas to paths: at least one of these must be 'main'
18-
schemas_and_paths: 'main=test.db'
19-
# directory where all *.db files are attached as schema, using base filename
20-
# as schema name, and where new schema are created. this can overlap with the dirs of
21-
# files in schemas_and_paths as long as there's no conflicts.
22-
schema_directory: '.'
13+
threads: &threads 1
14+
# Value is arbitrary
15+
database: &database database
16+
# Value of 'schema' must be defined in schema_paths below.
17+
# In most cases, this should be 'main'
18+
schema: &schema main
19+
# Connect schemas to paths: at least one of these must be 'main'
20+
schemas_and_paths: main=test.db
21+
# Directory where all *.db files are attached as schema, using
22+
# base filename as schema name, and where new schema are created.
23+
# This can overlap with the dirs of files in schemas_and_paths as
24+
# long as there are no conflicts.
25+
schema_directory: &schema_directory .
26+
default:
27+
type: *type
28+
threads: *threads
29+
database: *database
30+
schema: *schema
31+
schemas_and_paths:
32+
main: test.db
33+
schema_directory: *schema_directory

tests/test_utils.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_dbt_ls(self):
3535
:return: None
3636
"""
3737
for db_ls_kwarg, values in self.expected_dbt_ls_results.items():
38-
for value, expected_result_lines in values.items():
38+
for value, expected_result_parts in values.items():
3939
dbt_ls_kwargs = {db_ls_kwarg: value}
4040
result_lines = _utils.dbt_ls(
4141
self.ctx,
@@ -45,7 +45,10 @@ def test_dbt_ls(self):
4545
logger=self.logger,
4646
**dbt_ls_kwargs,
4747
)
48-
self.assertCountEqual(result_lines, expected_result_lines)
48+
result_parts = [
49+
list(Path(line).parts) for line in result_lines
50+
]
51+
self.assertCountEqual(result_parts, expected_result_parts)
4952

5053

5154
if __name__ == '__main__':

0 commit comments

Comments
 (0)