tinybird 0.0.1.dev109__py3-none-any.whl → 0.0.1.dev111__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/sql.py CHANGED
@@ -9,6 +9,24 @@ valid_chars_name: str = string.ascii_letters + string.digits + "._`*<>+-'"
9
9
  valid_chars_fn: str = valid_chars_name + "[](),=!?:/ \n\t\r"
10
10
 
11
11
  INDEX_WHITELIST = ["minmax", "set", "bloom_filter", "ngrambf_v1", "tokenbf_v1"]
12
+ INDEX_SUPPORTED_TYPES = {
13
+ "bloom_filter": [
14
+ "Int*",
15
+ "UInt*",
16
+ "Float*",
17
+ "Enum",
18
+ "Date",
19
+ "DateTime",
20
+ "String",
21
+ "FixedString",
22
+ "Array",
23
+ "LowCardinality",
24
+ "Nullable",
25
+ "UUID",
26
+ "Map",
27
+ ],
28
+ "ngrambf_v1": ["String", "FixedString", "Map"],
29
+ }
12
30
 
13
31
 
14
32
  @dataclass
@@ -39,12 +57,37 @@ class TableIndex:
39
57
  def clear_index_sql(self):
40
58
  return f"CLEAR INDEX IF EXISTS {self.name}"
41
59
 
42
- def validate_allowed(self):
60
+ def _validate_index_type(self, table_structure: List[Dict[str, Any]]):
61
+ for col in table_structure:
62
+ if col["normalized_name"] != self.expr:
63
+ continue
64
+ col_type = col["type"]
65
+ index_supported_types: Optional[str] = next((t for t in INDEX_SUPPORTED_TYPES if t in self.type_full), None)
66
+
67
+ if index_supported_types:
68
+ for supported_type in INDEX_SUPPORTED_TYPES.get(index_supported_types, []):
69
+ # Convert supported type to regex pattern
70
+ # Replace * with \d+ to match any number
71
+ pattern = supported_type.replace("*", r"\d+")
72
+ if re.match(f"^{pattern}$", col_type):
73
+ return
74
+ raise ValueError(
75
+ f"Not allowed data type '{col_type}' for index '{self.type_full}' for column '{self.expr}' "
76
+ )
77
+
78
+ def validate_allowed(self, table_structure: Optional[List[Dict[str, Any]]] = None):
43
79
  """
44
80
  Validate at API level not to depend on CLI version
45
81
  """
46
82
  if not any(index in self.type_full for index in INDEX_WHITELIST):
47
83
  raise ValueError(f"Not allowed index '{self.type_full}'")
84
+ try:
85
+ if table_structure:
86
+ self._validate_index_type(table_structure)
87
+ except ValueError as e:
88
+ raise e
89
+ except Exception:
90
+ logging.exception(f"Error validating index '{self.type_full}' for column '{self.expr}'")
48
91
 
49
92
 
50
93
  @dataclass
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.dev109'
8
- __revision__ = '421d6c4'
7
+ __version__ = '0.0.1.dev111'
8
+ __revision__ = '621864a'
@@ -49,7 +49,7 @@ jobs:
49
49
  steps:
50
50
  - uses: actions/checkout@v3
51
51
  - name: Install Tinybird CLI
52
- run: curl -LsSf https://api.tinybird.co/static/install.sh | sh
52
+ run: curl https://tinybird.co | sh
53
53
  - name: Build project
54
54
  run: tb build
55
55
  - name: Test project
@@ -81,7 +81,7 @@ jobs:
81
81
  steps:
82
82
  - uses: actions/checkout@v3
83
83
  - name: Install Tinybird CLI
84
- run: curl -LsSf https://api.tinybird.co/static/install.sh | sh
84
+ run: curl https://tinybird.co | sh
85
85
  - name: Deploy project
86
86
  run: tb --cloud --host ${{! env.TINYBIRD_HOST }} --token ${{! env.TINYBIRD_TOKEN }} deploy
