tinybird 4.6.22__tar.gz → 4.6.23.dev0__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.
Files changed (130) hide show
  1. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/PKG-INFO +1 -6
  2. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/pyproject.toml +25 -28
  3. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/client.py +8 -0
  4. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/sql_template.py +24 -55
  5. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/sql_template_fmt.py +2 -2
  6. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/syncasync.py +43 -0
  7. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/__cli__.py +2 -2
  8. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/client.py +8 -0
  9. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/common.py +3 -3
  10. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/create.py +4 -2
  11. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/pull.py +3 -73
  12. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datasource.py +1 -1
  13. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/exceptions.py +21 -0
  14. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/common.py +3 -3
  15. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/datasource.py +1 -1
  16. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tornado_template.py +93 -38
  17. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird.egg-info/PKG-INFO +1 -6
  18. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/setup.cfg +0 -0
  19. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/__cli__.py +0 -0
  20. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/ch_utils/constants.py +0 -0
  21. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/ch_utils/engine.py +0 -0
  22. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/check_pypi.py +0 -0
  23. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/config.py +0 -0
  24. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/context.py +0 -0
  25. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/datafile/common.py +0 -0
  26. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/datafile/exceptions.py +0 -0
  27. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/datafile/parse_connection.py +0 -0
  28. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/datafile/parse_datasource.py +0 -0
  29. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/datafile/parse_pipe.py +0 -0
  30. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/datatypes.py +0 -0
  31. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/feedback_manager.py +0 -0
  32. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/git_settings.py +0 -0
  33. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/iterating/__init__.py +0 -0
  34. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/iterating/data_branch_modes.py +0 -0
  35. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/prompts.py +0 -0
  36. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/service_datasources.py +0 -0
  37. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/sql.py +0 -0
  38. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/sql_toolset.py +0 -0
  39. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/check_pypi.py +0 -0
  40. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/cli.py +0 -0
  41. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/config.py +0 -0
  42. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/branch.py +0 -0
  43. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/build.py +0 -0
  44. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/build_common.py +0 -0
  45. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/cicd.py +0 -0
  46. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/cli.py +0 -0
  47. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/config.py +0 -0
  48. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/connection.py +0 -0
  49. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/connection_dynamodb.py +0 -0
  50. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/connection_kafka.py +0 -0
  51. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/connection_s3.py +0 -0
  52. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/copy.py +0 -0
  53. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/build.py +0 -0
  54. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/build_common.py +0 -0
  55. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  56. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  57. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/diff.py +0 -0
  58. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/fixture.py +0 -0
  59. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/format_common.py +0 -0
  60. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/format_connection.py +0 -0
  61. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  62. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  63. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  64. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/datafile/playground.py +0 -0
  65. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/deployment.py +0 -0
  66. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/deployment_common.py +0 -0
  67. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/deprecations.py +0 -0
  68. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/endpoint.py +0 -0
  69. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/feedback_manager.py +0 -0
  70. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/fmt.py +0 -0
  71. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/info.py +0 -0
  72. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/infra.py +0 -0
  73. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/job.py +0 -0
  74. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/job_common.py +0 -0
  75. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/llm.py +0 -0
  76. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/llm_utils.py +0 -0
  77. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/local.py +0 -0
  78. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/local_common.py +0 -0
  79. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/local_logs.py +0 -0
  80. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/login.py +0 -0
  81. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/login_common.py +0 -0
  82. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/logout.py +0 -0
  83. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/logs.py +0 -0
  84. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/materialization.py +0 -0
  85. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/open.py +0 -0
  86. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/pipe.py +0 -0
  87. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/preview.py +0 -0
  88. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/project.py +0 -0
  89. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/project_commands.py +0 -0
  90. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/py_project.py +0 -0
  91. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/query_output.py +0 -0
  92. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/regions.py +0 -0
  93. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/secret.py +0 -0
  94. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/secret_common.py +0 -0
  95. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/sink.py +0 -0
  96. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/table.py +0 -0
  97. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/telemetry.py +0 -0
  98. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/test.py +0 -0
  99. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/test_common.py +0 -0
  100. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  101. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/token.py +0 -0
  102. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/ts_project.py +0 -0
  103. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/watch.py +0 -0
  104. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/workspace.py +0 -0
  105. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb/modules/workspace_members.py +0 -0
  106. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli.py +0 -0
  107. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/auth.py +0 -0
  108. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/branch.py +0 -0
  109. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/cicd.py +0 -0
  110. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/cli.py +0 -0
  111. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/config.py +0 -0
  112. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/connection.py +0 -0
  113. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/exceptions.py +0 -0
  114. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/fmt.py +0 -0
  115. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/job.py +0 -0
  116. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/pipe.py +0 -0
  117. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/regions.py +0 -0
  118. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/tag.py +0 -0
  119. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/telemetry.py +0 -0
  120. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/test.py +0 -0
  121. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  122. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/workspace.py +0 -0
  123. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  124. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/utils/__init__.py +0 -0
  125. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird/utils/bools.py +0 -0
  126. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird.egg-info/SOURCES.txt +0 -0
  127. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird.egg-info/dependency_links.txt +0 -0
  128. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird.egg-info/entry_points.txt +0 -0
  129. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird.egg-info/requires.txt +0 -0
  130. {tinybird-4.6.22 → tinybird-4.6.23.dev0}/tinybird.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tinybird
