tinybird 0.0.1.dev47__tar.gz → 0.0.1.dev49__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.
Potentially problematic release.
This version of tinybird might be problematic. Click here for more details.
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/client.py +1 -6
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/prompts.py +8 -61
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/cli.py +0 -1
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/build.py +22 -9
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/cli.py +18 -63
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/create.py +17 -12
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/build.py +1 -2
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/common.py +8 -10
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datasource.py +33 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/deployment.py +65 -14
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/feedback_manager.py +1 -3
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/local_common.py +8 -12
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/login.py +1 -1
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/mock.py +2 -2
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/project.py +2 -2
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/shell.py +50 -17
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/test.py +9 -8
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/workspace.py +1 -1
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird.egg-info/SOURCES.txt +0 -1
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird.egg-info/top_level.txt +1 -0
- tinybird-0.0.1.dev47/tinybird/tb/modules/update.py +0 -182
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/setup.cfg +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/config.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/connectors.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/context.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/datafile.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/sql.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/auth.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/cicd.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/common.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/config.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/copy.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/endpoint.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/fmt.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/local.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/materialization.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/pipe.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/tag.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/token.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/watch.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird/tornado_template.py +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev47 → tinybird-0.0.1.dev49}/tinybird.egg-info/requires.txt +0 -0
|
@@ -697,12 +697,7 @@ class TinyB:
|
|
|
697
697
|
if local_host != self.host:
|
|
698
698
|
return data
|
|
699
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
|
-
|
|
700
|
+
local_workspaces = [x for x in data["workspaces"] if not x["name"].startswith("Tinybird_Local_")]
|
|
706
701
|
return {**data, "workspaces": local_workspaces}
|
|
707
702
|
|
|
708
703
|
async def user_workspaces_and_branches(self):
|
|
@@ -651,32 +651,6 @@ DATASOURCE sales_by_hour
|
|
|
651
651
|
"""
|
|
652
652
|
|
|
653
653
|
|
|
654
|
-
def ask_prompt(existing_resources: str) -> str:
|
|
655
|
-
return """
|
|
656
|
-
You are a Tinybird expert. You will be given a prompt to ask questions about Tinybird resources.
|
|
657
|
-
<existing_resources>{existing_resources}</existing_resources>
|
|
658
|
-
{datasource_instructions}
|
|
659
|
-
{pipe_instructions}
|
|
660
|
-
{sql_instructions}
|
|
661
|
-
{datasource_example}
|
|
662
|
-
{pipe_example}
|
|
663
|
-
{copy_pipe_instructions}
|
|
664
|
-
{materialized_pipe_instructions}
|
|
665
|
-
|
|
666
|
-
The previous instructions are explanations of how things work in Tinybird. Answer in natural language.
|
|
667
|
-
|
|
668
|
-
""".format(
|
|
669
|
-
existing_resources=existing_resources,
|
|
670
|
-
datasource_instructions=datasource_instructions,
|
|
671
|
-
datasource_example=datasource_example,
|
|
672
|
-
pipe_instructions=pipe_instructions,
|
|
673
|
-
pipe_example=pipe_example,
|
|
674
|
-
sql_instructions=sql_instructions,
|
|
675
|
-
copy_pipe_instructions=copy_pipe_instructions,
|
|
676
|
-
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
677
|
-
)
|
|
678
|
-
|
|
679
|
-
|
|
680
654
|
datasource_instructions = """
|
|
681
655
|
<datasource_file_instructions>
|
|
682
656
|
- Content cannot be empty.
|
|
@@ -790,39 +764,6 @@ sql_instructions = """
|
|
|
790
764
|
)
|
|
791
765
|
|
|
792
766
|
|
|
793
|
-
def update_prompt(existing_resources: str) -> str:
|
|
794
|
-
return """
|
|
795
|
-
You are a Tinybird expert. You will be given a prompt to update the existing Tinybird resources: datasources and/or pipes.
|
|
796
|
-
You will return the resources that need to be updated.
|
|
797
|
-
<existing_resources>{existing_resources}</existing_resources>
|
|
798
|
-
{datasource_instructions}
|
|
799
|
-
{pipe_instructions}
|
|
800
|
-
{sql_instructions}
|
|
801
|
-
{datasource_example}
|
|
802
|
-
{pipe_example}
|
|
803
|
-
{copy_pipe_instructions}
|
|
804
|
-
{materialized_pipe_instructions}
|
|
805
|
-
Use the following format to generate the response and do not wrap it in any other text, including the <response> tag.
|
|
806
|
-
<response>
|
|
807
|
-
<resource>
|
|
808
|
-
<type>[datasource or pipe]</type>
|
|
809
|
-
<name>[resource name here]</name>
|
|
810
|
-
<content>[resource content here]</content>
|
|
811
|
-
</resource>
|
|
812
|
-
</response>
|
|
813
|
-
|
|
814
|
-
""".format(
|
|
815
|
-
existing_resources=existing_resources,
|
|
816
|
-
datasource_instructions=datasource_instructions,
|
|
817
|
-
pipe_instructions=pipe_instructions,
|
|
818
|
-
sql_instructions=sql_instructions,
|
|
819
|
-
datasource_example=datasource_example,
|
|
820
|
-
pipe_example=pipe_example,
|
|
821
|
-
copy_pipe_instructions=copy_pipe_instructions,
|
|
822
|
-
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
823
|
-
)
|
|
824
|
-
|
|
825
|
-
|
|
826
767
|
def rules_prompt(source: Optional[str] = None) -> str:
|
|
827
768
|
base_command = source or "tb"
|
|
828
769
|
return """
|
|
@@ -837,7 +778,8 @@ You have commands at your disposal to develop a tinybird project:
|
|
|
837
778
|
- {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
779
|
- {base_command} --build token ls: to list all the tokens
|
|
839
780
|
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
|
|
781
|
+
When you need to work with 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
|
|
782
|
+
When you need to work with resources or data in production, add always the --prod flag before the command. Example: {base_command} --prod datasource ls
|
|
841
783
|
</command_calling>
|
|
842
784
|
<development_instructions>
|
|
843
785
|
- When asking to create a tinybird data project, if the needed folders are not already created, use the following structure:
|
|
@@ -854,7 +796,12 @@ When you need to check resources or data in the Tinybird environment that you up
|
|
|
854
796
|
- The format of the generated api endpoint urls is: http://localhost:80/v0/pipe/<pipe_name>.json?token=<token>
|
|
855
797
|
- Before running the tests, remember to have the project built with `{base_command} build` with the latest changes.
|
|
856
798
|
</development_instructions>
|
|
857
|
-
|
|
799
|
+
When asking for ingesting data, adding data or appending data do the following depending on the environment you want to work with:
|
|
800
|
+
<ingest_data_instructions>
|
|
801
|
+
- When building locally, create a .ndjson file with the data you want to ingest and do `{base_command} build` to ingest the data in the build env.
|
|
802
|
+
- When appending data in production, use `{base_command} --prod datasource append <datasource_name> <file_name>`
|
|
803
|
+
- When you have a response that says “there are rows in quarantine”, do `{base_command} --build|--prod datasource data <datasource_name>_quarantine` to understand what is the problem.
|
|
804
|
+
</ingest_data_instructions>
|
|
858
805
|
<datasource_file_instructions>
|
|
859
806
|
Follow these instructions when creating or updating .datasource files:
|
|
860
807
|
{datasource_instructions}
|
|
@@ -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.dev49'
|
|
8
|
+
__revision__ = 'a0a2378'
|
|
@@ -23,7 +23,6 @@ import tinybird.tb.modules.pipe
|
|
|
23
23
|
import tinybird.tb.modules.tag
|
|
24
24
|
import tinybird.tb.modules.test
|
|
25
25
|
import tinybird.tb.modules.token
|
|
26
|
-
import tinybird.tb.modules.update
|
|
27
26
|
import tinybird.tb.modules.workspace
|
|
28
27
|
import tinybird.tb.modules.workspace_members
|
|
29
28
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
+
import sys
|
|
4
5
|
import threading
|
|
5
6
|
import time
|
|
6
7
|
from pathlib import Path
|
|
@@ -15,7 +16,6 @@ from tinybird.tb.modules.common import push_data
|
|
|
15
16
|
from tinybird.tb.modules.datafile.build import folder_build
|
|
16
17
|
from tinybird.tb.modules.datafile.fixture import build_fixture_name, get_fixture_dir
|
|
17
18
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
18
|
-
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
19
19
|
from tinybird.tb.modules.project import Project
|
|
20
20
|
from tinybird.tb.modules.shell import Shell, print_table_formatted
|
|
21
21
|
from tinybird.tb.modules.watch import watch_project
|
|
@@ -29,7 +29,7 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
29
29
|
Validate and build the project server side.
|
|
30
30
|
"""
|
|
31
31
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
32
|
-
tb_client =
|
|
32
|
+
tb_client: TinyB = ctx.ensure_object(dict)["client"]
|
|
33
33
|
click.echo(FeedbackManager.highlight_building_project())
|
|
34
34
|
time_start = time.time()
|
|
35
35
|
|
|
@@ -40,15 +40,21 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
40
40
|
build_project(project, tb_client, file_changed)
|
|
41
41
|
try:
|
|
42
42
|
if file_changed:
|
|
43
|
-
asyncio.run(folder_build(project, filenames=[file_changed]))
|
|
44
|
-
|
|
43
|
+
asyncio.run(folder_build(project, tb_client, filenames=[file_changed]))
|
|
44
|
+
show_data(tb_client, file_changed, diff)
|
|
45
45
|
except Exception:
|
|
46
46
|
pass
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
try:
|
|
49
|
+
process()
|
|
50
|
+
except click.ClickException as e:
|
|
51
|
+
click.echo(e)
|
|
52
|
+
if not watch:
|
|
53
|
+
sys.exit(1)
|
|
54
|
+
else:
|
|
55
|
+
time_end = time.time()
|
|
56
|
+
elapsed_time = time_end - time_start
|
|
57
|
+
click.echo(FeedbackManager.success(message=f"\n✓ Build completed in {elapsed_time:.1f}s"))
|
|
52
58
|
|
|
53
59
|
if watch:
|
|
54
60
|
shell = Shell(project=project, tb_client=tb_client)
|
|
@@ -137,9 +143,16 @@ def build_project(project: Project, tb_client: TinyB, file_changed: Optional[str
|
|
|
137
143
|
|
|
138
144
|
if fixture_path.exists():
|
|
139
145
|
append_fixture(tb_client, ds_name, str(fixture_path))
|
|
146
|
+
|
|
140
147
|
except Exception:
|
|
141
148
|
pass
|
|
142
149
|
|
|
150
|
+
feedback = result.get("feedback", [])
|
|
151
|
+
for f in feedback:
|
|
152
|
+
click.echo(
|
|
153
|
+
FeedbackManager.warning(message=f"△ {f.get('level')}: {f.get('resource')}: {f.get('message')}")
|
|
154
|
+
)
|
|
155
|
+
|
|
143
156
|
elif build_result == "failed":
|
|
144
157
|
build_errors = result.get("errors")
|
|
145
158
|
error = True
|
|
@@ -198,7 +211,7 @@ def rebuild_fixture(project: Project, tb_client: TinyB, fixture: str) -> None:
|
|
|
198
211
|
click.echo(FeedbackManager.error_exception(error=e))
|
|
199
212
|
|
|
200
213
|
|
|
201
|
-
def
|
|
214
|
+
def show_data(tb_client: TinyB, filename: str, diff: Optional[str] = None):
|
|
202
215
|
table_name = diff
|
|
203
216
|
resource_path = Path(filename)
|
|
204
217
|
resource_name = resource_path.stem
|
|
@@ -7,7 +7,6 @@ import json
|
|
|
7
7
|
import logging
|
|
8
8
|
import os
|
|
9
9
|
from os import getcwd
|
|
10
|
-
from pathlib import Path
|
|
11
10
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
12
11
|
|
|
13
12
|
import click
|
|
@@ -20,7 +19,6 @@ from tinybird.client import (
|
|
|
20
19
|
TinyB,
|
|
21
20
|
)
|
|
22
21
|
from tinybird.config import get_config
|
|
23
|
-
from tinybird.prompts import ask_prompt
|
|
24
22
|
from tinybird.tb import __cli__
|
|
25
23
|
from tinybird.tb.modules.common import (
|
|
26
24
|
CatchAuthExceptions,
|
|
@@ -37,7 +35,6 @@ from tinybird.tb.modules.datafile.build import build_graph
|
|
|
37
35
|
from tinybird.tb.modules.datafile.diff import diff_command
|
|
38
36
|
from tinybird.tb.modules.datafile.pull import folder_pull
|
|
39
37
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
40
|
-
from tinybird.tb.modules.llm import LLM
|
|
41
38
|
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
42
39
|
from tinybird.tb.modules.project import Project
|
|
43
40
|
|
|
@@ -124,13 +121,9 @@ async def cli(
|
|
|
124
121
|
|
|
125
122
|
logging.debug("debug enabled")
|
|
126
123
|
|
|
127
|
-
|
|
128
|
-
client = await create_ctx_client(config, prod, build, skip_client, project)
|
|
124
|
+
client = await create_ctx_client(ctx, config, prod, build, project)
|
|
129
125
|
|
|
130
126
|
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"))
|
|
134
127
|
ctx.ensure_object(dict)["client"] = client
|
|
135
128
|
|
|
136
129
|
ctx.ensure_object(dict)["project"] = project
|
|
@@ -358,56 +351,6 @@ async def sql(
|
|
|
358
351
|
click.echo(FeedbackManager.info_no_rows())
|
|
359
352
|
|
|
360
353
|
|
|
361
|
-
@cli.command(hidden=True)
|
|
362
|
-
@click.argument("prompt")
|
|
363
|
-
@click.option("--folder", default=os.getcwd(), help="The folder to use for the project")
|
|
364
|
-
@coro
|
|
365
|
-
async def ask(prompt: str, folder: str) -> None:
|
|
366
|
-
"""Ask things about your data project."""
|
|
367
|
-
try:
|
|
368
|
-
config = CLIConfig.get_project_config(folder)
|
|
369
|
-
user_token = config.get_user_token()
|
|
370
|
-
|
|
371
|
-
if not user_token:
|
|
372
|
-
raise CLIException("This action requires authentication. Run 'tb login' first.")
|
|
373
|
-
|
|
374
|
-
datasource_paths = [
|
|
375
|
-
Path(folder) / "datasources" / f
|
|
376
|
-
for f in os.listdir(Path(folder) / "datasources")
|
|
377
|
-
if f.endswith(".datasource")
|
|
378
|
-
]
|
|
379
|
-
pipe_folders = ["endpoints", "pipes", "copies", "materializations", "sinks"]
|
|
380
|
-
pipe_paths = [
|
|
381
|
-
Path(folder) / pipe_folder / f
|
|
382
|
-
for pipe_folder in pipe_folders
|
|
383
|
-
if (Path(folder) / pipe_folder).exists()
|
|
384
|
-
for f in os.listdir(Path(folder) / pipe_folder)
|
|
385
|
-
if f.endswith(".pipe")
|
|
386
|
-
]
|
|
387
|
-
resources_xml = "\n".join(
|
|
388
|
-
[
|
|
389
|
-
f"<resource><type>{resource_type}</type><name>{resource_name}</name><content>{resource_content}</content></resource>"
|
|
390
|
-
for resource_type, resource_name, resource_content in [
|
|
391
|
-
("datasource", ds.stem, ds.read_text()) for ds in datasource_paths
|
|
392
|
-
]
|
|
393
|
-
+ [
|
|
394
|
-
(
|
|
395
|
-
"pipe",
|
|
396
|
-
pipe.stem,
|
|
397
|
-
pipe.read_text(),
|
|
398
|
-
)
|
|
399
|
-
for pipe in pipe_paths
|
|
400
|
-
]
|
|
401
|
-
]
|
|
402
|
-
)
|
|
403
|
-
|
|
404
|
-
client = config.get_client()
|
|
405
|
-
llm = LLM(user_token=user_token, host=client.host)
|
|
406
|
-
click.echo(llm.ask(system_prompt=ask_prompt(resources_xml), prompt=prompt))
|
|
407
|
-
except Exception as e:
|
|
408
|
-
raise CLIException(FeedbackManager.error_exception(error=e))
|
|
409
|
-
|
|
410
|
-
|
|
411
354
|
def __patch_click_output():
|
|
412
355
|
import re
|
|
413
356
|
|
|
@@ -425,7 +368,7 @@ def __patch_click_output():
|
|
|
425
368
|
if isinstance(substitution, str):
|
|
426
369
|
msg = re.sub(pattern, substitution, str(msg))
|
|
427
370
|
else:
|
|
428
|
-
msg = re.sub(pattern, lambda m: substitution(m.group(0)), str(msg)) # noqa
|
|
371
|
+
msg = re.sub(pattern, lambda m: substitution(m.group(0)), str(msg)) # noqa: B023
|
|
429
372
|
return msg
|
|
430
373
|
|
|
431
374
|
def _obfuscate_echo(msg: Any, *args: Any, **kwargs: Any) -> None:
|
|
@@ -445,11 +388,23 @@ def __unpatch_click_output():
|
|
|
445
388
|
click.secho = __old_click_secho
|
|
446
389
|
|
|
447
390
|
|
|
448
|
-
async def create_ctx_client(config: Dict[str, Any], prod: bool, build: bool,
|
|
449
|
-
|
|
391
|
+
async def create_ctx_client(ctx: Context, config: Dict[str, Any], prod: bool, build: bool, project: Project):
|
|
392
|
+
commands_without_ctx_client = ["auth", "check", "login", "local"]
|
|
393
|
+
command = ctx.invoked_subcommand
|
|
394
|
+
if command in commands_without_ctx_client:
|
|
450
395
|
return None
|
|
451
396
|
|
|
452
|
-
|
|
397
|
+
commands_always_prod = ["pull"]
|
|
398
|
+
commands_always_build = ["build", "test"]
|
|
399
|
+
commands_always_local = ["create", "mock"]
|
|
400
|
+
if (
|
|
401
|
+
(prod or command in commands_always_prod)
|
|
402
|
+
and command not in commands_always_build
|
|
403
|
+
and command not in commands_always_local
|
|
404
|
+
):
|
|
405
|
+
click.echo(FeedbackManager.gray(message=f"Running against {config.get('name') or 'production'}"))
|
|
453
406
|
return _get_tb_client(config.get("token", None), config["host"])
|
|
454
|
-
|
|
407
|
+
build = command in commands_always_build or build
|
|
408
|
+
if not build and command not in commands_always_local and command not in commands_always_build:
|
|
409
|
+
click.echo(FeedbackManager.gray(message="Running against Tinybird local\n"))
|
|
455
410
|
return await get_tinybird_local_client(str(project.path), build=build)
|
|
@@ -17,7 +17,6 @@ from tinybird.tb.modules.exceptions import CLIException
|
|
|
17
17
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
18
18
|
from tinybird.tb.modules.llm import LLM
|
|
19
19
|
from tinybird.tb.modules.llm_utils import extract_xml, parse_xml
|
|
20
|
-
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
21
20
|
from tinybird.tb.modules.project import Project
|
|
22
21
|
|
|
23
22
|
|
|
@@ -41,8 +40,8 @@ from tinybird.tb.modules.project import Project
|
|
|
41
40
|
help="Folder where datafiles will be placed",
|
|
42
41
|
)
|
|
43
42
|
@click.option("--rows", type=int, default=10, help="Number of events to send")
|
|
44
|
-
@click.option("--cursor", default=False, is_flag=True, help="Create .cursorrules file with Tinybird rules")
|
|
45
43
|
@click.option("--source", type=str, default="tb", help="Source of the command")
|
|
44
|
+
@click.option("--skip", is_flag=True, default=False, help="Skip following up on the generated data")
|
|
46
45
|
@click.pass_context
|
|
47
46
|
@coro
|
|
48
47
|
async def create(
|
|
@@ -51,11 +50,12 @@ async def create(
|
|
|
51
50
|
prompt: Optional[str],
|
|
52
51
|
folder: Optional[str],
|
|
53
52
|
rows: int,
|
|
54
|
-
cursor: bool,
|
|
55
53
|
source: str,
|
|
54
|
+
skip: bool,
|
|
56
55
|
) -> None:
|
|
57
56
|
"""Initialize a new project."""
|
|
58
57
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
58
|
+
local_client: TinyB = ctx.ensure_object(dict)["client"]
|
|
59
59
|
folder = folder or getcwd()
|
|
60
60
|
folder_path = Path(folder)
|
|
61
61
|
if not folder_path.exists():
|
|
@@ -78,7 +78,6 @@ async def create(
|
|
|
78
78
|
)
|
|
79
79
|
)
|
|
80
80
|
return
|
|
81
|
-
local_client = await get_tinybird_local_client(folder)
|
|
82
81
|
|
|
83
82
|
if not validate_project_structure(folder):
|
|
84
83
|
click.echo(FeedbackManager.highlight(message="\n» Creating new project structure..."))
|
|
@@ -88,7 +87,7 @@ async def create(
|
|
|
88
87
|
result = ""
|
|
89
88
|
if data or prompt:
|
|
90
89
|
click.echo(FeedbackManager.highlight(message="\n» Creating resources..."))
|
|
91
|
-
result = await create_resources(local_client, tb_client, user_token, data, prompt, folder)
|
|
90
|
+
result = await create_resources(local_client, tb_client, user_token, data, prompt, folder, skip)
|
|
92
91
|
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
93
92
|
|
|
94
93
|
if not already_has_cicd(folder):
|
|
@@ -97,6 +96,11 @@ async def create(
|
|
|
97
96
|
await init_cicd(data_project_dir=os.path.relpath(folder))
|
|
98
97
|
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
99
98
|
|
|
99
|
+
if not already_has_cursor_rules(folder):
|
|
100
|
+
click.echo(FeedbackManager.highlight(message="\n» Creating .cursorrules..."))
|
|
101
|
+
create_rules(folder, source, "cursor")
|
|
102
|
+
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
103
|
+
|
|
100
104
|
if should_generate_fixtures(result):
|
|
101
105
|
click.echo(FeedbackManager.highlight(message="\n» Generating fixtures..."))
|
|
102
106
|
|
|
@@ -130,12 +134,6 @@ async def create(
|
|
|
130
134
|
if data:
|
|
131
135
|
persist_fixture(fixture_name, data, folder)
|
|
132
136
|
click.echo(FeedbackManager.info(message=f"✓ /fixtures/{datasource_name}"))
|
|
133
|
-
|
|
134
|
-
if cursor:
|
|
135
|
-
click.echo(FeedbackManager.highlight(message="\n» Creating .cursorrules..."))
|
|
136
|
-
create_rules(folder, source, "cursor")
|
|
137
|
-
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
138
|
-
|
|
139
137
|
except Exception as e:
|
|
140
138
|
click.echo(FeedbackManager.error(message=f"Error: {str(e)}"))
|
|
141
139
|
|
|
@@ -158,6 +156,11 @@ def already_has_cicd(folder: str) -> bool:
|
|
|
158
156
|
return any((Path(folder) / path).exists() for path in ci_cd_paths)
|
|
159
157
|
|
|
160
158
|
|
|
159
|
+
def already_has_cursor_rules(folder: str) -> bool:
|
|
160
|
+
cursor_rules_paths = (".cursorrules", ".windsurfrules")
|
|
161
|
+
return any((Path(folder) / path).exists() for path in cursor_rules_paths)
|
|
162
|
+
|
|
163
|
+
|
|
161
164
|
def create_project_structure(folder: str):
|
|
162
165
|
folder_path = Path(folder)
|
|
163
166
|
for x in PROJECT_PATHS:
|
|
@@ -176,6 +179,7 @@ async def create_resources(
|
|
|
176
179
|
data: Optional[str],
|
|
177
180
|
prompt: Optional[str],
|
|
178
181
|
folder: str,
|
|
182
|
+
skip: bool,
|
|
179
183
|
):
|
|
180
184
|
result = ""
|
|
181
185
|
folder_path = Path(folder)
|
|
@@ -285,7 +289,8 @@ TYPE ENDPOINT
|
|
|
285
289
|
content = pipe["content"].replace("```", "")
|
|
286
290
|
pipe_path = generate_pipe_file(pipe["name"], content, folder)
|
|
287
291
|
generated_paths.append(pipe_path)
|
|
288
|
-
|
|
292
|
+
if skip:
|
|
293
|
+
break
|
|
289
294
|
iterations += 1
|
|
290
295
|
|
|
291
296
|
if iterations == 10:
|
|
@@ -42,12 +42,12 @@ from tinybird.tb.modules.datafile.exceptions import AlreadyExistsException, Incl
|
|
|
42
42
|
from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
|
|
43
43
|
from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
|
|
44
44
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
45
|
-
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
46
45
|
from tinybird.tb.modules.project import Project
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
async def folder_build(
|
|
50
49
|
project: Project,
|
|
50
|
+
tb_client: TinyB,
|
|
51
51
|
filenames: Optional[List[str]] = None,
|
|
52
52
|
is_internal: bool = False,
|
|
53
53
|
is_vendor: bool = False,
|
|
@@ -67,7 +67,6 @@ async def folder_build(
|
|
|
67
67
|
fork = False
|
|
68
68
|
release_created = False
|
|
69
69
|
folder = str(project.path)
|
|
70
|
-
tb_client = await get_tinybird_local_client(folder)
|
|
71
70
|
datasources: List[Dict[str, Any]] = await tb_client.datasources()
|
|
72
71
|
pipes: List[Dict[str, Any]] = await tb_client.pipes(dependencies=True)
|
|
73
72
|
|
|
@@ -207,7 +207,7 @@ class Datafile:
|
|
|
207
207
|
# [x] SQL in all nodes
|
|
208
208
|
# [x] Materialized nodes have target datasource
|
|
209
209
|
# [x] Only one materialized node
|
|
210
|
-
# [
|
|
210
|
+
# [x] Only one node of any specific type
|
|
211
211
|
# [ ] ...
|
|
212
212
|
repeated_node_names = [
|
|
213
213
|
name for name, count in filter(lambda x: x[1] > 1, Counter(n["name"] for n in self.nodes).items())
|
|
@@ -219,16 +219,14 @@ class Datafile:
|
|
|
219
219
|
for node in self.nodes:
|
|
220
220
|
if "sql" not in node:
|
|
221
221
|
raise DatafileValidationError(f"SQL missing for node {repr(node['name'])}")
|
|
222
|
-
|
|
222
|
+
non_standard_nodes_count = 0
|
|
223
223
|
for node in self.nodes:
|
|
224
|
-
if node.get("type", "").lower()
|
|
225
|
-
|
|
226
|
-
if
|
|
227
|
-
raise DatafileValidationError("Multiple
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
f"Materialized node {repr(node['name'])} missing target datasource"
|
|
231
|
-
)
|
|
224
|
+
if node.get("type", "").lower() not in {PipeNodeTypes.STANDARD, ""}:
|
|
225
|
+
non_standard_nodes_count += 1
|
|
226
|
+
if non_standard_nodes_count > 1:
|
|
227
|
+
raise DatafileValidationError("Multiple non-standard nodes in pipe. There can only be one")
|
|
228
|
+
if node.get("type", "").lower() == PipeNodeTypes.MATERIALIZED and "datasource" not in node:
|
|
229
|
+
raise DatafileValidationError(f"Materialized node {repr(node['name'])} missing target datasource")
|
|
232
230
|
elif self.kind == DatafileKind.datasource:
|
|
233
231
|
# TODO(eclbg):
|
|
234
232
|
# [x] Just one node
|
|
@@ -358,3 +358,36 @@ async def datasource_delete_rows(ctx, datasource_name, sql_condition, yes, wait,
|
|
|
358
358
|
raise CLIDatasourceException(FeedbackManager.error_datasource_does_not_exist(datasource=datasource_name))
|
|
359
359
|
except Exception as e:
|
|
360
360
|
raise CLIDatasourceException(FeedbackManager.error_exception(error=e))
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@datasource.command(
|
|
364
|
+
name="data",
|
|
365
|
+
context_settings=dict(
|
|
366
|
+
allow_extra_args=True,
|
|
367
|
+
ignore_unknown_options=True,
|
|
368
|
+
),
|
|
369
|
+
)
|
|
370
|
+
@click.argument("datasource")
|
|
371
|
+
@click.option("--limit", type=int, default=5, help="Limit the number of rows to return")
|
|
372
|
+
@click.pass_context
|
|
373
|
+
@coro
|
|
374
|
+
async def datasource_data(ctx: Context, datasource: str, limit: int):
|
|
375
|
+
"""Print data returned by an endpoint
|
|
376
|
+
|
|
377
|
+
Syntax: tb datasource data <datasource_name>
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
381
|
+
try:
|
|
382
|
+
res = await client.query(f"SELECT * FROM {datasource} LIMIT {limit} FORMAT JSON")
|
|
383
|
+
except AuthNoTokenException:
|
|
384
|
+
raise
|
|
385
|
+
except Exception as e:
|
|
386
|
+
raise CLIDatasourceException(FeedbackManager.error_exception(error=str(e)))
|
|
387
|
+
|
|
388
|
+
if not res["data"]:
|
|
389
|
+
click.echo(FeedbackManager.info_no_rows())
|
|
390
|
+
else:
|
|
391
|
+
echo_safe_humanfriendly_tables_format_smart_table(
|
|
392
|
+
data=[d.values() for d in res["data"]], column_names=res["data"][0].keys()
|
|
393
|
+
)
|