tinybird 0.0.1.dev110__tar.gz → 0.0.1.dev112__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 (108) hide show
  1. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/PKG-INFO +1 -1
  2. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/__cli__.py +2 -2
  3. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/cli.py +8 -1
  4. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/common.py +60 -86
  5. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/connection.py +42 -0
  6. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/create.py +11 -0
  7. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/parse_datasource.py +4 -2
  8. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/parse_pipe.py +2 -2
  9. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/feedback_manager.py +1 -1
  10. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/local.py +26 -11
  11. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird.egg-info/PKG-INFO +1 -1
  12. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/setup.cfg +0 -0
  13. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/__cli__.py +0 -0
  14. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/ch_utils/constants.py +0 -0
  15. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/ch_utils/engine.py +0 -0
  16. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/check_pypi.py +0 -0
  17. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/client.py +0 -0
  18. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/config.py +0 -0
  19. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/connectors.py +0 -0
  20. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/context.py +0 -0
  21. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/datafile.py +0 -0
  22. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/datatypes.py +0 -0
  23. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/feedback_manager.py +0 -0
  24. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/git_settings.py +0 -0
  25. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/prompts.py +0 -0
  26. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/sql.py +0 -0
  27. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/sql_template.py +0 -0
  28. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/sql_template_fmt.py +0 -0
  29. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/sql_toolset.py +0 -0
  30. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/syncasync.py +0 -0
  31. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/cli.py +0 -0
  32. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/auth.py +0 -0
  33. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/build.py +0 -0
  34. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/cicd.py +0 -0
  35. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/config.py +0 -0
  36. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/copy.py +0 -0
  37. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/build.py +0 -0
  38. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/build_common.py +0 -0
  39. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  40. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  41. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/common.py +0 -0
  42. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/diff.py +0 -0
  43. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/exceptions.py +0 -0
  44. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/fixture.py +0 -0
  45. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/format_common.py +0 -0
  46. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  47. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  48. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  49. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/playground.py +0 -0
  50. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datafile/pull.py +0 -0
  51. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/datasource.py +0 -0
  52. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/deployment.py +0 -0
  53. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/endpoint.py +0 -0
  54. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/exceptions.py +0 -0
  55. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/fmt.py +0 -0
  56. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/infra.py +0 -0
  57. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/job.py +0 -0
  58. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/llm.py +0 -0
  59. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/llm_utils.py +0 -0
  60. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/local_common.py +0 -0
  61. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/login.py +0 -0
  62. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/logout.py +0 -0
  63. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/materialization.py +0 -0
  64. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/mock.py +0 -0
  65. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/open.py +0 -0
  66. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/pipe.py +0 -0
  67. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/playground.py +0 -0
  68. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/project.py +0 -0
  69. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/regions.py +0 -0
  70. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/secret.py +0 -0
  71. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/shell.py +0 -0
  72. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/table.py +0 -0
  73. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/tag.py +0 -0
  74. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/telemetry.py +0 -0
  75. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/test.py +0 -0
  76. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  77. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
  78. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/token.py +0 -0
  79. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/watch.py +0 -0
  80. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/workspace.py +0 -0
  81. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb/modules/workspace_members.py +0 -0
  82. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli.py +0 -0
  83. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/auth.py +0 -0
  84. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/branch.py +0 -0
  85. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/cicd.py +0 -0
  86. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/cli.py +0 -0
  87. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/common.py +0 -0
  88. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/config.py +0 -0
  89. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/connection.py +0 -0
  90. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/datasource.py +0 -0
  91. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/exceptions.py +0 -0
  92. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/fmt.py +0 -0
  93. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/job.py +0 -0
  94. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/pipe.py +0 -0
  95. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/regions.py +0 -0
  96. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/tag.py +0 -0
  97. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/telemetry.py +0 -0
  98. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/test.py +0 -0
  99. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  100. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
  101. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/workspace.py +0 -0
  102. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  103. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird/tornado_template.py +0 -0
  104. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird.egg-info/SOURCES.txt +0 -0
  105. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird.egg-info/dependency_links.txt +0 -0
  106. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird.egg-info/entry_points.txt +0 -0
  107. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/tinybird.egg-info/requires.txt +0 -0
  108. {tinybird-0.0.1.dev110 → tinybird-0.0.1.dev112}/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.dev110
