tinybird-cli 5.9.1.dev3__tar.gz → 5.10.1.dev0__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-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/PKG-INFO +5 -8
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/__cli__.py +2 -2
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/client.py +5 -3
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/datafile.py +25 -16
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/feedback_manager.py +2 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/sql.py +1 -1
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/sql_template.py +4 -4
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/syncasync.py +4 -4
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/cli.py +4 -4
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/common.py +29 -6
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/connection.py +12 -1
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/datasource.py +1 -1
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tornado_template.py +1 -1
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/PKG-INFO +5 -8
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/setup.cfg +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/check_pypi.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/config.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/connectors.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/context.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/datatypes.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/git_settings.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/SOURCES.txt +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/entry_points.txt +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/requires.txt +0 -0
- {tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.10.1.dev0
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://www.tinybird.co/docs/cli/introduction.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -18,16 +18,13 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
|
|
|
18
18
|
Changelog
|
|
19
19
|
----------
|
|
20
20
|
|
|
21
|
-
5.
|
|
21
|
+
5.10.0
|
|
22
22
|
***********
|
|
23
23
|
|
|
24
|
-
- `Fixed` Correctly parse lambda expressions in indexes
|
|
25
|
-
|
|
26
|
-
5.9.1.dev2
|
|
27
|
-
***********
|
|
28
|
-
|
|
29
|
-
- `Changed` Upgrade clickhouse-toolset to 0.32.dev0
|
|
30
24
|
- `Added` new "File not found" error to `tb check` when including files from missing paths.
|
|
25
|
+
- `Added` support for Kafka Data Sources with CA certificate.
|
|
26
|
+
- `Changed` Upgrade clickhouse-toolset to 0.32.dev0
|
|
27
|
+
- `Fixed` Correctly parse lambda expressions in indexes
|
|
31
28
|
|
|
32
29
|
5.9.0
|
|
33
30
|
***********
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '5.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '5.10.1.dev0'
|
|
8
|
+
__revision__ = 'f8aa90b'
|
|
@@ -111,7 +111,7 @@ class TinyB(object):
|
|
|
111
111
|
retries: int = LIMIT_RETRIES,
|
|
112
112
|
use_token: Optional[str] = None,
|
|
113
113
|
**kwargs,
|
|
114
|
-
):
|
|
114
|
+
):
|
|
115
115
|
url = f"{self.host.strip('/')}/{endpoint.strip('/')}"
|
|
116
116
|
|
|
117
117
|
token_to_use = use_token if use_token else self.token
|
|
@@ -275,7 +275,7 @@ class TinyB(object):
|
|
|
275
275
|
bigquery_connection = (
|
|
276
276
|
await self.bigquery_connection() if connector == "bigquery" or connector is None else None
|
|
277
277
|
)
|
|
278
|
-
connectors = connectors
|
|
278
|
+
connectors = [*connectors, bigquery_connection] if bigquery_connection else connectors
|
|
279
279
|
if connector:
|
|
280
280
|
return [
|
|
281
281
|
{
|
|
@@ -865,6 +865,7 @@ class TinyB(object):
|
|
|
865
865
|
kafka_auto_offset_reset=None,
|
|
866
866
|
kafka_schema_registry_url=None,
|
|
867
867
|
kafka_sasl_mechanism="PLAIN",
|
|
868
|
+
kafka_ssl_ca_pem=None,
|
|
868
869
|
):
|
|
869
870
|
params = {
|
|
870
871
|
"service": "kafka",
|
|
@@ -880,7 +881,8 @@ class TinyB(object):
|
|
|
880
881
|
params["kafka_schema_registry_url"] = kafka_schema_registry_url
|
|
881
882
|
if kafka_auto_offset_reset:
|
|
882
883
|
params["kafka_auto_offset_reset"] = kafka_auto_offset_reset
|
|
883
|
-
|
|
884
|
+
if kafka_ssl_ca_pem:
|
|
885
|
+
params["kafka_ssl_ca_pem"] = kafka_ssl_ca_pem
|
|
884
886
|
connection_params = {key: value for key, value in params.items() if value is not None}
|
|
885
887
|
|
|
886
888
|
return await self._req(
|
|
@@ -60,7 +60,13 @@ from toposort import toposort
|
|
|
60
60
|
from tinybird.config import PROJECT_PATHS
|
|
61
61
|
from tinybird.sql_template_fmt import DEFAULT_FMT_LINE_LENGTH, format_sql_template
|
|
62
62
|
from tinybird.syncasync import sync_to_async
|
|
63
|
-
from tinybird.tb_cli_modules.common import
|
|
63
|
+
from tinybird.tb_cli_modules.common import (
|
|
64
|
+
_get_tb_client,
|
|
65
|
+
get_ca_pem_content,
|
|
66
|
+
get_current_main_workspace,
|
|
67
|
+
getenv_bool,
|
|
68
|
+
wait_job,
|
|
69
|
+
)
|
|
64
70
|
from tinybird.tb_cli_modules.config import CLIConfig
|
|
65
71
|
from tinybird.tb_cli_modules.exceptions import CLIGitReleaseException, CLIPipeException
|
|
66
72
|
|
|
@@ -72,7 +78,7 @@ from .sql_template import get_template_and_variables, get_used_tables_in_templat
|
|
|
72
78
|
from .tornado_template import UnClosedIfError
|
|
73
79
|
|
|
74
80
|
os.environ["GIT_PYTHON_REFRESH"] = "quiet"
|
|
75
|
-
from git import HEAD, Diff, GitCommandError, InvalidGitRepositoryError, Repo
|
|
81
|
+
from git import HEAD, Diff, GitCommandError, InvalidGitRepositoryError, Repo
|
|
76
82
|
|
|
77
83
|
INTERNAL_TABLES: Tuple[str, ...] = (
|
|
78
84
|
"datasources_ops_log",
|
|
@@ -960,7 +966,7 @@ def parse(
|
|
|
960
966
|
basepath: str = ".",
|
|
961
967
|
replace_includes: bool = True,
|
|
962
968
|
skip_eval: bool = False,
|
|
963
|
-
) -> Datafile:
|
|
969
|
+
) -> Datafile:
|
|
964
970
|
"""
|
|
965
971
|
Parses `s` string into a document
|
|
966
972
|
>>> d = parse("FROM SCRATCH\\nSOURCE 'https://example.com'\\n#this is a comment\\nMAINTAINER 'rambo' #this is me\\nNODE \\"test_01\\"\\n DESCRIPTION this is a node that does whatever\\nSQL >\\n\\n SELECT * from test_00\\n\\n\\nNODE \\"test_02\\"\\n DESCRIPTION this is a node that does whatever\\nSQL >\\n\\n SELECT * from test_01\\n WHERE a > 1\\n GROUP by a\\n")
|
|
@@ -1110,9 +1116,10 @@ def parse(
|
|
|
1110
1116
|
pass
|
|
1111
1117
|
finally:
|
|
1112
1118
|
file.seek(0)
|
|
1113
|
-
lines[lineno : lineno + 1] = [
|
|
1114
|
-
|
|
1115
|
-
|
|
1119
|
+
lines[lineno : lineno + 1] = [
|
|
1120
|
+
"",
|
|
1121
|
+
*list(StringIO(Template(file.read()).safe_substitute(attrs), newline=None)),
|
|
1122
|
+
]
|
|
1116
1123
|
except FileNotFoundError:
|
|
1117
1124
|
raise IncludeFileNotFoundException(f, lineno)
|
|
1118
1125
|
|
|
@@ -1211,6 +1218,7 @@ def parse(
|
|
|
1211
1218
|
"kafka_store_headers": assign_var("kafka_store_headers"),
|
|
1212
1219
|
"kafka_store_binary_headers": assign_var("kafka_store_binary_headers"),
|
|
1213
1220
|
"kafka_key_avro_deserialization": assign_var("kafka_key_avro_deserialization"),
|
|
1221
|
+
"kafka_ssl_ca_pem": assign_var("kafka_ssl_ca_pem"),
|
|
1214
1222
|
"import_service": assign_var("import_service"),
|
|
1215
1223
|
"import_connection_name": assign_var("import_connection_name"),
|
|
1216
1224
|
"import_schedule": assign_var("import_schedule"),
|
|
@@ -1318,7 +1326,7 @@ async def process_file(
|
|
|
1318
1326
|
workspace_map: Optional[Dict] = None,
|
|
1319
1327
|
workspace_lib_paths: Optional[List[Tuple[str, str]]] = None,
|
|
1320
1328
|
current_ws: Optional[Dict[str, Any]] = None,
|
|
1321
|
-
):
|
|
1329
|
+
):
|
|
1322
1330
|
if workspace_map is None:
|
|
1323
1331
|
workspace_map = {}
|
|
1324
1332
|
|
|
@@ -1349,6 +1357,7 @@ async def process_file(
|
|
|
1349
1357
|
"kafka_connection_name": params.get("kafka_connection_name", None),
|
|
1350
1358
|
"kafka_auto_offset_reset": params.get("kafka_auto_offset_reset", None),
|
|
1351
1359
|
"kafka_schema_registry_url": params.get("kafka_schema_registry_url", None),
|
|
1360
|
+
"kafka_ssl_ca_pem": get_ca_pem_content(params.get("kafka_ssl_ca_pem", None), filename),
|
|
1352
1361
|
}
|
|
1353
1362
|
|
|
1354
1363
|
connector = await tb_client.get_connection(**connector_params)
|
|
@@ -2868,7 +2877,7 @@ async def new_pipe(
|
|
|
2868
2877
|
config: Any = None,
|
|
2869
2878
|
fork_downstream: Optional[bool] = False,
|
|
2870
2879
|
fork: Optional[bool] = False,
|
|
2871
|
-
):
|
|
2880
|
+
):
|
|
2872
2881
|
# TODO use tb_client instead of calling the urls directly.
|
|
2873
2882
|
host = tb_client.host
|
|
2874
2883
|
token = tb_client.token
|
|
@@ -3270,10 +3279,10 @@ async def new_ds(
|
|
|
3270
3279
|
if job_url:
|
|
3271
3280
|
click.echo(FeedbackManager.success_dynamodb_initial_load(job_url=job_url))
|
|
3272
3281
|
|
|
3273
|
-
if
|
|
3282
|
+
if ds.get("tokens"):
|
|
3274
3283
|
await manage_tokens()
|
|
3275
3284
|
|
|
3276
|
-
if
|
|
3285
|
+
if ds.get("shared_with"):
|
|
3277
3286
|
if not user_token:
|
|
3278
3287
|
click.echo(FeedbackManager.info_skipping_shared_with_entry())
|
|
3279
3288
|
else:
|
|
@@ -4189,7 +4198,7 @@ async def folder_push(
|
|
|
4189
4198
|
use_main: bool = False,
|
|
4190
4199
|
check_outdated: bool = True,
|
|
4191
4200
|
hide_folders: bool = False,
|
|
4192
|
-
):
|
|
4201
|
+
):
|
|
4193
4202
|
workspaces: List[Dict[str, Any]] = (await tb_client.user_workspaces_and_branches()).get("workspaces", [])
|
|
4194
4203
|
current_ws: Dict[str, Any] = next(
|
|
4195
4204
|
(workspace for workspace in workspaces if config and workspace.get("id", ".") == config.get("id", "..")), {}
|
|
@@ -4754,7 +4763,7 @@ DATAFILE_INDENT = " " * 4
|
|
|
4754
4763
|
|
|
4755
4764
|
|
|
4756
4765
|
def format_schema(file_parts: List[str], node: Dict[str, Any]) -> List[str]:
|
|
4757
|
-
if
|
|
4766
|
+
if node.get("schema"):
|
|
4758
4767
|
file_parts.append("SCHEMA >")
|
|
4759
4768
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
4760
4769
|
columns = schema_to_sql_columns(node["columns"])
|
|
@@ -4766,7 +4775,7 @@ def format_schema(file_parts: List[str], node: Dict[str, Any]) -> List[str]:
|
|
|
4766
4775
|
|
|
4767
4776
|
|
|
4768
4777
|
def format_indices(file_parts: List[str], node: Dict[str, Any]) -> List[str]:
|
|
4769
|
-
if
|
|
4778
|
+
if node.get("indexes"):
|
|
4770
4779
|
indexes = node["indexes"]
|
|
4771
4780
|
file_parts.append("INDEXES >")
|
|
4772
4781
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
@@ -4995,7 +5004,7 @@ async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[
|
|
|
4995
5004
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
4996
5005
|
file_parts.append(f'COPY_MODE {node.get("mode")}')
|
|
4997
5006
|
|
|
4998
|
-
if
|
|
5007
|
+
if node.get(CopyParameters.COPY_SCHEDULE):
|
|
4999
5008
|
is_ondemand = node[CopyParameters.COPY_SCHEDULE].lower() == ON_DEMAND
|
|
5000
5009
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5001
5010
|
file_parts.append(
|
|
@@ -5154,7 +5163,7 @@ async def folder_pull(
|
|
|
5154
5163
|
verbose: bool = True,
|
|
5155
5164
|
progress_bar: bool = False,
|
|
5156
5165
|
fmt: bool = False,
|
|
5157
|
-
):
|
|
5166
|
+
):
|
|
5158
5167
|
pattern = re.compile(match) if match else None
|
|
5159
5168
|
|
|
5160
5169
|
def _get_latest_versions(resources: List[str]):
|
|
@@ -5321,7 +5330,7 @@ async def diff_command(
|
|
|
5321
5330
|
|
|
5322
5331
|
if filenames:
|
|
5323
5332
|
if len(filenames) == 1:
|
|
5324
|
-
filenames = [filenames[0]
|
|
5333
|
+
filenames = [filenames[0], *get_project_filenames(filenames[0])]
|
|
5325
5334
|
await folder_pull(client, target_dir, False, None, True, verbose=False)
|
|
5326
5335
|
else:
|
|
5327
5336
|
filenames = get_project_filenames(".")
|
|
@@ -238,6 +238,8 @@ class FeedbackManager:
|
|
|
238
238
|
error_connection_does_not_exists = error_message("Connection {connection_id} does not exist")
|
|
239
239
|
error_connection_create = error_message("Connection {connection_name} could not be created: {error}")
|
|
240
240
|
error_connection_integration_not_available = error_message("Connection could not be created: {error}")
|
|
241
|
+
error_connection_invalid_ca_pem = error_message("Invalid CA certificate in PEM format")
|
|
242
|
+
error_connection_ca_pem_not_found = error_message("CA certificate in PEM format not found at {ca_pem}")
|
|
241
243
|
error_workspace = error_message("Workspace {workspace} not found. use 'tb workspace ls' to list your workspaces")
|
|
242
244
|
error_deleted_include = error_message(
|
|
243
245
|
"Related include file {include_file} was deleted and it's used in {filename}. Delete or remove dependency from {filename}."
|
|
@@ -526,7 +526,7 @@ REGEX_WHITESPACE = re.compile(r"\s*")
|
|
|
526
526
|
REGEX_COMMENT = re.compile(r"\-\-[^\n\r]*[\n\r]")
|
|
527
527
|
|
|
528
528
|
|
|
529
|
-
def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
|
|
529
|
+
def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
|
|
530
530
|
# CH syntax from https://clickhouse.com/docs/en/sql-reference/statements/create/table/
|
|
531
531
|
# name1 [type1] [NULL|NOT NULL] [DEFAULT|MATERIALIZED|ALIAS expr1] [compression_codec] [TTL expr1]
|
|
532
532
|
try:
|
|
@@ -359,7 +359,7 @@ def defined(x=None):
|
|
|
359
359
|
return True
|
|
360
360
|
|
|
361
361
|
|
|
362
|
-
def array_type(types):
|
|
362
|
+
def array_type(types):
|
|
363
363
|
def _f(
|
|
364
364
|
x, _type=None, default=None, defined=True, required=None, description=None, enum=None, example=None, format=None
|
|
365
365
|
):
|
|
@@ -1370,7 +1370,7 @@ _namespace = {
|
|
|
1370
1370
|
}
|
|
1371
1371
|
|
|
1372
1372
|
|
|
1373
|
-
reserved_vars = set(["_tt_tmp", "_tt_append", "isinstance", "str", "error", "custom_error"
|
|
1373
|
+
reserved_vars = set(["_tt_tmp", "_tt_append", "isinstance", "str", "error", "custom_error", *list(vars(builtins))])
|
|
1374
1374
|
for p in DEFAULT_PARAM_NAMES: # we handle these in an specific manner
|
|
1375
1375
|
reserved_vars.discard(p) # `format` is part of builtins
|
|
1376
1376
|
error_vars = ["error", "custom_error"]
|
|
@@ -1552,7 +1552,7 @@ def get_var_names(t):
|
|
|
1552
1552
|
raise SQLTemplateException(e)
|
|
1553
1553
|
|
|
1554
1554
|
|
|
1555
|
-
def get_var_data(content, node_id=None):
|
|
1555
|
+
def get_var_data(content, node_id=None):
|
|
1556
1556
|
def node_to_value(x):
|
|
1557
1557
|
if type(x) in (ast.Bytes, ast.Str):
|
|
1558
1558
|
return x.s
|
|
@@ -1703,7 +1703,7 @@ def get_var_data(content, node_id=None): # noqa: C901
|
|
|
1703
1703
|
return [dict(name=k, **v) for k, v in vars.items()]
|
|
1704
1704
|
|
|
1705
1705
|
|
|
1706
|
-
def get_var_names_and_types(t, node_id=None):
|
|
1706
|
+
def get_var_names_and_types(t, node_id=None):
|
|
1707
1707
|
"""
|
|
1708
1708
|
>>> get_var_names_and_types(Template("SELECT * FROM filter_value WHERE description = {{Float32(with_value, 0.0)}}"))
|
|
1709
1709
|
[{'name': 'with_value', 'type': 'Float32', 'default': 0.0}]
|
|
@@ -177,7 +177,7 @@ class _WorkItem:
|
|
|
177
177
|
return
|
|
178
178
|
try:
|
|
179
179
|
result = self.fn(*self.args, **self.kwargs)
|
|
180
|
-
except BaseException as exc:
|
|
180
|
+
except BaseException as exc:
|
|
181
181
|
self.future.set_exception(exc)
|
|
182
182
|
# Break a reference cycle with the exception 'exc'
|
|
183
183
|
self = None
|
|
@@ -473,11 +473,11 @@ class AsyncToSync:
|
|
|
473
473
|
if exc_info[1]:
|
|
474
474
|
try:
|
|
475
475
|
raise exc_info[1]
|
|
476
|
-
except BaseException:
|
|
476
|
+
except BaseException:
|
|
477
477
|
result = await self.awaitable(*args, **kwargs)
|
|
478
478
|
else:
|
|
479
479
|
result = await self.awaitable(*args, **kwargs)
|
|
480
|
-
except BaseException as e:
|
|
480
|
+
except BaseException as e:
|
|
481
481
|
call_result.set_exception(e)
|
|
482
482
|
else:
|
|
483
483
|
call_result.set_result(result)
|
|
@@ -639,7 +639,7 @@ class SyncToAsync:
|
|
|
639
639
|
if exc_info[1]:
|
|
640
640
|
try:
|
|
641
641
|
raise exc_info[1]
|
|
642
|
-
except BaseException:
|
|
642
|
+
except BaseException:
|
|
643
643
|
return func(*args, **kwargs)
|
|
644
644
|
else:
|
|
645
645
|
return func(*args, **kwargs)
|
|
@@ -76,7 +76,7 @@ DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
|
|
|
76
76
|
]
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
@click.group(cls=CatchAuthExceptions, context_settings={"help_option_names": ["-h", "--help"]})
|
|
79
|
+
@click.group(cls=CatchAuthExceptions, context_settings={"help_option_names": ["-h", "--help"]})
|
|
80
80
|
@click.option(
|
|
81
81
|
"--debug/--no-debug",
|
|
82
82
|
default=False,
|
|
@@ -212,7 +212,7 @@ async def cli(
|
|
|
212
212
|
if ctx.invoked_subcommand == "auth":
|
|
213
213
|
return
|
|
214
214
|
|
|
215
|
-
from tinybird.connectors import create_connector
|
|
215
|
+
from tinybird.connectors import create_connector
|
|
216
216
|
|
|
217
217
|
if gcp_project_id and gcs_bucket and google_application_credentials and not sf_account:
|
|
218
218
|
bq_config = {
|
|
@@ -679,7 +679,7 @@ async def push(
|
|
|
679
679
|
return
|
|
680
680
|
|
|
681
681
|
|
|
682
|
-
@cli.command()
|
|
682
|
+
@cli.command()
|
|
683
683
|
@click.option(
|
|
684
684
|
"--folder", default=None, type=click.Path(exists=True, file_okay=False), help="Folder where files will be placed"
|
|
685
685
|
)
|
|
@@ -1251,7 +1251,7 @@ def __unpatch_click_output():
|
|
|
1251
1251
|
click.secho = __old_click_echo
|
|
1252
1252
|
|
|
1253
1253
|
|
|
1254
|
-
@cli.command(short_help="Learn how to include info about the CLI in your shell PROMPT")
|
|
1254
|
+
@cli.command(short_help="Learn how to include info about the CLI in your shell PROMPT")
|
|
1255
1255
|
@click.pass_context
|
|
1256
1256
|
@coro
|
|
1257
1257
|
async def prompt(_ctx: Context) -> None:
|
|
@@ -1133,17 +1133,15 @@ async def push_data(
|
|
|
1133
1133
|
appended_rows = 0
|
|
1134
1134
|
parser = None
|
|
1135
1135
|
|
|
1136
|
-
if
|
|
1136
|
+
if res.get("error"):
|
|
1137
1137
|
raise CLIException(FeedbackManager.error_exception(error=res["error"]))
|
|
1138
|
-
if
|
|
1138
|
+
if res.get("errors"):
|
|
1139
1139
|
raise CLIException(FeedbackManager.error_exception(error=res["errors"]))
|
|
1140
|
-
if
|
|
1140
|
+
if res.get("blocks"):
|
|
1141
1141
|
for block in res["blocks"]:
|
|
1142
1142
|
if "process_return" in block and block["process_return"] is not None:
|
|
1143
1143
|
process_return = block["process_return"][0]
|
|
1144
|
-
parser = (
|
|
1145
|
-
process_return["parser"] if "parser" in process_return and process_return["parser"] else parser
|
|
1146
|
-
)
|
|
1144
|
+
parser = process_return["parser"] if process_return.get("parser") else parser
|
|
1147
1145
|
if parser and parser != "clickhouse":
|
|
1148
1146
|
parser = process_return["parser"]
|
|
1149
1147
|
appended_rows += process_return["lines"]
|
|
@@ -2056,3 +2054,28 @@ async def create_aws_iamrole_connection(client: TinyB, service: str, connection_
|
|
|
2056
2054
|
"""
|
|
2057
2055
|
)
|
|
2058
2056
|
click.echo(FeedbackManager.success_connection_file_created(name=conn_file_name))
|
|
2057
|
+
|
|
2058
|
+
|
|
2059
|
+
def get_ca_pem_content(ca_pem: Optional[str], filename: Optional[str] = None) -> Optional[str]:
|
|
2060
|
+
if not ca_pem:
|
|
2061
|
+
return None
|
|
2062
|
+
|
|
2063
|
+
def is_valid_content(text_content: str) -> bool:
|
|
2064
|
+
return text_content.startswith("-----BEGIN CERTIFICATE-----")
|
|
2065
|
+
|
|
2066
|
+
ca_pem_content = ca_pem
|
|
2067
|
+
base_path = Path(getcwd(), filename).parent if filename else Path(getcwd())
|
|
2068
|
+
ca_pem_path = Path(base_path, ca_pem)
|
|
2069
|
+
path_exists = os.path.exists(ca_pem_path)
|
|
2070
|
+
|
|
2071
|
+
if not path_exists:
|
|
2072
|
+
raise CLIConnectionException(FeedbackManager.error_connection_ca_pem_not_found(ca_pem=ca_pem))
|
|
2073
|
+
|
|
2074
|
+
if ca_pem.endswith(".pem") and path_exists:
|
|
2075
|
+
with open(ca_pem_path, "r") as f:
|
|
2076
|
+
ca_pem_content = f.read()
|
|
2077
|
+
|
|
2078
|
+
if not is_valid_content(ca_pem_content):
|
|
2079
|
+
raise CLIConnectionException(FeedbackManager.error_connection_invalid_ca_pem())
|
|
2080
|
+
|
|
2081
|
+
return ca_pem_content
|
|
@@ -21,6 +21,7 @@ from tinybird.tb_cli_modules.common import (
|
|
|
21
21
|
coro,
|
|
22
22
|
create_aws_iamrole_connection,
|
|
23
23
|
echo_safe_humanfriendly_tables_format_smart_table,
|
|
24
|
+
get_ca_pem_content,
|
|
24
25
|
validate_aws_iamrole_connection_name,
|
|
25
26
|
validate_aws_iamrole_integration,
|
|
26
27
|
validate_connection_name,
|
|
@@ -44,6 +45,7 @@ DATA_CONNECTOR_SETTINGS: Dict[DataConnectorType, List[str]] = {
|
|
|
44
45
|
"kafka_security_protocol",
|
|
45
46
|
"kafka_sasl_mechanism",
|
|
46
47
|
"kafka_schema_registry_url",
|
|
48
|
+
"kafka_ssl_ca_pem",
|
|
47
49
|
],
|
|
48
50
|
DataConnectorType.GCLOUD_SCHEDULER: ["gcscheduler_region"],
|
|
49
51
|
DataConnectorType.SNOWFLAKE: [
|
|
@@ -131,6 +133,7 @@ def connection_create(ctx: Context) -> None:
|
|
|
131
133
|
default="PLAIN",
|
|
132
134
|
help="Authentication method for connection-based protocols. Defaults to 'PLAIN'",
|
|
133
135
|
)
|
|
136
|
+
@click.option("--ssl-ca-pem", default=None, help="Path or content of the CA Certificate file in PEM format")
|
|
134
137
|
@click.pass_context
|
|
135
138
|
@coro
|
|
136
139
|
async def connection_create_kafka(
|
|
@@ -142,6 +145,7 @@ async def connection_create_kafka(
|
|
|
142
145
|
auto_offset_reset: Optional[str],
|
|
143
146
|
schema_registry_url: Optional[str],
|
|
144
147
|
sasl_mechanism: Optional[str],
|
|
148
|
+
ssl_ca_pem: Optional[str],
|
|
145
149
|
) -> None:
|
|
146
150
|
"""
|
|
147
151
|
Add a Kafka connection
|
|
@@ -174,7 +178,14 @@ async def connection_create_kafka(
|
|
|
174
178
|
client: TinyB = obj["client"]
|
|
175
179
|
|
|
176
180
|
result = await client.connection_create_kafka(
|
|
177
|
-
bootstrap_servers,
|
|
181
|
+
bootstrap_servers,
|
|
182
|
+
key,
|
|
183
|
+
secret,
|
|
184
|
+
connection_name,
|
|
185
|
+
auto_offset_reset,
|
|
186
|
+
schema_registry_url,
|
|
187
|
+
sasl_mechanism,
|
|
188
|
+
get_ca_pem_content(ssl_ca_pem),
|
|
178
189
|
)
|
|
179
190
|
|
|
180
191
|
id = result["id"]
|
|
@@ -229,7 +229,7 @@ async def datasource_replace(
|
|
|
229
229
|
|
|
230
230
|
- Replace from local file `tb datasource replace [datasource_name] /path/to/local/file --sql-condition "country='ES'"`
|
|
231
231
|
|
|
232
|
-
- Replace from connector
|
|
232
|
+
- Replace from connector `tb datasource replace [datasource_name] --connector [connector_name] --sql [the_sql_to_extract_from] --sql-condition "country='ES'"`
|
|
233
233
|
"""
|
|
234
234
|
|
|
235
235
|
if not url and not connector:
|
|
@@ -848,7 +848,7 @@ def _parse(reader: _TemplateReader, template, in_block=None, in_loop=None):
|
|
|
848
848
|
# When there are more than 2 curlies in a row, use the
|
|
849
849
|
# innermost ones. This is useful when generating languages
|
|
850
850
|
# like latex where curlies are also meaningful
|
|
851
|
-
if curly + 2 < reader.remaining() and reader[curly + 1] == "{" and reader[curly + 2] == "{":
|
|
851
|
+
if curly + 2 < reader.remaining() and reader[curly + 1] == "{" and reader[curly + 2] == "{":
|
|
852
852
|
curly += 1
|
|
853
853
|
continue
|
|
854
854
|
break
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.10.1.dev0
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://www.tinybird.co/docs/cli/introduction.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -18,16 +18,13 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
|
|
|
18
18
|
Changelog
|
|
19
19
|
----------
|
|
20
20
|
|
|
21
|
-
5.
|
|
21
|
+
5.10.0
|
|
22
22
|
***********
|
|
23
23
|
|
|
24
|
-
- `Fixed` Correctly parse lambda expressions in indexes
|
|
25
|
-
|
|
26
|
-
5.9.1.dev2
|
|
27
|
-
***********
|
|
28
|
-
|
|
29
|
-
- `Changed` Upgrade clickhouse-toolset to 0.32.dev0
|
|
30
24
|
- `Added` new "File not found" error to `tb check` when including files from missing paths.
|
|
25
|
+
- `Added` support for Kafka Data Sources with CA certificate.
|
|
26
|
+
- `Changed` Upgrade clickhouse-toolset to 0.32.dev0
|
|
27
|
+
- `Fixed` Correctly parse lambda expressions in indexes
|
|
31
28
|
|
|
32
29
|
5.9.0
|
|
33
30
|
***********
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird/tb_cli_modules/workspace_members.py
RENAMED
|
File without changes
|
|
File without changes
|
{tinybird-cli-5.9.1.dev3 → tinybird-cli-5.10.1.dev0}/tinybird_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|