tinybird 0.0.1.dev70__tar.gz → 0.0.1.dev72__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 (101) hide show
  1. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/client.py +5 -1
  3. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/feedback_manager.py +2 -2
  4. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/prompts.py +2 -2
  5. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/sql_template.py +38 -5
  6. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/__cli__.py +2 -2
  7. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/cicd.py +1 -1
  8. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/cli.py +6 -4
  9. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/common.py +3 -3
  10. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/config.py +2 -1
  11. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/deployment.py +10 -1
  12. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/endpoint.py +9 -5
  13. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/feedback_manager.py +2 -2
  14. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/local_common.py +3 -3
  15. {tinybird-0.0.1.dev70/tinybird/tb_cli_modules → tinybird-0.0.1.dev72/tinybird/tb/modules}/telemetry.py +1 -1
  16. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/test.py +2 -1
  17. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -2
  18. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/cli.py +0 -1
  19. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/common.py +1 -1
  20. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/pipe.py +0 -1
  21. {tinybird-0.0.1.dev70/tinybird/tb/modules → tinybird-0.0.1.dev72/tinybird/tb_cli_modules}/telemetry.py +1 -1
  22. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -2
  23. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tornado_template.py +1 -1
  24. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird.egg-info/PKG-INFO +1 -1
  25. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/setup.cfg +0 -0
  26. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/__cli__.py +0 -0
  27. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/ch_utils/constants.py +0 -0
  28. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/ch_utils/engine.py +0 -0
  29. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/check_pypi.py +0 -0
  30. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/config.py +0 -0
  31. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/connectors.py +0 -0
  32. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/context.py +0 -0
  33. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/datafile.py +0 -0
  34. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/datatypes.py +0 -0
  35. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/git_settings.py +0 -0
  36. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/sql.py +0 -0
  37. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/sql_template_fmt.py +0 -0
  38. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/sql_toolset.py +0 -0
  39. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/syncasync.py +0 -0
  40. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/cli.py +0 -0
  41. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/auth.py +0 -0
  42. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/build.py +0 -0
  43. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/copy.py +0 -0
  44. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/create.py +0 -0
  45. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/build.py +0 -0
  46. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/build_common.py +0 -0
  47. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  48. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  49. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/common.py +0 -0
  50. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/diff.py +0 -0
  51. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  52. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/fixture.py +0 -0
  53. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/format_common.py +0 -0
  54. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  55. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  56. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
  57. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
  58. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  59. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datafile/pull.py +0 -0
  60. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/datasource.py +0 -0
  61. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/exceptions.py +0 -0
  62. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/fmt.py +0 -0
  63. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/job.py +0 -0
  64. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/llm.py +0 -0
  65. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/llm_utils.py +0 -0
  66. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/local.py +0 -0
  67. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/login.py +0 -0
  68. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/materialization.py +0 -0
  69. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/mock.py +0 -0
  70. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/pipe.py +0 -0
  71. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/project.py +0 -0
  72. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/regions.py +0 -0
  73. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/shell.py +0 -0
  74. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/table.py +0 -0
  75. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/tag.py +0 -0
  76. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  77. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/token.py +0 -0
  78. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/watch.py +0 -0
  79. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/workspace.py +0 -0
  80. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb/modules/workspace_members.py +0 -0
  81. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli.py +0 -0
  82. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/auth.py +0 -0
  83. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/branch.py +0 -0
  84. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/cicd.py +0 -0
  85. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/config.py +0 -0
  86. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/connection.py +0 -0
  87. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/datasource.py +0 -0
  88. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/exceptions.py +0 -0
  89. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/fmt.py +0 -0
  90. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/job.py +0 -0
  91. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/regions.py +0 -0
  92. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/tag.py +0 -0
  93. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/test.py +0 -0
  94. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  95. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/workspace.py +0 -0
  96. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  97. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird.egg-info/SOURCES.txt +0 -0
  98. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird.egg-info/dependency_links.txt +0 -0
  99. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird.egg-info/entry_points.txt +0 -0
  100. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird.egg-info/requires.txt +0 -0
  101. {tinybird-0.0.1.dev70 → tinybird-0.0.1.dev72}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev70
3
+ Version: 0.0.1.dev72
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -93,6 +93,7 @@ class TinyB:
93
93
  send_telemetry: bool = False,
94
94
  semver: Optional[str] = None,
