tinybird 0.0.1.dev20__tar.gz → 0.0.1.dev22__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.

Files changed (96) hide show
  1. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/prompts.py +2 -2
  3. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/__cli__.py +2 -2
  4. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/create.py +8 -6
  5. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/build.py +173 -102
  6. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/llm.py +12 -25
  7. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/local.py +9 -12
  8. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/mock.py +1 -2
  9. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/test.py +5 -4
  10. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird.egg-info/PKG-INFO +1 -1
  11. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/setup.cfg +0 -0
  12. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/__cli__.py +0 -0
  13. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/ch_utils/constants.py +0 -0
  14. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/ch_utils/engine.py +0 -0
  15. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/check_pypi.py +0 -0
  16. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/client.py +0 -0
  17. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/config.py +0 -0
  18. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/connectors.py +0 -0
  19. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/context.py +0 -0
  20. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/datafile.py +0 -0
  21. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/datatypes.py +0 -0
  22. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/feedback_manager.py +0 -0
  23. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/git_settings.py +0 -0
  24. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/sql.py +0 -0
  25. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/sql_template.py +0 -0
  26. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/sql_template_fmt.py +0 -0
  27. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/sql_toolset.py +0 -0
  28. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/syncasync.py +0 -0
  29. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/cli.py +0 -0
  30. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/auth.py +0 -0
  31. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/build.py +0 -0
  32. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/cicd.py +0 -0
  33. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/cli.py +0 -0
  34. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/common.py +0 -0
  35. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/config.py +0 -0
  36. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/connection.py +0 -0
  37. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/build_common.py +0 -0
  38. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  39. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  40. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/common.py +0 -0
  41. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/diff.py +0 -0
  42. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  43. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/fixture.py +0 -0
  44. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/format_common.py +0 -0
  45. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  46. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  47. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  48. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  49. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  50. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datafile/pull.py +0 -0
  51. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/datasource.py +0 -0
  52. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/exceptions.py +0 -0
  53. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/feedback_manager.py +0 -0
  54. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/fmt.py +0 -0
  55. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/job.py +0 -0
  56. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/local_common.py +0 -0
  57. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/login.py +0 -0
  58. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/pipe.py +0 -0
  59. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/regions.py +0 -0
  60. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/shell.py +0 -0
  61. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/table.py +0 -0
  62. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/tag.py +0 -0
  63. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/telemetry.py +0 -0
  64. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  65. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  66. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/token.py +0 -0
  67. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/watch.py +0 -0
  68. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/workspace.py +0 -0
  69. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb/modules/workspace_members.py +0 -0
  70. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli.py +0 -0
  71. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/auth.py +0 -0
  72. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/branch.py +0 -0
  73. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/cicd.py +0 -0
  74. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/cli.py +0 -0
  75. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/common.py +0 -0
  76. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/config.py +0 -0
  77. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/connection.py +0 -0
  78. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/datasource.py +0 -0
  79. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/exceptions.py +0 -0
  80. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/fmt.py +0 -0
  81. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/job.py +0 -0
  82. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/pipe.py +0 -0
  83. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/regions.py +0 -0
  84. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/tag.py +0 -0
  85. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/telemetry.py +0 -0
  86. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/test.py +0 -0
  87. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  88. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  89. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/workspace.py +0 -0
  90. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  91. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird/tornado_template.py +0 -0
  92. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird.egg-info/SOURCES.txt +0 -0
  93. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird.egg-info/dependency_links.txt +0 -0
  94. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird.egg-info/entry_points.txt +0 -0
  95. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird.egg-info/requires.txt +0 -0
  96. {tinybird-0.0.1.dev20 → tinybird-0.0.1.dev22}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird
3
- Version: 0.0.1.dev20
3
+ Version: 0.0.1.dev22
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -122,7 +122,7 @@ FROM numbers({rows})
122
122
 
123
123
  """
124
124
 
125
- create_test_calls_prompt = """
125
+ create_test_prompt = """
126
126
  You are a Tinybird expert. You will be given a pipe endpoint containing different nodes with SQL and Tinybird templating syntax. You will generate URLs to test it with different parameters combinations.
127
127
 
128
128
  <test>
@@ -141,6 +141,6 @@ You are a Tinybird expert. You will be given a pipe endpoint containing differen
141
141
  - The test command can have as many parameters as are needed to test the pipe.
142
142
  - The parameter within Tinybird templating syntax looks like this one {{String(my_param_name, default_value)}}.
143
143
  - If there are no parameters in the , you can omit parametrs and generate a single test command.
144
- - Extra context: {context}
144
+ - Extra context: {prompt}
145
145
  </instructions>
146
146
  """
