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.

@@ -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)))