3
- Version: 4.6.22
3
+ Version: 4.6.23.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -52,11 +52,6 @@ The Tinybird command-line tool allows you to use all the Tinybird functionality
52
52
  Changelog
53
53
  ----------
54
54
 
55
- 4.6.22
56
- ********
57
-
58
- - `Added` ``tb pull`` demotes sink and copy pipes that exceed the workspace's sink/copy pipe plan limit to plain pipes instead of failing, stripping their ``TYPE``/``EXPORT_*``/``TARGET_DATASOURCE``/``COPY_SCHEDULE`` settings and warning that the plan must be upgraded to restore them.
59
-
60
55
  4.6.21
61
56
  ********
62
57
 
@@ -18,35 +18,35 @@ authors = [
18
18
  dependencies = [
19
19
  "GitPython==3.1.44",
20
20
  "Markdown==3.5.1",
21
- "aioboto3~=15.0",
21
+ "aioboto3==14.0.0",
22
22
  "aiofiles==24.1.0",
23
- "aiohttp~=3.11",
24
- "anthropic~=1.9",
23
+ "aiohttp==3.11.2",
24
+ "anthropic==0.55.0",
25
25
  "async-lru==2.3.0",
26
26
  "aws-msk-iam-sasl-signer-python==1.0.2",
27
27
  "cachetools==5.5.0",
28
28
  "cffi==1.17.1",
29
29
  "chardet==4.0.0",
30
30
  "ciso8601==2.2.0",
31
- "click~=8.5",
31
+ "click==8.1.8",
32
32
  "clickhouse-cityhash==1.0.2.5",
33
33
  "clickhouse-driver==0.2.9",
34
34
  "confluent-kafka[avro,json,schemaregistry]==2.12.2",
35
35
  "contextvars==2.4",
36
36
  "cramjam==2.11.0",
37
37
  "croniter==6.2.2",
38
- "cryptography~=38.0",
38
+ "cryptography==3.4.8",
39
39
  "datasketch==1.6.5",
40
40
  "dnspython==2.8.0",
41
41
  "docker==7.1.0",
42
42
  "fastavro==1.12.2",
43
43
  "fastmcp==2.12.2",
44
- "google-cloud-aiplatform~=1.148",
44
+ "google-cloud-aiplatform==1.148.1",
45
45
  "google-cloud-compute==1.48.0",
46
46
  "google-cloud-scheduler==2.20.0",
47
47
  "google-cloud-secret-manager==2.29.0",
48
- "google-cloud-storage~=3.4",
49
- "google_api_core~=2.25",
48
+ "google-cloud-storage==3.4.1",
49
+ "google_api_core==2.25.2",
50
50
  "googleapis_common_protos==1.66.0",
51
51
  "grpcio_status==1.67.1",
52
52
  "humanfriendly==10.0",
@@ -69,7 +69,7 @@ dependencies = [
69
69
  "opentelemetry-sdk==1.38.0",
70
70
  "orb-billing==2.17.0",
71
71
  "orjson==3.11.5",
72
- "packaging~=26.3",
72
+ "packaging==23.2",
73
73
  "passlib==1.7.1",
74
74
  "posthog==7.28.0",
75
75
  "pre-commit==4.6.2",
@@ -83,10 +83,10 @@ dependencies = [
83
83
  "py-spy==0.4.2",
84
84
  "pyarrow==23.0.1",
85
85
  "pycurl==7.45.7",
86
- "pydantic-ai-slim[anthropic]~=2.0",
87
- "pydantic-ai-slim[google]~=2.0",
88
- "pydantic-ai-slim[retries]~=2.0",
89
- "pydantic~=2.12",
86
+ "pydantic-ai-slim[anthropic]==0.5.0",
87
+ "pydantic-ai-slim[google]==0.5.0",
88
+ "pydantic-ai-slim[retries]==0.5.0",
89
+ "pydantic==2.12.5",
90
90
  "pyjwt[crypto]==2.9.0",
91
91
  "pympler==1.1",
92
92
  "pynacl==1.5.0",
@@ -94,10 +94,10 @@ dependencies = [
94
94
  "python-dateutil==2.9.0.post0",
95
95
  "python-dotenv==1.1.0",
96
96
  "python-ulid==2.7.0",
97
- "pyyaml~=6.0",
97
+ "pyyaml==6.0.1",
98
98
  "redis[hiredis]==5.3.1",
99
99
  "requests==2.32.4",
100
- "sentry-sdk==2.69.2",
100
+ "sentry-sdk==2.69.1",
101
101
  "setproctitle==1.3.3",
102
102
  "shandy-sqlfmt==0.11.1",
103
103
  "shandy-sqlfmt[jinjafmt]==0.11.1",
@@ -108,7 +108,7 @@ dependencies = [
108
108
  "tabulate==0.8.10",
109
109
  "thefuzz==0.22.1",
110
110
  "tinybird-python-sdk[ai]==0.3.7",
111
- "tinybird-toolset==2.6.6",
111
+ "tinybird-toolset==2.6.2",
112
112
  "toposort==1.10",
113
113
  "tornado==6.5.5",
114
114
  "urllib3==1.26.20",
@@ -125,9 +125,9 @@ deploy = [
125
125
  "GitPython==3.1.44",
126
126
  "ansible==8.5.0",
127
127
  "ara==1.6.1",
128
- "boto3~=1.40",
128
+ "boto3==1.36.21",
129
129
  "fabric==3.2.2",
130
- "google-auth~=2.47",
130
+ "google-auth==2.47.0",
131
131
  "jsonnet",
132
132
  "prettytable==3.8.0",
133
133
  "requests==2.32.4",
@@ -142,7 +142,7 @@ devtools = [
142
142
  ]
143
143
  doc = [
144
144
  "Pallets-Sphinx-Themes==2.3.0",
145
- "pyOpenSSL~=23.2",
145
+ "pyOpenSSL<24.0.0",
146
146
  "sphinx-autobuild==2024.2.4",
147
147
  "sphinx-sitemap",
148
148
  "sphinx==7.3.7",
@@ -150,15 +150,15 @@ doc = [
150
150
  "sphinxcontrib-jquery==4.1",
151
151
  ]
152
152
  lint = [
153
- "botocore-stubs~=1.40",
153
+ "botocore-stubs==1.36.23",
154
154
  "flake8~=7.3",
155
155
  "flake8-async~=26.8",
156
156
  "mypy==2.3.1",
157
- "ruff==0.16.9",
157
+ "ruff==0.16.8",
158
158
  "types-Markdown",
159
159
  "types-PyYAML",
160
160
  "types-aiofiles==24.1.0.20241221",
161
- "types-boto3-lite~=1.40",
161
+ "types-boto3-lite==1.36.21",
162
162
  "types-cachetools",
163
163
  "types-chardet",
164
164
  "types-paramiko",
@@ -172,19 +172,18 @@ lint = [
172
172
  test = [
173
173
  "coverage==7.10.6",
174
174
  "freezegun==1.5.5",
175
- "google-auth~=2.47",
175
+ "google-auth==2.47.0",
176
176
  "gsutil==4.58",
177
- "httpx2~=2.13",
178
177
  "hypothesis==6.156.1",
179
178
  "oauth2client==3.0.0",
180
179
  "py==1.11.0",
181
- "pytest-asyncio~=1.4",
180
+ "pytest-asyncio==0.23.8",
182
181
  "pytest-cov==4.1.0",
183
182
  "pytest-env==1.1.3",
184
183
  "pytest-flakefinder==1.1.0",
185
184
  "pytest-timeout==2.3.1",
186
185
  "pytest-xdist==3.6.1",
187
- "pytest~=8.1",
186
+ "pytest==8.1.2",
188
187
  "rangehttpserver==1.4.0",
189
188
  "yappi==1.7.6",
190
189
  ]
@@ -206,8 +205,6 @@ colibri = "tinybird.colibri.cli:cli"
206
205
  members = [
207
206
  "chbackups",
208
207
  "data_connector",
209
- "gatherer",
210
- "tinybird_orchestrator",
211
208
  ]
212
209
 
213
210
  [tool.setuptools]
@@ -47,6 +47,14 @@ class TimeoutException(Exception):
47
47
  pass
48
48
 
49
49
 
50
+ class ReachRetryLimit(Exception):
51
+ pass
52
+
53
+
54
+ class ConnectorNothingToLoad(Exception):
55
+ pass
56
+
57
+
50
58
  class JobException(Exception):
51
59
  pass
52
60
 
@@ -1,4 +1,5 @@
1
1
  import ast
2
+ import builtins
2
3
  import linecache
3
4
  import logging
4
5
  import re
@@ -1335,10 +1336,8 @@ sqlescape_for_string_expression = sqlescape_generator(
1335
1336
  )
1336
1337
 
1337
1338
 
1338
- def escape_single_quote_str(s: str) -> str:
1339
- # ClickHouse string literals treat backslash as an escape char, so it must be doubled too:
1340
- # otherwise a trailing backslash escapes the closing quote and the following input becomes SQL
1341
- return "'" + s.replace("\\", "\\\\").replace("'", "''") + "'"
1339
+ def escape_single_quote_str(s):
1340
+ return "'" + s.replace("'", "''") + "'"
1342
1341
 
1343
1342
 
1344
1343
  def expression_wrapper(x, name, escape_arrays: bool = False):
@@ -1389,14 +1388,13 @@ _namespace = {
1389
1388
  }
1390
1389
 
1391
1390
 
1392
- # Built from the builtins templates can actually resolve: names missing from SAFE_BUILTINS (`type`, `dir`,
1393
- # `property`, `object`, ...) can only be template parameters, so they must be discovered as such to get a
1394
- # value (None or a test-mode placeholder) instead of raising NameError.
1395
- reserved_vars = {"_tt_tmp", "_tt_append", "isinstance", "str", "error", "custom_error", *SAFE_BUILTINS}
1391
+ reserved_vars = {"_tt_tmp", "_tt_append", "isinstance", "str", "error", "custom_error", *list(vars(builtins))}
1396
1392
  for p in DEFAULT_PARAM_NAMES: # we handle these in an specific manner
1397
1393
  reserved_vars.discard(p) # `format` is part of builtins
1398
- # Allow 'id' as a template parameter name despite being a builtin - https://gitlab.com/tinybird/analytics/-/issues/19119
1394
+ # Allow 'id', 'type' and 'dir' as template parameter names despite being builtins.
1399
1395
  reserved_vars.discard("id")
1396
+ reserved_vars.discard("type")
1397
+ reserved_vars.discard("dir")
1400
1398
  error_vars = ["error", "custom_error"]
1401
1399
 
1402
1400
 
@@ -1472,8 +1470,8 @@ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1472
1470
  return Expression(f"-- disable {feature}\n")
1473
1471
 
1474
1472
  namespace.update(_namespace)
1475
- # Default it here, not in _namespace, so it stays visible to variable extraction.
1476
- namespace.update({"id": None})
1473
+ # Default these here, not in _namespace, so they stay visible to variable extraction.
1474
+ namespace.update({"id": None, "type": None, "dir": None})
1477
1475
  namespace.update(kwargs)
1478
1476
  namespace.update(
1479
1477
  {
@@ -1822,7 +1820,7 @@ def get_var_names(t: Template):
1822
1820
  >>> [v['name'] for v in get_var_names(Template("{% for name in secret_names %}{{tb_secret(name)}}{% end %}"))]
1823
1821
  ['secret_names', 'name', 'tb_secret', 'name']
1824
1822
 
1825
- Type casting with date function in elif chain:
1823
+ Type casting with date function in elif chain (type is in reserved_vars):
1826
1824
  >>> t = Template("{% if kind == 'int' %}{{Int32(val, 0)}}{% elif kind == 'date' %}{{DateTime(val)}}{% elif kind == 'diff' %}{{date_diff_in_days(val, now)}}{% end %}")
1827
1825
  >>> [v['name'] for v in get_var_names(t)]
1828
1826
  ['kind', 'Int32', 'val', 'kind', 'DateTime', 'val', 'kind', 'date_diff_in_days', 'val', 'now']
@@ -2374,24 +2372,7 @@ def wrap_vars(t, escape_arrays: bool = False):
2374
2372
  return var
2375
2373
 
2376
2374
 
2377
- def _constant_table_name(node: ast.expr) -> Optional[str]:
2378
- """Value of a constant table() argument: a literal or a concatenation of string literals."""
2379
- if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
2380
- return str(node.value)
2381
- return _string_literal(node)
2382
-
2383
-
2384
- def _string_literal(node: ast.expr) -> Optional[str]:
2385
- if isinstance(node, ast.Constant) and isinstance(node.value, str):
2386
- return node.value
2387
- if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
2388
- left, right = _string_literal(node.left), _string_literal(node.right)
2389
- if left is not None and right is not None:
2390
- return left + right
2391
- return None
2392
-
2393
-
2394
- def get_used_tables_in_template(sql: str) -> List[str]:
2375
+ def get_used_tables_in_template(sql):
2395
2376
  """
2396
2377
  >>> get_used_tables_in_template("select * from {{table('test')}}")
2397
2378
  ['test']
@@ -2405,42 +2386,30 @@ def get_used_tables_in_template(sql: str) -> List[str]:
2405
2386
  []
2406
2387
  >>> get_used_tables_in_template("select * from {{table('my.test')}}, {{table('another.one')}}")
2407
2388
  ['my.test', 'another.one']
2408
-
2409
- Only constant table names can be known without rendering, so anything else is skipped
2410
- >>> get_used_tables_in_template("select * from {{table(tbl)}}, {{TABLE('b')}}, {{table('my.' + 'c')}}")
2411
- ['b', 'my.c']
2412
2389
  """
2413
- return list(_get_used_tables_in_template_cached(sql))
2414
-
2415
-
2416
- # Building the Template dominates the cost and the result only depends on the SQL, which deployments and
2417
- # /v0/sql pipelines scan repeatedly
2418
- @lru_cache(maxsize=2**10)
2419
- def _get_used_tables_in_template_cached(sql: str) -> Tuple[str, ...]:
2420
2390
  try:
2421
2391
  t = Template(sql)
2422
2392
 
2423
2393
  def _n(chunks, tables):
2424
2394
  for x in chunks:
2425
2395
  if type(x).__name__ == "_Expression":
2426
- # Read the names from the AST instead of executing the expression: this runs outside
2427
- # generate(), without the restricted builtins, on every pipe, query and deployment.
2428
- for node in ast.walk(ast.parse(x.expression)):
2429
- if (
2430
- isinstance(node, ast.Call)
2431
- and isinstance(node.func, ast.Name)
2432
- and node.func.id in ("table", "TABLE")
2433
- and node.args
2434
- ):
2435
- name = _constant_table_name(node.args[0])
2436
- if name is not None:
2437
- tables.append(name)
2396
+ c = compile(x.expression, "<string>", "exec", dont_inherit=True)
2397
+ v = [x.lower() for x in c.co_names if x not in _namespace and x not in reserved_vars]
2398
+ if "table" in v:
2399
+
2400
+ def _t(*args, **kwargs):
2401
+ return str(args[0])
2402
+
2403
+ n = {"table": _t, "TABLE": _t}
2404
+ e = "_tt_tmp = %s" % x.expression
2405
+ exec_in(e, n)
2406
+ tables += [n["_tt_tmp"]]
2438
2407
  elif type(x).__name__ == "_ControlBlock":
2439
2408
  _n(x.body.chunks, tables)
2440
2409
 
2441
- tables: List[str] = []
2410
+ tables = []
2442
2411
  _n(t.file.body.chunks, tables)
2443
- return tuple(tables)
2412
+ return tables
2444
2413
  except SecurityException as e:
2445
2414
  raise SQLTemplateException(e)
2446
2415
 
@@ -214,8 +214,8 @@ class TinybirdDialect(ClickHouse):
214
214
  ],
215
215
  }
216
216
 
217
- for section, rules in override_rules.items():
218
- for rule in rules:
217
+ for section in override_rules:
218
+ for rule in override_rules[section]:
219
219
  for rr in self.RULES[section]:
220
220
  if rr.name == rule.name:
221
221
  self.RULES[section].remove(rr)
@@ -260,6 +260,49 @@ def _iscoroutinefunction_or_partial(func: Any) -> bool:
260
260
  return asyncio.iscoroutinefunction(func)
261
261
 
262
262
 
263
+ class ThreadSensitiveContext:
264
+ """Async context manager to manage context for thread sensitive mode
265
+ This context manager controls which thread pool executor is used when in
266
+ thread sensitive mode. By default, a single thread pool executor is shared
267
+ within a process.
268
+ In Python 3.7+, the ThreadSensitiveContext() context manager may be used to
269
+ specify a thread pool per context.
270
+ In Python 3.6, usage of this context manager has no effect.
271
+ This context manager is re-entrant, so only the outer-most call to
272
+ ThreadSensitiveContext will set the context.
273
+ """
274
+
275
+ def __init__(self):
276
+ self.token = None
277
+
278
+ if contextvars:
279
+
280
+ async def __aenter__(self):
281
+ try:
282
+ SyncToAsync.thread_sensitive_context.get()
283
+ except LookupError:
284
+ self.token = SyncToAsync.thread_sensitive_context.set(self)
285
+
286
+ return self
287
+
288
+ async def __aexit__(self, exc, value, tb):
289
+ if not self.token:
290
+ return
291
+
292
+ executor = SyncToAsync.context_to_thread_executor.pop(self, None)
293
+ if executor:
294
+ executor.shutdown()
295
+ SyncToAsync.thread_sensitive_context.reset(self.token)
296
+
297
+ else:
298
+
299
+ async def __aenter__(self):
300
+ return self
301
+
302
+ async def __aexit__(self, exc, value, tb):
303
+ pass
304
+
305
+
263
306
  class AsyncToSync:
264
307
  """
265
308
  Utility class which turns an awaitable that only works on the thread with
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
4
4
  __url__ = 'https://www.tinybird.co/docs/forward/commands'
5
5
  __author__ = 'Tinybird'
6
6
  __author_email__ = 'support@tinybird.co'
7
- __version__ = '4.6.22'
8
- __revision__ = '5269fe22'
7
+ __version__ = '4.6.23.dev0'
8
+ __revision__ = '2456d09e'
@@ -58,6 +58,14 @@ class TimeoutException(Exception):
58
58
  pass
59
59
 
60
60
 
61
+ class ReachRetryLimit(Exception):
62
+ pass
63
+
64
+
65
+ class ConnectorNothingToLoad(Exception):
66
+ pass
67
+
68
+
61
69
  class JobException(Exception):
62
70
  pass
63
71
 
@@ -1277,11 +1277,11 @@ class ConnectionReplacements:
1277
1277
  """Maps prompt parameters to API parameters."""
1278
1278
 
1279
1279
  api_params = {}
1280
- for key, value in params.items():
1280
+ for key in params.keys():
1281
1281
  try:
1282
- api_params[ConnectionReplacements._PARAMS_REPLACEMENTS[service][key]] = value
1282
+ api_params[ConnectionReplacements._PARAMS_REPLACEMENTS[service][key]] = params[key]
1283
1283
  except KeyError:
1284
- api_params[key] = value
1284
+ api_params[key] = params[key]
1285
1285
 
1286
1286
  api_params["service"] = service
1287
1287
  return api_params
@@ -215,12 +215,14 @@ def create_project_structure(folder: str):
215
215
  "connections →": "Connect to and ingest data from popular sources: Kafka, S3 or GCS.",
216
216
  }
217
217
 
218
- for x, description in PROJECT_PATHS_DESCRIPTIONS.items():
218
+ for x in PROJECT_PATHS_DESCRIPTIONS.keys():
219
219
  try:
220
220
  path = x.split("→")[0].strip()
221
221
  f = folder_path / path
222
222
  f.mkdir()
223
- click.echo(FeedbackManager.info(message=f"./{x} ") + FeedbackManager.gray(message=description))
223
+ click.echo(
224
+ FeedbackManager.info(message=f"./{x} ") + FeedbackManager.gray(message=PROJECT_PATHS_DESCRIPTIONS[x])
225
+ )
224
226
  except FileExistsError:
225
227
  pass
226
228
 
@@ -1,11 +1,8 @@
1
- from datetime import datetime
2
1
  from pathlib import Path
3
2
  from typing import Any, Optional
4
3
 
5
4
  import click
6
5
 
7
- from tinybird.datafile.common import PipeNodeTypes
8
- from tinybird.datafile.parse_pipe import parse_pipe
9
6
  from tinybird.tb.client import AuthNoTokenException, TinyB
10
7
  from tinybird.tb.modules.datafile.format_datasource import format_datasource
11
8
  from tinybird.tb.modules.datafile.format_pipe import format_pipe
@@ -13,52 +10,6 @@ from tinybird.tb.modules.feedback_manager import FeedbackManager
13
10
 
14
11
  PULL_EXISTING_FILE_MAX_DEPTH = 5
15
12
 
16
- DEMOTABLE_NODE_TYPES = {
17
- PipeNodeTypes.DATA_SINK: ("sink_pipes", "Sink"),
18
- PipeNodeTypes.COPY: ("copy_pipes", "Copy"),
19
- }
20
-
21
-
22
- def _parse_created_at(value: Any) -> datetime:
23
- try:
24
- return datetime.fromisoformat(str(value))
25
- except ValueError:
26
- return datetime.min
27
-
28
-
29
- def pipes_over_node_type_limit(pipes: list[dict[str, Any]], node_type: str, limit: Optional[int]) -> set[str]:
30
- if limit is None:
31
- return set()
32
-
33
- matching_pipes = [p for p in pipes if p.get("type") == node_type]
34
- if len(matching_pipes) <= limit:
35
- return set()
36
-
37
- matching_pipes.sort(key=lambda p: _parse_created_at(p.get("created_at")))
38
- return {p["name"] for p in matching_pipes[limit:]}
39
-
40
-
41
- def pipes_over_plan_limits(pipes: list[dict[str, Any]], limits: dict[str, Any]) -> dict[str, str]:
42
- demoted: dict[str, str] = {}
43
- for node_type, (limits_key, _label) in DEMOTABLE_NODE_TYPES.items():
44
- limit = limits.get(limits_key, {}).get("max")
45
- for name in pipes_over_node_type_limit(pipes, node_type, limit):
46
- demoted[name] = node_type
47
- return demoted
48
-
49
-
50
- def demote_pipe_content(name: str, content: str, node_type: str) -> str:
51
- datafile = parse_pipe(name, content=content, replace_includes=False).datafile
52
- demoted = False
53
- for node in datafile.nodes:
54
- if (node.get("type") or "").lower() == node_type:
55
- node.pop("type", None)
56
- demoted = True
57
-
58
- if not demoted:
59
- return content
60
- return format_pipe(name, datafile=datafile)
61
-
62
13
 
63
14
  def folder_pull(
64
15
  client: TinyB,
@@ -110,7 +61,6 @@ def folder_pull(
110
61
  get_resource_function: str,
111
62
  progress_bar: bool = False,
112
63
  fmt: bool = False,
113
- demoted_pipe_types: Optional[dict[str, str]] = None,
114
64
  ) -> list[Path]:
115
65
  def write_resource(k: dict[str, Any]) -> Optional[Path]:
116
66
  name = f"{k['name']}.{extension}"
@@ -123,19 +73,8 @@ def folder_pull(
123
73
  else:
124
74
  resource = getattr(client, get_resource_function)(k["name"])
125
75
  resource_to_write = resource
126
- resource_type = k.get("type")
127
-
128
- demoted_node_type = demoted_pipe_types.get(k["name"]) if demoted_pipe_types else None
129
- if demoted_node_type:
130
- resource_to_write = demote_pipe_content(name, resource, demoted_node_type)
131
- resource_type = None
132
- label = DEMOTABLE_NODE_TYPES[demoted_node_type][1]
133
- warnings.append(
134
- f"{label} pipe '{k['name']}' exceeds the {demoted_node_type} pipe limit of your current "
135
- f"plan and was pulled as a plain pipe without its {demoted_node_type} configuration. "
136
- "Upgrade your plan and reconfigure it to restore it."
137
- )
138
- elif fmt:
76
+
77
+ if fmt:
139
78
  if extension == "datasource":
140
79
  resource_to_write = format_datasource(name, content=resource)
141
80
  elif extension == "pipe":
@@ -146,7 +85,7 @@ def folder_pull(
146
85
  dest_folder = Path(folder) / "vendor" / k["name"].split(".", 1)[0]
147
86
  name = f"{k['name'].split('.', 1)[1]}.{extension}"
148
87
 
149
- file_folder = get_file_folder(extension, resource_type)
88
+ file_folder = get_file_folder(extension, k.get("type"))
150
89
  f = Path(dest_folder) / file_folder if file_folder is not None else Path(dest_folder)
151
90
 
152
91
  existing_file = find_existing_resource_file(Path(dest_folder), name)
@@ -189,14 +128,6 @@ def folder_pull(
189
128
  pipes = client.pipes()
190
129
  connections = client.connections()
191
130
 
192
- demoted_pipe_types: dict[str, str] = {}
193
- if not only_vendored:
194
- try:
195
- limits = client.workspace_info().get("limits", {})
196
- except Exception:
197
- limits = {}
198
- demoted_pipe_types = pipes_over_plan_limits(pipes, limits)
199
-
200
131
  if only_vendored:
201
132
  written_files = write_files(
202
133
  resources=[ds for ds in datasources if "shared_from" in ds],
@@ -223,7 +154,6 @@ def folder_pull(
223
154
  get_resource_function="pipe_file",
224
155
  progress_bar=progress_bar,
225
156
  fmt=fmt,
226
- demoted_pipe_types=demoted_pipe_types,
227
157
  )
228
158
  )
229
159
  written_files.extend(
@@ -677,7 +677,7 @@ def datasource_start(ctx: Context, datasource_name: str) -> None:
677
677
 
678
678
  @datasource.command(name="delete")
679
679
  @click.argument("datasource_name")
680
- @click.option("--sql-condition", help="SQL WHERE condition to remove rows", hidden=True, required=True)
680
+ @click.option("--sql-condition", default=None, help="SQL WHERE condition to remove rows", hidden=True, required=True)
681
681
  @click.option("--yes", is_flag=True, default=False, help="Do not ask for confirmation")
682
682
  @click.option(
683
683
  "--wait/--no-wait",
@@ -92,6 +92,20 @@ class CLITokenException(CLIException):
92
92
  super().__init__(message, "token_error", **kw_telemetry_event_data)
93
93
 
94
94
 
95
+ class CLIBuildException(CLIException):
96
+ """Exceptions generated by the build commands"""
97
+
98
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
99
+ super().__init__(message, "build_error", **kw_telemetry_event_data)
100
+
101
+
102
+ class CLIDeploymentException(CLIException):
103
+ """Exceptions generated by the deployment commands"""
104
+
105
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
106
+ super().__init__(message, "deployment_error", **kw_telemetry_event_data)
107
+
108
+
95
109
  class CLITestException(CLIException):
96
110
  """Exceptions generated by the test commands"""
97
111
 
@@ -113,6 +127,13 @@ class CLIMockException(CLIException):
113
127
  super().__init__(message, "mock_error", **kw_telemetry_event_data)
114
128
 
115
129
 
130
+ class CLIAgentException(CLIException):
131
+ """Exceptions generated by the agent commands"""
132
+
133
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
134
+ super().__init__(message, "agent_error", **kw_telemetry_event_data)
135
+
136
+
116
137
  class CLILoginException(CLIException):
117
138
  """Exceptions generated by the login commands"""
118
139
 
@@ -1304,11 +1304,11 @@ class ConnectionReplacements:
1304
1304
  """Maps prompt parameters to API parameters."""
1305
1305
 
1306
1306
  api_params = {}
1307
- for key, value in params.items():
1307
+ for key in params.keys():
1308
1308
  try:
1309
- api_params[ConnectionReplacements._PARAMS_REPLACEMENTS[service][key]] = value
1309
+ api_params[ConnectionReplacements._PARAMS_REPLACEMENTS[service][key]] = params[key]
1310
1310
  except KeyError:
1311
- api_params[key] = value
1311
+ api_params[key] = params[key]
1312
1312
 
1313
1313
  api_params["service"] = service
1314
1314
  return api_params
@@ -385,7 +385,7 @@ async def datasource_truncate(ctx, datasource_name, yes, cascade):
385
385
 
386
386
  @datasource.command(name="delete")
387
387
  @click.argument("datasource_name")
388
- @click.option("--sql-condition", help="SQL WHERE condition to remove rows", hidden=True, required=True)
388
+ @click.option("--sql-condition", default=None, help="SQL WHERE condition to remove rows", hidden=True, required=True)
389
389
  @click.option("--yes", is_flag=True, default=False, help="Do not ask for confirmation")
390
390
  @click.option(
391
391
  "--wait/--no-wait",