87
87
  """
@@ -110,7 +110,7 @@ tinybird_ci_workflow:
110
110
  - {{ data_project_dir }}/**/*{% end %}
111
111
  before_script:
112
112
  - apt update && apt install -y curl
113
- - curl -LsSf https://api.tinybird.co/static/install.sh | sh
113
+ - curl https://tinybird.co | sh
114
114
  script:
115
115
  - export PATH="$HOME/.local/bin:$PATH"
116
116
  - cd $CI_PROJECT_DIR/{{ data_project_dir }}
@@ -1,8 +1,9 @@
1
1
  import os
2
- from typing import List, Optional
2
+ from typing import Dict, Optional
3
3
 
4
4
  import click
5
5
 
6
+ from tinybird.sql_template import render_template_with_secrets
6
7
  from tinybird.tb.modules.datafile.common import (
7
8
  Datafile,
8
9
  DatafileKind,
@@ -21,7 +22,7 @@ def parse_datasource(
21
22
  skip_eval: bool = False,
22
23
  hide_folders: bool = False,
23
24
  add_context_to_datafile_syntax_errors: bool = True,
24
- secrets: Optional[List[str]] = None,
25
+ secrets: Optional[Dict[str, str]] = None,
25
26
  ) -> Datafile:
26
27
  basepath = ""
27
28
  if not content:
@@ -31,6 +32,7 @@ def parse_datasource(
31
32
  else:
32
33
  s = content
33
34
 
35
+ s = render_template_with_secrets(filename, s, secrets=secrets or {})
34
36
  filename = format_filename(filename, hide_folders)
35
37
  try:
36
38
  doc = parse(
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import List, Optional
2
+ from typing import Dict, Optional
3
3
 
4
4
  import click
5
5
 
@@ -23,7 +23,7 @@ def parse_pipe(
23
23
  skip_eval: bool = False,
24
24
  hide_folders: bool = False,
25
25
  add_context_to_datafile_syntax_errors: bool = True,
26
- secrets: Optional[List[str]] = None,
26
+ secrets: Optional[Dict[str, str]] = None,
27
27
  ) -> Datafile:
28
28
  basepath = ""
29
29
  if not content:
@@ -1,12 +1,14 @@
1
1
  import re
2
2
  import subprocess
3
3
  import time
4
+ from typing import Optional
4
5
 
5
6
  import boto3
6
7
  import click
7
8
 
8
9
  import docker
9
10
  from docker.client import DockerClient
11
+ from docker.models.containers import Container
10
12
  from tinybird.tb.modules.cli import cli
11
13
  from tinybird.tb.modules.common import coro
12
14
  from tinybird.tb.modules.exceptions import CLIException
@@ -41,10 +43,9 @@ def start_tinybird_local(
41
43
  if pull_required:
42
44
  docker_client.images.pull(TB_IMAGE_NAME, platform="linux/amd64")
43
45
 
44
- container = None
45
- containers = docker_client.containers.list(all=True, filters={"name": TB_CONTAINER_NAME})
46
- if containers:
47
- container = containers[0]
46
+ environment = get_use_aws_creds() if use_aws_creds else {}
47
+
48
+ container = get_existing_container_with_matching_env(docker_client, TB_CONTAINER_NAME, environment)
48
49
 
49
50
  if container and not pull_required:
50
51
  # Container `start` is idempotent. It's safe to call it even if the container is already running.
@@ -53,8 +54,6 @@ def start_tinybird_local(
53
54
  if container:
54
55
  container.remove(force=True)
55
56
 
56
- environment = get_use_aws_creds() if use_aws_creds else {}
57
-
58
57
  container = docker_client.containers.run(
59
58
  TB_IMAGE_NAME,
60
59
  name=TB_CONTAINER_NAME,
@@ -82,6 +81,43 @@ def start_tinybird_local(
82
81
  image.remove(force=True)
83
82
 
84
83
 
84
+ def get_existing_container_with_matching_env(
85
+ docker_client: DockerClient, container_name: str, required_env: dict[str, str]
86
+ ) -> Optional[Container]:
87
+ """
88
+ Checks if a container with the given name exists and has matching environment variables.
89
+ If it exists but environment doesn't match, it returns None.
90
+
91
+ Args:
92
+ docker_client: The Docker client instance
93
+ container_name: The name of the container to check
94
+ required_env: Dictionary of environment variables that must be present
95
+
96
+ Returns:
97
+ The container if it exists with matching environment, None otherwise
98
+ """
99
+ container = None
100
+ containers = docker_client.containers.list(all=True, filters={"name": container_name})
101
+ if containers:
102
+ container = containers[0]
103
+
104
+ if container and required_env:
105
+ container_info = container.attrs
106
+ container_env = container_info.get("Config", {}).get("Env", [])
107
+ env_missing = False
108
+ for key, value in required_env.items():
109
+ env_var = f"{key}={value}"
110
+ if env_var not in container_env:
111
+ env_missing = True
112
+ break
113
+
114
+ if env_missing:
115
+ container.remove(force=True)
116
+ container = None
117
+
118
+ return container
119
+
120
+
85
121
  def get_docker_client() -> DockerClient:
86
122
  """Check if Docker is installed and running."""
87
123
  try:
@@ -94,7 +130,7 @@ def get_docker_client() -> DockerClient:
94
130
  )
95
131
 
96
132
 
97
- def get_use_aws_creds():
133
+ def get_use_aws_creds() -> dict[str, str]:
98
134
  credentials: dict[str, str] = {}
99
135
  try:
100
136
  # Get the boto3 session and credentials
@@ -113,14 +149,29 @@ def get_use_aws_creds():
113
149
  # Add region if available
114
150
  if session.region_name:
115
151
  credentials["AWS_DEFAULT_REGION"] = session.region_name
116
- except Exception:
117
- # TODO (rbarbadillo): We should handle this better. If users don't have AWS credentials, most times it's fine
118
- # but if they want to use S3, they'll need a warning.
119
- pass
152
+
153
+ click.echo(
154
+ FeedbackManager.success(
155
+ message=f"✓ AWS credentials found and will be passed to Tinybird Local (region: {session.region_name or 'not set'})"
156
+ )
157
+ )
158
+ else:
159
+ click.echo(
160
+ FeedbackManager.warning(
161
+ message="△ No AWS credentials found. S3 operations will not work in Tinybird Local."
162
+ )
163
+ )
164
+ except Exception as e:
165
+ click.echo(
166
+ FeedbackManager.warning(
167
+ message=f"△ Error retrieving AWS credentials: {str(e)}. S3 operations will not work in Tinybird Local."
168
+ )
169
+ )
170
+
120
171
  return credentials
121
172
 
122
173
 
123
- def stop_tinybird_local(docker_client):
174
+ def stop_tinybird_local(docker_client: DockerClient) -> None:
124
175
  """Stop the Tinybird container."""
125
176
  try:
126
177
  container = docker_client.containers.get(TB_CONTAINER_NAME)
@@ -129,7 +180,7 @@ def stop_tinybird_local(docker_client):
129
180
  pass
130
181
 
131
182
 
132
- def remove_tinybird_local(docker_client):
183
+ def remove_tinybird_local(docker_client: DockerClient) -> None:
133
184
  """Remove the Tinybird container."""
134
185
  try:
135
186
  container = docker_client.containers.get(TB_CONTAINER_NAME)
@@ -145,7 +196,7 @@ def remove_tinybird_local(docker_client):
145
196
  pass
146
197
 
147
198
 
148
- def update_cli():
199
+ def update_cli() -> None:
149
200
  click.echo(FeedbackManager.highlight(message="» Updating Tinybird CLI..."))
150
201
 
151
202
  try:
@@ -156,7 +207,7 @@ def update_cli():
156
207
  text=True,
157
208
  )
158
209
  except FileNotFoundError:
159
- raise CLIException("Cannot find required tool: uv. Reinstall using: curl -LsSf tbrd.co/fwd | sh")
210
+ raise CLIException("Cannot find required tool: uv. Reinstall using: curl https://tinybird.co | sh")
160
211
 
161
212
  stdout, stderr = process.communicate()
162
213
  if "Nothing to upgrade" not in stdout + stderr:
@@ -169,20 +220,20 @@ def update_cli():
169
220
 
170
221
 
171
222
  @cli.command()
172
- def update():
223
+ def update() -> None:
173
224
  """Update Tinybird CLI to the latest version."""
174
225
  update_cli()
175
226
 
176
227
 
177
228
  @cli.command(name="upgrade", hidden=True)
178
- def upgrade():
229
+ def upgrade() -> None:
179
230
  """Update Tinybird CLI to the latest version."""
180
231
  update_cli()
181
232
 
182
233
 
183
234
  @cli.group()
184
235
  @click.pass_context
185
- def local(ctx):
236
+ def local(ctx: click.Context) -> None:
186
237
  """Manage the local Tinybird instance."""
187
238
 
188
239
 
@@ -208,7 +259,12 @@ async def remove() -> None:
208
259
 
209
260
  @local.command()
210
261
  @coro
211
- @click.option("--use-aws-creds", default=False, is_flag=True, help="Use local AWS credentials")
262
+ @click.option(
263
+ "--use-aws-creds",
264
+ default=False,
265
+ is_flag=True,
266
+ help="Use local AWS credentials from your environment and pass them to the Tinybird docker container",
267
+ )
212
268
  async def start(use_aws_creds: bool) -> None:
213
269
  """Start Tinybird Local"""
214
270
  click.echo(FeedbackManager.highlight(message="» Starting Tinybird Local..."))
@@ -219,7 +275,12 @@ async def start(use_aws_creds: bool) -> None:
219
275
 
220
276
  @local.command()
221
277
  @coro
222
- @click.option("--use-aws-creds", is_flag=True, help="Use local AWS credentials")
278
+ @click.option(
279
+ "--use-aws-creds",
280
+ default=False,
281
+ is_flag=True,
282
+ help="Use local AWS credentials from your environment and pass them to the Tinybird docker container",
283
+ )
223
284
  async def restart(use_aws_creds: bool) -> None:
224
285
  """Restart Tinybird Local"""
225
286
  click.echo(FeedbackManager.highlight(message="» Restarting Tinybird Local..."))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev109
3
+ Version: 0.0.1.dev111
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -7,7 +7,7 @@ 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
9
  tinybird/prompts.py,sha256=0i4Bzg-60lV6NlrQ1Vu6NZ_2we3GqV3rExu77YfA0V4,33889
10
- tinybird/sql.py,sha256=J35bhdpuu84HW2tiLp-cs_nzkRwPhiy1yPcFhcWMCR4,46248
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
13
13
  tinybird/sql_toolset.py,sha256=KORVbNAUTfW1qo3U9oe7Z59xQ0QMsFhB0ji3HzY2JVo,15324
@@ -15,11 +15,11 @@ 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=gq1iOJ_OD1Jr2fuf07Ot_OShPnS-FIvM36rsSSSVtzs,252
18
+ tinybird/tb/__cli__.py,sha256=I7Yrc9jlvEPM-x0iwreh6-Gh2UYMf4--ijbZe2x9G78,252
19
19
  tinybird/tb/cli.py,sha256=H_HaZhkimKgkryYXpBjHfY9Qtg-ZORiONU3psDNpzDk,1135
20
20
  tinybird/tb/modules/auth.py,sha256=L1IatO2arRSzys3t8px8xVt8uPWUL5EVD0sFzAV_uVU,9022
21
21
  tinybird/tb/modules/build.py,sha256=h5drdmDFX8NHts9dA2Zepao7KSgMAl3DZGyFufVZP78,11085
22
- tinybird/tb/modules/cicd.py,sha256=F0hQw-TExU9W3NpUSY-msNZ4tlaPeTXjRDpFZ2B2STU,7023
22
+ tinybird/tb/modules/cicd.py,sha256=k2hCout_N1g_rRAMWo_cf9tAGiJ1Puu5eiTV2DPob20,6939
23
23
  tinybird/tb/modules/cli.py,sha256=XtdwMI5uPoKfhlpSuCuhzODRJfTCx1oXHz_bn3x1OBg,16047
24
24
  tinybird/tb/modules/common.py,sha256=6AmvMe8Uj-5A46aUlM3wJg7AilkJEAmHt1hTOb5IH2w,82957
25
25
  tinybird/tb/modules/config.py,sha256=FqdLpLaKpYubqw3xkB4EX06ufZYDgGRxONR_9i-y-KE,11416
@@ -36,7 +36,7 @@ tinybird/tb/modules/infra.py,sha256=GA5xnYLlVItPfJu_3_5NIdHQDuyfk2Z71wtcn9NncGA,
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
39
- tinybird/tb/modules/local.py,sha256=4BhxfkSTHpckXmH4aU_BothlV5n4JyAIoBKX3wP_BZg,7863
39
+ tinybird/tb/modules/local.py,sha256=VZZVHVsqf5BTQdwSNFII5IXjpsK6xoHGdv4zD-WclWc,9912
40
40
  tinybird/tb/modules/local_common.py,sha256=RN5OEncHdq7ua4AZ--WgKtaFuEsLvIhq_ROHJadRXXA,3188
41
41
  tinybird/tb/modules/login.py,sha256=lLCJ1kIq3sLcoSMH1kZge5isHh-fDwHPRHApIqbaCkw,6350
42
42
  tinybird/tb/modules/logout.py,sha256=ULooy1cDBD02-r7voZmhV7udA0ML5tVuflJyShrh56Y,1022
@@ -68,8 +68,8 @@ tinybird/tb/modules/datafile/fixture.py,sha256=si-9LB-LdKQSWDtVW82xDrHtFfko5bgBG
68
68
  tinybird/tb/modules/datafile/format_common.py,sha256=WaNV4tXrQU5gjV6MJP-5TGqg_Bre6ilNS8emvFl-X3c,1967
69
69
  tinybird/tb/modules/datafile/format_datasource.py,sha256=gpRsGnDEMxEo0pIlEHXKvyuwKIpqJJUCN9JRSiDYs_4,6156
70
70
  tinybird/tb/modules/datafile/format_pipe.py,sha256=58iSTrJ5lg-IsbpX8TQumQTuZ6UIotMsCIkNJd1M-pM,7418
71
- tinybird/tb/modules/datafile/parse_datasource.py,sha256=BNof0FnaIVZUG5ORFtZSw-gUmWID4o2ZQLVgfVIuHRI,1566
72
- tinybird/tb/modules/datafile/parse_pipe.py,sha256=tBjh3-I0iq7JdtB84RPYFrUlUOF2ZYWgQ_mwW5SPgmI,3467
71
+ tinybird/tb/modules/datafile/parse_datasource.py,sha256=cW08P_IaSl3kI3-ApjPW9BZTNaClkeC28Y7nwEw6KRE,1707
72
+ tinybird/tb/modules/datafile/parse_pipe.py,sha256=cGz83DLCZ9y4N9_h5PumpUy3QzhBGu1JC68h1siy5WM,3472
73
73
  tinybird/tb/modules/datafile/pipe_checker.py,sha256=LnDLGIHLJ3N7qHb2ptEbPr8CoczNfGwpjOY8EMdxfHQ,24649
74
74
  tinybird/tb/modules/datafile/playground.py,sha256=7yblQh3jlNfdY0ySSCBrXTK6mE9e0TFI-TbaGGV-qBE,56545
75
75
  tinybird/tb/modules/datafile/pull.py,sha256=vcjMUbjnZ9XQMGmL33J3ElpbXBTat8Yzp-haeDggZd4,5967
@@ -81,8 +81,8 @@ tinybird/tb_cli_modules/config.py,sha256=IsgdtFRnUrkY8-Zo32lmk6O7u3bHie1QCxLwgp4
81
81
  tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
82
82
  tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
83
83
  tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
84
- tinybird-0.0.1.dev109.dist-info/METADATA,sha256=v6-T3y67YWXtDvTUvKDY54ywJvMNaNpb150tom2JvtM,1612
85
- tinybird-0.0.1.dev109.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
86
- tinybird-0.0.1.dev109.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
87
- tinybird-0.0.1.dev109.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
88
- tinybird-0.0.1.dev109.dist-info/RECORD,,
84
+ tinybird-0.0.1.dev111.dist-info/METADATA,sha256=Od6iCtY8gfCnixP673yRdEc2fR8aRC3dgMrIt4NF15Y,1612
85
+ tinybird-0.0.1.dev111.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
86
+ tinybird-0.0.1.dev111.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
87
+ tinybird-0.0.1.dev111.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
88
+ tinybird-0.0.1.dev111.dist-info/RECORD,,