tinybird 4.6.6.dev0__tar.gz → 4.6.7__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-4.6.6.dev0 → tinybird-4.6.7}/PKG-INFO +13 -1
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/sql_template.py +9 -12
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/__cli__.py +2 -2
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/build.py +1 -46
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/config.py +0 -3
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/playground.py +1 -329
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/local_common.py +124 -22
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/login_common.py +12 -3
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/watch.py +1 -100
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/config.py +0 -6
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird.egg-info/PKG-INFO +13 -1
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/setup.cfg +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/__cli__.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/check_pypi.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/client.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/config.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/context.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/datafile/common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/datafile/exceptions.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/datafile/parse_connection.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/datafile/parse_datasource.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/datafile/parse_pipe.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/datatypes.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/feedback_manager.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/git_settings.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/iterating/__init__.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/iterating/data_branch_modes.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/prompts.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/service_datasources.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/sql.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/sql_toolset.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/syncasync.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/check_pypi.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/cli.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/client.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/config.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/branch.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/build_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/cicd.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/cli.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/connection.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/connection_dynamodb.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/connection_kafka.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/connection_s3.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/copy.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/create.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/build.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/format_connection.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/datasource.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/deployment.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/deployment_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/deprecations.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/endpoint.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/feedback_manager.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/fmt.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/info.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/infra.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/job.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/job_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/local.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/local_logs.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/login.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/logout.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/logs.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/materialization.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/open.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/pipe.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/preview.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/project.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/project_commands.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/py_project.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/query_output.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/secret.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/secret_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/sink.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/table.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/test.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/test_common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/token.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/ts_project.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/workspace.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird/tornado_template.py +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird.egg-info/SOURCES.txt +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-4.6.6.dev0 → tinybird-4.6.7}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: tinybird
|
|
3
|
-
Version: 4.6.
|
|
3
|
+
Version: 4.6.7
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://www.tinybird.co/docs/forward/commands
|
|
6
6
|
Author: Tinybird
|
|
@@ -52,6 +52,18 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
|
|
|
52
52
|
Changelog
|
|
53
53
|
----------
|
|
54
54
|
|
|
55
|
+
4.6.7.
|
|
56
|
+
*******
|
|
57
|
+
|
|
58
|
+
- `Fixed` `tb login` now raises an actionable error when the CLI cannot complete the authentication.
|
|
59
|
+
|
|
60
|
+
4.6.6
|
|
61
|
+
*******
|
|
62
|
+
|
|
63
|
+
- `Fixed` `tb local` now starts the Tinybird Local container using the host's native architecture (``linux/arm64`` on Apple Silicon, ``linux/amd64`` elsewhere) instead of always forcing ``linux/amd64``, so it no longer runs under emulation on arm64 machines.
|
|
64
|
+
- `Added` ``TB_LOCAL_IMAGE_PLATFORM`` environment variable to override the auto-detected image platform (e.g. ``linux/amd64`` to run the amd64 image emulated on an arm64 host, or to run a locally built single-arch image that does not match the host).
|
|
65
|
+
- `Fixed` `tb local start` new-version detection now normalizes Docker Hub image digests and no longer pulls when the registry is unreachable.
|
|
66
|
+
|
|
55
67
|
4.6.5
|
|
56
68
|
*******
|
|
57
69
|
|
|
@@ -1953,11 +1953,12 @@ def get_var_data(content, node_id=None):
|
|
|
1953
1953
|
"""
|
|
1954
1954
|
|
|
1955
1955
|
def node_to_value(x):
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1956
|
+
# ast.Constant supersedes the deprecated ast.Bytes/ast.Str/ast.Num/
|
|
1957
|
+
# ast.NameConstant node classes. Those were aliases of ast.Constant
|
|
1958
|
+
# since Python 3.8 (emitting DeprecationWarning on access in 3.12) and
|
|
1959
|
+
# were removed in Python 3.14. The parser only ever produces
|
|
1960
|
+
# ast.Constant nodes, so .value holds str/bytes/int/float/bool/None.
|
|
1961
|
+
if type(x) == ast.Constant: # noqa: E721
|
|
1961
1962
|
return x.value
|
|
1962
1963
|
elif type(x) == ast.Name: # noqa: E721
|
|
1963
1964
|
return x.id
|
|
@@ -1971,8 +1972,6 @@ def get_var_data(content, node_id=None):
|
|
|
1971
1972
|
if not r:
|
|
1972
1973
|
r = node_to_value(x.right)
|
|
1973
1974
|
return r
|
|
1974
|
-
elif type(x) == ast.Constant: # noqa: E721
|
|
1975
|
-
return x.value
|
|
1976
1975
|
elif type(x) == ast.UnaryOp and type(x.operand) == ast.Constant: # noqa: E721
|
|
1977
1976
|
if type(x.op) == ast.USub: # noqa: E721
|
|
1978
1977
|
return x.operand.value * -1
|
|
@@ -1991,11 +1990,9 @@ def get_var_data(content, node_id=None):
|
|
|
1991
1990
|
return []
|
|
1992
1991
|
|
|
1993
1992
|
first_elem = x.elts[0]
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
return [elem.n for elem in x.elts]
|
|
1998
|
-
elif type(first_elem) == ast.NameConstant or type(first_elem) == ast.Constant: # noqa: E721
|
|
1993
|
+
# See node_to_value: ast.Constant supersedes the deprecated
|
|
1994
|
+
# ast.Bytes/ast.Str/ast.Num/ast.NameConstant (removed in 3.14).
|
|
1995
|
+
if type(first_elem) == ast.Constant: # noqa: E721
|
|
1999
1996
|
return [elem.value for elem in x.elts]
|
|
2000
1997
|
elif type(first_elem) == ast.Name: # noqa: E721
|
|
2001
1998
|
return [elem.id for elem in x.elts]
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/forward/commands'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '4.6.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '4.6.7'
|
|
8
|
+
__revision__ = '1177944'
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
from copy import deepcopy
|
|
2
1
|
from functools import partial
|
|
3
2
|
from pathlib import Path
|
|
4
|
-
from typing import Any, Callable, Dict,
|
|
5
|
-
from urllib.parse import urlencode
|
|
3
|
+
from typing import Any, Callable, Dict, Optional
|
|
6
4
|
|
|
7
5
|
import click
|
|
8
6
|
|
|
9
|
-
from tinybird.datafile.exceptions import ParseException
|
|
10
|
-
from tinybird.datafile.parse_datasource import parse_datasource
|
|
11
|
-
from tinybird.datafile.parse_pipe import parse_pipe
|
|
12
7
|
from tinybird.tb.client import TinyB
|
|
13
8
|
from tinybird.tb.config import CLOUD_HOSTS
|
|
14
9
|
from tinybird.tb.modules.build_common import process
|
|
15
10
|
from tinybird.tb.modules.cli import cli, get_current_git_branch
|
|
16
|
-
from tinybird.tb.modules.config import CLIConfig
|
|
17
11
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
18
12
|
from tinybird.tb.modules.project import Project
|
|
19
|
-
from tinybird.tb.modules.query_output import print_table_formatted
|
|
20
13
|
from tinybird.tb.modules.watch import watch_project
|
|
21
14
|
|
|
22
15
|
|
|
@@ -182,41 +175,3 @@ def is_endpoint(f: Path) -> bool:
|
|
|
182
175
|
|
|
183
176
|
def is_pipe(f: Path) -> bool:
|
|
184
177
|
return f.suffix == ".pipe" and not is_vendor(f)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def check_filenames(filenames: List[str]):
|
|
188
|
-
parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
|
|
189
|
-
incl_suffix = ".incl"
|
|
190
|
-
|
|
191
|
-
for filename in filenames:
|
|
192
|
-
file_suffix = Path(filename).suffix
|
|
193
|
-
if file_suffix == incl_suffix:
|
|
194
|
-
continue
|
|
195
|
-
|
|
196
|
-
parser = parser_matrix.get(file_suffix)
|
|
197
|
-
if not parser:
|
|
198
|
-
raise ParseException(FeedbackManager.error_unsupported_datafile(extension=file_suffix))
|
|
199
|
-
|
|
200
|
-
parser(filename)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
def build_and_print_resource(config: CLIConfig, tb_client: TinyB, filename: str):
|
|
204
|
-
resource_path = Path(filename)
|
|
205
|
-
name = resource_path.stem
|
|
206
|
-
playground_name = name if filename.endswith(".pipe") else None
|
|
207
|
-
user_client = deepcopy(tb_client)
|
|
208
|
-
user_client.token = config.get_user_token() or ""
|
|
209
|
-
cli_params = {}
|
|
210
|
-
cli_params["workspace_id"] = config.get("id", None)
|
|
211
|
-
data = user_client._req(f"/v0/playgrounds?{urlencode(cli_params)}")
|
|
212
|
-
playgrounds = data["playgrounds"]
|
|
213
|
-
playground = next((p for p in playgrounds if p["name"] == (f"{playground_name}" + "__tb__playground")), None)
|
|
214
|
-
if not playground:
|
|
215
|
-
return
|
|
216
|
-
playground_id = playground["id"]
|
|
217
|
-
last_node = playground["nodes"][-1]
|
|
218
|
-
if not last_node:
|
|
219
|
-
return
|
|
220
|
-
node_sql = last_node["sql"]
|
|
221
|
-
res = tb_client.query(f"{node_sql} FORMAT JSON", playground=playground_id)
|
|
222
|
-
print_table_formatted(res, name)
|
|
@@ -197,9 +197,6 @@ class CLIConfig:
|
|
|
197
197
|
netloc: str = url_info.netloc.decode() if isinstance(url_info.netloc, bytes) else url_info.netloc
|
|
198
198
|
self["host"] = f"{scheme}://{netloc}"
|
|
199
199
|
|
|
200
|
-
def set_cwd(self, cwd: str) -> None:
|
|
201
|
-
self["cwd"] = cwd
|
|
202
|
-
|
|
203
200
|
def get_host(self, use_defaults_if_needed: bool = False) -> Optional[str]:
|
|
204
201
|
result: Optional[str] = self.get("host", None)
|
|
205
202
|
if result:
|
|
@@ -9,7 +9,6 @@ from pathlib import Path
|
|
|
9
9
|
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple
|
|
10
10
|
|
|
11
11
|
import click
|
|
12
|
-
from toposort import toposort
|
|
13
12
|
|
|
14
13
|
from tinybird.datafile.common import (
|
|
15
14
|
DEFAULT_CRON_PERIOD,
|
|
@@ -27,7 +26,7 @@ from tinybird.datafile.common import (
|
|
|
27
26
|
get_project_filenames,
|
|
28
27
|
pp,
|
|
29
28
|
)
|
|
30
|
-
from tinybird.datafile.exceptions import
|
|
29
|
+
from tinybird.datafile.exceptions import IncludeFileNotFoundException
|
|
31
30
|
from tinybird.datafile.parse_datasource import parse_datasource
|
|
32
31
|
from tinybird.datafile.parse_pipe import parse_pipe
|
|
33
32
|
from tinybird.sql import parse_table_structure, schema_to_sql_columns
|
|
@@ -35,339 +34,12 @@ from tinybird.sql_template import get_used_tables_in_template, render_sql_templa
|
|
|
35
34
|
from tinybird.tb.client import TinyB
|
|
36
35
|
from tinybird.tb.modules.common import get_ca_pem_content
|
|
37
36
|
from tinybird.tb.modules.config import CLIConfig
|
|
38
|
-
from tinybird.tb.modules.datafile.build_datasource import is_datasource
|
|
39
37
|
from tinybird.tb.modules.datafile.build_pipe import (
|
|
40
38
|
get_target_materialized_data_source_name,
|
|
41
|
-
is_endpoint,
|
|
42
39
|
is_endpoint_with_no_dependencies,
|
|
43
|
-
is_materialized,
|
|
44
40
|
new_pipe,
|
|
45
41
|
)
|
|
46
42
|
from tinybird.tb.modules.feedback_manager import FeedbackManager, get_cli_name
|
|
47
|
-
from tinybird.tb.modules.project import Project
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def folder_playground(
|
|
51
|
-
project: Project,
|
|
52
|
-
config: CLIConfig,
|
|
53
|
-
tb_client: TinyB,
|
|
54
|
-
filenames: Optional[List[str]] = None,
|
|
55
|
-
is_internal: bool = False,
|
|
56
|
-
current_ws: Optional[Dict[str, Any]] = None,
|
|
57
|
-
local_ws: Optional[Dict[str, Any]] = None,
|
|
58
|
-
):
|
|
59
|
-
build = True
|
|
60
|
-
dry_run = False
|
|
61
|
-
force = True
|
|
62
|
-
only_changes = True
|
|
63
|
-
debug = False
|
|
64
|
-
run_tests = False
|
|
65
|
-
verbose = False
|
|
66
|
-
raise_on_exists = False
|
|
67
|
-
fork_downstream = True
|
|
68
|
-
fork = False
|
|
69
|
-
release_created = False
|
|
70
|
-
folder = str(project.path)
|
|
71
|
-
datasources: List[Dict[str, Any]] = tb_client.datasources()
|
|
72
|
-
pipes: List[Dict[str, Any]] = tb_client.pipes(dependencies=True)
|
|
73
|
-
build = True
|
|
74
|
-
dry_run = False
|
|
75
|
-
force = True
|
|
76
|
-
only_changes = True
|
|
77
|
-
debug = False
|
|
78
|
-
check = True
|
|
79
|
-
populate = False
|
|
80
|
-
populate_subset = None
|
|
81
|
-
populate_condition = None
|
|
82
|
-
tests_to_run = 0
|
|
83
|
-
override_datasource = False
|
|
84
|
-
skip_confirmation = True
|
|
85
|
-
wait = False
|
|
86
|
-
unlink_on_populate_error = False
|
|
87
|
-
only_response_times = False
|
|
88
|
-
run_tests = False
|
|
89
|
-
verbose = False
|
|
90
|
-
as_standard = False
|
|
91
|
-
raise_on_exists = False
|
|
92
|
-
fork_downstream = True
|
|
93
|
-
fork = False
|
|
94
|
-
release_created = False
|
|
95
|
-
tests_relative_change = 0.01
|
|
96
|
-
tests_sample_by_params = 0
|
|
97
|
-
tests_filter_by = None
|
|
98
|
-
tests_failfast = False
|
|
99
|
-
tests_ignore_order = False
|
|
100
|
-
tests_validate_processed_bytes = False
|
|
101
|
-
tests_check_requests_from_branch = False
|
|
102
|
-
user_token = None
|
|
103
|
-
ignore_sql_errors = False
|
|
104
|
-
is_vendor = False
|
|
105
|
-
current_ws = current_ws or local_ws
|
|
106
|
-
|
|
107
|
-
existing_resources: List[str] = [x["name"] for x in datasources] + [x["name"] for x in pipes]
|
|
108
|
-
remote_resource_names = [get_remote_resource_name_without_version(x) for x in existing_resources]
|
|
109
|
-
|
|
110
|
-
if not filenames:
|
|
111
|
-
filenames = get_project_filenames(folder)
|
|
112
|
-
|
|
113
|
-
# build graph to get new versions for all the files involved in the query
|
|
114
|
-
# dependencies need to be processed always to get the versions
|
|
115
|
-
dependencies_graph = build_graph(
|
|
116
|
-
filenames,
|
|
117
|
-
tb_client,
|
|
118
|
-
dir_path=folder,
|
|
119
|
-
process_dependencies=True,
|
|
120
|
-
skip_connectors=True,
|
|
121
|
-
vendor_paths=[],
|
|
122
|
-
current_ws=current_ws,
|
|
123
|
-
only_changes=only_changes,
|
|
124
|
-
fork_downstream=fork_downstream,
|
|
125
|
-
is_internal=is_internal,
|
|
126
|
-
build=build,
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
if debug:
|
|
130
|
-
pp.pprint(dependencies_graph.to_run)
|
|
131
|
-
|
|
132
|
-
def should_push_file(
|
|
133
|
-
name: str,
|
|
134
|
-
remote_resource_names: List[str],
|
|
135
|
-
force: bool,
|
|
136
|
-
run_tests: bool,
|
|
137
|
-
) -> bool:
|
|
138
|
-
"""
|
|
139
|
-
Function to know if we need to run a file or not
|
|
140
|
-
"""
|
|
141
|
-
if name not in remote_resource_names:
|
|
142
|
-
return True
|
|
143
|
-
# When we need to try to push a file when it doesn't exist and the version is different that the existing one
|
|
144
|
-
resource_full_name = name
|
|
145
|
-
if resource_full_name not in existing_resources:
|
|
146
|
-
return True
|
|
147
|
-
return force or run_tests
|
|
148
|
-
|
|
149
|
-
def push(
|
|
150
|
-
name: str,
|
|
151
|
-
to_run: Dict[str, Dict[str, Any]],
|
|
152
|
-
dry_run: bool,
|
|
153
|
-
fork_downstream: Optional[bool] = False,
|
|
154
|
-
fork: Optional[bool] = False,
|
|
155
|
-
):
|
|
156
|
-
if name in to_run:
|
|
157
|
-
resource = to_run[name]["resource"]
|
|
158
|
-
if resource == "datasources":
|
|
159
|
-
return
|
|
160
|
-
if not dry_run:
|
|
161
|
-
if should_push_file(name, remote_resource_names, force, run_tests):
|
|
162
|
-
click.echo(FeedbackManager.info_processing_new_resource(name=name, version=""))
|
|
163
|
-
try:
|
|
164
|
-
exec_file(
|
|
165
|
-
to_run[name],
|
|
166
|
-
config,
|
|
167
|
-
tb_client,
|
|
168
|
-
force,
|
|
169
|
-
check,
|
|
170
|
-
debug and verbose,
|
|
171
|
-
populate,
|
|
172
|
-
populate_subset,
|
|
173
|
-
populate_condition,
|
|
174
|
-
unlink_on_populate_error,
|
|
175
|
-
wait,
|
|
176
|
-
user_token,
|
|
177
|
-
override_datasource,
|
|
178
|
-
ignore_sql_errors,
|
|
179
|
-
skip_confirmation,
|
|
180
|
-
only_response_times,
|
|
181
|
-
run_tests,
|
|
182
|
-
as_standard,
|
|
183
|
-
tests_to_run,
|
|
184
|
-
tests_relative_change,
|
|
185
|
-
tests_sample_by_params,
|
|
186
|
-
tests_filter_by,
|
|
187
|
-
tests_failfast,
|
|
188
|
-
tests_ignore_order,
|
|
189
|
-
tests_validate_processed_bytes,
|
|
190
|
-
tests_check_requests_from_branch,
|
|
191
|
-
current_ws,
|
|
192
|
-
local_ws,
|
|
193
|
-
fork_downstream,
|
|
194
|
-
fork,
|
|
195
|
-
build,
|
|
196
|
-
is_vendor,
|
|
197
|
-
)
|
|
198
|
-
if not run_tests:
|
|
199
|
-
click.echo(
|
|
200
|
-
FeedbackManager.success_create(
|
|
201
|
-
name=(
|
|
202
|
-
name
|
|
203
|
-
if to_run[name]["version"] is None
|
|
204
|
-
else f"{name}__v{to_run[name]['version']}"
|
|
205
|
-
)
|
|
206
|
-
)
|
|
207
|
-
)
|
|
208
|
-
except Exception as e:
|
|
209
|
-
filename = to_run[name]["filename"]
|
|
210
|
-
exception = FeedbackManager.error_push_file_exception(
|
|
211
|
-
filename=filename,
|
|
212
|
-
error=e,
|
|
213
|
-
)
|
|
214
|
-
raise click.ClickException(exception)
|
|
215
|
-
elif raise_on_exists:
|
|
216
|
-
raise AlreadyExistsException(
|
|
217
|
-
FeedbackManager.warning_name_already_exists(
|
|
218
|
-
name=name if to_run[name]["version"] is None else f"{name}__v{to_run[name]['version']}"
|
|
219
|
-
)
|
|
220
|
-
)
|
|
221
|
-
elif name_matches_existing_resource(resource, name, tb_client):
|
|
222
|
-
if resource == "pipes":
|
|
223
|
-
click.echo(FeedbackManager.error_pipe_cannot_be_pushed(name=name))
|
|
224
|
-
else:
|
|
225
|
-
click.echo(FeedbackManager.error_datasource_cannot_be_pushed(name=name))
|
|
226
|
-
else:
|
|
227
|
-
click.echo(
|
|
228
|
-
FeedbackManager.warning_name_already_exists(
|
|
229
|
-
name=(name if to_run[name]["version"] is None else f"{name}__v{to_run[name]['version']}")
|
|
230
|
-
)
|
|
231
|
-
)
|
|
232
|
-
if dry_run:
|
|
233
|
-
if should_push_file(name, remote_resource_names, force, run_tests):
|
|
234
|
-
extension = "pipe" if resource == "pipes" else "datasource"
|
|
235
|
-
click.echo(FeedbackManager.info_building_resource(name=f"{name}.{extension}", version=""))
|
|
236
|
-
elif name_matches_existing_resource(resource, name, tb_client):
|
|
237
|
-
if resource == "pipes":
|
|
238
|
-
click.echo(FeedbackManager.warning_pipe_cannot_be_pushed(name=name))
|
|
239
|
-
else:
|
|
240
|
-
click.echo(FeedbackManager.warning_datasource_cannot_be_pushed(name=name))
|
|
241
|
-
else:
|
|
242
|
-
click.echo(FeedbackManager.warning_dry_name_already_exists(name=name))
|
|
243
|
-
|
|
244
|
-
def push_files(
|
|
245
|
-
dependency_graph: GraphDependencies,
|
|
246
|
-
dry_run: bool = False,
|
|
247
|
-
):
|
|
248
|
-
endpoints_dep_map = dict()
|
|
249
|
-
processed = set()
|
|
250
|
-
|
|
251
|
-
resources_to_run = dependency_graph.to_run
|
|
252
|
-
|
|
253
|
-
# This will generate the graph from right to left and will fill the gaps of the dependencies
|
|
254
|
-
# If we have a graph like this:
|
|
255
|
-
# A -> B -> C
|
|
256
|
-
# If we only modify A, the normal dependencies graph will only contain a node like _{A => B}
|
|
257
|
-
# But we need a graph that contains A, B and C and the dependencies between them to deploy them in the right order
|
|
258
|
-
dependencies_graph_fork_downstream, resources_to_run_fork_downstream = generate_forkdownstream_graph(
|
|
259
|
-
dependency_graph.all_dep_map,
|
|
260
|
-
dependency_graph.all_resources,
|
|
261
|
-
resources_to_run,
|
|
262
|
-
list(dependency_graph.dep_map.keys()),
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
# First, we will deploy the datasources that need to be deployed.
|
|
266
|
-
# We need to deploy the datasources from left to right as some datasources might have MV that depend on the column types of previous datasources. Ex: `test_change_column_type_landing_datasource` test
|
|
267
|
-
groups = [group for group in toposort(dependencies_graph_fork_downstream)]
|
|
268
|
-
|
|
269
|
-
groups.reverse()
|
|
270
|
-
for group in groups:
|
|
271
|
-
for name in group:
|
|
272
|
-
if name in processed or not is_datasource(resources_to_run_fork_downstream[name]):
|
|
273
|
-
continue
|
|
274
|
-
|
|
275
|
-
# If we are trying to modify a Kafka or CDK datasource, we need to inform the user that the resource needs to be post-released
|
|
276
|
-
kafka_connection_name = (
|
|
277
|
-
resources_to_run_fork_downstream[name].get("params", {}).get("kafka_connection_name")
|
|
278
|
-
)
|
|
279
|
-
service = resources_to_run_fork_downstream[name].get("params", {}).get("import_service")
|
|
280
|
-
if release_created and (kafka_connection_name or service):
|
|
281
|
-
connector = "Kafka" if kafka_connection_name else service
|
|
282
|
-
error_msg = FeedbackManager.error_connector_require_post_release(connector=connector)
|
|
283
|
-
raise click.ClickException(error_msg)
|
|
284
|
-
|
|
285
|
-
push(
|
|
286
|
-
name,
|
|
287
|
-
resources_to_run_fork_downstream,
|
|
288
|
-
dry_run,
|
|
289
|
-
fork_downstream,
|
|
290
|
-
fork,
|
|
291
|
-
)
|
|
292
|
-
processed.add(name)
|
|
293
|
-
|
|
294
|
-
# Now, we will create a map of all the endpoints and there dependencies
|
|
295
|
-
# We are using the forkdownstream graph to get the dependencies of the endpoints as the normal dependencies graph only contains the resources that are going to be deployed
|
|
296
|
-
# But does not include the missing gaps
|
|
297
|
-
# If we have ENDPOINT_A ----> MV_PIPE_B -----> DATASOURCE_B ------> ENDPOINT_C
|
|
298
|
-
# Where endpoint A is being used in the MV_PIPE_B, if we only modify the endpoint A
|
|
299
|
-
# The dependencies graph will only contain the endpoint A and the MV_PIPE_B, but not the DATASOURCE_B and the ENDPOINT_C
|
|
300
|
-
groups = [group for group in toposort(dependencies_graph_fork_downstream)]
|
|
301
|
-
for group in groups:
|
|
302
|
-
for name in group:
|
|
303
|
-
if name in processed or not is_endpoint(resources_to_run_fork_downstream[name]):
|
|
304
|
-
continue
|
|
305
|
-
|
|
306
|
-
endpoints_dep_map[name] = dependencies_graph_fork_downstream[name]
|
|
307
|
-
|
|
308
|
-
# Now that we have the dependencies of the endpoints, we need to check that the resources has not been deployed yet and only care about the endpoints that depend on endpoints
|
|
309
|
-
groups = [group for group in toposort(endpoints_dep_map)]
|
|
310
|
-
|
|
311
|
-
# As we have used the forkdownstream graph to get the dependencies of the endpoints, we have all the dependencies of the endpoints
|
|
312
|
-
# But we need to deploy the endpoints and the dependencies of the endpoints from left to right
|
|
313
|
-
# So we need to reverse the groups
|
|
314
|
-
groups.reverse()
|
|
315
|
-
for group in groups:
|
|
316
|
-
for name in group:
|
|
317
|
-
if name in processed or not is_endpoint(resources_to_run_fork_downstream[name]):
|
|
318
|
-
continue
|
|
319
|
-
|
|
320
|
-
push(
|
|
321
|
-
name,
|
|
322
|
-
resources_to_run_fork_downstream,
|
|
323
|
-
dry_run,
|
|
324
|
-
fork_downstream,
|
|
325
|
-
fork,
|
|
326
|
-
)
|
|
327
|
-
processed.add(name)
|
|
328
|
-
|
|
329
|
-
# Now we should have the endpoints and datasources deployed, we can deploy the rest of the pipes (copy & sinks)
|
|
330
|
-
# We need to rely on the forkdownstream graph as it contains all the modified pipes as well as the dependencies of the pipes
|
|
331
|
-
# In this case, we don't need to generate a new graph as we did for the endpoints as the pipes are not going to be used as dependencies and the datasources are already deployed
|
|
332
|
-
groups = [group for group in toposort(dependencies_graph_fork_downstream)]
|
|
333
|
-
for group in groups:
|
|
334
|
-
for name in group:
|
|
335
|
-
if name in processed or is_materialized(resources_to_run_fork_downstream.get(name)):
|
|
336
|
-
continue
|
|
337
|
-
|
|
338
|
-
push(
|
|
339
|
-
name,
|
|
340
|
-
resources_to_run_fork_downstream,
|
|
341
|
-
dry_run,
|
|
342
|
-
fork_downstream,
|
|
343
|
-
fork,
|
|
344
|
-
)
|
|
345
|
-
processed.add(name)
|
|
346
|
-
|
|
347
|
-
# Finally, we need to deploy the materialized views from right to left.
|
|
348
|
-
# We need to rely on the forkdownstream graph as it contains all the modified materialized views as well as the dependencies of the materialized views
|
|
349
|
-
# In this case, we don't need to generate a new graph as we did for the endpoints as the pipes are not going to be used as dependencies and the datasources are already deployed
|
|
350
|
-
groups = [group for group in toposort(dependencies_graph_fork_downstream)]
|
|
351
|
-
for group in groups:
|
|
352
|
-
for name in group:
|
|
353
|
-
if name in processed or not is_materialized(resources_to_run_fork_downstream.get(name)):
|
|
354
|
-
continue
|
|
355
|
-
|
|
356
|
-
push(
|
|
357
|
-
name,
|
|
358
|
-
resources_to_run_fork_downstream,
|
|
359
|
-
dry_run,
|
|
360
|
-
fork_downstream,
|
|
361
|
-
fork,
|
|
362
|
-
)
|
|
363
|
-
processed.add(name)
|
|
364
|
-
|
|
365
|
-
push_files(dependencies_graph, dry_run)
|
|
366
|
-
|
|
367
|
-
if not dry_run and not run_tests and verbose:
|
|
368
|
-
click.echo(FeedbackManager.info_not_pushing_fixtures())
|
|
369
|
-
|
|
370
|
-
return dependencies_graph.to_run
|
|
371
43
|
|
|
372
44
|
|
|
373
45
|
def name_matches_existing_resource(resource: str, name: str, tb_client: TinyB):
|