tinybird 0.0.1.dev47__py3-none-any.whl → 0.0.1.dev49__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.
Potentially problematic release.
This version of tinybird might be problematic. Click here for more details.
- tinybird/client.py +1 -6
- tinybird/prompts.py +8 -61
- tinybird/tb/__cli__.py +2 -2
- tinybird/tb/cli.py +0 -1
- tinybird/tb/modules/build.py +22 -9
- tinybird/tb/modules/cli.py +18 -63
- tinybird/tb/modules/create.py +17 -12
- tinybird/tb/modules/datafile/build.py +1 -2
- tinybird/tb/modules/datafile/common.py +8 -10
- tinybird/tb/modules/datasource.py +33 -0
- tinybird/tb/modules/deployment.py +65 -14
- tinybird/tb/modules/feedback_manager.py +1 -3
- tinybird/tb/modules/local_common.py +8 -12
- tinybird/tb/modules/login.py +1 -1
- tinybird/tb/modules/mock.py +2 -2
- tinybird/tb/modules/project.py +2 -2
- tinybird/tb/modules/shell.py +50 -17
- tinybird/tb/modules/test.py +9 -8
- tinybird/tb/modules/workspace.py +1 -1
- {tinybird-0.0.1.dev47.dist-info → tinybird-0.0.1.dev49.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev47.dist-info → tinybird-0.0.1.dev49.dist-info}/RECORD +24 -25
- {tinybird-0.0.1.dev47.dist-info → tinybird-0.0.1.dev49.dist-info}/top_level.txt +1 -0
- tinybird/tb/modules/update.py +0 -182
- {tinybird-0.0.1.dev47.dist-info → tinybird-0.0.1.dev49.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev47.dist-info → tinybird-0.0.1.dev49.dist-info}/entry_points.txt +0 -0
tinybird/tb/modules/update.py
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import re
|
|
3
|
-
from os import getcwd
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
|
-
import click
|
|
8
|
-
|
|
9
|
-
from tinybird.client import TinyB
|
|
10
|
-
from tinybird.prompts import mock_prompt, update_prompt
|
|
11
|
-
from tinybird.tb.modules.cli import cli
|
|
12
|
-
from tinybird.tb.modules.common import check_user_token_with_client, coro, generate_datafile
|
|
13
|
-
from tinybird.tb.modules.config import CLIConfig
|
|
14
|
-
from tinybird.tb.modules.datafile.fixture import build_fixture_name, persist_fixture
|
|
15
|
-
from tinybird.tb.modules.exceptions import CLIException
|
|
16
|
-
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
17
|
-
from tinybird.tb.modules.llm import LLM
|
|
18
|
-
from tinybird.tb.modules.llm_utils import extract_xml, parse_xml
|
|
19
|
-
from tinybird.tb.modules.local_common import get_tinybird_local_client
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@cli.command(hidden=True)
|
|
23
|
-
@click.argument("prompt")
|
|
24
|
-
@click.option(
|
|
25
|
-
"--folder",
|
|
26
|
-
default=".",
|
|
27
|
-
type=click.Path(exists=False, file_okay=False),
|
|
28
|
-
help="Folder where project files will be placed",
|
|
29
|
-
)
|
|
30
|
-
@coro
|
|
31
|
-
async def update(
|
|
32
|
-
prompt: str,
|
|
33
|
-
folder: str,
|
|
34
|
-
) -> None:
|
|
35
|
-
"""Update resources in the project."""
|
|
36
|
-
folder = folder or getcwd()
|
|
37
|
-
folder_path = Path(folder)
|
|
38
|
-
if not folder_path.exists():
|
|
39
|
-
folder_path.mkdir()
|
|
40
|
-
|
|
41
|
-
try:
|
|
42
|
-
config = CLIConfig.get_project_config(folder)
|
|
43
|
-
tb_client = config.get_client()
|
|
44
|
-
user_token: Optional[str] = None
|
|
45
|
-
try:
|
|
46
|
-
user_token = config.get_user_token()
|
|
47
|
-
if not user_token:
|
|
48
|
-
raise CLIException("No user token found")
|
|
49
|
-
await check_user_token_with_client(tb_client, token=user_token)
|
|
50
|
-
except Exception as e:
|
|
51
|
-
click.echo(
|
|
52
|
-
FeedbackManager.error(message=f"This action requires authentication. Run 'tb login' first. Error: {e}")
|
|
53
|
-
)
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
local_client = await get_tinybird_local_client(folder)
|
|
57
|
-
|
|
58
|
-
click.echo(FeedbackManager.highlight(message="\n» Updating resources..."))
|
|
59
|
-
datasources_updated = await update_resources(tb_client, user_token, prompt, folder)
|
|
60
|
-
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
61
|
-
|
|
62
|
-
if datasources_updated and user_token:
|
|
63
|
-
click.echo(FeedbackManager.highlight(message="\n» Generating fixtures..."))
|
|
64
|
-
|
|
65
|
-
datasource_files = [f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")]
|
|
66
|
-
for datasource_file in datasource_files:
|
|
67
|
-
datasource_path = Path(folder) / "datasources" / datasource_file
|
|
68
|
-
llm = LLM(user_token=user_token, host=tb_client.host)
|
|
69
|
-
datasource_name = datasource_path.stem
|
|
70
|
-
datasource_content = datasource_path.read_text()
|
|
71
|
-
has_json_path = "`json:" in datasource_content
|
|
72
|
-
if has_json_path:
|
|
73
|
-
prompt = f"<datasource_schema>{datasource_content}</datasource_schema>\n<user_input>{prompt}</user_input>"
|
|
74
|
-
response = llm.ask(system_prompt=mock_prompt(rows=20), prompt=prompt)
|
|
75
|
-
sql = extract_xml(response, "sql")
|
|
76
|
-
sql = sql.split("FORMAT")[0]
|
|
77
|
-
result = await local_client.query(f"{sql} FORMAT JSON")
|
|
78
|
-
data = result.get("data", [])
|
|
79
|
-
fixture_name = build_fixture_name(
|
|
80
|
-
datasource_path.absolute().as_posix(), datasource_name, datasource_content
|
|
81
|
-
)
|
|
82
|
-
if data:
|
|
83
|
-
persist_fixture(fixture_name, data, folder)
|
|
84
|
-
click.echo(FeedbackManager.info(message=f"✓ /fixtures/{datasource_name}"))
|
|
85
|
-
|
|
86
|
-
click.echo(FeedbackManager.success(message="✓ Done!\n"))
|
|
87
|
-
except Exception as e:
|
|
88
|
-
click.echo(FeedbackManager.error(message=f"Error: {str(e)}"))
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
async def update_resources(
|
|
92
|
-
tb_client: TinyB,
|
|
93
|
-
user_token: str,
|
|
94
|
-
prompt: str,
|
|
95
|
-
folder: str,
|
|
96
|
-
):
|
|
97
|
-
datasource_paths = [
|
|
98
|
-
Path(folder) / "datasources" / f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")
|
|
99
|
-
]
|
|
100
|
-
pipes_paths = [
|
|
101
|
-
Path(folder) / "endpoints" / f for f in os.listdir(Path(folder) / "endpoints") if f.endswith(".pipe")
|
|
102
|
-
]
|
|
103
|
-
resources_xml = "\n".join(
|
|
104
|
-
[
|
|
105
|
-
f"<resource><type>{resource_type}</type><name>{resource_name}</name><content>{resource_content}</content></resource>"
|
|
106
|
-
for resource_type, resource_name, resource_content in [
|
|
107
|
-
("datasource", ds.stem, ds.read_text()) for ds in datasource_paths
|
|
108
|
-
]
|
|
109
|
-
+ [
|
|
110
|
-
(
|
|
111
|
-
"pipe",
|
|
112
|
-
pipe.stem,
|
|
113
|
-
pipe.read_text(),
|
|
114
|
-
)
|
|
115
|
-
for pipe in pipes_paths
|
|
116
|
-
]
|
|
117
|
-
]
|
|
118
|
-
)
|
|
119
|
-
llm = LLM(user_token=user_token, host=tb_client.host)
|
|
120
|
-
result = llm.ask(system_prompt=update_prompt(resources_xml), prompt=prompt)
|
|
121
|
-
result = extract_xml(result, "response")
|
|
122
|
-
resources = parse_xml(result, "resource")
|
|
123
|
-
datasources = []
|
|
124
|
-
pipes = []
|
|
125
|
-
for resource_xml in resources:
|
|
126
|
-
resource_type = extract_xml(resource_xml, "type")
|
|
127
|
-
name = extract_xml(resource_xml, "name")
|
|
128
|
-
content = extract_xml(resource_xml, "content")
|
|
129
|
-
resource = {
|
|
130
|
-
"name": name,
|
|
131
|
-
"content": content,
|
|
132
|
-
}
|
|
133
|
-
if resource_type.lower() == "datasource":
|
|
134
|
-
datasources.append(resource)
|
|
135
|
-
elif resource_type.lower() == "pipe":
|
|
136
|
-
pipes.append(resource)
|
|
137
|
-
|
|
138
|
-
for ds in datasources:
|
|
139
|
-
content = ds["content"].replace("```", "")
|
|
140
|
-
filename = f"{ds['name']}.datasource"
|
|
141
|
-
generate_datafile(
|
|
142
|
-
content,
|
|
143
|
-
filename=filename,
|
|
144
|
-
data=None,
|
|
145
|
-
_format="ndjson",
|
|
146
|
-
force=True,
|
|
147
|
-
folder=folder,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
for pipe in pipes:
|
|
151
|
-
content = pipe["content"].replace("```", "")
|
|
152
|
-
generate_pipe_file(pipe["name"], content, folder)
|
|
153
|
-
|
|
154
|
-
return len(datasources) > 0
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def generate_pipe_file(name: str, content: str, folder: str):
|
|
158
|
-
def is_copy(content: str) -> bool:
|
|
159
|
-
return re.search(r"TYPE copy", content, re.IGNORECASE) is not None
|
|
160
|
-
|
|
161
|
-
def is_materialization(content: str) -> bool:
|
|
162
|
-
return re.search(r"TYPE materialized", content, re.IGNORECASE) is not None
|
|
163
|
-
|
|
164
|
-
def is_sink(content: str) -> bool:
|
|
165
|
-
return re.search(r"TYPE sink", content, re.IGNORECASE) is not None
|
|
166
|
-
|
|
167
|
-
if is_copy(content):
|
|
168
|
-
pathname = "copies"
|
|
169
|
-
elif is_materialization(content):
|
|
170
|
-
pathname = "materializations"
|
|
171
|
-
elif is_sink(content):
|
|
172
|
-
pathname = "sinks"
|
|
173
|
-
else:
|
|
174
|
-
pathname = "endpoints"
|
|
175
|
-
|
|
176
|
-
base = Path(folder) / pathname
|
|
177
|
-
if not base.exists():
|
|
178
|
-
base = Path()
|
|
179
|
-
f = base / (f"{name}.pipe")
|
|
180
|
-
with open(f"{f}", "w") as file:
|
|
181
|
-
file.write(content)
|
|
182
|
-
click.echo(FeedbackManager.info_file_created(file=f.relative_to(folder)))
|
|
File without changes
|
|
File without changes
|