tinybird-cli 6.5.7.dev0__py3-none-any.whl → 6.5.8.dev0__py3-none-any.whl
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__.py +2 -2
- tinybird/ch_utils/constants.py +1 -0
- tinybird/ch_utils/engine.py +90 -54
- tinybird/client.py +58 -46
- tinybird/config.py +0 -4
- tinybird/datafile_common.py +67 -44
- tinybird/datatypes.py +34 -12
- tinybird/feedback_manager.py +5 -0
- tinybird/git_settings.py +1 -3
- tinybird/sql.py +3 -10
- tinybird/sql_template.py +121 -98
- tinybird/sql_template_fmt.py +10 -15
- tinybird/sql_toolset.py +63 -11
- tinybird/syncasync.py +9 -54
- tinybird/tb_cli_modules/branch.py +4 -25
- tinybird/tb_cli_modules/cicd.py +2 -0
- tinybird/tb_cli_modules/cli.py +5 -9
- tinybird/tb_cli_modules/common.py +30 -97
- tinybird/tb_cli_modules/config.py +1 -2
- tinybird/tb_cli_modules/datasource.py +2 -2
- tinybird/tb_cli_modules/pipe.py +49 -34
- tinybird/tb_cli_modules/tinyunit/tinyunit.py +4 -4
- tinybird/tb_cli_modules/token.py +1 -2
- tinybird/tb_cli_modules/workspace.py +11 -13
- tinybird/tornado_template.py +227 -83
- tinybird/utils/__init__.py +0 -0
- tinybird/utils/bools.py +19 -0
- {tinybird_cli-6.5.7.dev0.dist-info → tinybird_cli-6.5.8.dev0.dist-info}/METADATA +9 -1
- tinybird_cli-6.5.8.dev0.dist-info/RECORD +45 -0
- tinybird_cli-6.5.7.dev0.dist-info/RECORD +0 -43
- {tinybird_cli-6.5.7.dev0.dist-info → tinybird_cli-6.5.8.dev0.dist-info}/WHEEL +0 -0
- {tinybird_cli-6.5.7.dev0.dist-info → tinybird_cli-6.5.8.dev0.dist-info}/entry_points.txt +0 -0
- {tinybird_cli-6.5.7.dev0.dist-info → tinybird_cli-6.5.8.dev0.dist-info}/top_level.txt +0 -0
tinybird/datafile_common.py
CHANGED
|
@@ -70,6 +70,7 @@ from tinybird.tb_cli_modules.common import (
|
|
|
70
70
|
)
|
|
71
71
|
from tinybird.tb_cli_modules.config import CLIConfig
|
|
72
72
|
from tinybird.tb_cli_modules.exceptions import CLIGitReleaseException, CLIPipeException
|
|
73
|
+
from tinybird.utils.bools import parse_bool, parse_optional_bool
|
|
73
74
|
|
|
74
75
|
from .ch_utils.engine import ENABLED_ENGINES
|
|
75
76
|
from .client import AuthException, AuthNoTokenException, CanNotBeDeletedException, DoesNotExistException, TinyB
|
|
@@ -130,6 +131,7 @@ class CopyParameters:
|
|
|
130
131
|
TARGET_DATASOURCE = "target_datasource"
|
|
131
132
|
COPY_SCHEDULE = "copy_schedule"
|
|
132
133
|
COPY_MODE = "copy_mode"
|
|
134
|
+
ON_DEMAND_COMPUTE = "on_demand_compute"
|
|
133
135
|
|
|
134
136
|
|
|
135
137
|
class CopyModes:
|
|
@@ -424,8 +426,7 @@ class CLIGitRelease:
|
|
|
424
426
|
def is_dirty_to_release(self, use_include_dir: bool = True) -> bool:
|
|
425
427
|
if use_include_dir:
|
|
426
428
|
return any(self.repo.is_dirty(path=p) for p in self.paths) or self.has_untracked_files()
|
|
427
|
-
|
|
428
|
-
return self.repo.is_dirty(path=self.path) or self.has_untracked_files()
|
|
429
|
+
return self.repo.is_dirty(path=self.path) or self.has_untracked_files()
|
|
429
430
|
|
|
430
431
|
def is_dirty_to_init(self) -> bool:
|
|
431
432
|
return self.is_dirty_to_release(use_include_dir=False) or self.is_head_empty()
|
|
@@ -474,8 +475,7 @@ class CLIGitRelease:
|
|
|
474
475
|
if not self.is_head_outdated(current_release["commit"]):
|
|
475
476
|
if check_outdated:
|
|
476
477
|
raise CLIGitReleaseException(FeedbackManager.error_head_outdated(commit=self.head_commit()))
|
|
477
|
-
|
|
478
|
-
click.echo(FeedbackManager.warning_head_outdated(commit=self.head_commit()))
|
|
478
|
+
click.echo(FeedbackManager.warning_head_outdated(commit=self.head_commit()))
|
|
479
479
|
except CLIGitReleaseException as e:
|
|
480
480
|
if check_outdated:
|
|
481
481
|
raise e
|
|
@@ -533,8 +533,7 @@ class CLIGitRelease:
|
|
|
533
533
|
async def update_release(
|
|
534
534
|
self, tb_client: TinyB, current_ws: Dict[str, Any], commit: Optional[str] = None
|
|
535
535
|
) -> Dict[str, Any]:
|
|
536
|
-
|
|
537
|
-
return release
|
|
536
|
+
return await tb_client.workspace_commit_update(current_ws["id"], commit or self.head().commit.hexsha)
|
|
538
537
|
|
|
539
538
|
|
|
540
539
|
class Deployment:
|
|
@@ -851,6 +850,11 @@ def parse_pipe(
|
|
|
851
850
|
sql = ""
|
|
852
851
|
doc = parse(s, basepath=basepath, replace_includes=replace_includes, skip_eval=skip_eval)
|
|
853
852
|
for node in doc.nodes:
|
|
853
|
+
if node.get("type", "").lower() == PipeNodeTypes.COPY and CopyParameters.ON_DEMAND_COMPUTE in node:
|
|
854
|
+
try:
|
|
855
|
+
node[CopyParameters.ON_DEMAND_COMPUTE] = parse_optional_bool(node[CopyParameters.ON_DEMAND_COMPUTE])
|
|
856
|
+
except ValueError:
|
|
857
|
+
raise click.ClickException("ON_DEMAND_COMPUTE must be true or false")
|
|
854
858
|
sql = node.get("sql", "")
|
|
855
859
|
source_sql = sql.strip()
|
|
856
860
|
if not source_sql:
|
|
@@ -1229,6 +1233,7 @@ def parse(
|
|
|
1229
1233
|
"copy_schedule": assign_node_var(CopyParameters.COPY_SCHEDULE),
|
|
1230
1234
|
"copy_mode": assign_node_var("mode"),
|
|
1231
1235
|
"mode": assign_node_var("mode"),
|
|
1236
|
+
"on_demand_compute": assign_node_var(CopyParameters.ON_DEMAND_COMPUTE),
|
|
1232
1237
|
"resource": assign_node_var("resource"),
|
|
1233
1238
|
"filter": assign_node_var("filter"),
|
|
1234
1239
|
"token": add_token,
|
|
@@ -1345,12 +1350,11 @@ def parse(
|
|
|
1345
1350
|
except IndexError as e:
|
|
1346
1351
|
if "node" in line.lower():
|
|
1347
1352
|
raise click.ClickException(FeedbackManager.error_missing_node_name())
|
|
1348
|
-
|
|
1353
|
+
if "sql" in line.lower():
|
|
1349
1354
|
raise click.ClickException(FeedbackManager.error_missing_sql_command())
|
|
1350
|
-
|
|
1355
|
+
if "datasource" in line.lower():
|
|
1351
1356
|
raise click.ClickException(FeedbackManager.error_missing_datasource_name())
|
|
1352
|
-
|
|
1353
|
-
raise ValidationException(f"Validation error, found {line} in line {str(lineno)}: {str(e)}", lineno=lineno)
|
|
1357
|
+
raise ValidationException(f"Validation error, found {line} in line {str(lineno)}: {str(e)}", lineno=lineno)
|
|
1354
1358
|
except IncludeFileNotFoundException as e:
|
|
1355
1359
|
raise IncludeFileNotFoundException(str(e), lineno=lineno)
|
|
1356
1360
|
except Exception as e:
|
|
@@ -1671,7 +1675,7 @@ async def process_file(
|
|
|
1671
1675
|
|
|
1672
1676
|
return resources
|
|
1673
1677
|
|
|
1674
|
-
|
|
1678
|
+
if DataFileExtensions.PIPE in filename:
|
|
1675
1679
|
doc = parse_pipe(filename)
|
|
1676
1680
|
version = f"__v{doc.version}" if doc.version is not None else ""
|
|
1677
1681
|
name = os.path.basename(filename).split(".")[0]
|
|
@@ -1691,6 +1695,7 @@ async def process_file(
|
|
|
1691
1695
|
"target_datasource": node.get("target_datasource", None),
|
|
1692
1696
|
"copy_schedule": node.get(CopyParameters.COPY_SCHEDULE, None),
|
|
1693
1697
|
"mode": node.get("mode", CopyModes.APPEND),
|
|
1698
|
+
"on_demand_compute": node.get(CopyParameters.ON_DEMAND_COMPUTE, None),
|
|
1694
1699
|
}
|
|
1695
1700
|
|
|
1696
1701
|
is_export_node = ExportReplacements.is_export_node(node)
|
|
@@ -1777,7 +1782,7 @@ async def process_file(
|
|
|
1777
1782
|
"filtering_tags": doc.filtering_tags,
|
|
1778
1783
|
}
|
|
1779
1784
|
]
|
|
1780
|
-
|
|
1785
|
+
if DataFileExtensions.TOKEN in filename:
|
|
1781
1786
|
doc = parse_token(filename)
|
|
1782
1787
|
name = os.path.basename(filename).split(DataFileExtensions.TOKEN)[0]
|
|
1783
1788
|
description = doc.description or ""
|
|
@@ -1794,8 +1799,7 @@ async def process_file(
|
|
|
1794
1799
|
"description": description,
|
|
1795
1800
|
}
|
|
1796
1801
|
]
|
|
1797
|
-
|
|
1798
|
-
raise click.ClickException(FeedbackManager.error_file_extension(filename=filename))
|
|
1802
|
+
raise click.ClickException(FeedbackManager.error_file_extension(filename=filename))
|
|
1799
1803
|
|
|
1800
1804
|
|
|
1801
1805
|
def full_path_by_name(
|
|
@@ -1831,6 +1835,21 @@ def full_path_by_name(
|
|
|
1831
1835
|
return None
|
|
1832
1836
|
|
|
1833
1837
|
|
|
1838
|
+
def local_copy_node_uses_on_demand_compute(folder: str, pipe_name: str) -> Optional[bool]:
|
|
1839
|
+
"""Reads ON_DEMAND_COMPUTE from the local datafile. Returns None when there is no parseable copy pipe to compare"""
|
|
1840
|
+
pipe_path = next((f for f in get_project_filenames(folder) if f.endswith(f"/{pipe_name}.pipe")), None)
|
|
1841
|
+
if pipe_path is None:
|
|
1842
|
+
return None
|
|
1843
|
+
try:
|
|
1844
|
+
datafile = parse_pipe(pipe_path)
|
|
1845
|
+
except Exception:
|
|
1846
|
+
return None
|
|
1847
|
+
copy_node = next((node for node in datafile.nodes if node.get("type", "").lower() == PipeNodeTypes.COPY), None)
|
|
1848
|
+
if copy_node is None:
|
|
1849
|
+
return None
|
|
1850
|
+
return parse_optional_bool(copy_node.get(CopyParameters.ON_DEMAND_COMPUTE))
|
|
1851
|
+
|
|
1852
|
+
|
|
1834
1853
|
def find_file_by_name(
|
|
1835
1854
|
folder: str,
|
|
1836
1855
|
name: str,
|
|
@@ -2045,13 +2064,12 @@ class PipeChecker(unittest.TestCase):
|
|
|
2045
2064
|
headers = {"Authorization": f"Bearer {self.token}"}
|
|
2046
2065
|
if self.http_method == "GET":
|
|
2047
2066
|
return requests.get(pipe_url, headers=headers, verify=not getenv_bool("TB_DISABLE_SSL_CHECKS", False))
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
)
|
|
2067
|
+
return requests.post(
|
|
2068
|
+
pipe_url,
|
|
2069
|
+
headers=headers,
|
|
2070
|
+
verify=not getenv_bool("TB_DISABLE_SSL_CHECKS", False),
|
|
2071
|
+
data=self.pipe_request_params,
|
|
2072
|
+
)
|
|
2055
2073
|
|
|
2056
2074
|
def _write_performance(self):
|
|
2057
2075
|
return ""
|
|
@@ -2706,6 +2724,13 @@ async def check_copy_pipe(pipe, copy_node, tb_client: TinyB):
|
|
|
2706
2724
|
if not is_valid_mode:
|
|
2707
2725
|
raise CLIPipeException(FeedbackManager.error_creating_copy_pipe_invalid_mode(mode=mode))
|
|
2708
2726
|
|
|
2727
|
+
on_demand_compute = copy_node["params"].get(CopyParameters.ON_DEMAND_COMPUTE)
|
|
2728
|
+
if on_demand_compute not in (None, ""):
|
|
2729
|
+
try:
|
|
2730
|
+
parse_bool(on_demand_compute)
|
|
2731
|
+
except ValueError:
|
|
2732
|
+
raise CLIPipeException("ON_DEMAND_COMPUTE must be true or false")
|
|
2733
|
+
|
|
2709
2734
|
if not pipe:
|
|
2710
2735
|
return
|
|
2711
2736
|
|
|
@@ -3150,6 +3175,7 @@ async def new_pipe(
|
|
|
3150
3175
|
schedule_cron_should_be_removed = current_schedule_cron and not schedule_cron
|
|
3151
3176
|
copy_params["schedule_cron"] = "None" if schedule_cron_should_be_removed else schedule_cron
|
|
3152
3177
|
copy_params["mode"] = mode
|
|
3178
|
+
copy_params["on_demand_compute"] = parse_optional_bool(copy_node.get(CopyParameters.ON_DEMAND_COMPUTE))
|
|
3153
3179
|
await tb_client.pipe_update_copy(**copy_params)
|
|
3154
3180
|
except Exception as e:
|
|
3155
3181
|
raise Exception(
|
|
@@ -3798,12 +3824,11 @@ def get_name_version(ds: str) -> Dict[str, Any]:
|
|
|
3798
3824
|
tk = ds.rsplit("__", 2)
|
|
3799
3825
|
if len(tk) == 1:
|
|
3800
3826
|
return {"name": tk[0], "version": None}
|
|
3801
|
-
|
|
3827
|
+
if len(tk) == 2:
|
|
3802
3828
|
if len(tk[1]):
|
|
3803
3829
|
if tk[1][0] == "v" and _PATTERN_VERSION_NUMBER.match(tk[1][1:]):
|
|
3804
3830
|
return {"name": tk[0], "version": int(tk[1][1:])}
|
|
3805
|
-
|
|
3806
|
-
return {"name": tk[0] + "__" + tk[1], "version": None}
|
|
3831
|
+
return {"name": tk[0] + "__" + tk[1], "version": None}
|
|
3807
3832
|
elif len(tk) == 3 and len(tk[2]):
|
|
3808
3833
|
if tk[2] == "checker":
|
|
3809
3834
|
return {"name": tk[0] + "__" + tk[1] + "__" + tk[2], "version": None}
|
|
@@ -4667,7 +4692,7 @@ async def folder_push(
|
|
|
4667
4692
|
fork,
|
|
4668
4693
|
)
|
|
4669
4694
|
else:
|
|
4670
|
-
#
|
|
4695
|
+
# Connected datasources require post-release changes to avoid modifying the live connection.
|
|
4671
4696
|
kafka_connection_name = (
|
|
4672
4697
|
resources_to_run_fork_downstream[name].get("params", {}).get("kafka_connection_name")
|
|
4673
4698
|
)
|
|
@@ -5007,8 +5032,7 @@ async def format_datasource(
|
|
|
5007
5032
|
format_import_settings(file_parts, doc.nodes[0])
|
|
5008
5033
|
format_shared_with(file_parts, doc)
|
|
5009
5034
|
result = "".join(file_parts)
|
|
5010
|
-
|
|
5011
|
-
return result
|
|
5035
|
+
return result.rstrip("\n") + "\n"
|
|
5012
5036
|
|
|
5013
5037
|
|
|
5014
5038
|
def format_version(file_parts: List[str], doc: Datafile) -> List[str]:
|
|
@@ -5120,17 +5144,16 @@ async def format_engine(
|
|
|
5120
5144
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5121
5145
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5122
5146
|
return file_parts
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
for
|
|
5129
|
-
|
|
5130
|
-
file_parts.append(f"ENGINE_{arg[0].upper()} {elem or empty}")
|
|
5131
|
-
file_parts.append(DATAFILE_NEW_LINE)
|
|
5147
|
+
if node.get("engine", None):
|
|
5148
|
+
empty = '""'
|
|
5149
|
+
file_parts.append(f"ENGINE {node['engine']['type']}" if node.get("engine", {}).get("type") else empty)
|
|
5150
|
+
file_parts.append(DATAFILE_NEW_LINE)
|
|
5151
|
+
for arg in sorted(node["engine"].get("args", [])):
|
|
5152
|
+
elem = ", ".join([x.strip() for x in arg[1].split(",")])
|
|
5153
|
+
file_parts.append(f"ENGINE_{arg[0].upper()} {elem or empty}")
|
|
5132
5154
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5133
|
-
|
|
5155
|
+
file_parts.append(DATAFILE_NEW_LINE)
|
|
5156
|
+
return file_parts
|
|
5134
5157
|
|
|
5135
5158
|
|
|
5136
5159
|
async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[str]:
|
|
@@ -5162,6 +5185,9 @@ async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[
|
|
|
5162
5185
|
else:
|
|
5163
5186
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5164
5187
|
file_parts.append(f"{CopyParameters.COPY_SCHEDULE.upper()} {ON_DEMAND}")
|
|
5188
|
+
if parse_optional_bool(node.get(CopyParameters.ON_DEMAND_COMPUTE)):
|
|
5189
|
+
file_parts.append(DATAFILE_NEW_LINE)
|
|
5190
|
+
file_parts.append("ON_DEMAND_COMPUTE true")
|
|
5165
5191
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5166
5192
|
|
|
5167
5193
|
# Sink or Stream pipe
|
|
@@ -5296,8 +5322,7 @@ async def format_pipe(
|
|
|
5296
5322
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
5297
5323
|
|
|
5298
5324
|
result = "".join(file_parts)
|
|
5299
|
-
|
|
5300
|
-
return result
|
|
5325
|
+
return result.rstrip("\n") + "\n"
|
|
5301
5326
|
|
|
5302
5327
|
|
|
5303
5328
|
def format_sql(
|
|
@@ -5632,6 +5657,7 @@ async def diff_files(
|
|
|
5632
5657
|
click.echo(f"Unsupported file type: {filename}")
|
|
5633
5658
|
if lines:
|
|
5634
5659
|
return [f"{l}\n" for l in lines.split("\n")] if with_format else lines # noqa: E741
|
|
5660
|
+
return None
|
|
5635
5661
|
|
|
5636
5662
|
try:
|
|
5637
5663
|
lines1 = await parse(from_file, with_format, resource_source="remote")
|
|
@@ -5641,7 +5667,7 @@ async def diff_files(
|
|
|
5641
5667
|
raise click.ClickException(FeedbackManager.error_diff_file(filename=filename))
|
|
5642
5668
|
|
|
5643
5669
|
if not lines1 or not lines2:
|
|
5644
|
-
return
|
|
5670
|
+
return None
|
|
5645
5671
|
|
|
5646
5672
|
diff = difflib.unified_diff(
|
|
5647
5673
|
lines1, lines2, fromfile=f"{Path(from_file).name} {from_file_suffix}", tofile=f"{to_file} {to_file_suffix}"
|
|
@@ -5661,10 +5687,7 @@ def is_materialized(resource: Optional[Dict[str, Any]]) -> bool:
|
|
|
5661
5687
|
if not resource:
|
|
5662
5688
|
return False
|
|
5663
5689
|
|
|
5664
|
-
|
|
5665
|
-
node.get("params", {}).get("type", None) == "materialized" for node in resource.get("nodes", []) or []
|
|
5666
|
-
)
|
|
5667
|
-
return is_materialized
|
|
5690
|
+
return any(node.get("params", {}).get("type", None) == "materialized" for node in resource.get("nodes", []) or [])
|
|
5668
5691
|
|
|
5669
5692
|
|
|
5670
5693
|
def is_endpoint_with_no_dependencies(
|
tinybird/datatypes.py
CHANGED
|
@@ -120,52 +120,74 @@ def datetime_test(x: str) -> bool:
|
|
|
120
120
|
return any(p.match(x) for p in datetime_patterns)
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
def bounded_integer(x: str, pattern: re.Pattern[str]) -> Optional[int]:
|
|
124
|
+
if pattern.match(x) is None:
|
|
125
|
+
return None
|
|
126
|
+
digits = x.lstrip("+-").lstrip("0")
|
|
127
|
+
# 256-bit unsigned integers have at most 78 decimal digits.
|
|
128
|
+
if len(digits) > 78:
|
|
129
|
+
return None
|
|
130
|
+
return int(x) if len(x) <= 78 else int(digits or "0") * (-1 if x.startswith("-") else 1)
|
|
131
|
+
|
|
132
|
+
|
|
123
133
|
def int_8_test(x: str) -> bool:
|
|
124
|
-
|
|
134
|
+
value = bounded_integer(x, intx_re)
|
|
135
|
+
return value is not None and -int_8_max <= value < int_8_max
|
|
125
136
|
|
|
126
137
|
|
|
127
138
|
def int16_test(x: str) -> bool:
|
|
128
|
-
|
|
139
|
+
value = bounded_integer(x, intx_re)
|
|
140
|
+
return value is not None and -int16_max <= value < int16_max
|
|
129
141
|
|
|
130
142
|
|
|
131
143
|
def int32_test(x: str) -> bool:
|
|
132
|
-
|
|
144
|
+
value = bounded_integer(x, intx_re)
|
|
145
|
+
return value is not None and -int32_max <= value < int32_max
|
|
133
146
|
|
|
134
147
|
|
|
135
148
|
def int64_test(x: str) -> bool:
|
|
136
|
-
|
|
149
|
+
value = bounded_integer(x, intx_re)
|
|
150
|
+
return value is not None and -int64_max <= value < int64_max
|
|
137
151
|
|
|
138
152
|
|
|
139
153
|
def int128_test(x: str) -> bool:
|
|
140
|
-
|
|
154
|
+
value = bounded_integer(x, intx_re)
|
|
155
|
+
return value is not None and -int128_max <= value < int128_max
|
|
141
156
|
|
|
142
157
|
|
|
143
158
|
def int256_test(x: str) -> bool:
|
|
144
|
-
|
|
159
|
+
value = bounded_integer(x, intx_re)
|
|
160
|
+
return value is not None and -int256_max <= value < int256_max
|
|
145
161
|
|
|
146
162
|
|
|
147
163
|
def uint_8_test(x: str) -> bool:
|
|
148
|
-
|
|
164
|
+
value = bounded_integer(x, uintx_re)
|
|
165
|
+
return value is not None and 0 <= value < uint_8_max
|
|
149
166
|
|
|
150
167
|
|
|
151
168
|
def uint16_test(x: str) -> bool:
|
|
152
|
-
|
|
169
|
+
value = bounded_integer(x, uintx_re)
|
|
170
|
+
return value is not None and 0 <= value < uint16_max
|
|
153
171
|
|
|
154
172
|
|
|
155
173
|
def uint32_test(x: str) -> bool:
|
|
156
|
-
|
|
174
|
+
value = bounded_integer(x, uintx_re)
|
|
175
|
+
return value is not None and 0 <= value < uint32_max
|
|
157
176
|
|
|
158
177
|
|
|
159
178
|
def uint64_test(x: str) -> bool:
|
|
160
|
-
|
|
179
|
+
value = bounded_integer(x, uintx_re)
|
|
180
|
+
return value is not None and 0 <= value < uint64_max
|
|
161
181
|
|
|
162
182
|
|
|
163
183
|
def uint128_test(x: str) -> bool:
|
|
164
|
-
|
|
184
|
+
value = bounded_integer(x, intx_re)
|
|
185
|
+
return value is not None and 0 <= value < uint128_max
|
|
165
186
|
|
|
166
187
|
|
|
167
188
|
def uint256_test(x: str) -> bool:
|
|
168
|
-
|
|
189
|
+
value = bounded_integer(x, intx_re)
|
|
190
|
+
return value is not None and 0 <= value < uint256_max
|
|
169
191
|
|
|
170
192
|
|
|
171
193
|
def float_test(x: str) -> bool:
|
tinybird/feedback_manager.py
CHANGED
|
@@ -572,6 +572,11 @@ class FeedbackManager:
|
|
|
572
572
|
"You can read more about the pricing at https://www.tinybird.co/docs/classic/work-with-data/process-and-copy/materialized-views#compute-compute-separation-for-populates\n\n"
|
|
573
573
|
"Do you want to proceed with on-demand compute?"
|
|
574
574
|
)
|
|
575
|
+
warning_confirm_on_demand_compute_differs_from_datafile = warning_message(
|
|
576
|
+
"The local datafile of pipe '{pipe}' does not set ON_DEMAND_COMPUTE true, but --on-demand-compute was passed.\n"
|
|
577
|
+
"On-demand compute uses dedicated resources that are billed separately from your regular usage.\n\n"
|
|
578
|
+
"Do you want to proceed?"
|
|
579
|
+
)
|
|
575
580
|
|
|
576
581
|
warning_confirm_delete_token = prompt_message("Do you want to delete Token {token}?")
|
|
577
582
|
warning_confirm_refresh_token = prompt_message("Do you want to refresh Token {token}?")
|
tinybird/git_settings.py
CHANGED
|
@@ -137,9 +137,7 @@ def bump_version(version: str, next_version: Optional[str]) -> str:
|
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
def get_default_init_files_deploy(workspace_name: str) -> Dict[str, str]:
|
|
140
|
-
|
|
140
|
+
return {
|
|
141
141
|
path.replace("tinybird_", f"tinybird_{workspace_name.lower()}_"): content
|
|
142
142
|
for path, content in DEFAULT_INIT_FILES_DEPLOY.items()
|
|
143
143
|
}
|
|
144
|
-
|
|
145
|
-
return modified_files
|
tinybird/sql.py
CHANGED
|
@@ -129,15 +129,9 @@ class TableProjection:
|
|
|
129
129
|
def add_projection_sql(self):
|
|
130
130
|
return f"ADD {self.to_sql()}"
|
|
131
131
|
|
|
132
|
-
def drop_projection_sql(self):
|
|
133
|
-
return f"DROP PROJECTION IF EXISTS {self.name}"
|
|
134
|
-
|
|
135
132
|
def materialize_projection_sql(self):
|
|
136
133
|
return f"MATERIALIZE PROJECTION IF EXISTS {self.name}"
|
|
137
134
|
|
|
138
|
-
def clear_projection_sql(self):
|
|
139
|
-
return f"CLEAR PROJECTION IF EXISTS {self.name}"
|
|
140
|
-
|
|
141
135
|
|
|
142
136
|
def as_subquery(sql: str) -> str:
|
|
143
137
|
return f"""(\n{sql}\n)"""
|
|
@@ -675,10 +669,9 @@ def _parse_table_structure(schema: str) -> List[Dict[str, Any]]:
|
|
|
675
669
|
)
|
|
676
670
|
advance_single_char()
|
|
677
671
|
return schema[begin:i]
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
return get_backticked()
|
|
672
|
+
# backticked name
|
|
673
|
+
advance_single_char()
|
|
674
|
+
return get_backticked()
|
|
682
675
|
|
|
683
676
|
def parse_expr(lookup: Iterable[SyntaxExpr]) -> str:
|
|
684
677
|
nonlocal i, line, pos
|