3
+ Version: 0.0.1.dev112
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird
@@ -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.dev110'
8
- __revision__ = '034b6bf'
7
+ __version__ = '0.0.1.dev112'
8
+ __revision__ = 'eb9e376'
@@ -6,6 +6,7 @@
6
6
  import json
7
7
  import logging
8
8
  import os
9
+ import shutil
9
10
  import sys
10
11
  from os import getcwd
11
12
  from pathlib import Path
@@ -48,7 +49,13 @@ DEFAULT_PATTERNS: List[Tuple[str, Union[str, Callable[[str], str]]]] = [
48
49
  VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
49
50
 
50
51
 
51
- @click.group(cls=CatchAuthExceptions, context_settings={"help_option_names": ["-h", "--help"]})
52
+ @click.group(
53
+ cls=CatchAuthExceptions,
54
+ context_settings={
55
+ "help_option_names": ["-h", "--help"],
56
+ "max_content_width": shutil.get_terminal_size().columns - 10,
57
+ },
58
+ )
52
59
  @click.option(
53
60
  "--debug/--no-debug",
54
61
  default=False,
@@ -1751,90 +1751,69 @@ async def remove_release(
1751
1751
  click.echo(FeedbackManager.info_no_release_deleted())
1752
1752
 
1753
1753
 
1754
- async def validate_aws_iamrole_integration(
1754
+ async def run_aws_iamrole_connection_flow(
1755
1755
  client: TinyB,
1756
1756
  service: str,
1757
- role_arn: Optional[str],
1758
- region: Optional[str],
1759
- policy: str = "write",
1760
- no_validate: Optional[bool] = False,
1757
+ policy: str = "read",
1761
1758
  ):
1762
- if no_validate is False:
1763
- access_policy, trust_policy, external_id = await get_aws_iamrole_policies(
1764
- client, service=service, policy=policy
1765
- )
1759
+ if service == DataConnectorType.AMAZON_DYNAMODB:
1760
+ raise NotImplementedError("DynamoDB is not supported yet")
1766
1761
 
1767
- if not role_arn:
1768
- if not click.confirm(
1769
- FeedbackManager.prompt_s3_iamrole_connection_login_aws(),
1770
- show_default=False,
1771
- prompt_suffix="Press y to continue:",
1772
- ):
1773
- sys.exit(1)
1762
+ resource_type = "table" if service == DataConnectorType.AMAZON_DYNAMODB else "bucket"
1763
+ resource_name = click.prompt(f"Enter the name of the {resource_type}")
1764
+ validate_string_connector_param(resource_type.capitalize(), resource_name)
1774
1765
 
1775
- access_policy_copied = True
1776
- try:
1777
- pyperclip.copy(access_policy)
1778
- except Exception:
1779
- access_policy_copied = False
1766
+ resource_region = click.prompt(f"Enter the region where the {resource_type} is located")
1767
+ validate_string_connector_param("Region", resource_region)
1780
1768
 
1781
- replacements_dict = {
1782
- "<bucket>": "<bucket> with your bucket name",
1783
- "<table_name>": "<table_name> with your DynamoDB table name",
1784
- }
1769
+ access_policy, trust_policy, external_id = await get_aws_iamrole_policies(client, service=service, policy=policy)
1770
+ access_policy = access_policy.replace("<bucket>", resource_name)
1785
1771
 
1786
- replacements = [
1787
- replacements_dict.get(replacement, "")
1788
- for replacement in replacements_dict.keys()
1789
- if replacement in access_policy
1790
- ]
1772
+ if not click.confirm(
1773
+ FeedbackManager.prompt_s3_iamrole_connection_login_aws(),
1774
+ show_default=False,
1775
+ prompt_suffix="Press y to continue:",
1776
+ ):
1777
+ sys.exit(1)
1791
1778
 
1792
- if not click.confirm(
1793
- (
1794
- FeedbackManager.prompt_s3_iamrole_connection_policy(
1795
- access_policy=access_policy, replacements=", ".join(replacements)
1796
- )
1797
- if access_policy_copied
1798
- else FeedbackManager.prompt_s3_iamrole_connection_policy_not_copied(access_policy=access_policy)
1799
- ),
1800
- show_default=False,
1801
- prompt_suffix="Press y to continue:",
1802
- ):
1803
- sys.exit(1)
1804
-
1805
- trust_policy_copied = True
1806
- try:
1807
- pyperclip.copy(trust_policy)
1808
- except Exception:
1809
- trust_policy_copied = False
1810
-
1811
- if not click.confirm(
1812
- (
1813
- FeedbackManager.prompt_s3_iamrole_connection_role(trust_policy=trust_policy)
1814
- if trust_policy_copied
1815
- else FeedbackManager.prompt_s3_iamrole_connection_role_not_copied(trust_policy=trust_policy)
1816
- ),
1817
- show_default=False,
1818
- prompt_suffix="Press y to continue:",
1819
- ):
1820
- sys.exit(1)
1821
- else:
1822
- try:
1823
- trust_policy = await client.get_trust_policy(service)
1824
- external_id = trust_policy["Statement"][0]["Condition"]["StringEquals"]["sts:ExternalId"]
1825
- except Exception:
1826
- external_id = ""
1779
+ access_policy_copied = True
1780
+ try:
1781
+ pyperclip.copy(access_policy)
1782
+ except Exception:
1783
+ access_policy_copied = False
1827
1784
 
1828
- if not role_arn:
1829
- role_arn = click.prompt("Enter the ARN of the role you just created")
1830
- validate_string_connector_param("Role ARN", role_arn)
1785
+ if not click.confirm(
1786
+ (
1787
+ FeedbackManager.prompt_s3_iamrole_connection_policy(access_policy=access_policy)
1788
+ if access_policy_copied
1789
+ else FeedbackManager.prompt_s3_iamrole_connection_policy_not_copied(access_policy=access_policy)
1790
+ ),
1791
+ show_default=False,
1792
+ prompt_suffix="Press y to continue:",
1793
+ ):
1794
+ sys.exit(1)
1831
1795
 
1832
- if not region:
1833
- region_resource = "table" if service == DataConnectorType.AMAZON_DYNAMODB else "bucket"
1834
- region = click.prompt(f"Enter the region where the {region_resource} is located")
1835
- validate_string_connector_param("Region", region)
1796
+ trust_policy_copied = True
1797
+ try:
1798
+ pyperclip.copy(trust_policy)
1799
+ except Exception:
1800
+ trust_policy_copied = False
1836
1801
 
1837
- return role_arn, region, external_id
1802
+ if not click.confirm(
1803
+ (
1804
+ FeedbackManager.prompt_s3_iamrole_connection_role(trust_policy=trust_policy)
1805
+ if trust_policy_copied
1806
+ else FeedbackManager.prompt_s3_iamrole_connection_role_not_copied(trust_policy=trust_policy)
1807
+ ),
1808
+ show_default=False,
1809
+ prompt_suffix="Press y to continue:",
1810
+ ):
1811
+ sys.exit(1)
1812
+
1813
+ role_arn = click.prompt("Enter the ARN of the role you just created")
1814
+ validate_string_connector_param("Role ARN", role_arn)
1815
+
1816
+ return role_arn, resource_region, external_id
1838
1817
 
1839
1818
 
1840
1819
  async def get_aws_iamrole_policies(client: TinyB, service: str, policy: str = "write"):
@@ -1867,20 +1846,15 @@ async def get_aws_iamrole_policies(client: TinyB, service: str, policy: str = "w
1867
1846
  return json.dumps(access_policy, indent=4), json.dumps(trust_policy, indent=4), external_id
1868
1847
 
1869
1848
 
1870
- async def validate_aws_iamrole_connection_name(
1871
- client: TinyB, connection_name: Optional[str], no_validate: Optional[bool] = False
1872
- ) -> str:
1873
- if connection_name and no_validate is False:
1874
- if await client.get_connector(connection_name, skip_bigquery=True) is not None:
1875
- raise CLIConnectionException(FeedbackManager.info_connection_already_exists(name=connection_name))
1876
- else:
1877
- while not connection_name:
1878
- connection_name = click.prompt("Enter the name for this connection", default=None, show_default=False)
1879
- assert isinstance(connection_name, str)
1849
+ async def validate_aws_iamrole_connection_name(client: TinyB) -> str:
1850
+ connection_name = None
1851
+ while not connection_name:
1852
+ connection_name = click.prompt("Enter the name for this connection", default=None, show_default=False)
1853
+ assert isinstance(connection_name, str)
1880
1854
 
1881
- if no_validate is False and await client.get_connector(connection_name) is not None:
1882
- click.echo(FeedbackManager.info_connection_already_exists(name=connection_name))
1883
- connection_name = None
1855
+ if await client.get_connector(connection_name) is not None:
1856
+ click.echo(FeedbackManager.info_connection_already_exists(name=connection_name))
1857
+ connection_name = None
1884
1858
  assert isinstance(connection_name, str)
1885
1859
  return connection_name
1886
1860
 
@@ -15,8 +15,12 @@ from tinybird.tb.modules.common import (
15
15
  _get_setting_value,
16
16
  coro,
17
17
  echo_safe_humanfriendly_tables_format_smart_table,
18
+ run_aws_iamrole_connection_flow,
19
+ validate_aws_iamrole_connection_name,
18
20
  )
21
+ from tinybird.tb.modules.create import generate_aws_iamrole_connection_file
19
22
  from tinybird.tb.modules.feedback_manager import FeedbackManager
23
+ from tinybird.tb.modules.project import Project
20
24
 
21
25
  DATA_CONNECTOR_SETTINGS: Dict[DataConnectorType, List[str]] = {
22
26
  DataConnectorType.KAFKA: [
@@ -123,3 +127,41 @@ async def connection_ls(ctx: Context, service: Optional[DataConnectorType] = Non
123
127
  column_names = [c.replace("kafka_", "") for c in columns]
124
128
  echo_safe_humanfriendly_tables_format_smart_table(table, column_names=column_names)
125
129
  click.echo("\n")
130
+
131
+
132
+ @connection.group(name="create")
133
+ @click.pass_context
134
+ def connection_create(ctx: Context) -> None:
135
+ """Create a connection."""
136
+
137
+
138
+ @connection_create.command(name="s3", short_help="Creates a AWS S3 connection.")
139
+ @click.pass_context
140
+ @coro
141
+ async def connection_create_s3(ctx: Context) -> None:
142
+ """
143
+ Creates a AWS S3 connection.
144
+
145
+ \b
146
+ $ tb connection create s3
147
+ """
148
+ project: Project = ctx.ensure_object(dict)["project"]
149
+ obj: Dict[str, Any] = ctx.ensure_object(dict)
150
+ client: TinyB = obj["client"]
151
+ service = DataConnectorType.AMAZON_S3
152
+ connection_name = await validate_aws_iamrole_connection_name(client)
153
+ role_arn, region, external_id = await run_aws_iamrole_connection_flow(
154
+ client,
155
+ service=service,
156
+ policy="read", # For now only read since we only support import from S3
157
+ )
158
+
159
+ await generate_aws_iamrole_connection_file(
160
+ name=connection_name, service=service, role_arn=role_arn, region=region, folder=project.folder
161
+ )
162
+ if external_id:
163
+ click.echo(
164
+ FeedbackManager.success_s3_iam_connection_created(
165
+ connection_name=connection_name, external_id=external_id, role_arn=role_arn
166
+ )
167
+ )
@@ -353,6 +353,17 @@ def generate_connection_file(name: str, content: str, folder: str) -> Path:
353
353
  return f.relative_to(folder)
354
354
 
355
355
 
356
+ async def generate_aws_iamrole_connection_file(
357
+ name: str, service: str, role_arn: str, region: str, folder: str
358
+ ) -> None:
359
+ content = f"""TYPE {service}
360
+
361
+ S3_ARN {role_arn}
362
+ S3_REGION {region}
363
+ """
364
+ generate_connection_file(name, content, folder)
365
+
366
+
356
367
  def create_rules(folder: str, source: str, agent: str):
357
368
  if agent == "cursor":
358
369
  extension = ".cursorrules"
@@ -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:
@@ -498,7 +498,7 @@ Ready? """
498
498
 
499
499
  prompt_s3_iamrole_connection_login_aws = prompt_message("""[1] Log into your AWS Console\n\n""")
500
500
  prompt_s3_iamrole_connection_policy = prompt_message(
501
- """\n[2] Go to IAM > Policies. Create a new policy with the following permissions. Please, replace {replacements}:\n\n{access_policy}\n\n(The policy has been copied to your clipboard)\n\n"""
501
+ """\n[2] Go to IAM > Policies. Create a new policy with the following permissions:\n\n{access_policy}\n\n(The policy has been copied to your clipboard)\n\n"""
502
502
  )
503
503
  prompt_s3_iamrole_connection_policy_not_copied = prompt_message(
504
504
  """\n[2] Go to IAM > Policies. Create a new policy with the following permissions. Please, copy this policy and replace <bucket> with your bucket name:\n\n{access_policy}\n\n"""
@@ -130,7 +130,7 @@ def get_docker_client() -> DockerClient:
130
130
  )
131
131
 
132
132
 
133
- def get_use_aws_creds():
133
+ def get_use_aws_creds() -> dict[str, str]:
134
134
  credentials: dict[str, str] = {}
135
135
  try:
136
136
  # Get the boto3 session and credentials
@@ -149,14 +149,29 @@ def get_use_aws_creds():
149
149
  # Add region if available
150
150
  if session.region_name:
151
151
  credentials["AWS_DEFAULT_REGION"] = session.region_name
152
- except Exception:
153
- # TODO (rbarbadillo): We should handle this better. If users don't have AWS credentials, most times it's fine
154
- # but if they want to use S3, they'll need a warning.
155
- 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
+
156
171
  return credentials
157
172
 
158
173
 
159
- def stop_tinybird_local(docker_client):
174
+ def stop_tinybird_local(docker_client: DockerClient) -> None:
160
175
  """Stop the Tinybird container."""
161
176
  try:
162
177
  container = docker_client.containers.get(TB_CONTAINER_NAME)
@@ -165,7 +180,7 @@ def stop_tinybird_local(docker_client):
165
180
  pass
166
181
 
167
182
 
168
- def remove_tinybird_local(docker_client):
183
+ def remove_tinybird_local(docker_client: DockerClient) -> None:
169
184
  """Remove the Tinybird container."""
170
185
  try:
171
186
  container = docker_client.containers.get(TB_CONTAINER_NAME)
@@ -181,7 +196,7 @@ def remove_tinybird_local(docker_client):
181
196
  pass
182
197
 
183
198
 
184
- def update_cli():
199
+ def update_cli() -> None:
185
200
  click.echo(FeedbackManager.highlight(message="» Updating Tinybird CLI..."))
186
201
 
187
202
  try:
@@ -205,20 +220,20 @@ def update_cli():
205
220
 
206
221
 
207
222
  @cli.command()
208
- def update():
223
+ def update() -> None:
209
224
  """Update Tinybird CLI to the latest version."""
210
225
  update_cli()
211
226
 
212
227
 
213
228
  @cli.command(name="upgrade", hidden=True)
214
- def upgrade():
229
+ def upgrade() -> None:
215
230
  """Update Tinybird CLI to the latest version."""
216
231
  update_cli()
217
232
 
218
233
 
219
234
  @cli.group()
220
235
  @click.pass_context
221
- def local(ctx):
236
+ def local(ctx: click.Context) -> None:
222
237
  """Manage the local Tinybird instance."""
223
238
 
224
239
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 0.0.1.dev110
3
+ Version: 0.0.1.dev112
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/cli/introduction.html
6
6
  Author: Tinybird