tinybird 0.0.1.dev112__py3-none-any.whl → 0.0.1.dev114__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/prompts.py CHANGED
@@ -954,3 +954,35 @@ FORWARD_QUERY >
954
954
  </forward_query_example>
955
955
  </deployment_instruction>
956
956
  """
957
+
958
+
959
+ def readme_prompt(readme: str, host: str, token: str, resources_xml: str) -> str:
960
+ return f"""
961
+ You are an expert in SQL and Tinybird. Follow these instructions to generate a new README.md file for a tinybird project:
962
+ Current README.md file:
963
+ <current_resources_xml>
964
+ {resources_xml}
965
+ </current_resources_xml>
966
+ <readme>{readme}</readme>
967
+ <readme_instructions>
968
+ - If it is not present in the current readme, generate a new ## Tinybird section with the following content:
969
+ - ### Overview section:
970
+ - Explaining the purpose of the project.
971
+ - ### Data sources section:
972
+ - Explaining the purpose of each datasource.
973
+ - Add a snippet of how to ingest data into each datasource like the following (where the payload example matches the datasource schema respecting non-nullable types):
974
+ curl -X POST "{host}/v0/events?name=events" \
975
+ -H "Authorization: Bearer {token}" \
976
+ -d '{{"date":"2025-01-31","id":"123","user_id":"abc"}}'
977
+ - ### Endpoints section:
978
+ - Explaining the purpose of each endpoint.
979
+ - Add a snippet of how to use each endpoint like the following:
980
+ curl -X GET "{host}/v0/pipes/pipe_name.json?token={token}"
981
+ - DateTime parameters must be formatted as YYYY-MM-DD HH:MM:SS, or else will fail.
982
+ - Do not include any other extra info related to Tinybird just maintain the existing one in the <readme> tag.
983
+ - Make sure the API host is correct, {host}.
984
+ - It is mandatory to return a <resource> tag with type "readme" in the response.
985
+ - The response must follow the following format:
986
+ <readme>[readme content here]</readme>
987
+ </readme_instructions>
988
+ """
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.dev112'
8
- __revision__ = 'eb9e376'
7
+ __version__ = '0.0.1.dev114'
8
+ __revision__ = '9878107'
tinybird/tb/cli.py CHANGED
@@ -24,7 +24,6 @@ import tinybird.tb.modules.materialization
24
24
  import tinybird.tb.modules.mock
25
25
  import tinybird.tb.modules.open
26
26
  import tinybird.tb.modules.pipe
27
- import tinybird.tb.modules.playground
28
27
  import tinybird.tb.modules.secret
29
28
  import tinybird.tb.modules.tag
30
29
  import tinybird.tb.modules.test
@@ -4,23 +4,30 @@ import logging
4
4
  import sys
5
5
  import threading
6
6
  import time
7
+ from copy import deepcopy
7
8
  from functools import partial
8
9
  from pathlib import Path
9
- from typing import Callable, Optional
10
+ from typing import Callable, List, Optional
10
11
  from urllib.parse import urlencode
11
12
 
12
13
  import click
13
14
  import requests
14
15
 
16
+ import tinybird.context as context
15
17
  from tinybird.client import TinyB
16
18
  from tinybird.tb.modules.cli import cli
17
19
  from tinybird.tb.modules.common import push_data
20
+ from tinybird.tb.modules.config import CLIConfig
18
21
  from tinybird.tb.modules.datafile.build import folder_build
22
+ from tinybird.tb.modules.datafile.exceptions import ParseException
19
23
  from tinybird.tb.modules.datafile.fixture import get_fixture_dir, persist_fixture
24
+ from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
25
+ from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
26
+ from tinybird.tb.modules.datafile.playground import folder_playground
20
27
  from tinybird.tb.modules.feedback_manager import FeedbackManager
21
28
  from tinybird.tb.modules.project import Project
22
29
  from tinybird.tb.modules.shell import Shell, print_table_formatted
23
- from tinybird.tb.modules.watch import watch_project
30
+ from tinybird.tb.modules.watch import watch_files, watch_project
24
31
 
25
32
 
26
33
  @cli.command()
@@ -43,8 +50,12 @@ def build(ctx: click.Context, watch: bool) -> None:
43
50
 
44
51
 
45
52
  @cli.command("dev", help="Build the project server side and watch for changes.")
53
+ @click.option("--data-origin", type=str, default="", help="Data origin: local or cloud")
46
54
  @click.pass_context
47
- def dev(ctx: click.Context) -> None:
55
+ def dev(ctx: click.Context, data_origin: str) -> None:
56
+ if data_origin == "cloud":
57
+ return dev_cloud(ctx)
58
+
48
59
  project: Project = ctx.ensure_object(dict)["project"]
49
60
  tb_client: TinyB = ctx.ensure_object(dict)["client"]
50
61
  click.echo(FeedbackManager.highlight_building_project())
@@ -284,3 +295,113 @@ def rebuild_fixture_sql(project: Project, tb_client: TinyB, sql_file: str) -> No
284
295
  result = asyncio.run(tb_client.query(f"{sql} FORMAT JSON"))
285
296
  data = result.get("data", [])
286
297
  persist_fixture(datasource_name, data, project.folder)
298
+
299
+
300
+ def is_vendor(f: Path) -> bool:
301
+ return f.parts[0] == "vendor"
302
+
303
+
304
+ def get_vendor_workspace(f: Path) -> str:
305
+ return f.parts[1]
306
+
307
+
308
+ def is_endpoint(f: Path) -> bool:
309
+ return f.suffix == ".pipe" and not is_vendor(f) and f.parts[0] == "endpoints"
310
+
311
+
312
+ def is_pipe(f: Path) -> bool:
313
+ return f.suffix == ".pipe" and not is_vendor(f)
314
+
315
+
316
+ def check_filenames(filenames: List[str]):
317
+ parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
318
+ incl_suffix = ".incl"
319
+
320
+ for filename in filenames:
321
+ file_suffix = Path(filename).suffix
322
+ if file_suffix == incl_suffix:
323
+ continue
324
+
325
+ parser = parser_matrix.get(file_suffix)
326
+ if not parser:
327
+ raise ParseException(FeedbackManager.error_unsupported_datafile(extension=file_suffix))
328
+
329
+ parser(filename)
330
+
331
+
332
+ def dev_cloud(
333
+ ctx: click.Context,
334
+ ) -> None:
335
+ project: Project = ctx.ensure_object(dict)["project"]
336
+ config = CLIConfig.get_project_config()
337
+ tb_client: TinyB = config.get_client()
338
+ context.disable_template_security_validation.set(True)
339
+
340
+ async def process(filenames: List[str], watch: bool = False):
341
+ datafiles = [f for f in filenames if f.endswith(".datasource") or f.endswith(".pipe")]
342
+ if len(datafiles) > 0:
343
+ check_filenames(filenames=datafiles)
344
+ await folder_playground(
345
+ project, config, tb_client, filenames=datafiles, is_internal=False, current_ws=None, local_ws=None
346
+ )
347
+ if len(filenames) > 0 and watch:
348
+ filename = filenames[0]
349
+ await build_and_print_resource(config, tb_client, filename)
350
+
351
+ datafiles = project.get_project_files()
352
+ filenames = datafiles
353
+
354
+ async def build_once(filenames: List[str]):
355
+ ok = False
356
+ try:
357
+ click.echo(FeedbackManager.highlight(message="» Building project...\n"))
358
+ time_start = time.time()
359
+ await process(filenames=filenames, watch=False)
360
+ time_end = time.time()
361
+ elapsed_time = time_end - time_start
362
+
363
+ click.echo(FeedbackManager.success(message=f"\n✓ Build completed in {elapsed_time:.1f}s"))
364
+ ok = True
365
+ except Exception as e:
366
+ error_path = Path(".tb_error.txt")
367
+ if error_path.exists():
368
+ content = error_path.read_text()
369
+ content += f"\n\n{str(e)}"
370
+ error_path.write_text(content)
371
+ else:
372
+ error_path.write_text(str(e))
373
+ click.echo(FeedbackManager.error_exception(error=e))
374
+ ok = False
375
+ return ok
376
+
377
+ build_ok = asyncio.run(build_once(filenames))
378
+
379
+ shell = Shell(project=project, tb_client=tb_client, playground=True)
380
+ click.echo(FeedbackManager.gray(message="\nWatching for changes..."))
381
+ watcher_thread = threading.Thread(
382
+ target=watch_files, args=(filenames, process, shell, project, build_ok), daemon=True
383
+ )
384
+ watcher_thread.start()
385
+ shell.run()
386
+
387
+
388
+ async def build_and_print_resource(config: CLIConfig, tb_client: TinyB, filename: str):
389
+ resource_path = Path(filename)
390
+ name = resource_path.stem
391
+ playground_name = name if filename.endswith(".pipe") else None
392
+ user_client = deepcopy(tb_client)
393
+ user_client.token = config.get_user_token() or ""
394
+ cli_params = {}
395
+ cli_params["workspace_id"] = config.get("id", None)
396
+ data = await user_client._req(f"/v0/playgrounds?{urlencode(cli_params)}")
397
+ playgrounds = data["playgrounds"]
398
+ playground = next((p for p in playgrounds if p["name"] == (f"{playground_name}" + "__tb__playground")), None)
399
+ if not playground:
400
+ return
401
+ playground_id = playground["id"]
402
+ last_node = playground["nodes"][-1]
403
+ if not last_node:
404
+ return
405
+ node_sql = last_node["sql"]
406
+ res = await tb_client.query(f"{node_sql} FORMAT JSON", playground=playground_id)
407
+ print_table_formatted(res, name)
@@ -120,7 +120,9 @@ tinybird_ci_workflow:
120
120
  services:
121
121
  - name: tinybirdco/tinybird-local:beta
122
122
  alias: tinybird-local
123
+ """
123
124
 