@@ -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.dev20'
8
- __revision__ = '6125327'
7
+ __version__ = '0.0.1.dev22'
8
+ __revision__ = 'fad51ec'
@@ -56,10 +56,11 @@ async def create(
56
56
  folder = folder or getcwd()
57
57
  try:
58
58
  config = CLIConfig.get_project_config(folder)
59
+ user_token: Optional[str] = None
59
60
 
60
61
  if prompt:
61
- user_token = config.get_user_token()
62
62
  try:
63
+ user_token = config.get_user_token()
63
64
  if not user_token:
64
65
  raise CLIException("No user token found")
65
66
  await check_user_token(ctx, token=user_token)
@@ -69,7 +70,7 @@ async def create(
69
70
 
70
71
  tb_client = config.get_client()
71
72
  click.echo(FeedbackManager.gray(message="Creating new project structure..."))
72
- await project_create(tb_client, data, prompt, folder)
73
+ await project_create(tb_client, user_token, data, prompt, folder)
73
74
  click.echo(FeedbackManager.success(message="✓ Scaffolding completed!\n"))
74
75
 
75
76
  click.echo(FeedbackManager.gray(message="\nCreating CI/CD files for GitHub and GitLab..."))
@@ -145,11 +146,11 @@ async def create(
145
146
  )
146
147
  click.echo(FeedbackManager.info(message=f"✓ /fixtures/{ds_name}"))
147
148
  persist_fixture(fixture_name, data_content)
148
- elif prompt:
149
+ elif prompt and user_token:
149
150
  datasource_files = [f for f in os.listdir(Path(folder) / "datasources") if f.endswith(".datasource")]
150
151
  for datasource_file in datasource_files:
151
152
  datasource_path = Path(folder) / "datasources" / datasource_file
152
- llm = LLM(client=tb_client)
153
+ llm = LLM(user_token=user_token, client=tb_client)
153
154
  datasource_name = datasource_path.stem
154
155
  datasource_content = datasource_path.read_text()
155
156
  has_json_path = "`json:" in datasource_content
@@ -171,6 +172,7 @@ async def create(
171
172
 
172
173
  async def project_create(
173
174
  client: TinyB,
175
+ user_token: Optional[str],
174
176
  data: Optional[str],
175
177
  prompt: Optional[str],
176
178
  folder: str,
@@ -203,9 +205,9 @@ TYPE ENDPOINT
203
205
  """,
204
206
  folder,
205
207
  )
206
- elif prompt:
208
+ elif prompt and user_token:
207
209
  try:
208
- llm = LLM(client=client)
210
+ llm = LLM(user_token=user_token, client=client)
209
211
  result = await llm.create_project(prompt)
210
212
  for ds in result.datasources:
211
213
  content = ds.content.replace("```", "")
@@ -689,6 +689,148 @@ class GraphDependencies:
689
689
  all_resources: Dict[str, Dict[str, Any]]
690
690
 
691
691
 
692
+ async def process(
693
+ filename: str,
694
+ tb_client: TinyB,
695
+ deps: List[str],
696
+ dep_map: Dict[str, Any],
697
+ to_run: Dict[str, Any],
698
+ vendor_paths: Optional[List[Tuple[str, str]]] = None,
699
+ skip_connectors: bool = False,
700
+ current_ws: Optional[Dict[str, Any]] = None,
701
+ changed: Optional[Dict[str, Any]] = None,
702
+ fork_downstream: Optional[bool] = False,
703
+ is_internal: Optional[bool] = False,
704
+ dir_path: Optional[str] = None,
705
+ verbose: bool = False,
706
+ embedded_datasources: Optional[Dict[str, Any]] = None,
707
+ ):
708
+ name, kind = filename.rsplit(".", 1)
709
+ warnings = []
710
+
711
+ try:
712
+ res = await process_file(
713
+ filename,
714
+ tb_client,
715
+ skip_connectors=skip_connectors,
716
+ current_ws=current_ws,
717
+ )
718
+ except click.ClickException as e:
719
+ raise e
720
+ except IncludeFileNotFoundException as e:
721
+ raise click.ClickException(FeedbackManager.error_deleted_include(include_file=str(e), filename=filename))
722
+ except Exception as e:
723
+ raise click.ClickException(str(e))
724
+
725
+ for r in res:
726
+ resource_name = r["resource_name"]
727
+ warnings = r.get("warnings", [])
728
+ if (
729
+ changed
730
+ and resource_name in changed
731
+ and (not changed[resource_name] or changed[resource_name] in ["shared", "remote"])
732
+ ):
733
+ continue
734
+
735
+ if (
736
+ fork_downstream
737
+ and r.get("resource", "") == "pipes"
738
+ and any(["engine" in x.get("params", {}) for x in r.get("nodes", [])])
739
+ ):
740
+ raise click.ClickException(FeedbackManager.error_forkdownstream_pipes_with_engine(pipe=resource_name))
741
+
742
+ to_run[resource_name] = r
743
+ file_deps = r.get("deps", [])
744
+ deps += file_deps
745
+ # calculate and look for deps
746
+ dep_list = []
747
+ for x in file_deps:
748
+ if x not in INTERNAL_TABLES or is_internal:
749
+ f, ds = find_file_by_name(dir_path, x, verbose, vendor_paths=vendor_paths, resource=r)
750
+ if f:
751
+ dep_list.append(f.rsplit(".", 1)[0])
752
+ if ds:
753
+ ds_fn = ds["resource_name"]
754
+ prev = to_run.get(ds_fn, {})
755
+ to_run[ds_fn] = deepcopy(r)
756
+ try:
757
+ to_run[ds_fn]["deps"] = list(
758
+ set(to_run[ds_fn].get("deps", []) + prev.get("deps", []) + [resource_name])
759
+ )
760
+ except ValueError:
761
+ pass
762
+ embedded_datasources[x] = to_run[ds_fn]
763
+ else:
764
+ e_ds = embedded_datasources.get(x, None)
765
+ if e_ds:
766
+ dep_list.append(e_ds["resource_name"])
767
+
768
+ dep_map[resource_name] = set(dep_list)
769
+ return os.path.basename(name), warnings
770
+
771
+
772
+ async def get_processed(
773
+ filenames: Iterable[str],
774
+ changed: Optional[Dict[str, Any]] = None,
775
+ verbose: bool = False,
776
+ deps: List[str] = [],
777
+ dep_map: Dict[str, Any] = {},
778
+ to_run: Dict[str, Any] = {},
779
+ vendor_paths: Optional[List[Tuple[str, str]]] = None,
780
+ processed: Set[str] = set(),
781
+ tb_client: TinyB = None,
782
+ skip_connectors: bool = False,
783
+ current_ws: Optional[Dict[str, Any]] = None,
784
+ fork_downstream: Optional[bool] = False,
785
+ is_internal: Optional[bool] = False,
786
+ dir_path: Optional[str] = None,
787
+ embedded_datasources: Optional[Dict[str, Any]] = None,
788
+ ):
789
+ for filename in filenames:
790
+ # just process changed filenames (tb deploy and --only-changes)
791
+ if changed:
792
+ resource = Path(filename).resolve().stem
793
+ if resource in changed and (not changed[resource] or changed[resource] in ["shared", "remote"]):
794
+ continue
795
+ if os.path.isdir(filename):
796
+ await get_processed(filenames=get_project_filenames(filename))
797
+ else:
798
+ if verbose:
799
+ click.echo(FeedbackManager.info_processing_file(filename=filename))
800
+
801
+ if ".incl" in filename:
802
+ click.echo(FeedbackManager.warning_skipping_include_file(file=filename))
803
+
804
+ name, warnings = await process(
805
+ filename=filename,
806
+ tb_client=tb_client,
807
+ deps=deps,
808
+ dep_map=dep_map,
809
+ to_run=to_run,
810
+ vendor_paths=vendor_paths,
811
+ skip_connectors=skip_connectors,
812
+ current_ws=current_ws,
813
+ changed=changed,
814
+ fork_downstream=fork_downstream,
815
+ is_internal=is_internal,
816
+ dir_path=dir_path,
817
+ verbose=verbose,
818
+ embedded_datasources=embedded_datasources,
819
+ )
820
+ processed.add(name)
821
+
822
+ if verbose:
823
+ if len(warnings) == 1:
824
+ click.echo(FeedbackManager.warning_pipe_restricted_param(word=warnings[0]))
825
+ elif len(warnings) > 1:
826
+ click.echo(
827
+ FeedbackManager.warning_pipe_restricted_params(
828
+ words=", ".join(["'{}'".format(param) for param in warnings[:-1]]),
829
+ last_word=warnings[-1],
830
+ )
831
+ )
832
+
833
+
692
834
  async def build_graph(
693
835
  filenames: Iterable[str],
694
836
  tb_client: TinyB,
@@ -740,109 +882,24 @@ async def build_graph(
740
882
  all_dep_map = all_dependencies_graph.dep_map
741
883
  all_resources = all_dependencies_graph.to_run
742
884
 
743
- async def process(
744
- filename: str,
745
- deps: List[str],
746
- dep_map: Dict[str, Any],
747
- to_run: Dict[str, Any],
748
- vendor_paths: Optional[List[Tuple[str, str]]],
749
- ):
750
- name, kind = filename.rsplit(".", 1)
751
- warnings = []
752
-
753
- try:
754
- res = await process_file(
755
- filename,
756
- tb_client,
757
- skip_connectors=skip_connectors,
758
- current_ws=current_ws,
759
- )
760
- except click.ClickException as e:
761
- raise e
762
- except IncludeFileNotFoundException as e:
763
- raise click.ClickException(FeedbackManager.error_deleted_include(include_file=str(e), filename=filename))
764
- except Exception as e:
765
- raise click.ClickException(str(e))
766
-
767
- for r in res:
768
- resource_name = r["resource_name"]
769
- warnings = r.get("warnings", [])
770
- if (
771
- changed
772
- and resource_name in changed
773
- and (not changed[resource_name] or changed[resource_name] in ["shared", "remote"])
774
- ):
775
- continue
776
-
777
- if (
778
- fork_downstream
779
- and r.get("resource", "") == "pipes"
780
- and any(["engine" in x.get("params", {}) for x in r.get("nodes", [])])
781
- ):
782
- raise click.ClickException(FeedbackManager.error_forkdownstream_pipes_with_engine(pipe=resource_name))
783
-
784
- to_run[resource_name] = r
785
- file_deps = r.get("deps", [])
786
- deps += file_deps
787
- # calculate and look for deps
788
- dep_list = []
789
- for x in file_deps:
790
- if x not in INTERNAL_TABLES or is_internal:
791
- f, ds = find_file_by_name(dir_path, x, verbose, vendor_paths=vendor_paths, resource=r)
792
- if f:
793
- dep_list.append(f.rsplit(".", 1)[0])
794
- if ds:
795
- ds_fn = ds["resource_name"]
796
- prev = to_run.get(ds_fn, {})
797
- to_run[ds_fn] = deepcopy(r)
798
- try:
799
- to_run[ds_fn]["deps"] = list(
800
- set(to_run[ds_fn].get("deps", []) + prev.get("deps", []) + [resource_name])
801
- )
802
- except ValueError:
803
- pass
804
- embedded_datasources[x] = to_run[ds_fn]
805
- else:
806
- e_ds = embedded_datasources.get(x, None)
807
- if e_ds:
808
- dep_list.append(e_ds["resource_name"])
809
-
810
- dep_map[resource_name] = set(dep_list)
811
- return os.path.basename(name), warnings
812
-
813
885
  processed = set()
814
886
 
815
- async def get_processed(filenames: Iterable[str]):
816
- for filename in filenames:
817
- # just process changed filenames (tb deploy and --only-changes)
818
- if changed:
819
- resource = Path(filename).resolve().stem
820
- if resource in changed and (not changed[resource] or changed[resource] in ["shared", "remote"]):
821
- continue
822
- if os.path.isdir(filename):
823
- await get_processed(filenames=get_project_filenames(filename))
824
- else:
825
- if verbose:
826
- click.echo(FeedbackManager.info_processing_file(filename=filename))
827
-
828
- if ".incl" in filename:
829
- click.echo(FeedbackManager.warning_skipping_include_file(file=filename))
830
-
831
- name, warnings = await process(filename, deps, dep_map, to_run, vendor_paths)
832
- processed.add(name)
833
-
834
- if verbose:
835
- if len(warnings) == 1:
836
- click.echo(FeedbackManager.warning_pipe_restricted_param(word=warnings[0]))
837
- elif len(warnings) > 1:
838
- click.echo(
839
- FeedbackManager.warning_pipe_restricted_params(
840
- words=", ".join(["'{}'".format(param) for param in warnings[:-1]]),
841
- last_word=warnings[-1],
842
- )
843
- )
844
-
845
- await get_processed(filenames=filenames)
887
+ await get_processed(
888
+ filenames=filenames,
889
+ tb_client=tb_client,
890
+ changed=changed,
891
+ deps=deps,
892
+ dep_map=dep_map,
893
+ to_run=to_run,
894
+ vendor_paths=vendor_paths,
895
+ processed=processed,
896
+ skip_connectors=skip_connectors,
897
+ current_ws=current_ws,
898
+ fork_downstream=fork_downstream,
899
+ is_internal=is_internal,
900
+ dir_path=dir_path,
901
+ embedded_datasources=embedded_datasources,
902
+ )
846
903
 
847
904
  if process_dependencies:
848
905
  if only_changes:
@@ -878,7 +935,21 @@ async def build_graph(
878
935
  click.echo(FeedbackManager.info_skipping_resource(resource=processed_filename))
879
936
  continue
880
937
  click.echo(FeedbackManager.info_processing_file(filename=processed_filename))
881
- await process(str(f), deps, dep_map, to_run, vendor_paths)
938
+ await process(
939
+ filename=str(f),
940
+ tb_client=tb_client,
941
+ deps=deps,
942
+ dep_map=dep_map,
943
+ to_run=to_run,
944
+ vendor_paths=vendor_paths,
945
+ skip_connectors=skip_connectors,
946
+ current_ws=current_ws,
947
+ fork_downstream=fork_downstream,
948
+ is_internal=is_internal,
949
+ dir_path=dir_path,
950
+ verbose=verbose,
951
+ embedded_datasources=embedded_datasources,
952
+ )
882
953
 
883
954
  return GraphDependencies(dep_map, to_run, all_dep_map, all_resources)
884
955
 
@@ -8,8 +8,6 @@ from openai import OpenAI
8
8
  from pydantic import BaseModel
9
9
 
10
10
  from tinybird.client import TinyB
11
- from tinybird.prompts import create_test_calls_prompt
12
- from tinybird.tb.modules.config import CLIConfig
13
11
 
14
12
 
15
13
  class DataFile(BaseModel):
@@ -33,13 +31,10 @@ class TestExpectations(BaseModel):
33
31
 
34
32
 
35
33
  class LLM:
36
- def __init__(self, client: TinyB, api_key: Optional[str] = None):
37
- self.client = client
38
- user_token = CLIConfig.get_project_config().get_user_token()
39
- user_client = deepcopy(client)
40
- if user_token:
41
- user_client.token = user_token
42
- self.user_client = user_client
34
+ def __init__(self, user_token: str, client: TinyB, api_key: Optional[str] = None):
35
+ self.user_client = deepcopy(client)
36
+ self.user_client.token = user_token
37
+
43
38
  self.openai = OpenAI(api_key=api_key) if api_key else None
44
39
 
45
40
  async def _execute(self, action_fn: Callable[[], Awaitable[str]], checker_fn: Callable[[str], bool]):
@@ -79,20 +74,12 @@ class LLM:
79
74
  result = response.get("result", "")
80
75
  return result.replace("elementAt", "arrayElement")
81
76
 
82
- async def create_test_commands(
83
- self, pipe_content: str, pipe_params: set[str], context: Optional[str] = None
84
- ) -> TestExpectations:
85
- if not self.openai:
86
- raise ValueError("OpenAI API key is not set")
87
-
88
- completion = self.openai.beta.chat.completions.parse(
89
- model="gpt-4o",
90
- messages=[
91
- {"role": "system", "content": create_test_calls_prompt.format(context=context or "")},
92
- {"role": "user", "content": f"Pipe content: {pipe_content}\nPipe params: {pipe_params}"},
93
- ],
94
- temperature=0.2,
95
- seed=42,
96
- response_format=TestExpectations,
77
+ async def create_tests(self, pipe_content: str, pipe_params: set[str], prompt: str = "") -> TestExpectations:
78
+ response = await self.user_client._req(
79
+ "/v0/llm/create/tests",
80
+ method="POST",
81
+ data=json.dumps({"pipe_content": pipe_content, "pipe_params": list(pipe_params), "prompt": prompt}),
82
+ headers={"Content-Type": "application/json"},
97
83
  )
98
- return completion.choices[0].message.parsed or TestExpectations(tests=[])
84
+ result = response.get("result", "")
85
+ return TestExpectations.model_validate(result)
@@ -59,18 +59,15 @@ def start_tinybird_local(
59
59
  )
60
60
 
61
61
  click.echo(FeedbackManager.info(message="* Waiting for Tinybird Local to be ready..."))
62
- for attempt in range(10):
63
- try:
64
- run = container.exec_run("tb --no-version-warning sql 'SELECT 1 AS healthcheck' --format json").output
65
- # dont parse the json as docker sometimes returns warning messages
66
- # todo: rafa, make this rigth
67
- if b'"healthcheck": 1' in run:
68
- break
69
- raise RuntimeError("Unexpected response from Tinybird")
70
- except Exception:
71
- if attempt == 9: # Last attempt
72
- raise CLIException("Tinybird Local not ready yet. Please try again in a few seconds.")
73
- time.sleep(5) # Wait 5 seconds before retrying
62
+ while True:
63
+ container.reload() # Refresh container attributes
64
+ health = container.attrs.get("State", {}).get("Health", {}).get("Status")
65
+ if health == "healthy":
66
+ break
67
+ if health == "unhealthy":
68
+ raise CLIException("Tinybird Local is unhealthy. Please try running `tb local restart` in a few seconds.")
69
+
70
+ time.sleep(5)
74
71
 
75
72
  # Remove tinybird-local dangling images to avoid running out of disk space
76
73
  images = docker_client.images.list(name=re.sub(r":.*$", "", TB_IMAGE_NAME), all=True, filters={"dangling": True})
@@ -41,7 +41,6 @@ async def mock(ctx: click.Context, datasource: str, rows: int, prompt: str, fold
41
41
  if not prompt:
42
42
  # load the prompt from the fixture.prompt file if it exists
43
43
  if prompt_path.exists():
44
- click.echo(FeedbackManager.gray(message=f"Using prompt for {prompt_path}..."))
45
44
  prompt = prompt_path.read_text()
46
45
  else:
47
46
  click.echo(FeedbackManager.gray(message=f"Overriding prompt for {datasource_name}..."))
@@ -61,7 +60,7 @@ async def mock(ctx: click.Context, datasource: str, rows: int, prompt: str, fold
61
60
  click.echo(FeedbackManager.error(message="This action requires authentication. Run 'tb login' first."))
62
61
  return
63
62
 
64
- llm = LLM(client=user_client)
63
+ llm = LLM(user_token=user_token, client=user_client)
65
64
  tb_client = await get_tinybird_local_client(os.path.abspath(folder))
66
65
  sql = await llm.generate_sql_sample_data(datasource_content, rows=rows, prompt=prompt)
67
66
  if os.environ.get("TB_DEBUG", "") != "":
@@ -89,11 +89,12 @@ async def test_create(pipe: str, prompt: Optional[str], folder: str) -> None:
89
89
  pipe_nodes = await client._req(f"/v0/pipes/{pipe_name}")
90
90
  pipe_params = set([param["name"] for node in pipe_nodes["nodes"] for param in node["params"]])
91
91
 
92
- llm_config = CLIConfig.get_llm_config()
93
- llm = LLM(client=client, api_key=llm_config["api_key"])
92
+ config = CLIConfig.get_project_config(folder)
93
+ user_token = config.get_user_token()
94
+ llm = LLM(user_token=user_token, client=config.get_client())
94
95
 
95
- test_expectations = await llm.create_test_commands(
96
- pipe_content=pipe_content, pipe_params=pipe_params, context=prompt
96
+ test_expectations = await llm.create_tests(
97
+ pipe_content=pipe_content, pipe_params=pipe_params, prompt=prompt or ""
97
98
  )
98
99
  valid_test_expectations = []
99
100
  for test in test_expectations.tests:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinybird
3
- Version: 0.0.1.dev20
3
+ Version: 0.0.1.dev22
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
File without changes