tinybird 0.0.1.dev44__py3-none-any.whl → 0.0.1.dev46__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/client.py +17 -1
- tinybird/prompts.py +105 -12
- tinybird/tb/__cli__.py +2 -2
- tinybird/tb/modules/build.py +7 -4
- tinybird/tb/modules/cli.py +16 -5
- tinybird/tb/modules/common.py +1 -1
- tinybird/tb/modules/create.py +32 -16
- tinybird/tb/modules/datafile/common.py +1 -1
- tinybird/tb/modules/datafile/format_datasource.py +1 -1
- tinybird/tb/modules/datafile/format_pipe.py +4 -4
- tinybird/tb/modules/datafile/pipe_checker.py +3 -3
- tinybird/tb/modules/feedback_manager.py +5 -1
- tinybird/tb/modules/local_common.py +10 -7
- tinybird/tb/modules/pipe.py +6 -5
- tinybird/tb/modules/shell.py +3 -3
- tinybird/tb/modules/test.py +1 -1
- tinybird/tb/modules/tinyunit/tinyunit.py +1 -1
- tinybird/tb/modules/workspace.py +2 -1
- {tinybird-0.0.1.dev44.dist-info → tinybird-0.0.1.dev46.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev44.dist-info → tinybird-0.0.1.dev46.dist-info}/RECORD +23 -23
- {tinybird-0.0.1.dev44.dist-info → tinybird-0.0.1.dev46.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev44.dist-info → tinybird-0.0.1.dev46.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev44.dist-info → tinybird-0.0.1.dev46.dist-info}/top_level.txt +0 -0
tinybird/client.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
+
import os
|
|
4
5
|
import ssl
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Any, Callable, Dict, List, Mapping, Optional, Set, Union
|
|
@@ -91,6 +92,7 @@ class TinyB:
|
|
|
91
92
|
disable_ssl_checks: bool = False,
|
|
92
93
|
send_telemetry: bool = False,
|
|
93
94
|
semver: Optional[str] = None,
|
|
95
|
+
env: Optional[str] = "production",
|
|
94
96
|
):
|
|
95
97
|
ctx = ssl.create_default_context()
|
|
96
98
|
ctx.check_hostname = False
|
|
@@ -102,6 +104,7 @@ class TinyB:
|
|
|
102
104
|
self.disable_ssl_checks = disable_ssl_checks
|
|
103
105
|
self.send_telemetry = send_telemetry
|
|
104
106
|
self.semver = semver
|
|
107
|
+
self.env = env
|
|
105
108
|
|
|
106
109
|
async def _req_raw(
|
|
107
110
|
self,
|
|
@@ -687,7 +690,20 @@ class TinyB:
|
|
|
687
690
|
return await self._req(f"/v0/jobs/{job_id}/cancel", method="POST", data=b"")
|
|
688
691
|
|
|
689
692
|
async def user_workspaces(self):
|
|
690
|
-
|
|
693
|
+
data = await self._req("/v0/user/workspaces/?with_environments=false")
|
|
694
|
+
# TODO: this is repeated in local_common.py but I'm avoiding circular imports
|
|
695
|
+
local_port = int(os.getenv("TB_LOCAL_PORT", 80))
|
|
696
|
+
local_host = f"http://localhost:{local_port}"
|
|
697
|
+
if local_host != self.host:
|
|
698
|
+
return data
|
|
699
|
+
|
|
700
|
+
local_workspaces = [
|
|
701
|
+
x
|
|
702
|
+
for x in data["workspaces"]
|
|
703
|
+
if x["name"].startswith("Tinybird_Local_") and not x["name"].startswith("Tinybird_Local_Build_")
|
|
704
|
+
]
|
|
705
|
+
|
|
706
|
+
return {**data, "workspaces": local_workspaces}
|
|
691
707
|
|
|
692
708
|
async def user_workspaces_and_branches(self):
|
|
693
709
|
return await self._req("/v0/user/workspaces/?with_environments=true")
|
tinybird/prompts.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
1
3
|
general_functions = [
|
|
2
4
|
"BLAKE3",
|
|
3
5
|
"CAST",
|
|
@@ -368,8 +370,7 @@ You are a Tinybird expert. You will be given a pipe containing different nodes w
|
|
|
368
370
|
|
|
369
371
|
<instructions>
|
|
370
372
|
- Every test name must be unique.
|
|
371
|
-
- The test
|
|
372
|
-
- The test command can have as many parameters as are needed to test the pipe.
|
|
373
|
+
- The test can have as many parameters as are needed to test the pipe.
|
|
373
374
|
- The parameter within Tinybird templating syntax looks like this one {{String(my_param_name, default_value)}}.
|
|
374
375
|
- If there are no parameters, you can omit parameters and generate a single test.
|
|
375
376
|
- The format of the parameters is the following: ?param1=value1¶m2=value2¶m3=value3
|
|
@@ -759,6 +760,10 @@ sql_instructions = """
|
|
|
759
760
|
AND {{{{DateTime(end_date)}}}}
|
|
760
761
|
{{%end%}}
|
|
761
762
|
</valid_condition_without_now>
|
|
763
|
+
- Parameters must not be quoted.
|
|
764
|
+
- When you use defined function with a paremeter inside, do NOT add quotes around the parameter:
|
|
765
|
+
<invalid_defined_function_with_parameter>{{% if defined('my_param') %}}</invalid_defined_function_with_parameter>
|
|
766
|
+
<valid_defined_function_without_parameter>{{% if defined(my_param) %}}</valid_defined_function_without_parameter>
|
|
762
767
|
- Use datasource names as table names when doing SELECT statements.
|
|
763
768
|
- Do not use pipe names as table names.
|
|
764
769
|
- The available datasource names to use in the SQL are the ones present in the existing_resources section or the ones you will create.
|
|
@@ -776,7 +781,6 @@ sql_instructions = """
|
|
|
776
781
|
- When aliasing a column, use first the column name and then the alias.
|
|
777
782
|
- General functions and aggregate functions are case sensitive.
|
|
778
783
|
- Character insensitive functions are case insensitive.
|
|
779
|
-
- When you use defined function with a paremeter inside, do NOT add quotes around the parameter.
|
|
780
784
|
- Parameters are never quoted in any case.
|
|
781
785
|
</sql_instructions>
|
|
782
786
|
""".format(
|
|
@@ -819,22 +823,111 @@ Use the following format to generate the response and do not wrap it in any othe
|
|
|
819
823
|
)
|
|
820
824
|
|
|
821
825
|
|
|
822
|
-
|
|
826
|
+
def rules_prompt(source: Optional[str] = None) -> str:
|
|
827
|
+
base_command = source or "tb"
|
|
828
|
+
return """
|
|
823
829
|
You are an expert in SQL and Tinybird. Follow these instructions when working with .datasource and .pipe files:
|
|
824
830
|
|
|
831
|
+
<command_calling>
|
|
832
|
+
You have commands at your disposal to develop a tinybird project:
|
|
833
|
+
- {base_command} build: to build the project locally and check it works.
|
|
834
|
+
- {base_command} deployment create --wait --auto: to create a deployment and promote it automatically
|
|
835
|
+
- {base_command} test run: to run existing tests
|
|
836
|
+
- {base_command} --build endpoint url <pipe_name>: to get the url of an endpoint, token included.
|
|
837
|
+
- {base_command} --build endpoint data <pipe_name>: to get the data of an endpoint. You can pass parameters to the endpoint like this: {base_command} --build endpoint data <pipe_name> --param1 value1 --param2 value2
|
|
838
|
+
- {base_command} --build token ls: to list all the tokens
|
|
839
|
+
There are other commands that you can use, but these are the most common ones. Run `{base_command} -h` to see all the commands if needed.
|
|
840
|
+
When you need to check resources or data in the Tinybird environment that you updated with the build command, add always the --build flag before the command. Example: {base_command} --build datasource ls
|
|
841
|
+
</command_calling>
|
|
842
|
+
<development_instructions>
|
|
843
|
+
- When asking to create a tinybird data project, if the needed folders are not already created, use the following structure:
|
|
844
|
+
├── copies
|
|
845
|
+
├── datasources
|
|
846
|
+
├── endpoints
|
|
847
|
+
├── fixtures
|
|
848
|
+
├── materializations
|
|
849
|
+
├── sinks
|
|
850
|
+
└── tests
|
|
851
|
+
- The local development server will be available at http://localhost:80. Even if some response uses another base url, use always http://localhost:80.
|
|
852
|
+
- After every change in your .datasource, .pipe or .ndjson files, run `{base_command} build` to build the project locally.
|
|
853
|
+
- When you need to ingest data locally in a datasource, create a .ndjson file with the same name of the datasource and the data you want and run `{base_command} build` so the data is ingested.
|
|
854
|
+
- The format of the generated api endpoint urls is: http://localhost:80/v0/pipe/<pipe_name>.json?token=<token>
|
|
855
|
+
- Before running the tests, remember to have the project built with `{base_command} build` with the latest changes.
|
|
856
|
+
</development_instructions>
|
|
857
|
+
|
|
858
|
+
<datasource_file_instructions>
|
|
859
|
+
Follow these instructions when creating or updating .datasource files:
|
|
825
860
|
{datasource_instructions}
|
|
861
|
+
</datasource_file_instructions>
|
|
862
|
+
|
|
863
|
+
<pipe_file_instructions>
|
|
864
|
+
Follow these instructions when creating or updating .pipe files:
|
|
826
865
|
{pipe_instructions}
|
|
827
866
|
{sql_instructions}
|
|
828
867
|
{datasource_example}
|
|
829
868
|
{pipe_example}
|
|
830
869
|
{copy_pipe_instructions}
|
|
831
870
|
{materialized_pipe_instructions}
|
|
871
|
+
</pipe_file_instructions>
|
|
872
|
+
<test_file_instructions>
|
|
873
|
+
Follow these instructions when creating or updating .yaml files for tests:
|
|
874
|
+
{test_instructions}
|
|
875
|
+
</test_file_instructions>
|
|
832
876
|
""".format(
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
877
|
+
base_command=base_command,
|
|
878
|
+
datasource_instructions=datasource_instructions,
|
|
879
|
+
pipe_instructions=pipe_instructions,
|
|
880
|
+
sql_instructions=sql_instructions,
|
|
881
|
+
datasource_example=datasource_example,
|
|
882
|
+
pipe_example=pipe_example,
|
|
883
|
+
copy_pipe_instructions=copy_pipe_instructions,
|
|
884
|
+
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
885
|
+
test_instructions=test_instructions,
|
|
886
|
+
)
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
test_instructions = """
|
|
890
|
+
- The test file name must match the name of the pipe it is testing.
|
|
891
|
+
- Every scenario name must be unique inside the test file.
|
|
892
|
+
- When looking for the parameters available, you will find them in the pipes in the following format: {{{{String(my_param_name, default_value)}}}}.
|
|
893
|
+
- If there are no parameters, you can omit parameters and generate a single test.
|
|
894
|
+
- The format of the parameters is the following: param1=value1¶m2=value2¶m3=value3
|
|
895
|
+
- If some parameters are provided by the user and you need to use them, preserve in the same format as they were provided, like case sensitive
|
|
896
|
+
- Test as many scenarios as possible.
|
|
897
|
+
- The format of the test file is the following:
|
|
898
|
+
<test_file_format>
|
|
899
|
+
- name: kpis_single_day
|
|
900
|
+
description: Test hourly granularity for a single day
|
|
901
|
+
parameters: date_from=2024-01-01&date_to=2024-01-01
|
|
902
|
+
expected_result: |
|
|
903
|
+
{"date":"2024-01-01 00:00:00","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
904
|
+
{"date":"2024-01-01 01:00:00","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
905
|
+
|
|
906
|
+
- name: kpis_date_range
|
|
907
|
+
description: Test daily granularity for a date range
|
|
908
|
+
parameters: date_from=2024-01-01&date_to=2024-01-31
|
|
909
|
+
expected_result: |
|
|
910
|
+
{"date":"2024-01-01","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
911
|
+
{"date":"2024-01-02","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
912
|
+
|
|
913
|
+
- name: kpis_default_range
|
|
914
|
+
description: Test default behavior without date parameters (last 7 days)
|
|
915
|
+
parameters: ''
|
|
916
|
+
expected_result: |
|
|
917
|
+
{"date":"2025-01-10","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
918
|
+
{"date":"2025-01-11","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
919
|
+
|
|
920
|
+
- name: kpis_fixed_time
|
|
921
|
+
description: Test with fixed timestamp for consistent testing
|
|
922
|
+
parameters: fixed_time=2024-01-15T12:00:00
|
|
923
|
+
expected_result: ''
|
|
924
|
+
|
|
925
|
+
- name: kpis_single_day
|
|
926
|
+
description: Test single day with hourly granularity
|
|
927
|
+
parameters: date_from=2024-01-01&date_to=2024-01-01
|
|
928
|
+
expected_result: |
|
|
929
|
+
{"date":"2024-01-01 00:00:00","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
930
|
+
{"date":"2024-01-01 01:00:00","visits":0,"pageviews":0,"bounce_rate":null,"avg_session_sec":0}
|
|
931
|
+
|
|
932
|
+
</test_file_format>
|
|
933
|
+
"""
|
tinybird/tb/__cli__.py
CHANGED
|
@@ -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__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev46'
|
|
8
|
+
__revision__ = '7b9942e'
|
tinybird/tb/modules/build.py
CHANGED
|
@@ -28,10 +28,9 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
28
28
|
"""
|
|
29
29
|
Validate and build the project server side.
|
|
30
30
|
"""
|
|
31
|
-
|
|
32
31
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
33
|
-
tb_client = asyncio.run(get_tinybird_local_client(str(project.path)))
|
|
34
|
-
click.echo(FeedbackManager.
|
|
32
|
+
tb_client = asyncio.run(get_tinybird_local_client(str(project.path), build=True))
|
|
33
|
+
click.echo(FeedbackManager.highlight_building_project())
|
|
35
34
|
time_start = time.time()
|
|
36
35
|
|
|
37
36
|
def process(file_changed: Optional[str] = None, diff: Optional[str] = None) -> None:
|
|
@@ -72,6 +71,7 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
72
71
|
TINYBIRD_API_URL = tb_client.host + "/v1/build"
|
|
73
72
|
logging.debug(TINYBIRD_API_URL)
|
|
74
73
|
TINYBIRD_API_KEY = tb_client.token
|
|
74
|
+
error = False
|
|
75
75
|
try:
|
|
76
76
|
files = [
|
|
77
77
|
("context://", ("cli-version", "1.0.0", "text/plain")),
|
|
@@ -141,13 +141,14 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
141
141
|
pass
|
|
142
142
|
|
|
143
143
|
elif build_result == "failed":
|
|
144
|
-
click.echo(FeedbackManager.error(message="Build failed"))
|
|
145
144
|
build_errors = result.get("errors")
|
|
145
|
+
error = True
|
|
146
146
|
for build_error in build_errors:
|
|
147
147
|
filename_bit = f"{build_error.get('filename', '')}"
|
|
148
148
|
error_msg = ((filename_bit + "\n\n") if filename_bit else "") + build_error.get("error")
|
|
149
149
|
click.echo(FeedbackManager.error(message=error_msg))
|
|
150
150
|
else:
|
|
151
|
+
error = True
|
|
151
152
|
click.echo(FeedbackManager.error(message=f"Unknown build result. Error: {result.get('error')}"))
|
|
152
153
|
|
|
153
154
|
except Exception as e:
|
|
@@ -155,6 +156,8 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
155
156
|
finally:
|
|
156
157
|
for fd in fds:
|
|
157
158
|
fd.close()
|
|
159
|
+
if error:
|
|
160
|
+
raise click.ClickException(FeedbackManager.error_build_failed())
|
|
158
161
|
|
|
159
162
|
|
|
160
163
|
def append_fixture(
|
tinybird/tb/modules/cli.py
CHANGED
|
@@ -59,12 +59,20 @@ VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
|
|
|
59
59
|
@click.option("--host", help="Use custom host, defaults to TB_HOST envvar, then to https://api.tinybird.co")
|
|
60
60
|
@click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
|
|
61
61
|
@click.option("--prod/--local", is_flag=True, default=False, help="Run against production or local")
|
|
62
|
+
@click.option("--build", is_flag=True, default=False, help="Run against build mode")
|
|
62
63
|
@click.option("--folder", type=str, help="Folder where files will be placed")
|
|
63
64
|
@click.version_option(version=VERSION)
|
|
64
65
|
@click.pass_context
|
|
65
66
|
@coro
|
|
66
67
|
async def cli(
|
|
67
|
-
ctx: Context,
|
|
68
|
+
ctx: Context,
|
|
69
|
+
debug: bool,
|
|
70
|
+
token: str,
|
|
71
|
+
host: str,
|
|
72
|
+
show_tokens: bool,
|
|
73
|
+
prod: bool,
|
|
74
|
+
build: bool,
|
|
75
|
+
folder: Optional[str],
|
|
68
76
|
) -> None:
|
|
69
77
|
"""
|
|
70
78
|
Use `OBFUSCATE_REGEX_PATTERN` and `OBFUSCATE_PATTERN_SEPARATOR` environment variables to define a regex pattern and a separator (in case of a single string with multiple regex) to obfuscate secrets in the CLI output.
|
|
@@ -116,10 +124,13 @@ async def cli(
|
|
|
116
124
|
|
|
117
125
|
logging.debug("debug enabled")
|
|
118
126
|
|
|
119
|
-
skip_client = ctx.invoked_subcommand in ["auth", "check", "login", "
|
|
120
|
-
client = await create_ctx_client(config, prod, skip_client, project)
|
|
127
|
+
skip_client = ctx.invoked_subcommand in ["auth", "check", "login", "local", "build"]
|
|
128
|
+
client = await create_ctx_client(config, prod, build, skip_client, project)
|
|
121
129
|
|
|
122
130
|
if client:
|
|
131
|
+
if not build:
|
|
132
|
+
target = config.get("name", "production") if prod else "Tinybird local"
|
|
133
|
+
click.echo(FeedbackManager.gray(message=f"Running against {target}\n"))
|
|
123
134
|
ctx.ensure_object(dict)["client"] = client
|
|
124
135
|
|
|
125
136
|
ctx.ensure_object(dict)["project"] = project
|
|
@@ -434,11 +445,11 @@ def __unpatch_click_output():
|
|
|
434
445
|
click.secho = __old_click_secho
|
|
435
446
|
|
|
436
447
|
|
|
437
|
-
async def create_ctx_client(config: Dict[str, Any], prod: bool, skip_client: bool, project: Project):
|
|
448
|
+
async def create_ctx_client(config: Dict[str, Any], prod: bool, build: bool, skip_client: bool, project: Project):
|
|
438
449
|
if skip_client:
|
|
439
450
|
return None
|
|
440
451
|
|
|
441
452
|
if prod:
|
|
442
453
|
return _get_tb_client(config.get("token", None), config["host"])
|
|
443
454
|
|
|
444
|
-
return await get_tinybird_local_client(str(project.path))
|
|
455
|
+
return await get_tinybird_local_client(str(project.path), build=build)
|
tinybird/tb/modules/common.py
CHANGED
|
@@ -1362,7 +1362,7 @@ async def try_update_config_with_remote(
|
|
|
1362
1362
|
def ask_for_admin_token_interactively(ui_host: str, default_token: Optional[str]) -> str:
|
|
1363
1363
|
return (
|
|
1364
1364
|
click.prompt(
|
|
1365
|
-
f
|
|
1365
|
+
f'\nCopy the "admin your@email" token from {ui_host}/tokens and paste it here {"OR press enter to use the token from .tinyb file" if default_token else ""}',
|
|
1366
1366
|
hide_input=True,
|
|
1367
1367
|
show_default=False,
|
|
1368
1368
|
default=default_token,
|
tinybird/tb/modules/create.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import Optional
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from tinybird.client import TinyB
|
|
10
|
-
from tinybird.prompts import create_prompt,
|
|
10
|
+
from tinybird.prompts import create_prompt, mock_prompt, rules_prompt
|
|
11
11
|
from tinybird.tb.modules.cicd import init_cicd
|
|
12
12
|
from tinybird.tb.modules.cli import cli
|
|
13
13
|
from tinybird.tb.modules.common import _generate_datafile, check_user_token_with_client, coro, generate_datafile
|
|
@@ -36,12 +36,13 @@ from tinybird.tb.modules.project import Project
|
|
|
36
36
|
)
|
|
37
37
|
@click.option(
|
|
38
38
|
"--folder",
|
|
39
|
-
default="
|
|
39
|
+
default="",
|
|
40
40
|
type=click.Path(exists=False, file_okay=False),
|
|
41
41
|
help="Folder where datafiles will be placed",
|
|
42
42
|
)
|
|
43
43
|
@click.option("--rows", type=int, default=10, help="Number of events to send")
|
|
44
44
|
@click.option("--cursor", default=False, is_flag=True, help="Create .cursorrules file with Tinybird rules")
|
|
45
|
+
@click.option("--source", type=str, default="tb", help="Source of the command")
|
|
45
46
|
@click.pass_context
|
|
46
47
|
@coro
|
|
47
48
|
async def create(
|
|
@@ -51,6 +52,7 @@ async def create(
|
|
|
51
52
|
folder: Optional[str],
|
|
52
53
|
rows: int,
|
|
53
54
|
cursor: bool,
|
|
55
|
+
source: str,
|
|
54
56
|
) -> None:
|
|
55
57
|
"""Initialize a new project."""
|
|
56
58
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
@@ -83,9 +85,11 @@ async def create(
|
|
|
83
85
|
create_project_structure(folder)
|
|
84
86
|
click.echo(FeedbackManager.success(message="✓ Scaffolding completed!\n"))
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
result = ""
|
|
89
|
+
if data or prompt:
|
|
90
|
+
click.echo(FeedbackManager.highlight(message="\n» Creating resources..."))
|
|
91
|
+
result = await create_resources(local_client, tb_client, user_token, data, prompt, folder)
|
|
92
|
+
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
89
93
|
|
|
90
94
|
if not already_has_cicd(folder):
|
|
91
95
|
click.echo(FeedbackManager.highlight(message="\n» Creating CI/CD files for GitHub and GitLab..."))
|
|
@@ -118,8 +122,8 @@ async def create(
|
|
|
118
122
|
response = llm.ask(system_prompt=mock_prompt(rows), prompt=prompt)
|
|
119
123
|
sql = extract_xml(response, "sql")
|
|
120
124
|
sql = sql.split("FORMAT")[0]
|
|
121
|
-
|
|
122
|
-
data =
|
|
125
|
+
query_result = await local_client.query(f"{sql} FORMAT JSON")
|
|
126
|
+
data = query_result.get("data", [])
|
|
123
127
|
fixture_name = build_fixture_name(
|
|
124
128
|
datasource_path.absolute().as_posix(), datasource_name, datasource_content
|
|
125
129
|
)
|
|
@@ -127,9 +131,9 @@ async def create(
|
|
|
127
131
|
persist_fixture(fixture_name, data, folder)
|
|
128
132
|
click.echo(FeedbackManager.info(message=f"✓ /fixtures/{datasource_name}"))
|
|
129
133
|
|
|
130
|
-
if cursor
|
|
134
|
+
if cursor:
|
|
131
135
|
click.echo(FeedbackManager.highlight(message="\n» Creating .cursorrules..."))
|
|
132
|
-
|
|
136
|
+
create_rules(folder, source, "cursor")
|
|
133
137
|
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
134
138
|
|
|
135
139
|
except Exception as e:
|
|
@@ -336,13 +340,15 @@ def generate_pipe_file(name: str, content: str, folder: str) -> Path:
|
|
|
336
340
|
return f.relative_to(folder)
|
|
337
341
|
|
|
338
342
|
|
|
339
|
-
def
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
343
|
+
def create_rules(folder: str, source: str, agent: str):
|
|
344
|
+
if agent == "cursor":
|
|
345
|
+
extension = ".cursorrules"
|
|
346
|
+
elif agent == "windsurf":
|
|
347
|
+
extension = ".windsurfrules"
|
|
348
|
+
else:
|
|
349
|
+
extension = ".txt"
|
|
350
|
+
rules_file = Path(folder) / extension
|
|
351
|
+
rules_file.write_text(rules_prompt(source))
|
|
346
352
|
|
|
347
353
|
|
|
348
354
|
def get_context_file() -> Path:
|
|
@@ -360,3 +366,13 @@ def get_context() -> str:
|
|
|
360
366
|
def save_context(prompt: str, feedback: str):
|
|
361
367
|
context_file = get_context_file()
|
|
362
368
|
context_file.write_text(f"- {prompt}\n{feedback}")
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
@cli.command("rules")
|
|
372
|
+
@click.option("--agent", type=str, default="cursor", help="Agent to use for rules")
|
|
373
|
+
@click.option("--source", type=str, default="tb", help="Source of the command")
|
|
374
|
+
@click.pass_context
|
|
375
|
+
def rules(ctx: click.Context, agent: str, source: str):
|
|
376
|
+
"""Create agent rules for the project."""
|
|
377
|
+
project: Project = ctx.ensure_object(dict)["project"]
|
|
378
|
+
create_rules(str(project.path), source, agent)
|
|
@@ -526,7 +526,7 @@ def format_parse_error(
|
|
|
526
526
|
message += f" found at position {adjusted_position - len(keyword)}"
|
|
527
527
|
else:
|
|
528
528
|
message += (
|
|
529
|
-
f" found {repr(table_structure[i]) if len(table_structure)>i else 'EOF'} at position {adjusted_position}"
|
|
529
|
+
f" found {repr(table_structure[i]) if len(table_structure) > i else 'EOF'} at position {adjusted_position}"
|
|
530
530
|
)
|
|
531
531
|
return message
|
|
532
532
|
|
|
@@ -148,7 +148,7 @@ async def format_engine(
|
|
|
148
148
|
else:
|
|
149
149
|
if node.get("engine", None):
|
|
150
150
|
empty = '""'
|
|
151
|
-
file_parts.append(f
|
|
151
|
+
file_parts.append(f"ENGINE {node['engine']['type']}" if node.get("engine", {}).get("type") else empty)
|
|
152
152
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
153
153
|
for arg in sorted(node["engine"].get("args", [])):
|
|
154
154
|
elem = ", ".join([x.strip() for x in arg[1].split(",")])
|
|
@@ -42,7 +42,7 @@ async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[
|
|
|
42
42
|
if node_type == PipeNodeTypes.MATERIALIZED:
|
|
43
43
|
file_parts.append(node_type_upper)
|
|
44
44
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
45
|
-
file_parts.append(f
|
|
45
|
+
file_parts.append(f"DATASOURCE {node['datasource']}")
|
|
46
46
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
47
47
|
await format_engine(file_parts, node)
|
|
48
48
|
|
|
@@ -50,10 +50,10 @@ async def format_node_type(file_parts: List[str], node: Dict[str, Any]) -> List[
|
|
|
50
50
|
if node_type == PipeNodeTypes.COPY:
|
|
51
51
|
file_parts.append(node_type_upper)
|
|
52
52
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
53
|
-
file_parts.append(f
|
|
53
|
+
file_parts.append(f"TARGET_DATASOURCE {node['target_datasource']}")
|
|
54
54
|
if node.get("mode"):
|
|
55
55
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
56
|
-
file_parts.append(f
|
|
56
|
+
file_parts.append(f"COPY_MODE {node.get('mode')}")
|
|
57
57
|
|
|
58
58
|
if node.get(CopyParameters.COPY_SCHEDULE):
|
|
59
59
|
is_ondemand = node[CopyParameters.COPY_SCHEDULE].lower() == ON_DEMAND
|
|
@@ -112,7 +112,7 @@ async def format_node(
|
|
|
112
112
|
if item and not unroll_includes:
|
|
113
113
|
return
|
|
114
114
|
|
|
115
|
-
file_parts.append(f
|
|
115
|
+
file_parts.append(f"NODE {node['name'].strip()}")
|
|
116
116
|
file_parts.append(DATAFILE_NEW_LINE)
|
|
117
117
|
|
|
118
118
|
from collections import namedtuple
|
|
@@ -288,8 +288,8 @@ class PipeCheckerRunner:
|
|
|
288
288
|
AND extractURLParameter(assumeNotNull(url), 'debug') <> 'query'
|
|
289
289
|
AND error = 0
|
|
290
290
|
AND not mapContains(parameters, '__tb__semver')
|
|
291
|
-
{" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else
|
|
292
|
-
{
|
|
291
|
+
{" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else ""}
|
|
292
|
+
{extra_where_clause}
|
|
293
293
|
Limit 5000000 -- Enough to bring data while not processing all requests from highly used pipes
|
|
294
294
|
)
|
|
295
295
|
group by request_param_names, http_method
|
|
@@ -315,7 +315,7 @@ class PipeCheckerRunner:
|
|
|
315
315
|
AND extractURLParameter(assumeNotNull(url), 'debug') <> 'query'
|
|
316
316
|
AND error = 0
|
|
317
317
|
AND not mapContains(parameters, '__tb__semver')
|
|
318
|
-
{" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else
|
|
318
|
+
{" AND " + " AND ".join([f"mapContains(pipe_request_params, '{match}')" for match in matches]) if matches and len(matches) > 0 else ""}
|
|
319
319
|
{extra_where_clause}
|
|
320
320
|
LIMIT {limit}
|
|
321
321
|
)
|
|
@@ -432,6 +432,7 @@ class FeedbackManager:
|
|
|
432
432
|
error_updating_tag = error_message("Error updating tag: {error}")
|
|
433
433
|
error_tag_generic = error_message("There was an issue updating tags. {error}")
|
|
434
434
|
error_tag_not_found = error_message("Tag {tag_name} not found.")
|
|
435
|
+
error_build_failed = error_message("Build failed")
|
|
435
436
|
|
|
436
437
|
info_incl_relative_path = info_message("** Relative path {path} does not exist, skipping.")
|
|
437
438
|
info_ignoring_incl_file = info_message(
|
|
@@ -849,6 +850,7 @@ Ready? """
|
|
|
849
850
|
)
|
|
850
851
|
info_tag_list = info_message("** Tags:")
|
|
851
852
|
info_tag_resources = info_message("** Resources tagged by {tag_name}:")
|
|
853
|
+
info_build_failed = info_message("** Build failed")
|
|
852
854
|
warning_no_release = warning_message(
|
|
853
855
|
"** Warning: Workspace does not have Releases, run `tb init --git` to activate them."
|
|
854
856
|
)
|
|
@@ -964,7 +966,7 @@ Ready? """
|
|
|
964
966
|
)
|
|
965
967
|
success_datasource_alter = success_message("** The Data Source has been correctly updated.")
|
|
966
968
|
success_datasource_kafka_connected = success_message(
|
|
967
|
-
"** Data Source '{id}' created\n
|
|
969
|
+
"** Data Source '{id}' created\n** Kafka streaming connection configured successfully!"
|
|
968
970
|
)
|
|
969
971
|
success_datasource_shared = success_message(
|
|
970
972
|
"** The Data Source {datasource} has been correctly shared with {workspace}"
|
|
@@ -1040,6 +1042,8 @@ Ready? """
|
|
|
1040
1042
|
|
|
1041
1043
|
debug_running_file = print_message("** Running {file}", bcolors.CGREY)
|
|
1042
1044
|
|
|
1045
|
+
highlight_building_project = info_highlight_message("\n» Building project...")
|
|
1046
|
+
|
|
1043
1047
|
success = success_message("{message}")
|
|
1044
1048
|
info = info_message("{message}")
|
|
1045
1049
|
highlight = info_highlight_message("{message}")
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
import requests
|
|
7
6
|
|
|
@@ -9,19 +8,19 @@ from tinybird.client import TinyB
|
|
|
9
8
|
from tinybird.tb.modules.config import CLIConfig
|
|
10
9
|
from tinybird.tb.modules.exceptions import CLIException
|
|
11
10
|
|
|
12
|
-
TB_IMAGE_NAME = "
|
|
11
|
+
TB_IMAGE_NAME = "registry.gitlab.com/tinybird/analytics/tinybird-local-jammy-3.11:beta"
|
|
13
12
|
TB_CONTAINER_NAME = "tinybird-local"
|
|
14
13
|
TB_LOCAL_PORT = int(os.getenv("TB_LOCAL_PORT", 80))
|
|
15
14
|
TB_LOCAL_HOST = f"http://localhost:{TB_LOCAL_PORT}"
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
async def get_tinybird_local_client(path:
|
|
17
|
+
async def get_tinybird_local_client(path: str, build: bool = False) -> TinyB:
|
|
19
18
|
"""Get a Tinybird client connected to the local environment."""
|
|
20
|
-
config = await get_tinybird_local_config(path)
|
|
19
|
+
config = await get_tinybird_local_config(path, build=build)
|
|
21
20
|
return config.get_client(host=TB_LOCAL_HOST)
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
async def get_tinybird_local_config(path:
|
|
23
|
+
async def get_tinybird_local_config(path: str, build: bool = False) -> CLIConfig:
|
|
25
24
|
"""Craft a client config with a workspace name based on the path of the project files
|
|
26
25
|
|
|
27
26
|
It uses the tokens from tinybird local
|
|
@@ -41,11 +40,15 @@ async def get_tinybird_local_config(path: Optional[str] = None) -> CLIConfig:
|
|
|
41
40
|
if path:
|
|
42
41
|
folder_hash = hashlib.sha256(path.encode()).hexdigest()
|
|
43
42
|
user_client = config.get_client(host=TB_LOCAL_HOST, token=user_token)
|
|
44
|
-
ws_name = f"Tinybird_Local_Build_{folder_hash}"
|
|
43
|
+
ws_name = f"Tinybird_Local_Build_{folder_hash}" if build else f"Tinybird_Local_{folder_hash}"
|
|
45
44
|
logging.debug(f"Workspace used for build: {ws_name}")
|
|
46
45
|
|
|
47
46
|
user_workspaces = requests.get(f"{TB_LOCAL_HOST}/v0/user/workspaces?token={user_token}").json()
|
|
48
|
-
local_workspaces =
|
|
47
|
+
local_workspaces = (
|
|
48
|
+
[ws for ws in user_workspaces["workspaces"] if ws["name"].startswith(ws_name)]
|
|
49
|
+
if user_workspaces.get("workspaces")
|
|
50
|
+
else []
|
|
51
|
+
)
|
|
49
52
|
local_workspaces = sorted(local_workspaces, key=lambda x: x["name"])
|
|
50
53
|
|
|
51
54
|
ws = None
|
tinybird/tb/modules/pipe.py
CHANGED
|
@@ -20,10 +20,10 @@ from tinybird.tb.modules.exceptions import CLIPipeException
|
|
|
20
20
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
@cli.group(hidden=
|
|
23
|
+
@cli.group(hidden=False)
|
|
24
24
|
@click.pass_context
|
|
25
25
|
def pipe(ctx):
|
|
26
|
-
"""
|
|
26
|
+
"""Pipe commands"""
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@pipe.command(name="ls")
|
|
@@ -41,10 +41,10 @@ async def pipe_ls(ctx: Context, match: str, format_: str):
|
|
|
41
41
|
"""List pipes"""
|
|
42
42
|
|
|
43
43
|
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
44
|
-
pipes = await client.pipes(dependencies=False, node_attrs="name", attrs="name,updated_at")
|
|
44
|
+
pipes = await client.pipes(dependencies=False, node_attrs="name", attrs="name,updated_at,type")
|
|
45
45
|
pipes = sorted(pipes, key=lambda p: p["updated_at"])
|
|
46
46
|
|
|
47
|
-
columns = ["name", "published date", "nodes"]
|
|
47
|
+
columns = ["name", "published date", "nodes", "type"]
|
|
48
48
|
table_human_readable = []
|
|
49
49
|
table_machine_readable = []
|
|
50
50
|
pattern = re.compile(match) if match else None
|
|
@@ -52,12 +52,13 @@ async def pipe_ls(ctx: Context, match: str, format_: str):
|
|
|
52
52
|
tk = get_name_version(t["name"])
|
|
53
53
|
if pattern and not pattern.search(tk["name"]):
|
|
54
54
|
continue
|
|
55
|
-
table_human_readable.append((tk["name"], t["updated_at"][:-7], len(t["nodes"])))
|
|
55
|
+
table_human_readable.append((tk["name"], t["updated_at"][:-7], len(t["nodes"]), t["type"]))
|
|
56
56
|
table_machine_readable.append(
|
|
57
57
|
{
|
|
58
58
|
"name": tk["name"],
|
|
59
59
|
"published date": t["updated_at"][:-7],
|
|
60
60
|
"nodes": len(t["nodes"]),
|
|
61
|
+
"type": t["type"],
|
|
61
62
|
}
|
|
62
63
|
)
|
|
63
64
|
|
tinybird/tb/modules/shell.py
CHANGED
|
@@ -245,7 +245,7 @@ class Shell:
|
|
|
245
245
|
click.echo(FeedbackManager.error(message=f"'tb {arg}' command is not available in watch mode"))
|
|
246
246
|
|
|
247
247
|
def handle_mock(self, arg):
|
|
248
|
-
subprocess.run(f"tb --folder {self.project.folder} mock {arg}", shell=True, text=True)
|
|
248
|
+
subprocess.run(f"tb --build --folder {self.project.folder} mock {arg}", shell=True, text=True)
|
|
249
249
|
|
|
250
250
|
def handle_tb(self, arg):
|
|
251
251
|
click.echo("")
|
|
@@ -259,7 +259,7 @@ class Shell:
|
|
|
259
259
|
elif arg.startswith("mock"):
|
|
260
260
|
self.handle_mock(arg)
|
|
261
261
|
else:
|
|
262
|
-
subprocess.run(f"tb --folder {self.project.folder} {arg}", shell=True, text=True)
|
|
262
|
+
subprocess.run(f"tb --build --folder {self.project.folder} {arg}", shell=True, text=True)
|
|
263
263
|
|
|
264
264
|
def default(self, argline):
|
|
265
265
|
click.echo("")
|
|
@@ -271,7 +271,7 @@ class Shell:
|
|
|
271
271
|
elif len(arg.split()) == 1 and arg in self.project.pipes + self.project.datasources:
|
|
272
272
|
self.run_sql(f"select * from {arg}")
|
|
273
273
|
else:
|
|
274
|
-
subprocess.run(f"tb --folder {self.project.folder} {arg}", shell=True, text=True)
|
|
274
|
+
subprocess.run(f"tb --build --folder {self.project.folder} {arg}", shell=True, text=True)
|
|
275
275
|
|
|
276
276
|
def run_sql(self, query, rows_limit=20):
|
|
277
277
|
try:
|
tinybird/tb/modules/test.py
CHANGED
|
@@ -102,7 +102,7 @@ async def test_create(ctx: click.Context, name_or_filename: str, prompt: str, sk
|
|
|
102
102
|
pipe_path = root_path / pipe_path
|
|
103
103
|
pipe_content = pipe_path.read_text()
|
|
104
104
|
|
|
105
|
-
client = await get_tinybird_local_client(folder)
|
|
105
|
+
client = await get_tinybird_local_client(folder, build=True)
|
|
106
106
|
pipe = await client._req(f"/v0/pipes/{pipe_name}")
|
|
107
107
|
parameters = set([param["name"] for node in pipe["nodes"] for param in node["params"]])
|
|
108
108
|
|
|
@@ -155,7 +155,7 @@ def parse_file(file: str) -> Iterable[TestCase]:
|
|
|
155
155
|
)
|
|
156
156
|
except Exception as e:
|
|
157
157
|
raise CLIException(
|
|
158
|
-
f"""Error: {FeedbackManager.error_exception(error=e)} reading file, check "{file}"->"{definition.get(
|
|
158
|
+
f"""Error: {FeedbackManager.error_exception(error=e)} reading file, check "{file}"->"{definition.get("name")}" """
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
|
tinybird/tb/modules/workspace.py
CHANGED
|
@@ -8,6 +8,7 @@ from typing import Optional
|
|
|
8
8
|
import click
|
|
9
9
|
from click import Context
|
|
10
10
|
|
|
11
|
+
from tinybird.client import TinyB
|
|
11
12
|
from tinybird.config import get_display_host
|
|
12
13
|
from tinybird.tb.modules.cli import cli
|
|
13
14
|
from tinybird.tb.modules.common import (
|
|
@@ -41,7 +42,7 @@ async def workspace_ls(ctx: Context) -> None:
|
|
|
41
42
|
"""List all the workspaces you have access to in the account you're currently authenticated into."""
|
|
42
43
|
|
|
43
44
|
config = CLIConfig.get_project_config()
|
|
44
|
-
client =
|
|
45
|
+
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
45
46
|
|
|
46
47
|
response = await client.user_workspaces()
|
|
47
48
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
tinybird/__cli__.py,sha256=esPl5QDTzuQgHe5FuxWLm-fURFigGGwjnYLh9GuWUw4,232
|
|
2
|
-
tinybird/client.py,sha256=
|
|
2
|
+
tinybird/client.py,sha256=Qh7UH6mT7rBFwTZis9PBfi88GBWdAubYFvLxNPmhc9s,52110
|
|
3
3
|
tinybird/config.py,sha256=ENRNyEMXHj_P882o31iFz0hTveziLabVRrxiWE5RRBE,6233
|
|
4
4
|
tinybird/connectors.py,sha256=7Gjms7b5MAaBFGi3xytsJurCylprONpFcYrzp4Fw2Rc,15241
|
|
5
5
|
tinybird/context.py,sha256=A3GBApac9xO6hrAMJ1s9dMrI_ou9aKF84CdEjtPddMk,1417
|
|
6
6
|
tinybird/datatypes.py,sha256=XNypumfqNjsvLJ5iNXnbVHRvAJe0aQwI3lS6Cxox-e0,10979
|
|
7
7
|
tinybird/feedback_manager.py,sha256=g1r9NcFfKXdk_13soaiTZLvdoUGleVfawl6Yfj3zmRw,67823
|
|
8
8
|
tinybird/git_settings.py,sha256=Sw_8rGmribEFJ4Z_6idrVytxpFYk7ez8ei0qHULzs3E,3934
|
|
9
|
-
tinybird/prompts.py,sha256=
|
|
9
|
+
tinybird/prompts.py,sha256=XpHaObqoKwIkx1qpAPVCupGwInJ6LirAy9OH9LCiubE,31856
|
|
10
10
|
tinybird/sql.py,sha256=igHaRIeEREN5XYowwpIGYG8gDB5kn5p2cDNL1t8uc40,46168
|
|
11
11
|
tinybird/sql_template.py,sha256=GmMLAI10MTqjQo9qztuQHLRWs67teozsWDxUBdvkAn4,93668
|
|
12
12
|
tinybird/sql_template_fmt.py,sha256=KUHdj5rYCYm_rKKdXYSJAE9vIyXUQLB0YSZnUXHeBlY,10196
|
|
@@ -15,59 +15,59 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
|
|
|
15
15
|
tinybird/tornado_template.py,sha256=FL85SMPq2dH4JqKovmSbaolGdEzwOO91NqOzqXo2Qr0,41863
|
|
16
16
|
tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
|
|
17
17
|
tinybird/ch_utils/engine.py,sha256=OXkBhlzGjZotjD0vaT-rFIbSGV4tpiHxE8qO_ip0SyQ,40454
|
|
18
|
-
tinybird/tb/__cli__.py,sha256=
|
|
18
|
+
tinybird/tb/__cli__.py,sha256=wWCBkLJ6jQtVEUW3Uqk-4Vw4LjWoj5iFSAW3axQ9-iI,251
|
|
19
19
|
tinybird/tb/cli.py,sha256=X6zLCVI10wOxcu-USGfbp_jjz1cojH5X-9dL7D8c8aI,960
|
|
20
20
|
tinybird/tb/modules/auth.py,sha256=EzRWFmwRkXNhUmRaruEVFLdkbUg8xMSix0cAWl5D4Jg,9029
|
|
21
|
-
tinybird/tb/modules/build.py,sha256=
|
|
21
|
+
tinybird/tb/modules/build.py,sha256=lQXivX0kn3ej0CzeJK34ZFYBWAm2QB1JyPWciuH2c-Q,8060
|
|
22
22
|
tinybird/tb/modules/cicd.py,sha256=xxXwy-QekJcG14kkJeGNl7LkHduhZXfvBZE8WrU6-t4,5351
|
|
23
|
-
tinybird/tb/modules/cli.py,sha256=
|
|
24
|
-
tinybird/tb/modules/common.py,sha256=
|
|
23
|
+
tinybird/tb/modules/cli.py,sha256=yBCyRs25Z1ucuX9LnjHkVIEaPoyM8WPBsp5J6t_TCO8,17608
|
|
24
|
+
tinybird/tb/modules/common.py,sha256=TWcGJUgzJCQvzI1oMKbNdx-KTRmMGvB25BawHpsaV8Q,70610
|
|
25
25
|
tinybird/tb/modules/config.py,sha256=mie3oMVTf5YOUFEiLs88P16U4LkJafJjSpjwyAkFHog,10979
|
|
26
26
|
tinybird/tb/modules/copy.py,sha256=wxyxZg8BPiWDgbW5HXJKYQp7_EumBXmAilo3McbCQOo,5916
|
|
27
|
-
tinybird/tb/modules/create.py,sha256=
|
|
27
|
+
tinybird/tb/modules/create.py,sha256=fqEI83cENISWgFnoNPlXNsNx_R0Im-zMaL1PfJDGWUQ,14263
|
|
28
28
|
tinybird/tb/modules/datasource.py,sha256=hHt-rn4VWrQ4EWG797wnLqRhRP-3C4chAdk_vXxCmVI,13712
|
|
29
29
|
tinybird/tb/modules/deployment.py,sha256=0e00lLMaNoVnONYdA51Zy9Sa_-4jWqePoYeFyHUn5PU,10241
|
|
30
30
|
tinybird/tb/modules/endpoint.py,sha256=9arqN1JQCMb0Nd3-EJ7lukOYkGHHCpQmiiZpp5FqPhc,9432
|
|
31
31
|
tinybird/tb/modules/exceptions.py,sha256=4A2sSjCEqKUMqpP3WI00zouCWW4uLaghXXLZBSw04mY,3363
|
|
32
|
-
tinybird/tb/modules/feedback_manager.py,sha256=
|
|
32
|
+
tinybird/tb/modules/feedback_manager.py,sha256=0DSaHP4tPT1PnYVrH4N2d2vnealrBS1jI3CSMex_Us8,68572
|
|
33
33
|
tinybird/tb/modules/fmt.py,sha256=poh6_cwVGSf-sBu6LKWuO2TANL_J8Sgm25sPpwxa3Aw,3558
|
|
34
34
|
tinybird/tb/modules/job.py,sha256=956Pj8BEEsiD2GZsV9RKKVM3I_CveOLgS82lykO5ukk,2963
|
|
35
35
|
tinybird/tb/modules/llm.py,sha256=AC0VSphTOM2t-v1_3NLvNN_FIbgMo4dTyMqIv5nniPo,835
|
|
36
36
|
tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCfxvg,3469
|
|
37
37
|
tinybird/tb/modules/local.py,sha256=x4xuCGVkoa8KLYGZEJnFUP8HUkKX05Frp_djRVjVjTs,5669
|
|
38
|
-
tinybird/tb/modules/local_common.py,sha256=
|
|
38
|
+
tinybird/tb/modules/local_common.py,sha256=8Igj0Lxw5awEKGV87eJDg37UkhqLbozRcSr2dEnu_Ik,2954
|
|
39
39
|
tinybird/tb/modules/login.py,sha256=0cS-f3MsQFHc6xjw8FRWJm4EJBH9C7Ri68EcO_tiwes,6508
|
|
40
40
|
tinybird/tb/modules/materialization.py,sha256=HQKRTH6lkcYiDQJihbFqF_in58ezXG4ggZ_7Ywp_nUM,5738
|
|
41
41
|
tinybird/tb/modules/mock.py,sha256=maaPY91mQx8m9x-1-2r9svljRO8VO8-uqD-71VfXBCU,5271
|
|
42
|
-
tinybird/tb/modules/pipe.py,sha256=
|
|
42
|
+
tinybird/tb/modules/pipe.py,sha256=pH2KwgH6Xbvl3kT8vMelpKvT6bcyB4EKFDvGfOsxXbg,2418
|
|
43
43
|
tinybird/tb/modules/project.py,sha256=YH-pwioIBIYxSmy6awM6Ya6WoB7MSM2fte-x9Gbr6lc,2604
|
|
44
44
|
tinybird/tb/modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
|
|
45
|
-
tinybird/tb/modules/shell.py,sha256=
|
|
45
|
+
tinybird/tb/modules/shell.py,sha256=iVJ_TC0WEOMVacc6LximIZWHeL2RGohQKv-oU75HpL4,13018
|
|
46
46
|
tinybird/tb/modules/table.py,sha256=4XrtjM-N0zfNtxVkbvLDQQazno1EPXnxTyo7llivfXk,11035
|
|
47
47
|
tinybird/tb/modules/tag.py,sha256=anPmMUBc-TbFovlpFi8GPkKA18y7Y0GczMsMms5TZsU,3502
|
|
48
48
|
tinybird/tb/modules/telemetry.py,sha256=iEGnMuCuNhvF6ln__j6X9MSTwL_0Hm-GgFHHHvhfknk,10466
|
|
49
|
-
tinybird/tb/modules/test.py,sha256=
|
|
49
|
+
tinybird/tb/modules/test.py,sha256=s15UQg1TzYrI-9WUA7eYpQcx-BsCRTa6Oj71K-Zbcr0,13100
|
|
50
50
|
tinybird/tb/modules/token.py,sha256=sPdJoBE-6dd3Sd6W-prst7VOoJ0NbvP0uTaB6dXHs5s,12711
|
|
51
51
|
tinybird/tb/modules/update.py,sha256=GWYfbKnB0yf4ywAUp8jItaZY0ltBnaIMcLSiPpwtbMc,6832
|
|
52
52
|
tinybird/tb/modules/watch.py,sha256=Kredt5C7OOiI6YOivuR5QBdiDY4J_xLiwqHOROnfcsU,8591
|
|
53
|
-
tinybird/tb/modules/workspace.py,sha256=
|
|
53
|
+
tinybird/tb/modules/workspace.py,sha256=bSV_aMK_05LvkT-Y0kj_stoGCQu8SgUie9BuMuKcRZs,6400
|
|
54
54
|
tinybird/tb/modules/workspace_members.py,sha256=Ai6iCOzXX1zQ8q9iXIFSFHsBJlT-8Q28DaG5Ie-UweY,8726
|
|
55
55
|
tinybird/tb/modules/datafile/build.py,sha256=VgQ0k-dBNE0hXdnxB12NW5I0XpxEosN2vaszboj3LZY,51045
|
|
56
56
|
tinybird/tb/modules/datafile/build_common.py,sha256=IXl-Z51zUi1dypV7meNenX0iu2UmowNeqgG6WHyMHlk,4562
|
|
57
57
|
tinybird/tb/modules/datafile/build_datasource.py,sha256=4aP8_DYCRGghXntZSeWDNJxjps1QRVa7WHoYCzQwQts,17355
|
|
58
58
|
tinybird/tb/modules/datafile/build_pipe.py,sha256=Jgv3YKIvMfjPiSIdw1k2mpaoDdAWMiMRaSHwRgyI97E,28258
|
|
59
|
-
tinybird/tb/modules/datafile/common.py,sha256=
|
|
59
|
+
tinybird/tb/modules/datafile/common.py,sha256=rk0jHAmyl9ogWZhayVruoPihtNhNmdgCK2e4PEHadg4,78829
|
|
60
60
|
tinybird/tb/modules/datafile/diff.py,sha256=-0J7PsBO64T7LOZSkZ4ZFHHCPvT7cKItnJkbz2PkndU,6754
|
|
61
61
|
tinybird/tb/modules/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
|
|
62
62
|
tinybird/tb/modules/datafile/fixture.py,sha256=bdZndItV6ibOegPCrN3OgKdkpjDFCFvoSoiZVsCV_XQ,1852
|
|
63
63
|
tinybird/tb/modules/datafile/format_common.py,sha256=WaNV4tXrQU5gjV6MJP-5TGqg_Bre6ilNS8emvFl-X3c,1967
|
|
64
|
-
tinybird/tb/modules/datafile/format_datasource.py,sha256=
|
|
65
|
-
tinybird/tb/modules/datafile/format_pipe.py,sha256=
|
|
64
|
+
tinybird/tb/modules/datafile/format_datasource.py,sha256=gpRsGnDEMxEo0pIlEHXKvyuwKIpqJJUCN9JRSiDYs_4,6156
|
|
65
|
+
tinybird/tb/modules/datafile/format_pipe.py,sha256=58iSTrJ5lg-IsbpX8TQumQTuZ6UIotMsCIkNJd1M-pM,7418
|
|
66
66
|
tinybird/tb/modules/datafile/parse_datasource.py,sha256=kk35PzesoJOd0LKjYp4kOyCwq4Qo4TiZnoI9qcXjB4k,1519
|
|
67
67
|
tinybird/tb/modules/datafile/parse_pipe.py,sha256=N2qZOeq3hyFrSJWQbMN1rKmD71i2xDjT90oCBMJ789M,3337
|
|
68
|
-
tinybird/tb/modules/datafile/pipe_checker.py,sha256=
|
|
68
|
+
tinybird/tb/modules/datafile/pipe_checker.py,sha256=SAXxGyHXB_p7ngQ7M0sUIUmx8yKooCdPXWHk4RzTanE,24665
|
|
69
69
|
tinybird/tb/modules/datafile/pull.py,sha256=vcjMUbjnZ9XQMGmL33J3ElpbXBTat8Yzp-haeDggZd4,5967
|
|
70
|
-
tinybird/tb/modules/tinyunit/tinyunit.py,sha256=
|
|
70
|
+
tinybird/tb/modules/tinyunit/tinyunit.py,sha256=LZGrsvIAUy5O2bZtGbi9O80QGIfXe_Du8c0PDNxeQcc,11727
|
|
71
71
|
tinybird/tb/modules/tinyunit/tinyunit_lib.py,sha256=hGh1ZaXC1af7rKnX7222urkj0QJMhMWclqMy59dOqwE,1922
|
|
72
72
|
tinybird/tb_cli_modules/cicd.py,sha256=0lMkb6CVOFZl5HOwgY8mK4T4mgI7O8335UngLXtCc-c,13851
|
|
73
73
|
tinybird/tb_cli_modules/common.py,sha256=SnC_PLCJHwaFaNg7LsUtc1s5jgiD_vkglbva0D3w8RA,78833
|
|
@@ -75,8 +75,8 @@ tinybird/tb_cli_modules/config.py,sha256=6u6B5QCdiQLbJkCkwtnKGs9H3nP-KXXhC75mF7B
|
|
|
75
75
|
tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
|
|
76
76
|
tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
|
|
77
77
|
tinybird/tb_cli_modules/telemetry.py,sha256=iEGnMuCuNhvF6ln__j6X9MSTwL_0Hm-GgFHHHvhfknk,10466
|
|
78
|
-
tinybird-0.0.1.
|
|
79
|
-
tinybird-0.0.1.
|
|
80
|
-
tinybird-0.0.1.
|
|
81
|
-
tinybird-0.0.1.
|
|
82
|
-
tinybird-0.0.1.
|
|
78
|
+
tinybird-0.0.1.dev46.dist-info/METADATA,sha256=LrKDawiKiRC2LI8bb0GTS9ujjyOTKUJEfu6PT1lunXM,2482
|
|
79
|
+
tinybird-0.0.1.dev46.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
|
80
|
+
tinybird-0.0.1.dev46.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
|
|
81
|
+
tinybird-0.0.1.dev46.dist-info/top_level.txt,sha256=pgw6AzERHBcW3YTi2PW4arjxLkulk2msOz_SomfOEuc,45
|
|
82
|
+
tinybird-0.0.1.dev46.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|