125
+ GITLAB_CD_YML = """
124
126
  tinybird_cd_workflow:
125
127
  image: ubuntu:latest
126
128
  stage: deploy
@@ -217,6 +219,11 @@ class GitLabCICDGenerator(CICDGeneratorBase):
217
219
  file_name="tinybird-ci.yml",
218
220
  dir_path=".gitlab/tinybird",
219
221
  ),
222
+ CICDFile(
223
+ template=GITLAB_CD_YML,
224
+ file_name="tinybird-cd.yml",
225
+ dir_path=".gitlab/tinybird",
226
+ ),
220
227
  ]
221
228
 
222
229
 
@@ -372,7 +372,7 @@ async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, b
372
372
  if command in commands_without_ctx_client:
373
373
  return None
374
374
 
375
- commands_always_cloud = ["pull", "playground", "infra"]
375
+ commands_always_cloud = ["pull", "infra"]
376
376
  commands_always_build = ["build", "test", "dev", "create"]
377
377
  commands_always_local: List[str] = []
378
378
  if (
@@ -6,7 +6,7 @@ from typing import Optional, Tuple
6
6
  import click
7
7
 
8
8
  from tinybird.client import TinyB
9
- from tinybird.prompts import create_prompt, mock_prompt, rules_prompt
9
+ from tinybird.prompts import create_prompt, mock_prompt, readme_prompt, rules_prompt
10
10
  from tinybird.tb.modules.cicd import init_cicd
11
11
  from tinybird.tb.modules.cli import cli
12
12
  from tinybird.tb.modules.common import _generate_datafile, coro, generate_datafile
@@ -88,12 +88,32 @@ async def create(
88
88
  click.echo(FeedbackManager.success(message="✓ Scaffolding completed!\n"))
89
89
  created_something = True
90
90
  result = ""
91
- if data or prompt:
91
+ if (data or prompt) and user_token:
92
92
  click.echo(FeedbackManager.highlight(message="\n» Creating resources..."))
93
93
  result, created_something = await create_resources(
94
94
  local_client, tb_client, user_token, data, prompt, folder
95
95
  )
96
96
  click.echo(FeedbackManager.success(message="✓ Done!\n"))
97
+ if prompt:
98
+ readme_path = Path(root_folder) / "README.md"
99
+ if readme_path.exists():
100
+ click.echo(FeedbackManager.highlight(message="\n» Updating README.md..."))
101
+ else:
102
+ click.echo(FeedbackManager.highlight(message="\n» Creating README.md..."))
103
+ readme_path.touch()
104
+ llm = LLM(user_token=str(user_token), host=tb_client.host)
105
+ readme_user_prompt = prompt or ""
106
+ all_resources_xml = get_resources_xml(project)
107
+ readme_response = llm.ask(
108
+ system_prompt=readme_prompt(
109
+ readme_path.read_text(), tb_client.host, tb_client.token, all_resources_xml
110
+ ),
111
+ prompt=readme_user_prompt,
112
+ )
113
+ readme_result = extract_xml(readme_response, "readme")
114
+ readme_path.write_text(readme_result)
115
+ click.echo(FeedbackManager.success(message="✓ Done!\n"))
116
+ created_something = True
97
117
 
98
118
  if not already_has_cicd(root_folder):
99
119
  click.echo(FeedbackManager.highlight(message="\n» Creating CI/CD files for GitHub and GitLab..."))
@@ -390,3 +410,30 @@ def get_context() -> str:
390
410
  def save_context(prompt: str, feedback: str):
391
411
  context_file = get_context_file()
392
412
  context_file.write_text(f"- {prompt}\n{feedback}")
413
+
414
+
415
+ def get_resources_xml(project: Project) -> str:
416
+ folder = project.folder
417
+ datasource_paths = [
418
+ Path(folder) / "datasources" / f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")
419
+ ]
420
+ pipes_paths = [
421
+ Path(folder) / "endpoints" / f for f in os.listdir(Path(folder) / "endpoints") if f.endswith(".pipe")
422
+ ]
423
+ resources_xml = "\n".join(
424
+ [
425
+ f"<resource><type>{resource_type}</type><name>{resource_name}</name><content>{resource_content}</content></resource>"
426
+ for resource_type, resource_name, resource_content in [
427
+ ("datasource", ds.stem, ds.read_text()) for ds in datasource_paths
428
+ ]
429
+ + [
430
+ (
431
+ "pipe",
432
+ pipe.stem,
433
+ pipe.read_text(),
434
+ )
435
+ for pipe in pipes_paths
436
+ ]
437
+ ]
438
+ )
439
+ return resources_xml
@@ -5,7 +5,9 @@ from tinybird.tb.modules.common import format_data_to_ndjson
5
5
 
6
6
 
7
7
  def get_fixture_dir(folder: str) -> Path:
8
- return Path(folder) / "fixtures"
8
+ fixture_dir = Path(folder) / "fixtures"
9
+ fixture_dir.mkdir(exist_ok=True)
10
+ return fixture_dir
9
11
 
10
12
 
11
13
  def persist_fixture_sql(fixture_name: str, sql: str, folder: str) -> Path:
@@ -371,7 +371,7 @@ async def infra_init(
371
371
 
372
372
  # Create infra directory if it doesn't exist
373
373
  infra_dir = Path(f"infra/{cloud_provider}")
374
- infra_dir.mkdir(exist_ok=True)
374
+ infra_dir.mkdir(parents=True, exist_ok=True)
375
375
  yaml_path = infra_dir / "k8s.yaml"
376
376
  tf_path = infra_dir / "main.tf"
377
377
  config_path = infra_dir / "config.json"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev112
3
+ Version: 0.0.1.dev114
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -6,7 +6,7 @@ tinybird/context.py,sha256=FfqYfrGX_I7PKGTQo93utaKPDNVYWelg4Hsp3evX5wM,1291
6
6
  tinybird/datatypes.py,sha256=XNypumfqNjsvLJ5iNXnbVHRvAJe0aQwI3lS6Cxox-e0,10979
7
7
  tinybird/feedback_manager.py,sha256=a_ZhFX2zcB7vRknIcmHKMdQbb0c7TqlTBQ_5hPuWh88,69267
8
8
  tinybird/git_settings.py,sha256=Sw_8rGmribEFJ4Z_6idrVytxpFYk7ez8ei0qHULzs3E,3934
9
- tinybird/prompts.py,sha256=0i4Bzg-60lV6NlrQ1Vu6NZ_2we3GqV3rExu77YfA0V4,33889
9
+ tinybird/prompts.py,sha256=6J-dE0gOSOaIwdEwJUhEQS1Ztllz_qZnpnrv-tDoJWA,35511
10
10
  tinybird/sql.py,sha256=C_B81wwv3BsqyXGhF5oTk9DcTUkrp7NwIFqSzd3Dmjc,47854
11
11
  tinybird/sql_template.py,sha256=mK0yeRFctbXTAu0VNMjIzoFBJoh9PoniAVgEatA5SG4,99832
12
12
  tinybird/sql_template_fmt.py,sha256=KUHdj5rYCYm_rKKdXYSJAE9vIyXUQLB0YSZnUXHeBlY,10196
@@ -15,24 +15,24 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
15
15
  tinybird/tornado_template.py,sha256=jjNVDMnkYFWXflmT8KU_Ssbo5vR8KQq3EJMk5vYgXRw,41959
16
16
  tinybird/ch_utils/constants.py,sha256=aYvg2C_WxYWsnqPdZB1ZFoIr8ZY-XjUXYyHKE9Ansj0,3890
17
17
  tinybird/ch_utils/engine.py,sha256=BZuPM7MFS7vaEKK5tOMR2bwSAgJudPrJt27uVEwZmTY,40512
18
- tinybird/tb/__cli__.py,sha256=XBYsgERHHC2rSmVZ_I1ovdmeZxmG3you6UQuNA4-qR4,252
19
- tinybird/tb/cli.py,sha256=H_HaZhkimKgkryYXpBjHfY9Qtg-ZORiONU3psDNpzDk,1135
18
+ tinybird/tb/__cli__.py,sha256=oSBzIf8CfiivgRMZVJ4qnjLtMX0xrIl0cX3SL-V8eJg,252
19
+ tinybird/tb/cli.py,sha256=uDLwcbwSJfVFw-pceijZJqaq26z5jNsey0QaUGFjt7w,1097
20
20
  tinybird/tb/modules/auth.py,sha256=L1IatO2arRSzys3t8px8xVt8uPWUL5EVD0sFzAV_uVU,9022
21
- tinybird/tb/modules/build.py,sha256=h5drdmDFX8NHts9dA2Zepao7KSgMAl3DZGyFufVZP78,11085
22
- tinybird/tb/modules/cicd.py,sha256=k2hCout_N1g_rRAMWo_cf9tAGiJ1Puu5eiTV2DPob20,6939
23
- tinybird/tb/modules/cli.py,sha256=sZEYoJVfqN6zaCSN5NQRrzQLXxeJ5nDO7EnFXit9qh8,16157
21
+ tinybird/tb/modules/build.py,sha256=Lx1Q-kcxJN0G3pN3qCD8c8RmTpsmMoxCPhmn4DS2QMM,15563
22
+ tinybird/tb/modules/cicd.py,sha256=A7zJZF9HkJ6NPokplgNjmefMrpUlRbFxBbjMZhq5OTI,7110
23
+ tinybird/tb/modules/cli.py,sha256=cyvTGb17eWHdfI61Rom0ooD5D2aI1gRqx2nSi1gqtWA,16143
24
24
  tinybird/tb/modules/common.py,sha256=d2kkXrkoMBmh_CirBBgLw1E1_cxKUUB3ZE_Mx1x9tww,81717
25
25
  tinybird/tb/modules/config.py,sha256=FqdLpLaKpYubqw3xkB4EX06ufZYDgGRxONR_9i-y-KE,11416
26
26
  tinybird/tb/modules/connection.py,sha256=IL095_8ideKM1Ueen3BdsYvJKA05VAdpv7bSQjhXKJo,5354
27
27
  tinybird/tb/modules/copy.py,sha256=MAVqKip8_QhOYq99U_XuqSO6hCLJEh5sFtbhcXtI3SI,5802
28
- tinybird/tb/modules/create.py,sha256=3Yz257QM7c8OgWlVRacnNXFkZPsDQFNLzJSVr83Xe70,14335
28
+ tinybird/tb/modules/create.py,sha256=hIFZeaVKxNij80jKMWT9Pq9M-Uoo2hoUXfb1VdD5H_8,16401
29
29
  tinybird/tb/modules/datasource.py,sha256=dNCK9iCR2xPLfwqqwg2ixyE6NuoVEiJU2mBZBmOYrVY,16906
30
30
  tinybird/tb/modules/deployment.py,sha256=UIW3W0qKBRk2o4gE8WDjmq9-UkrNZjtkbyKvcQR203k,19515
31
31
  tinybird/tb/modules/endpoint.py,sha256=EhVoGAXsFz-83Fiwj1gI-I73iRRvL49d0W81un7hvPE,12080
32
32
  tinybird/tb/modules/exceptions.py,sha256=4A2sSjCEqKUMqpP3WI00zouCWW4uLaghXXLZBSw04mY,3363
33
33
  tinybird/tb/modules/feedback_manager.py,sha256=7e-O-LyTi_hTln47Y_FuSWerggZQLUGqfTJeYK6D9i4,69479
34
34
  tinybird/tb/modules/fmt.py,sha256=qpf9APqKTKL2uphNgdbj4OMVyLkAxZn6dn4eHF99L5g,3553
35
- tinybird/tb/modules/infra.py,sha256=GA5xnYLlVItPfJu_3_5NIdHQDuyfk2Z71wtcn9NncGA,33189
35
+ tinybird/tb/modules/infra.py,sha256=fnbsfx8paRE8RHPbjdSOiOEvtyQbJ95OrHZuCighgKA,33203
36
36
  tinybird/tb/modules/job.py,sha256=956Pj8BEEsiD2GZsV9RKKVM3I_CveOLgS82lykO5ukk,2963
37
37
  tinybird/tb/modules/llm.py,sha256=AC0VSphTOM2t-v1_3NLvNN_FIbgMo4dTyMqIv5nniPo,835
38
38
  tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCfxvg,3469
@@ -44,7 +44,6 @@ tinybird/tb/modules/materialization.py,sha256=r8Q9HXcYEmfrEzP4WpiasCKDJdSkTPaAKJ
44
44
  tinybird/tb/modules/mock.py,sha256=2E26N8TMK1sP7eRc9N1nODdc_vU1jBeGRs8e-fbQ5Dc,4516
45
45
  tinybird/tb/modules/open.py,sha256=s3eJLFtF6OnXX5OLZzBz58dYaG-TGDCYFSJHttm919g,1317
46
46
  tinybird/tb/modules/pipe.py,sha256=gcLz0qHgwKDLsWFY3yFLO9a0ETAV1dFbI8YeLHi9460,2429
47
- tinybird/tb/modules/playground.py,sha256=bN0whphoSO6p1_u3b6OAUoc3ieG5Cl3qNXwt2HcUOp8,4834
48
47
  tinybird/tb/modules/project.py,sha256=Jpoi-3ybIixN8bHCqOMnuaKByXjrdN_Gvlpa24L-e4U,3124
49
48
  tinybird/tb/modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
50
49
  tinybird/tb/modules/secret.py,sha256=xxzfKxfFN7GORib1WslCaFDHt_dgnjmfOewyptPU_VM,2820
@@ -64,7 +63,7 @@ tinybird/tb/modules/datafile/build_pipe.py,sha256=w-Wd08gZYAEcak9FdBijVfIU2_Wn_P
64
63
  tinybird/tb/modules/datafile/common.py,sha256=4pvW92X9BXomaN3-WhQOjvnAHY96O4dTsp4USBdknzk,83192
65
64
  tinybird/tb/modules/datafile/diff.py,sha256=-0J7PsBO64T7LOZSkZ4ZFHHCPvT7cKItnJkbz2PkndU,6754
66
65
  tinybird/tb/modules/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
67
- tinybird/tb/modules/datafile/fixture.py,sha256=si-9LB-LdKQSWDtVW82xDrHtFfko5bgBG1cvjqqrcPU,1064
66
+ tinybird/tb/modules/datafile/fixture.py,sha256=V3WGfPLIR78el3oCNWNkySWs6LxIufyIM0mDrrT3aWc,1131
68
67
  tinybird/tb/modules/datafile/format_common.py,sha256=WaNV4tXrQU5gjV6MJP-5TGqg_Bre6ilNS8emvFl-X3c,1967
69
68
  tinybird/tb/modules/datafile/format_datasource.py,sha256=gpRsGnDEMxEo0pIlEHXKvyuwKIpqJJUCN9JRSiDYs_4,6156
70
69
  tinybird/tb/modules/datafile/format_pipe.py,sha256=58iSTrJ5lg-IsbpX8TQumQTuZ6UIotMsCIkNJd1M-pM,7418
@@ -81,8 +80,8 @@ tinybird/tb_cli_modules/config.py,sha256=IsgdtFRnUrkY8-Zo32lmk6O7u3bHie1QCxLwgp4
81
80
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
82
81
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
83
82
  tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
84
- tinybird-0.0.1.dev112.dist-info/METADATA,sha256=qVwK9fWPocmfDDsDhlUcPh61jVOZhCV7vZAgMzLn-xs,1612
85
- tinybird-0.0.1.dev112.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
86
- tinybird-0.0.1.dev112.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
87
- tinybird-0.0.1.dev112.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
88
- tinybird-0.0.1.dev112.dist-info/RECORD,,
83
+ tinybird-0.0.1.dev114.dist-info/METADATA,sha256=Ux1FdUuaSZl8cASQfvbIVk6DzZ-aTQOhWcPvmqCDWUI,1612
84
+ tinybird-0.0.1.dev114.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
85
+ tinybird-0.0.1.dev114.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
86
+ tinybird-0.0.1.dev114.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
87
+ tinybird-0.0.1.dev114.dist-info/RECORD,,
@@ -1,135 +0,0 @@
1
- import asyncio
2
- import threading
3
- import time
4
- from copy import deepcopy
5
- from pathlib import Path
6
- from typing import List
7
- from urllib.parse import urlencode
8
-
9
- import click
10
-
11
- import tinybird.context as context
12
- from tinybird.client import TinyB
13
- from tinybird.tb.modules.cli import cli
14
- from tinybird.tb.modules.config import CLIConfig
15
- from tinybird.tb.modules.datafile.exceptions import ParseException
16
- from tinybird.tb.modules.datafile.parse_datasource import parse_datasource
17
- from tinybird.tb.modules.datafile.parse_pipe import parse_pipe
18
- from tinybird.tb.modules.datafile.playground import folder_playground
19
- from tinybird.tb.modules.feedback_manager import FeedbackManager
20
- from tinybird.tb.modules.project import Project
21
- from tinybird.tb.modules.shell import Shell, print_table_formatted
22
- from tinybird.tb.modules.watch import watch_files
23
-
24
-
25
- def is_vendor(f: Path) -> bool:
26
- return f.parts[0] == "vendor"
27
-
28
-
29
- def get_vendor_workspace(f: Path) -> str:
30
- return f.parts[1]
31
-
32
-
33
- def is_endpoint(f: Path) -> bool:
34
- return f.suffix == ".pipe" and not is_vendor(f) and f.parts[0] == "endpoints"
35
-
36
-
37
- def is_pipe(f: Path) -> bool:
38
- return f.suffix == ".pipe" and not is_vendor(f)
39
-
40
-
41
- def check_filenames(filenames: List[str]):
42
- parser_matrix = {".pipe": parse_pipe, ".datasource": parse_datasource}
43
- incl_suffix = ".incl"
44
-
45
- for filename in filenames:
46
- file_suffix = Path(filename).suffix
47
- if file_suffix == incl_suffix:
48
- continue
49
-
50
- parser = parser_matrix.get(file_suffix)
51
- if not parser:
52
- raise ParseException(FeedbackManager.error_unsupported_datafile(extension=file_suffix))
53
-
54
- parser(filename)
55
-
56
-
57
- @cli.command()
58
- @click.pass_context
59
- def playground(
60
- ctx: click.Context,
61
- ) -> None:
62
- """Build the project in Tinybird Local."""
63
- project: Project = ctx.ensure_object(dict)["project"]
64
- tb_client: TinyB = ctx.ensure_object(dict)["client"]
65
- config = CLIConfig.get_project_config()
66
- context.disable_template_security_validation.set(True)
67
-
68
- async def process(filenames: List[str], watch: bool = False):
69
- datafiles = [f for f in filenames if f.endswith(".datasource") or f.endswith(".pipe")]
70
- if len(datafiles) > 0:
71
- check_filenames(filenames=datafiles)
72
- await folder_playground(
73
- project, config, tb_client, filenames=datafiles, is_internal=False, current_ws=None, local_ws=None
74
- )
75
- if len(filenames) > 0 and watch:
76
- filename = filenames[0]
77
- await build_and_print_resource(config, tb_client, filename)
78
-
79
- datafiles = project.get_project_files()
80
- filenames = datafiles
81
-
82
- async def build_once(filenames: List[str]):
83
- ok = False
84
- try:
85
- click.echo(FeedbackManager.highlight(message="» Building project...\n"))
86
- time_start = time.time()
87
- await process(filenames=filenames, watch=False)
88
- time_end = time.time()
89
- elapsed_time = time_end - time_start
90
-
91
- click.echo(FeedbackManager.success(message=f"\n✓ Build completed in {elapsed_time:.1f}s"))
92
- ok = True
93
- except Exception as e:
94
- error_path = Path(".tb_error.txt")
95
- if error_path.exists():
96
- content = error_path.read_text()
97
- content += f"\n\n{str(e)}"
98
- error_path.write_text(content)
99
- else:
100
- error_path.write_text(str(e))
101
- click.echo(FeedbackManager.error_exception(error=e))
102
- ok = False
103
- return ok
104
-
105
- build_ok = asyncio.run(build_once(filenames))
106
-
107
- shell = Shell(project=project, tb_client=tb_client, playground=True)
108
- click.echo(FeedbackManager.gray(message="\nWatching for changes..."))
109
- watcher_thread = threading.Thread(
110
- target=watch_files, args=(filenames, process, shell, project, build_ok), daemon=True
111
- )
112
- watcher_thread.start()
113
- shell.run()
114
-
115
-
116
- async def build_and_print_resource(config: CLIConfig, tb_client: TinyB, filename: str):
117
- resource_path = Path(filename)
118
- name = resource_path.stem
119
- playground_name = name if filename.endswith(".pipe") else None
120
- user_client = deepcopy(tb_client)
121
- user_client.token = config.get_user_token() or ""
122
- cli_params = {}
123
- cli_params["workspace_id"] = config.get("id", None)
124
- data = await user_client._req(f"/v0/playgrounds?{urlencode(cli_params)}")
125
- playgrounds = data["playgrounds"]
126
- playground = next((p for p in playgrounds if p["name"] == (f"{playground_name}" + "__tb__playground")), None)
127
- if not playground:
128
- return
129
- playground_id = playground["id"]
130
- last_node = playground["nodes"][-1]
131
- if not last_node:
132
- return
133
- node_sql = last_node["sql"]
134
- res = await tb_client.query(f"{node_sql} FORMAT JSON", playground=playground_id)
135
- print_table_formatted(res, name)