tinybird-cli 3.2.0__tar.gz → 3.6.1.dev9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/PKG-INFO +106 -7
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/__cli__.py +3 -3
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/ch_utils/engine.py +52 -2
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/client.py +15 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/config.py +1 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/connector_settings.py +89 -3
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/context.py +1 -0
- tinybird-cli-3.6.1.dev9/tinybird/data_connectors/credentials.py +31 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/datafile.py +685 -271
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/feedback_manager.py +87 -18
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/git_settings.py +13 -1
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/sql.py +91 -3
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/sql_template.py +50 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/sql_template_fmt.py +22 -1
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/auth.py +1 -1
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/branch.py +28 -1
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/cicd.py +66 -30
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/cli.py +71 -24
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/common.py +40 -22
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/connection.py +146 -2
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/datasource.py +20 -2
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/pipe.py +43 -8
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/test.py +19 -3
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/workspace_members.py +3 -3
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tornado_template.py +1 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/PKG-INFO +106 -7
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/SOURCES.txt +1 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/requires.txt +1 -1
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/top_level.txt +1 -1
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/setup.cfg +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/check_pypi.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/connectors.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/datatypes.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/syncasync.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-3.2.0 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/entry_points.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.1.dev9
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
|
-
Home-page: https://
|
|
5
|
+
Home-page: https://www.tinybird.co/docs/cli/introduction.html
|
|
6
6
|
Author: Tinybird
|
|
7
7
|
Author-email: support@tinybird.co
|
|
8
8
|
Requires-Python: >=3.8, <3.12
|
|
@@ -11,7 +11,7 @@ Provides-Extra: bigquery
|
|
|
11
11
|
Provides-Extra: snowflake
|
|
12
12
|
|
|
13
13
|
Tinybird CLI
|
|
14
|
-
|
|
14
|
+
=============
|
|
15
15
|
|
|
16
16
|
The Tinybird command-line tool allows you to use all the Tinybird functionality directly from the command line. Additionally, it includes several functions to create and manage data projects easily.
|
|
17
17
|
|
|
@@ -19,16 +19,115 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
3.6.1.dev9
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Fixed` Added correct URL for checking available regions
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
3.6.1.dev8
|
|
29
|
+
************
|
|
30
|
+
|
|
31
|
+
- `Fixed` Report better error message on `tb diff` when two Datafiles have the same name
|
|
32
|
+
|
|
33
|
+
3.6.1.dev7
|
|
34
|
+
************
|
|
35
|
+
|
|
36
|
+
- `Fixed` `tb deploy` supports deployment when a `.incl` file is removed
|
|
37
|
+
|
|
38
|
+
3.6.1.dev6
|
|
39
|
+
************
|
|
40
|
+
|
|
41
|
+
- `Fixed` Some issues when using `--fmt: off` with `CASE` in the sql
|
|
42
|
+
|
|
43
|
+
3.6.1.dev5
|
|
44
|
+
************
|
|
45
|
+
|
|
46
|
+
- `Fixed` Avoid `tb fmt` to error if there's a `CASE` in the sql
|
|
47
|
+
|
|
48
|
+
3.6.1.dev4
|
|
49
|
+
************
|
|
50
|
+
|
|
51
|
+
- `Fixed` regression tests query when filtering by specific parameter
|
|
52
|
+
|
|
53
|
+
3.6.1.dev3
|
|
54
|
+
************
|
|
55
|
+
|
|
56
|
+
- `Changed` behavior when running `tb deploy` on a branch to push the connection settings to the backend. This change is the backend that decides what to do.
|
|
57
|
+
|
|
58
|
+
3.6.1.dev2
|
|
59
|
+
************
|
|
60
|
+
|
|
61
|
+
- `Changed` fixed major version of tinybird-cli to lower than 4 when using `tb init --git`
|
|
62
|
+
|
|
63
|
+
3.6.0
|
|
64
|
+
************
|
|
65
|
+
|
|
66
|
+
- `Added` Add new envvar `TB_INCL_RELATIVE_PATH` in .tinyenv to look for Datafiles out of the Data Project directory
|
|
67
|
+
- `Changed` On-demand Sink run checks the pipe type instead of checking the workspace connectors
|
|
68
|
+
|
|
69
|
+
3.5.0
|
|
70
|
+
************
|
|
71
|
+
|
|
72
|
+
- `Added` Token management in Copy pipes datafiles
|
|
73
|
+
- `Added` Better error report on `tb push` when trying to push a pipe with bad templating
|
|
74
|
+
- `Added` credential validation for S3 connections
|
|
75
|
+
- `Added` `tb connection create` now supports `s3_iamrole` as service type
|
|
76
|
+
- `Changed` error message when trying to modify a datasource without bumping the major semver version to add a link to the documentation.
|
|
77
|
+
- `Changed` GH workflow files and secret includes the workspace name when generated from the UI and CLI
|
|
78
|
+
- `Changed` rename `INDICES` to `INDEXES`
|
|
79
|
+
- `Changed` Save git commit to workspace on `tb push --only-changes`
|
|
80
|
+
- `Fixed` Fix error message when deleting an `.incl` file with the git workflow
|
|
81
|
+
- `Fixed` support `tb deploy --dry-run`
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
3.4.0
|
|
85
|
+
************
|
|
86
|
+
|
|
87
|
+
- `Added` Support `tb deploy` .datasource with `INDEXES`
|
|
88
|
+
- `Added` Support `tb push` .datasource with `INDEXES`
|
|
89
|
+
- `Added` Support `tb deploy` in a post release of a .datasource with `INDEXES`
|
|
90
|
+
- `Added` Check backfill on preview is required when `tb deploy` modified datasources. Disable check with `TB_CHECK_BACKFILL_REQUIRED=0`.
|
|
91
|
+
- `Changed` Allow spaces when managing multiple Workspace members
|
|
92
|
+
- `Changed` `tb deploy` to not allow pushing materialized views with datasource definition in the same datafile. We are blocking this as has unsupported behavior and it misleading and less flexible than having 2 files one for the datasource and one for the materialized view.
|
|
93
|
+
- `Changed` `tb deploy` to deploy the datasources from top to bottom to make sure that if we modified the column in some datasource in the top. It will be deployed before the datasources that depend on it.
|
|
94
|
+
- `Changed` Post-release required when deploying changes that include changing a Copy Pipe.
|
|
95
|
+
- `Changed` script `exec_test.sh` from `tb init --git` to run retries to avoid flakiness in tests
|
|
96
|
+
- `Changed` Update `tb release rm --oldest-rollback` to use new API
|
|
97
|
+
- `Fixed` Post-release recommended instead of required when deploying changes that include changing a Copy Pipe. Displays a warning when other number of the semver is increased.
|
|
98
|
+
- `Fixed` Fixed bug when a Data Source was created using an INDEX
|
|
99
|
+
- `Fixed` Avoid None git diff change type
|
|
100
|
+
- `Fixed` `tb deploy` to deploy the endpoints in the correct order when there are endpoints depending on other endpoints.
|
|
101
|
+
- `Fixed` `tb push` pipe with multiple tokens
|
|
102
|
+
- `Fixed` `IMPORT` and `ENGINE` changes were not detected `tb deploy`
|
|
103
|
+
- `Removed` part of the code supporting python 3.6 as we stopped giving support 18 month ago
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
3.3.0
|
|
107
|
+
************
|
|
108
|
+
|
|
109
|
+
- `Added` Show warning when doing data or pipe operations directly against Live.
|
|
110
|
+
- `Added` `bi_stats`, `bi_stats_rt` and `endpoint_errors` to the list of service data sources that the CLI ignore when looking for dependencies of pipes being pushed.
|
|
111
|
+
- `Added` S3 Iam Role connection creation
|
|
112
|
+
- `Added` Connector credential validation
|
|
113
|
+
- `Added` Data quality tests inside a `skip_in_branch` folder inside the `tests` folder are skipped when running on a branch. Use this to skip tests in the CI piipeline that should only run with production data.
|
|
114
|
+
- `Changed` Stop creating endpoints folder on tb init
|
|
115
|
+
- `Changed` Small refactoring of the connector credentials
|
|
116
|
+
- `Fixed` Progress bar in `tb init --git`.
|
|
117
|
+
- `Fixed` Don't do diff when there are no modified resources on `tb deploy`.
|
|
118
|
+
- `Fixed` Upgrade GitPython dependency to 3.1.32. That version fixes the security vulnerability `CVE-2022-24439 <https://github.com/advisories/GHSA-hcpj-qp55-gfph>`
|
|
119
|
+
- `Fixed` Homepage URL in PyPI
|
|
120
|
+
|
|
22
121
|
3.2.0
|
|
23
122
|
************
|
|
24
123
|
|
|
25
124
|
- `Changed` `tb init --git` uses v3.1.0 of the CI templates (See release notes: https://github.com/tinybirdco/ci/releases/tag/v3.1.0)
|
|
26
|
-
- `Changed` Allow alter
|
|
125
|
+
- `Changed` Allow alter data source with JSON paths to add DEFAULTS if the data source already has any (See release notes: https://github.com/tinybirdco/ci/releases/tag/v3.1.0)
|
|
27
126
|
|
|
28
127
|
3.1.0
|
|
29
128
|
************
|
|
30
129
|
|
|
31
|
-
- `Added` `tb init --cicd` to generate CI/CD files not only when using `--git`. Combine with `--force`
|
|
130
|
+
- `Added` `tb init --cicd` to generate CI/CD files not only when using `--git`. Combine with `--force` to overwrite
|
|
32
131
|
- `Added` Ignore format changes on `tb deploy` by default
|
|
33
132
|
- `Changed` `tb init --git` and `tb release generate` include `set -euxo pipefail` in the generated bash scripts
|
|
34
133
|
- `Changed` `tb init --git` uses github.com/tinybirdco/ci => v3.0.0
|
|
@@ -36,7 +135,7 @@ Changelog
|
|
|
36
135
|
- `Changed` `tb release promote` automatically deletes de oldest rollback Release if `export TB_FORCE_REMOVE_OLDEST_ROLLBACK=1`
|
|
37
136
|
- `Changed` option `--node` in `tb pipe populate` to required as it is already mandatory to specify the node to populate. Now, it will provide an error message if the `--node` option is not provided.
|
|
38
137
|
- `Changed` Better error report on `tb fmt --diff`. Use it in CI to standardize Datafile formatting
|
|
39
|
-
- `Changed` `tb init --git` generates a requirements.txt file to install the latest tinybird-cli release from
|
|
138
|
+
- `Changed` `tb init --git` generates a requirements.txt file to install the latest tinybird-cli release from PyPI
|
|
40
139
|
- `Changed` `tb deploy` shows an example when failing because of a missing `--semver` argument
|
|
41
140
|
- `Fixed` When parsing the response of a CSV `tb sql` command, the CLI was interpreting the result as an error in some cases.
|
|
42
141
|
|
|
@@ -45,7 +144,7 @@ Changelog
|
|
|
45
144
|
|
|
46
145
|
Major version updated to 3.0.0 due to the change in the logic of `tb deploy`. From this version on, `tb deploy` promotes Releases to Live or Preview based on the semver version.
|
|
47
146
|
|
|
48
|
-
See `our Version Control guides <https://
|
|
147
|
+
See `our Version Control guides <https://www.tinybird.co/docs/version-control/deployment-strategies.html#semver-deployment-behaviour>`_ for more details about our semver deployment behaviour.
|
|
49
148
|
|
|
50
149
|
- `Added` `syncing` status to git remote settings
|
|
51
150
|
- `Added` `tb release rm --oldest-rollback --force --yes` deletes the oldest rollback Release by creation date
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
__name__ = 'tinybird-cli'
|
|
3
3
|
__description__ = 'Tinybird Command Line Tool'
|
|
4
|
-
__url__ = 'https://
|
|
4
|
+
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '3.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '3.6.1.dev9'
|
|
8
|
+
__revision__ = 'ff22a5b'
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import re
|
|
3
3
|
from collections import defaultdict
|
|
4
|
+
from dataclasses import asdict
|
|
4
5
|
from typing import Any, Callable, Dict, Iterable, List, Optional
|
|
5
6
|
|
|
6
|
-
from ..sql import col_name, engine_replicated_to_local, parse_table_structure
|
|
7
|
+
from ..sql import TableIndex, col_name, engine_replicated_to_local, parse_indexes_structure, parse_table_structure
|
|
7
8
|
|
|
8
9
|
DEFAULT_EMPTY_PARAMETERS = ["ttl", "partition_key", "sorting_key"]
|
|
9
10
|
DEFAULT_JOIN_EMPTY_PARAMETERS = ["join_strictness", "join_type", "key_columns"]
|
|
@@ -31,7 +32,20 @@ class TableDetails:
|
|
|
31
32
|
>>> ed.to_datafile()
|
|
32
33
|
''
|
|
33
34
|
|
|
35
|
+
>>> ed = TableDetails({ "engine_full": "MergeTree() PARTITION BY toYear(timestamp) ORDER BY (timestamp, cityHash64(location)) SAMPLE BY cityHash64(location) SETTINGS index_granularity = 32, index_granularity_bytes = 2048", "engine": "MergeTree", "partition_key": "toYear(timestamp)", "sorting_key": "timestamp, cityHash64(location)", "primary_key": "timestamp, cityHash64(location)", "sampling_key": "cityHash64(location)", "settings": "index_granularity = 32, index_granularity_bytes = 2048", "ttl": None })
|
|
36
|
+
>>> ed.diff_ttl("toDate(timestamp) + toIntervalDay(1)")
|
|
37
|
+
True
|
|
34
38
|
>>> ed = TableDetails({ "engine_full": "MergeTree() PARTITION BY toYear(timestamp) ORDER BY (timestamp, cityHash64(location)) SAMPLE BY cityHash64(location) SETTINGS index_granularity = 32, index_granularity_bytes = 2048 TTL toDate(timestamp) + INTERVAL 1 DAY", "engine": "MergeTree", "partition_key": "toYear(timestamp)", "sorting_key": "timestamp, cityHash64(location)", "primary_key": "timestamp, cityHash64(location)", "sampling_key": "cityHash64(location)", "settings": "index_granularity = 32, index_granularity_bytes = 2048", "ttl": "toDate(timestamp) + INTERVAL 1 DAY" })
|
|
39
|
+
>>> ed.diff_ttl("toDate(timestamp) + toIntervalDay(1)")
|
|
40
|
+
False
|
|
41
|
+
>>> ed.diff_ttl("toDate(timestamp) + toIntervalDay(2)")
|
|
42
|
+
True
|
|
43
|
+
>>> ed.diff_ttl("toDate(timestamp) + INTERVAL DAY 2")
|
|
44
|
+
True
|
|
45
|
+
>>> ed.diff_ttl("toDate(timestamp) + INTERVAL 1 DAY")
|
|
46
|
+
False
|
|
47
|
+
>>> ed.diff_ttl("")
|
|
48
|
+
True
|
|
35
49
|
>>> ed.engine_full
|
|
36
50
|
'MergeTree() PARTITION BY toYear(timestamp) ORDER BY (timestamp, cityHash64(location)) SAMPLE BY cityHash64(location) SETTINGS index_granularity = 32, index_granularity_bytes = 2048 TTL toDate(timestamp) + INTERVAL 1 DAY'
|
|
37
51
|
>>> ed.engine
|
|
@@ -131,6 +145,16 @@ class TableDetails:
|
|
|
131
145
|
return is_aggregating or is_replacing or is_collapsing
|
|
132
146
|
return False
|
|
133
147
|
|
|
148
|
+
def diff_ttl(self, new_ttl: str) -> bool:
|
|
149
|
+
try:
|
|
150
|
+
from tinybird.sql_toolset import format_sql
|
|
151
|
+
|
|
152
|
+
current_ttl = format_sql(f"select {self.ttl}")[7:]
|
|
153
|
+
new_ttl = format_sql(f"select {new_ttl}")[7:]
|
|
154
|
+
return current_ttl != new_ttl
|
|
155
|
+
except Exception:
|
|
156
|
+
return self.ttl != new_ttl
|
|
157
|
+
|
|
134
158
|
@property
|
|
135
159
|
def partition_key(self) -> Optional[str]:
|
|
136
160
|
return self.details.get("partition_key", None)
|
|
@@ -204,6 +228,10 @@ class TableDetails:
|
|
|
204
228
|
"row_count": self.details.get("total_rows", None),
|
|
205
229
|
}
|
|
206
230
|
|
|
231
|
+
@property
|
|
232
|
+
def indexes(self) -> List[TableIndex]:
|
|
233
|
+
return _parse_indexes(str(self.details.get("create_table_query", "")))
|
|
234
|
+
|
|
207
235
|
def to_json(self, exclude: Optional[List[str]] = None, include_empty_details: bool = False):
|
|
208
236
|
# name, database are not exported since they are not part of the engine
|
|
209
237
|
d: Dict[str, Any] = {
|
|
@@ -234,6 +262,8 @@ class TableDetails:
|
|
|
234
262
|
d["version"] = self.version
|
|
235
263
|
if self.ttl:
|
|
236
264
|
d["ttl"] = self.ttl.strip()
|
|
265
|
+
if self.indexes:
|
|
266
|
+
d["indexes"] = [asdict(index) for index in self.indexes]
|
|
237
267
|
|
|
238
268
|
if self.engine_full:
|
|
239
269
|
engine_params = engine_params_from_engine_full(self.engine_full)
|
|
@@ -253,7 +283,9 @@ class TableDetails:
|
|
|
253
283
|
return d
|
|
254
284
|
|
|
255
285
|
def to_datafile(self, include_empty_details: bool = False) -> str:
|
|
256
|
-
d: Dict[str, Any] = self.to_json(
|
|
286
|
+
d: Dict[str, Any] = self.to_json(
|
|
287
|
+
exclude=["engine", "engine_full", "indexes"], include_empty_details=include_empty_details
|
|
288
|
+
)
|
|
257
289
|
engine: str = self.engine
|
|
258
290
|
|
|
259
291
|
datafile: str = ""
|
|
@@ -774,3 +806,21 @@ def ttl_condition_from_engine_full(engine_full: Optional[str]) -> Optional[str]:
|
|
|
774
806
|
except Exception as e:
|
|
775
807
|
logging.error(str(e))
|
|
776
808
|
return None
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
def _parse_indexes(create_table_query_expr: str) -> List[TableIndex]:
|
|
812
|
+
if create_table_query_expr == "":
|
|
813
|
+
return []
|
|
814
|
+
try:
|
|
815
|
+
from tinybird.sql_toolset import format_sql
|
|
816
|
+
|
|
817
|
+
indexes = [
|
|
818
|
+
line.strip()
|
|
819
|
+
for line in format_sql(create_table_query_expr).splitlines()
|
|
820
|
+
if line.strip().startswith("INDEX")
|
|
821
|
+
]
|
|
822
|
+
except ModuleNotFoundError:
|
|
823
|
+
# this is not needed from CLI
|
|
824
|
+
return []
|
|
825
|
+
|
|
826
|
+
return parse_indexes_structure(indexes)
|
|
@@ -306,6 +306,7 @@ class TinyB(object):
|
|
|
306
306
|
description: Optional[str] = None,
|
|
307
307
|
ttl: Optional[str] = None,
|
|
308
308
|
dry_run: bool = False,
|
|
309
|
+
indexes: Optional[str] = None,
|
|
309
310
|
):
|
|
310
311
|
params = {"dry": "true" if dry_run else "false"}
|
|
311
312
|
if new_schema:
|
|
@@ -314,6 +315,8 @@ class TinyB(object):
|
|
|
314
315
|
params.update({"description": description})
|
|
315
316
|
if ttl:
|
|
316
317
|
params.update({"ttl": ttl})
|
|
318
|
+
if indexes:
|
|
319
|
+
params.update({"indexes": indexes})
|
|
317
320
|
res = await self._req(f"/v0/datasources/{ds_name}/alter", method="POST", data=params)
|
|
318
321
|
|
|
319
322
|
if "Error" in res:
|
|
@@ -991,6 +994,12 @@ class TinyB(object):
|
|
|
991
994
|
response = await self._req(f"/v0/connectors/snowflake/warehouses?{urlencode(params)}", method="POST", data="")
|
|
992
995
|
return response["warehouses"]
|
|
993
996
|
|
|
997
|
+
async def get_s3_trust_policy(self) -> Dict[str, Any]:
|
|
998
|
+
return await self._req("/v0/integrations/s3/policies/trust-policy")
|
|
999
|
+
|
|
1000
|
+
async def get_s3_access_policy(self) -> Dict[str, Any]:
|
|
1001
|
+
return await self._req("/v0/integrations/s3/policies/access-policy")
|
|
1002
|
+
|
|
994
1003
|
async def sql_get_format(self, sql: str, with_clickhouse_format: bool = False) -> str:
|
|
995
1004
|
try:
|
|
996
1005
|
if with_clickhouse_format:
|
|
@@ -1099,6 +1108,12 @@ class TinyB(object):
|
|
|
1099
1108
|
params["confirmation"] = confirmation
|
|
1100
1109
|
return await self._req(f"/v0/workspaces/{workspace_id}/releases/{semver}?{urlencode(params)}", method="DELETE")
|
|
1101
1110
|
|
|
1111
|
+
async def release_oldest_rollback(
|
|
1112
|
+
self,
|
|
1113
|
+
workspace_id: str,
|
|
1114
|
+
):
|
|
1115
|
+
return await self._req(f"/v0/workspaces/{workspace_id}/releases/oldest-rollback", method="GET")
|
|
1116
|
+
|
|
1102
1117
|
async def token_list(self, match: Optional[str] = None):
|
|
1103
1118
|
tokens = await self.tokens()
|
|
1104
1119
|
return [token for token in tokens if (not match or token["name"].find(match) != -1) and "token" in token]
|
|
@@ -20,6 +20,7 @@ VERSION = f"{__cli__.__version__} (rev {__revision__})"
|
|
|
20
20
|
DEFAULT_UI_HOST = "https://ui.tinybird.co"
|
|
21
21
|
SUPPORTED_CONNECTORS = ["bigquery", "snowflake"]
|
|
22
22
|
PROJECT_PATHS = ["datasources", "datasources/fixtures", "endpoints", "pipes", "tests", "scripts", "deploy"]
|
|
23
|
+
DEPRECATED_PROJECT_PATHS = ["endpoints"]
|
|
23
24
|
MIN_WORKSPACE_ID_LENGTH = 36
|
|
24
25
|
|
|
25
26
|
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from typing import List, Optional
|
|
4
|
+
from typing import List, Optional, Union
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
|
+
from tinybird.data_connectors.credentials import (
|
|
9
|
+
GCSConnectorCredentials,
|
|
10
|
+
GCSServiceAccountCredentials,
|
|
11
|
+
IAMRoleAWSCredentials,
|
|
12
|
+
S3ConnectorCredentials,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
GCS_BASE_URL = "https://storage.googleapis.com"
|
|
16
|
+
|
|
8
17
|
|
|
9
18
|
class DataConnectorType(str, Enum):
|
|
10
19
|
KAFKA = "kafka"
|
|
@@ -13,6 +22,7 @@ class DataConnectorType(str, Enum):
|
|
|
13
22
|
BIGQUERY = "bigquery"
|
|
14
23
|
GCLOUD_STORAGE = "gcs"
|
|
15
24
|
GCLOUD_STORAGE_HMAC = "gcs_hmac"
|
|
25
|
+
GCLOUD_STORAGE_SA = "gcs_service_account"
|
|
16
26
|
AMAZON_S3 = "s3"
|
|
17
27
|
AMAZON_S3_IAMROLE = "s3_iamrole"
|
|
18
28
|
|
|
@@ -24,7 +34,11 @@ DataConnectors = DataConnectorType # this is just to make picking happy
|
|
|
24
34
|
|
|
25
35
|
|
|
26
36
|
class DataConnectorSetting(BaseModel):
|
|
27
|
-
|
|
37
|
+
def get_region(self) -> str:
|
|
38
|
+
return "unknown"
|
|
39
|
+
|
|
40
|
+
def get_provider_name(self) -> str:
|
|
41
|
+
return "unknown"
|
|
28
42
|
|
|
29
43
|
|
|
30
44
|
class KafkaConnectorSetting(DataConnectorSetting):
|
|
@@ -42,12 +56,42 @@ class S3ConnectorSetting(DataConnectorSetting):
|
|
|
42
56
|
s3_access_key_id: str
|
|
43
57
|
s3_secret_access_key: str
|
|
44
58
|
s3_region: str
|
|
59
|
+
endpoint_url: Optional[str] = None
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def credentials(self) -> S3ConnectorCredentials:
|
|
63
|
+
return S3ConnectorCredentials(
|
|
64
|
+
access_key_id=self.s3_access_key_id,
|
|
65
|
+
secret_access_key=self.s3_secret_access_key,
|
|
66
|
+
region=self.s3_region,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def get_provider_name(self) -> str:
|
|
70
|
+
return DataConnectorType.AMAZON_S3
|
|
71
|
+
|
|
72
|
+
def get_region(self) -> str:
|
|
73
|
+
return self.s3_region
|
|
45
74
|
|
|
46
75
|
|
|
47
76
|
class S3IAMConnectorSetting(DataConnectorSetting):
|
|
48
77
|
s3_iamrole_arn: str
|
|
49
78
|
s3_iamrole_region: str
|
|
50
|
-
s3_iamrole_external_id:
|
|
79
|
+
s3_iamrole_external_id: str
|
|
80
|
+
endpoint_url: Optional[str] = None
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def credentials(self) -> IAMRoleAWSCredentials:
|
|
84
|
+
return IAMRoleAWSCredentials(
|
|
85
|
+
role_arn=self.s3_iamrole_arn,
|
|
86
|
+
external_id=self.s3_iamrole_external_id,
|
|
87
|
+
region=self.s3_iamrole_region,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def get_provider_name(self) -> str:
|
|
91
|
+
return DataConnectorType.AMAZON_S3
|
|
92
|
+
|
|
93
|
+
def get_region(self) -> str:
|
|
94
|
+
return self.s3_iamrole_region
|
|
51
95
|
|
|
52
96
|
|
|
53
97
|
class SnowflakeConnectorSetting(DataConnectorSetting):
|
|
@@ -69,9 +113,32 @@ class BigQueryConnectorSetting(DataConnectorSetting):
|
|
|
69
113
|
account: Optional[str] = None
|
|
70
114
|
|
|
71
115
|
|
|
116
|
+
class GCSServiceAccountConnectorSetting(DataConnectorSetting):
|
|
117
|
+
account_email: str
|
|
118
|
+
endpoint_url: str = GCS_BASE_URL
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def credentials(self) -> GCSServiceAccountCredentials:
|
|
122
|
+
return GCSServiceAccountCredentials(account_email=self.account_email)
|
|
123
|
+
|
|
124
|
+
def get_provider_name(self) -> str:
|
|
125
|
+
return DataConnectorType.GCLOUD_STORAGE
|
|
126
|
+
|
|
127
|
+
|
|
72
128
|
class GCSHmacConnectorSetting(DataConnectorSetting):
|
|
73
129
|
gcs_hmac_access_id: str
|
|
74
130
|
gcs_hmac_secret: str
|
|
131
|
+
endpoint_url: str = GCS_BASE_URL
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def credentials(self) -> GCSConnectorCredentials:
|
|
135
|
+
return GCSConnectorCredentials(
|
|
136
|
+
access_key_id=self.gcs_hmac_access_id,
|
|
137
|
+
secret_access_key=self.gcs_hmac_secret,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def get_provider_name(self) -> str:
|
|
141
|
+
return DataConnectorType.GCLOUD_STORAGE
|
|
75
142
|
|
|
76
143
|
|
|
77
144
|
class GCSConnectorSetting(DataConnectorSetting):
|
|
@@ -90,10 +157,15 @@ DATA_CONNECTOR_SETTINGS: dict[DataConnectors, type[DataConnectorSetting]] = {
|
|
|
90
157
|
DataConnectors.BIGQUERY: BigQueryConnectorSetting,
|
|
91
158
|
DataConnectors.GCLOUD_STORAGE: GCSConnectorSetting,
|
|
92
159
|
DataConnectors.GCLOUD_STORAGE_HMAC: GCSHmacConnectorSetting,
|
|
160
|
+
DataConnectors.GCLOUD_STORAGE_SA: GCSServiceAccountConnectorSetting,
|
|
93
161
|
DataConnectors.AMAZON_S3: S3ConnectorSetting,
|
|
94
162
|
DataConnectors.AMAZON_S3_IAMROLE: S3IAMConnectorSetting,
|
|
95
163
|
}
|
|
96
164
|
|
|
165
|
+
SinkConnectorSettings = Union[
|
|
166
|
+
S3ConnectorSetting, S3IAMConnectorSetting, GCSHmacConnectorSetting, GCSServiceAccountConnectorSetting
|
|
167
|
+
]
|
|
168
|
+
|
|
97
169
|
|
|
98
170
|
class DataLinkerSettings:
|
|
99
171
|
kafka = [
|
|
@@ -137,6 +209,13 @@ class DataSinkSettings:
|
|
|
137
209
|
"format",
|
|
138
210
|
"compression",
|
|
139
211
|
]
|
|
212
|
+
gcs_service_account = [
|
|
213
|
+
"bucket_path",
|
|
214
|
+
"file_template",
|
|
215
|
+
"partition_node",
|
|
216
|
+
"format",
|
|
217
|
+
"compression",
|
|
218
|
+
]
|
|
140
219
|
|
|
141
220
|
|
|
142
221
|
class DataSensitiveSettings:
|
|
@@ -151,3 +230,10 @@ class DataSensitiveSettings:
|
|
|
151
230
|
gcs_hmac: List[str] = ["gcs_hmac_secret"]
|
|
152
231
|
s3: List[str] = ["s3_secret_access_key"]
|
|
153
232
|
s3_iamrole: List[str] = ["s3_iamrole_arn"]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
CLI_EXCLUDED_SETTINGS = {
|
|
236
|
+
"gcs_hmac": ["endpoint_url"],
|
|
237
|
+
"s3": ["endpoint_url"],
|
|
238
|
+
"s3_iamrole": ["endpoint_url"],
|
|
239
|
+
}
|
|
@@ -6,6 +6,7 @@ table_id: ContextVar[str] = ContextVar("table_id")
|
|
|
6
6
|
hfi_frequency: ContextVar[float] = ContextVar("hfi_frequency")
|
|
7
7
|
hfi_frequency_gatherer: ContextVar[float] = ContextVar("hfi_frequency_gatherer")
|
|
8
8
|
hfi_use_gatherer: ContextVar[bool] = ContextVar("hfi_use_gatherer")
|
|
9
|
+
use_gatherer: ContextVar[bool] = ContextVar("use_gatherer")
|
|
9
10
|
disable_template_security_validation: ContextVar[bool] = ContextVar("disable_template_security_validation")
|
|
10
11
|
origin: ContextVar[str] = ContextVar("origin")
|
|
11
12
|
request_id: ContextVar[str] = ContextVar("request_id")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import dataclasses
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ConnectorCredentials(abc.ABC):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclasses.dataclass(frozen=True)
|
|
10
|
+
class S3ConnectorCredentials(ConnectorCredentials):
|
|
11
|
+
access_key_id: str
|
|
12
|
+
secret_access_key: str
|
|
13
|
+
region: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclasses.dataclass(frozen=True)
|
|
17
|
+
class IAMRoleAWSCredentials(ConnectorCredentials):
|
|
18
|
+
role_arn: str
|
|
19
|
+
external_id: str
|
|
20
|
+
region: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclasses.dataclass(frozen=True)
|
|
24
|
+
class GCSConnectorCredentials(ConnectorCredentials):
|
|
25
|
+
access_key_id: str
|
|
26
|
+
secret_access_key: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclasses.dataclass(frozen=True)
|
|
30
|
+
class GCSServiceAccountCredentials(ConnectorCredentials):
|
|
31
|
+
account_email: str
|