95
95
  env: Optional[str] = "production",
96
+ staging: bool = False,
96
97
  ):
97
98
  ctx = ssl.create_default_context()
98
99
  ctx.check_hostname = False
@@ -105,6 +106,7 @@ class TinyB:
105
106
  self.send_telemetry = send_telemetry
106
107
  self.semver = semver
107
108
  self.env = env
109
+ self.staging = staging
108
110
 
109
111
  async def _req_raw(
110
112
  self,
@@ -125,6 +127,8 @@ class TinyB:
125
127
  url += ("&" if "?" in url else "?") + "cli_version=" + quote(self.version)
126
128
  if self.semver:
127
129
  url += ("&" if "?" in url else "?") + "__tb__semver=" + self.semver
130
+ if self.staging:
131
+ url += ("&" if "?" in url else "?") + "__tb__deployment=staging"
128
132
 
129
133
  verify_ssl = not self.disable_ssl_checks
130
134
  try:
@@ -197,7 +201,7 @@ class TinyB:
197
201
  if not token_to_use:
198
202
  raise AuthNoTokenException(f"Forbidden: {error}")
199
203
  raise AuthException(f"Forbidden: {error}")
200
- if response.status_code == 204 or response.status_code == 205:
204
+ if response.status_code in (204, 205):
201
205
  return None
202
206
  if response.status_code == 404:
203
207
  error = parse_error_response(response)
@@ -458,7 +458,7 @@ class FeedbackManager:
458
458
  info_releases_detected = info_message("** Live Release: {current_semver} => New Release: {semver}")
459
459
  info_dry_releases_detected = info_message("** [DRY RUN] Live Release: {current_semver} => New Release: {semver}")
460
460
  info_pre_prompt_auth_login_user_token = info_message(
461
- "ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here."
461
+ "ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here." # noqa: RUF001
462
462
  )
463
463
  prompt_auth_login_user_token = prompt_message("❓ User token:")
464
464
 
@@ -609,7 +609,7 @@ Ready? """
609
609
  )
610
610
  warning_datasource_sync = warning_message("** Warning: Do you want to sync the Data Source {datasource}?")
611
611
  warning_datasource_sync_bucket = warning_message(
612
- "** Warning: Do you want to ingest all the selected files (new and previous) from the {datasource} bucket? Be aware that data might be duplicated if you have previously ingested those files.\n"
612
+ "** Warning: Do you want to ingest all the selected files (new and previous) from the {datasource} bucket? Be aware that data might be duplicated if you have previously ingested those files.\n"
613
613
  )
614
614
  warning_users_dont_exist = warning_message(
615
615
  "** Warning: The following users do not exist in the workspace {workspace}: {users}"
@@ -790,10 +790,10 @@ When you need to work with resources or data in cloud, add always the --cloud fl
790
790
  ├── materializations
791
791
  ├── pipes
792
792
  └── tests
793
- - The local development server will be available at http://localhost:80. Even if some response uses another base url, use always http://localhost:80.
793
+ - The local development server will be available at http://localhost:7181. Even if some response uses another base url, use always http://localhost:7181.
794
794
  - After every change in your .datasource, .pipe or .ndjson files, run `{base_command} build` to build the project locally.
795
795
  - When you need to ingest data locally in a datasource, create a .ndjson file with the same name of the datasource and the data you want and run `{base_command} build` so the data is ingested.
796
- - The format of the generated api endpoint urls is: http://localhost:80/v0/pipe/<pipe_name>.json?token=<token>
796
+ - The format of the generated api endpoint urls is: http://localhost:7181/v0/pipe/<pipe_name>.json?token=<token>
797
797
  - Before running the tests, remember to have the project built with `{base_command} build` with the latest changes.
798
798
  </development_instructions>
799
799
  When asking for ingesting data, adding data or appending data do the following depending on the environment you want to work with:
@@ -385,9 +385,12 @@ def array_type(types):
385
385
  x = default
386
386
  else:
387
387
  if _type and _type in types:
388
- x = ",".join(map(str, [types[_type](x) for _ in range(2)]))
388
+ if _type == "String":
389
+ x = ""
390
+ else:
391
+ x = ",".join(map(str, [types[_type](x) for _ in range(2)]))
389
392
  else:
390
- x = ",".join([f"__no_value__{i}" for i in range(2)])
393
+ x = ""
391
394
  elif x is None:
392
395
  x = default
393
396
  if x is None:
@@ -405,7 +408,7 @@ def array_type(types):
405
408
  values.append(expression_wrapper(types[_type](t), str(t)))
406
409
  else:
407
410
  raise SQLTemplateException(
408
- f"Error validating {x}[{i}]({t}) to type {_type}",
411
+ f"Error validating [{x}][{i}] ({'empty string' if t == '' else t}) to type {_type}",
409
412
  documentation="/cli/advanced-templates.html",
410
413
  )
411
414
  else:
@@ -2056,7 +2059,11 @@ def render_sql_template(
2056
2059
  >>> render_sql_template("SELECT {{ Array(embedding, 'Float32') }}", {'token':'testing', 'embedding': '1,2,3,4, null'})
2057
2060
  Traceback (most recent call last):
2058
2061
  ...
2059
- tinybird.sql_template.SQLTemplateException: Template Syntax Error: Error validating 1,2,3,4, null[4]( null) to type Float32
2062
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: Error validating [1,2,3,4, null][4] ( null) to type Float32
2063
+ >>> render_sql_template("SELECT {{ Array(embedding, 'Int32', '') }}", {'token':'testing', 'embedding': ''})
2064
+ Traceback (most recent call last):
2065
+ ...
2066
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: Error validating [][0] (empty string) to type Int32
2060
2067
  >>> render_sql_template('{% if test %}SELECT 1{% else %} select 2 {% end %}')
2061
2068
  (' select 2 ', {}, [])
2062
2069
  >>> render_sql_template('{% if Int32(test, 1) %}SELECT 1{% else %} select 2 {% end %}')
@@ -2096,7 +2103,7 @@ def render_sql_template(
2096
2103
  >>> render_sql_template("SELECT {{Array(foo, 'Int32')}}", test_mode=True)
2097
2104
  ('SELECT [0,0]', {}, [])
2098
2105
  >>> render_sql_template("SELECT {{Array(foo)}}", test_mode=True)
2099
- ("SELECT ['__no_value__0','__no_value__1']", {}, [])
2106
+ ("SELECT ['']", {}, [])
2100
2107
  >>> render_sql_template("{{max_threads(2)}} SELECT 1")
2101
2108
  ('-- max_threads 2\\n SELECT 1', {'max_threads': 2}, [])
2102
2109
  >>> render_sql_template("SELECT {{String(foo)}}", test_mode=True)
@@ -2183,6 +2190,14 @@ def render_sql_template(
2183
2190
  ("% SELECT ['pre','pro']", {}, [])
2184
2191
  >>> render_sql_template("% SELECT {{Array(click_selector, 'String', 'pre,pro')}}", {'click_selector': 'hi,hello'})
2185
2192
  ("% SELECT ['hi','hello']", {}, [])
2193
+ >>> render_sql_template("% SELECT {{Array(click_selector, 'String', '')}}")
2194
+ ("% SELECT ['']", {}, [])
2195
+ >>> render_sql_template("SELECT {{ Array(embedding, 'Int32', '') }}")
2196
+ Traceback (most recent call last):
2197
+ ...
2198
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: Error validating [][0] (empty string) to type Int32
2199
+ >>> render_sql_template("% SELECT {{Array(click_selector, 'String', '')}}", test_mode=True)
2200
+ ("% SELECT ['']", {}, [])
2186
2201
  >>> render_sql_template("% SELECT now() > {{DateTime64(variable, '2020-09-09 10:10:10.000')}}", {})
2187
2202
  ("% SELECT now() > '2020-09-09 10:10:10.000'", {}, [])
2188
2203
  >>> render_sql_template("% SELECT {% if defined(x) %} x, 1", {})
@@ -2241,6 +2256,16 @@ def render_sql_template(
2241
2256
  Traceback (most recent call last):
2242
2257
  ...
2243
2258
  tinybird.sql_template.SQLTemplateException: Template Syntax Error: Required parameter is not defined. Check the parameters test. Please provide a value or set a default value in the pipe code.
2259
+ >>> render_sql_template("SELECT * FROM test WHERE {% for item in JSON(filters, '[{}]') %} {{item.get('operand')}} {% end %}")
2260
+ Traceback (most recent call last):
2261
+ ...
2262
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: expression "item.get('operand')" evaluated to null
2263
+ >>> render_sql_template("SELECT * FROM test WHERE {% for item in JSON(filters, '[{\\\"operand\\\":\\\"test\\\"}]') %} {{item.get('operand')}} {% end %}")
2264
+ ("SELECT * FROM test WHERE 'test' ", {}, [])
2265
+ >>> render_sql_template("SELECT * FROM test WHERE {% for item in JSON(filters, '[\\\"test\\\"]') %} {{item.get('operator')}} {% end %}")
2266
+ Traceback (most recent call last):
2267
+ ...
2268
+ tinybird.sql_template.SQLTemplateException: Template Syntax Error: 'str' object has no attribute 'get'. Make sure you're using an object/dictionary where trying to use .get()
2244
2269
  """
2245
2270
  escape_split_to_array = ff_split_to_array_escape.get(False)
2246
2271
 
@@ -2308,6 +2333,14 @@ def render_sql_template(
2308
2333
  except SQLTemplateException as e:
2309
2334
  format_SQLTemplateException_message(e, vars_and_types=template_variables_with_types)
2310
2335
  raise
2336
+ except AttributeError as e:
2337
+ # This happens when trying to use `get` on a string or when the object is None
2338
+ if "'str' object has no attribute 'get'" in str(e):
2339
+ raise SQLTemplateException(
2340
+ "'str' object has no attribute 'get'. Make sure you're using an object/dictionary where trying to use .get()",
2341
+ documentation="/cli/advanced-templates.html",
2342
+ )
2343
+ raise SQLTemplateException(str(e), documentation="/cli/advanced-templates.html")
2311
2344
  except Exception as e:
2312
2345
  # errors might vary here, we need to support as much as possible
2313
2346
  # https://gitlab.com/tinybird/analytics/-/issues/943
@@ -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.dev70'
8
- __revision__ = 'f8064d4'
7
+ __version__ = '0.0.1.dev72'
8
+ __revision__ = 'f2d1d8b'
@@ -41,7 +41,7 @@ jobs:
41
41
  tinybird:
42
42
  image: tinybirdco/tinybird-local:beta
43
43
  ports:
44
- - 80:80
44
+ - 7181:7181
45
45
  steps:
46
46
  - uses: actions/checkout@v3
47
47
  - name: Install Tinybird CLI
@@ -57,6 +57,7 @@ VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
57
57
  @click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
58
58
  @click.option("--cloud/--local", is_flag=True, default=False, help="Run against cloud or local")
59
59
  @click.option("--build", is_flag=True, default=False, help="Run against build mode")
60
+ @click.option("--staging", is_flag=True, default=False, help="Run against a staging deployment.")
60
61
  @click.version_option(version=VERSION)
61
62
  @click.pass_context
62
63
  @coro
@@ -68,6 +69,7 @@ async def cli(
68
69
  show_tokens: bool,
69
70
  cloud: bool,
70
71
  build: bool,
72
+ staging: bool,
71
73
  ) -> None:
72
74
  """
73
75
  Use `OBFUSCATE_REGEX_PATTERN` and `OBFUSCATE_PATTERN_SEPARATOR` environment variables to define a regex pattern and a separator (in case of a single string with multiple regex) to obfuscate secrets in the CLI output.
@@ -121,7 +123,7 @@ async def cli(
121
123
 
122
124
  logging.debug("debug enabled")
123
125
 
124
- client = await create_ctx_client(ctx, config, cloud, build)
126
+ client = await create_ctx_client(ctx, config, cloud, build, staging)
125
127
 
126
128
  if client:
127
129
  ctx.ensure_object(dict)["client"] = client
@@ -386,7 +388,7 @@ def __unpatch_click_output():
386
388
  click.secho = __old_click_secho
387
389
 
388
390
 
389
- async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, build: bool):
391
+ async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, build: bool, staging: bool):
390
392
  commands_without_ctx_client = ["auth", "check", "login", "local", "upgrade"]
391
393
  command = ctx.invoked_subcommand
392
394
  if command in commands_without_ctx_client:
@@ -403,11 +405,11 @@ async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, b
403
405
  click.echo(
404
406
  FeedbackManager.gray(message=f"Running against Tinybird Cloud: Workspace {config.get('name', 'default')}")
405
407
  )
406
- return _get_tb_client(config.get("token", None), config["host"])
408
+ return _get_tb_client(config.get("token", None), config["host"], staging=staging)
407
409
  build = command in commands_always_build or build
408
410
  if not build and command not in commands_always_local and command not in commands_always_build:
409
411
  click.echo(FeedbackManager.gray(message="Running against Tinybird Local\n"))
410
- return await get_tinybird_local_client(config, build=build)
412
+ return await get_tinybird_local_client(config, build=build, staging=staging)
411
413
 
412
414
 
413
415
  def get_target_env(cloud: bool, build: bool) -> str:
@@ -375,9 +375,9 @@ def getenv_bool(key: str, default: bool) -> bool:
375
375
  return v.lower() == "true" or v == "1"
376
376
 
377
377
 
378
- def _get_tb_client(token: str, host: str) -> TinyB:
378
+ def _get_tb_client(token: str, host: str, staging: bool = False) -> TinyB:
379
379
  disable_ssl: bool = getenv_bool("TB_DISABLE_SSL_CHECKS", False)
380
- return TinyB(token, host, version=VERSION, disable_ssl_checks=disable_ssl, send_telemetry=True)
380
+ return TinyB(token, host, version=VERSION, disable_ssl_checks=disable_ssl, send_telemetry=True, staging=staging)
381
381
 
382
382
 
383
383
  def create_tb_client(ctx: Context) -> TinyB:
@@ -554,7 +554,7 @@ def format_host(host: str, subdomain: Optional[str] = None) -> str:
554
554
  if subdomain and not is_localhost:
555
555
  url_info = urlparse(host)
556
556
  current_subdomain = url_info.netloc.split(".")[0]
557
- if current_subdomain == "api" or current_subdomain == "ui":
557
+ if current_subdomain in ("api", "ui"):
558
558
  host = host.replace(current_subdomain, subdomain)
559
559
  if "localhost" in host or is_localhost:
560
560
  host = f"http://{host}" if "http" not in host else host
@@ -219,7 +219,7 @@ class CLIConfig:
219
219
  return CLIConfig.DEFAULTS["host"]
220
220
  return None
221
221
 
222
- def get_client(self, token: Optional[str] = None, host: Optional[str] = None) -> tbc.TinyB:
222
+ def get_client(self, token: Optional[str] = None, host: Optional[str] = None, staging: bool = False) -> tbc.TinyB:
223
223
  """Returns a new TinyB client configured with:
224
224
 
225
225
  - token:
@@ -242,6 +242,7 @@ class CLIConfig:
242
242
  version=CURRENT_VERSION,
243
243
  disable_ssl_checks=FeatureFlags.ignore_ssl_errors(),
244
244
  send_telemetry=FeatureFlags.send_telemetry(),
245
+ staging=staging,
245
246
  )
246
247
 
247
248
  def get_user_client(self, host: Optional[str] = None) -> tbc.TinyB:
@@ -352,7 +352,16 @@ def create_deployment(
352
352
  click.echo(FeedbackManager.success(message="\n✓ Deployment is valid"))
353
353
  else:
354
354
  click.echo(FeedbackManager.error(message="\n✗ Deployment is not valid"))
355
-
355
+ deploy_errors = result.get("errors")
356
+ for deploy_error in deploy_errors:
357
+ if deploy_error.get("filename", None):
358
+ click.echo(
359
+ FeedbackManager.error(
360
+ message=f"{deploy_error.get('filename')}\n\n{deploy_error.get('error')}"
361
+ )
362
+ )
363
+ else:
364
+ click.echo(FeedbackManager.error(message=f"{deploy_error.get('error')}"))
356
365
  return
357
366
 
358
367
  deploy_result = result.get("result")
@@ -56,7 +56,7 @@ async def endpoint_ls(ctx: Context, match: str, format_: str):
56
56
  if pattern and not pattern.search(tk["name"]):
57
57
  continue
58
58
  token = get_endpoint_token(tokens, tk["name"]) or client.token
59
- endpoint_url = build_endpoint_url(client, tk["name"], token)
59
+ endpoint_url = build_endpoint_url(client, tk["name"], token, client.staging)
60
60
  table_human_readable.append((tk["name"], t["updated_at"][:-7], len(t["nodes"]), endpoint_url))
61
61
  table_machine_readable.append(
62
62
  {
@@ -166,7 +166,7 @@ async def endpoint_url(ctx: Context, pipe: str, language: str):
166
166
  client: TinyB = ctx.ensure_object(dict)["client"]
167
167
  tokens = await client.tokens()
168
168
  token = get_endpoint_token(tokens, pipe) or client.token
169
- click.echo(build_endpoint_snippet(client, pipe, token, language))
169
+ click.echo(build_endpoint_snippet(client, pipe, token, language, client.staging))
170
170
  if language != "http":
171
171
  click.echo(FeedbackManager.success(message="\n✓ Code snippet copied to clipboard!\n"))
172
172
 
@@ -269,8 +269,10 @@ async def endpoint_stats(ctx: click.Context, pipes: Tuple[str, ...], format_: st
269
269
  echo_safe_humanfriendly_tables_format_smart_table(table_human_readable, column_names=columns)
270
270
 
271
271
 
272
- def build_endpoint_snippet(tb_client: TinyB, pipe_name: str, token: str, language: str) -> Optional[str]:
273
- endpoint_url = build_endpoint_url(tb_client, pipe_name, token)
272
+ def build_endpoint_snippet(
273
+ tb_client: TinyB, pipe_name: str, token: str, language: str, staging: bool = False
274
+ ) -> Optional[str]:
275
+ endpoint_url = build_endpoint_url(tb_client, pipe_name, token, staging)
274
276
  if language == "http":
275
277
  return endpoint_url
276
278
 
@@ -293,13 +295,15 @@ def build_endpoint_snippet(tb_client: TinyB, pipe_name: str, token: str, languag
293
295
  return snippet
294
296
 
295
297
 
296
- def build_endpoint_url(tb_client: TinyB, pipe_name: str, token: str) -> str:
298
+ def build_endpoint_url(tb_client: TinyB, pipe_name: str, token: str, staging: bool = False) -> str:
297
299
  example_params = {
298
300
  "format": "json",
299
301
  "pipe": pipe_name,
300
302
  "q": "",
301
303
  "token": token,
302
304
  }
305
+ if staging:
306
+ example_params["__tb__deployment"] = "staging"
303
307
  response = requests.get(f"{tb_client.host}/examples/query.http?{urlencode(example_params)}")
304
308
  return response.text.replace("http://localhost:8001", tb_client.host)
305
309
 
@@ -466,7 +466,7 @@ class FeedbackManager:
466
466
  info_releases_detected = info_message("** Live Release: {current_semver} => New Release: {semver}")
467
467
  info_dry_releases_detected = info_message("** [DRY RUN] Live Release: {current_semver} => New Release: {semver}")
468
468
  info_pre_prompt_auth_login_user_token = info_message(
469
- "ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here."
469
+ "ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here." # noqa: RUF001
470
470
  )
471
471
  prompt_auth_login_user_token = prompt_message("❓ User token:")
472
472
 
@@ -617,7 +617,7 @@ Ready? """
617
617
  )
618
618
  warning_datasource_sync = warning_message("** Warning: Do you want to sync the Data Source {datasource}?")
619
619
  warning_datasource_sync_bucket = warning_message(
620
- "** Warning: Do you want to ingest all the selected files (new and previous) from the {datasource} bucket? Be aware that data might be duplicated if you have previously ingested those files.\n"
620
+ "** Warning: Do you want to ingest all the selected files (new and previous) from the {datasource} bucket? Be aware that data might be duplicated if you have previously ingested those files.\n"
621
621
  )
622
622
  warning_users_dont_exist = warning_message(
623
623
  "** Warning: The following users do not exist in the workspace {workspace}: {users}"
@@ -11,14 +11,14 @@ from tinybird.tb.modules.exceptions import CLIException
11
11
 
12
12
  TB_IMAGE_NAME = "tinybirdco/tinybird-local:beta"
13
13
  TB_CONTAINER_NAME = "tinybird-local"
14
- TB_LOCAL_PORT = int(os.getenv("TB_LOCAL_PORT", 80))
14
+ TB_LOCAL_PORT = int(os.getenv("TB_LOCAL_PORT", 7181))
15
15
  TB_LOCAL_HOST = f"http://localhost:{TB_LOCAL_PORT}"
16
16
 
17
17
 
18
- async def get_tinybird_local_client(config_obj: Dict[str, Any], build: bool = False) -> TinyB:
18
+ async def get_tinybird_local_client(config_obj: Dict[str, Any], build: bool = False, staging: bool = False) -> TinyB:
19
19
  """Get a Tinybird client connected to the local environment."""
20
20
  config = await get_tinybird_local_config(config_obj, build=build)
21
- return config.get_client(host=TB_LOCAL_HOST)
21
+ return config.get_client(host=TB_LOCAL_HOST, staging=staging)
22
22
 
23
23
 
24
24
  async def get_tinybird_local_config(config_obj: Dict[str, Any], build: bool = False) -> CLIConfig:
@@ -206,7 +206,7 @@ class TelemetryHelper:
206
206
 
207
207
  self.log(f"Received status {r.status_code}: {r.text}")
208
208
 
209
- if r.status_code == 200 or r.status_code == 202:
209
+ if r.status_code in (200, 202):
210
210
  self.log(f"Successfully sent {len(events)} events to {self.tb_host}")
211
211
  self.events.clear()
212
212
  return
@@ -5,6 +5,7 @@
5
5
 
6
6
  import difflib
7
7
  import glob
8
+ import sys
8
9
  import urllib.parse
9
10
  from pathlib import Path
10
11
  from typing import Any, Dict, List, Optional, Tuple
@@ -265,7 +266,7 @@ async def run_tests(ctx: click.Context, name: Tuple[str, ...]) -> None:
265
266
 
266
267
  if failed_tests_count:
267
268
  click.echo(FeedbackManager.error(message=f"\n✗ {test_count - failed_tests_count}/{test_count} passed"))
268
- exit(1)
269
+ sys.exit(1)
269
270
  else:
270
271
  click.echo(FeedbackManager.success(message=f"\n✓ {test_count}/{test_count} passed"))
271
272
 
@@ -190,8 +190,6 @@ def generate_file(file: str, overwrite: bool = False) -> None:
190
190
  else:
191
191
  raise CLIException(FeedbackManager.error_file_already_exists(file=p))
192
192
 
193
- return
194
-
195
193
 
196
194
  async def run_test_file(tb_client: TinyB, file: str) -> List[TestResult]:
197
195
  results: List[TestResult] = []
@@ -676,7 +676,6 @@ async def push(
676
676
  user_token=user_token,
677
677
  is_internal=is_internal,
678
678
  )
679
- return
680
679
 
681
680
 
682
681
  @cli.command()
@@ -600,7 +600,7 @@ def format_host(host: str, subdomain: Optional[str] = None) -> str:
600
600
  if subdomain and not is_localhost:
601
601
  url_info = urlparse(host)
602
602
  current_subdomain = url_info.netloc.split(".")[0]
603
- if current_subdomain == "api" or current_subdomain == "ui":
603
+ if current_subdomain in ("api", "ui"):
604
604
  host = host.replace(current_subdomain, subdomain)
605
605
  if "localhost" in host or is_localhost:
606
606
  host = f"http://{host}" if "http" not in host else host
@@ -701,7 +701,6 @@ async def regression_test(
701
701
  tests_validate_processed_bytes=validate_processed_bytes,
702
702
  tests_check_requests_from_branch=check_requests_from_main,
703
703
  )
704
- return
705
704
 
706
705
 
707
706
  @pipe_copy.command(name="run", short_help="Run an on-demand copy job")
@@ -206,7 +206,7 @@ class TelemetryHelper:
206
206
 
207
207
  self.log(f"Received status {r.status_code}: {r.text}")
208
208
 
209
- if r.status_code == 200 or r.status_code == 202:
209
+ if r.status_code in (200, 202):
210
210
  self.log(f"Successfully sent {len(events)} events to {self.tb_host}")
211
211
  self.events.clear()
212
212
  return
@@ -190,8 +190,6 @@ def generate_file(file: str, overwrite: bool = False) -> None:
190
190
  else:
191
191
  raise CLIException(FeedbackManager.error_file_already_exists(file=p))
192
192
 
193
- return
194
-
195
193
 
196
194
  async def run_test_file(tb_client: TinyB, file: str) -> List[TestResult]:
197
195
  results: List[TestResult] = []
@@ -1144,7 +1144,7 @@ def check_valid_expr(expr):
1144
1144
  return
1145
1145
  if isinstance(expr.value, str):
1146
1146
  return
1147
- if isinstance(expr.value, type(None)):
1147
+ if expr.value is None:
1148
1148
  return
1149
1149
  raise SecurityException(f"Invalid Constant: {ast.dump(expr)}")
1150
1150
  elif isinstance(expr, ast.Name):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev70
3
+ Version: 0.0.1.dev72
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