tinybird 4.6.22__tar.gz → 4.6.22.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.22.dev0}/PKG-INFO +1 -11
  2. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/pyproject.toml +25 -29
  3. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/client.py +8 -0
  4. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/sql_template.py +25 -54
  5. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/sql_template_fmt.py +2 -2
  6. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/syncasync.py +43 -0
  7. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/__cli__.py +2 -2
  8. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/client.py +8 -0
  9. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/common.py +3 -3
  10. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/create.py +4 -2
  11. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/pull.py +3 -73
  12. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datasource.py +1 -1
  13. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/deployment_common.py +6 -4
  14. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/exceptions.py +21 -0
  15. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/common.py +3 -3
  16. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/datasource.py +1 -1
  17. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tornado_template.py +93 -38
  18. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird.egg-info/PKG-INFO +1 -11
  19. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/setup.cfg +0 -0
  20. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/__cli__.py +0 -0
  21. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/ch_utils/constants.py +0 -0
  22. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/ch_utils/engine.py +0 -0
  23. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/check_pypi.py +0 -0
  24. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/config.py +0 -0
  25. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/context.py +0 -0
  26. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/datafile/common.py +0 -0
  27. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/datafile/exceptions.py +0 -0
  28. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/datafile/parse_connection.py +0 -0
  29. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/datafile/parse_datasource.py +0 -0
  30. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/datafile/parse_pipe.py +0 -0
  31. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/datatypes.py +0 -0
  32. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/feedback_manager.py +0 -0
  33. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/git_settings.py +0 -0
  34. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/iterating/__init__.py +0 -0
  35. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/iterating/data_branch_modes.py +0 -0
  36. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/prompts.py +0 -0
  37. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/service_datasources.py +0 -0
  38. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/sql.py +0 -0
  39. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/sql_toolset.py +0 -0
  40. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/check_pypi.py +0 -0
  41. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/cli.py +0 -0
  42. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/config.py +0 -0
  43. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/branch.py +0 -0
  44. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/build.py +0 -0
  45. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/build_common.py +0 -0
  46. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/cicd.py +0 -0
  47. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/cli.py +0 -0
  48. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/config.py +0 -0
  49. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/connection.py +0 -0
  50. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/connection_dynamodb.py +0 -0
  51. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/connection_kafka.py +0 -0
  52. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/connection_s3.py +0 -0
  53. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/copy.py +0 -0
  54. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/build.py +0 -0
  55. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/build_common.py +0 -0
  56. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
  57. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
  58. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/diff.py +0 -0
  59. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/fixture.py +0 -0
  60. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/format_common.py +0 -0
  61. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/format_connection.py +0 -0
  62. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
  63. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
  64. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
  65. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/datafile/playground.py +0 -0
  66. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/deployment.py +0 -0
  67. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/deprecations.py +0 -0
  68. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/endpoint.py +0 -0
  69. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/feedback_manager.py +0 -0
  70. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/fmt.py +0 -0
  71. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/info.py +0 -0
  72. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/infra.py +0 -0
  73. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/job.py +0 -0
  74. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/job_common.py +0 -0
  75. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/llm.py +0 -0
  76. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/llm_utils.py +0 -0
  77. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/local.py +0 -0
  78. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/local_common.py +0 -0
  79. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/local_logs.py +0 -0
  80. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/login.py +0 -0
  81. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/login_common.py +0 -0
  82. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/logout.py +0 -0
  83. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/logs.py +0 -0
  84. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/materialization.py +0 -0
  85. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/open.py +0 -0
  86. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/pipe.py +0 -0
  87. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/preview.py +0 -0
  88. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/project.py +0 -0
  89. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/project_commands.py +0 -0
  90. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/py_project.py +0 -0
  91. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/query_output.py +0 -0
  92. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/regions.py +0 -0
  93. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/secret.py +0 -0
  94. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/secret_common.py +0 -0
  95. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/sink.py +0 -0
  96. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/table.py +0 -0
  97. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/telemetry.py +0 -0
  98. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/test.py +0 -0
  99. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/test_common.py +0 -0
  100. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
  101. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/token.py +0 -0
  102. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/ts_project.py +0 -0
  103. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/watch.py +0 -0
  104. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/workspace.py +0 -0
  105. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb/modules/workspace_members.py +0 -0
  106. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli.py +0 -0
  107. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/auth.py +0 -0
  108. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/branch.py +0 -0
  109. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/cicd.py +0 -0
  110. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/cli.py +0 -0
  111. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/config.py +0 -0
  112. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/connection.py +0 -0
  113. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/exceptions.py +0 -0
  114. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/fmt.py +0 -0
  115. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/job.py +0 -0
  116. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/pipe.py +0 -0
  117. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/regions.py +0 -0
  118. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/tag.py +0 -0
  119. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/telemetry.py +0 -0
  120. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/test.py +0 -0
  121. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
  122. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/workspace.py +0 -0
  123. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/tb_cli_modules/workspace_members.py +0 -0
  124. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/utils/__init__.py +0 -0
  125. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird/utils/bools.py +0 -0
  126. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird.egg-info/SOURCES.txt +0 -0
  127. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird.egg-info/dependency_links.txt +0 -0
  128. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird.egg-info/entry_points.txt +0 -0
  129. {tinybird-4.6.22 → tinybird-4.6.22.dev0}/tinybird.egg-info/requires.txt +0 -0
  130. {tinybird-4.6.22 → tinybird-4.6.22.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.22.dev0
4
4
  Summary: Tinybird Command Line Tool
5
5
  Home-page: https://www.tinybird.co/docs/forward/commands
6
6
  Author: Tinybird
@@ -52,16 +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
- 4.6.21
61
- ********
62
-
63
- - `Fixed` ``tb deployment discard`` now discards the deployment that is not live, instead of assuming the live deployment is listed first. Previously, if removing the old deployment failed after a promotion, the command refused to discard it.
64
-
65
55
  4.6.20
66
56
  ********
67
57
 
@@ -18,35 +18,34 @@ 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",
25
- "async-lru==2.3.0",
23
+ "aiohttp==3.11.2",
24
+ "anthropic==0.55.0",
26
25
  "aws-msk-iam-sasl-signer-python==1.0.2",
27
26
  "cachetools==5.5.0",
28
27
  "cffi==1.17.1",
29
28
  "chardet==4.0.0",
30
29
  "ciso8601==2.2.0",
31
- "click~=8.5",
30
+ "click==8.1.8",
32
31
  "clickhouse-cityhash==1.0.2.5",
33
32
  "clickhouse-driver==0.2.9",
34
33
  "confluent-kafka[avro,json,schemaregistry]==2.12.2",
35
34
  "contextvars==2.4",
36
35
  "cramjam==2.11.0",
37
36
  "croniter==6.2.2",
38
- "cryptography~=38.0",
37
+ "cryptography==3.4.8",
39
38
  "datasketch==1.6.5",
40
39
  "dnspython==2.8.0",
41
40
  "docker==7.1.0",
42
41
  "fastavro==1.12.2",
43
42
  "fastmcp==2.12.2",
44
- "google-cloud-aiplatform~=1.148",
43
+ "google-cloud-aiplatform==1.148.1",
45
44
  "google-cloud-compute==1.48.0",
46
45
  "google-cloud-scheduler==2.20.0",
47
46
  "google-cloud-secret-manager==2.29.0",
48
- "google-cloud-storage~=3.4",
49
- "google_api_core~=2.25",
47
+ "google-cloud-storage==3.4.1",
48
+ "google_api_core==2.25.2",
50
49
  "googleapis_common_protos==1.66.0",
51
50
  "grpcio_status==1.67.1",
52
51
  "humanfriendly==10.0",
@@ -69,7 +68,7 @@ dependencies = [
69
68
  "opentelemetry-sdk==1.38.0",
70
69
  "orb-billing==2.17.0",
71
70
  "orjson==3.11.5",
72
- "packaging~=26.3",
71
+ "packaging==23.2",
73
72
  "passlib==1.7.1",
74
73
  "posthog==7.28.0",
75
74
  "pre-commit==4.6.2",
@@ -83,10 +82,10 @@ dependencies = [
83
82
  "py-spy==0.4.2",
84
83
  "pyarrow==23.0.1",
85
84
  "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",
85
+ "pydantic-ai-slim[anthropic]==0.5.0",
86
+ "pydantic-ai-slim[google]==0.5.0",
87
+ "pydantic-ai-slim[retries]==0.5.0",
88
+ "pydantic==2.12.5",
90
89
  "pyjwt[crypto]==2.9.0",
91
90
  "pympler==1.1",
92
91
  "pynacl==1.5.0",
@@ -94,10 +93,10 @@ dependencies = [
94
93
  "python-dateutil==2.9.0.post0",
95
94
  "python-dotenv==1.1.0",
96
95
  "python-ulid==2.7.0",
97
- "pyyaml~=6.0",
96
+ "pyyaml==6.0.1",
98
97
  "redis[hiredis]==5.3.1",
99
98
  "requests==2.32.4",
100
- "sentry-sdk==2.69.2",
99
+ "sentry-sdk==2.69.1",
101
100
  "setproctitle==1.3.3",
102
101
  "shandy-sqlfmt==0.11.1",
103
102
  "shandy-sqlfmt[jinjafmt]==0.11.1",
@@ -108,7 +107,7 @@ dependencies = [
108
107
  "tabulate==0.8.10",
109
108
  "thefuzz==0.22.1",
110
109
  "tinybird-python-sdk[ai]==0.3.7",
111
- "tinybird-toolset==2.6.6",
110
+ "tinybird-toolset==2.6.2",
112
111
  "toposort==1.10",
113
112
  "tornado==6.5.5",
114
113
  "urllib3==1.26.20",
@@ -125,9 +124,9 @@ deploy = [
125
124
  "GitPython==3.1.44",
126
125
  "ansible==8.5.0",
127
126
  "ara==1.6.1",
128
- "boto3~=1.40",
127
+ "boto3==1.36.21",
129
128
  "fabric==3.2.2",
130
- "google-auth~=2.47",
129
+ "google-auth==2.47.0",
131
130
  "jsonnet",
132
131
  "prettytable==3.8.0",
133
132
  "requests==2.32.4",
@@ -142,7 +141,7 @@ devtools = [
142
141
  ]
143
142
  doc = [
144
143
  "Pallets-Sphinx-Themes==2.3.0",
145
- "pyOpenSSL~=23.2",
144
+ "pyOpenSSL<24.0.0",
146
145
  "sphinx-autobuild==2024.2.4",
147
146
  "sphinx-sitemap",
148
147
  "sphinx==7.3.7",
@@ -150,15 +149,15 @@ doc = [
150
149
  "sphinxcontrib-jquery==4.1",
151
150
  ]
152
151
  lint = [
153
- "botocore-stubs~=1.40",
152
+ "botocore-stubs==1.36.23",
154
153
  "flake8~=7.3",
155
154
  "flake8-async~=26.8",
156
155
  "mypy==2.3.1",
157
- "ruff==0.16.9",
156
+ "ruff==0.16.8",
158
157
  "types-Markdown",
159
158
  "types-PyYAML",
160
159
  "types-aiofiles==24.1.0.20241221",
161
- "types-boto3-lite~=1.40",
160
+ "types-boto3-lite==1.36.21",
162
161
  "types-cachetools",
163
162
  "types-chardet",
164
163
  "types-paramiko",
@@ -172,19 +171,18 @@ lint = [
172
171
  test = [
173
172
  "coverage==7.10.6",
174
173
  "freezegun==1.5.5",
175
- "google-auth~=2.47",
174
+ "google-auth==2.47.0",
176
175
  "gsutil==4.58",
177
- "httpx2~=2.13",
178
176
  "hypothesis==6.156.1",
179
177
  "oauth2client==3.0.0",
180
178
  "py==1.11.0",
181
- "pytest-asyncio~=1.4",
179
+ "pytest-asyncio==0.23.8",
182
180
  "pytest-cov==4.1.0",
183
181
  "pytest-env==1.1.3",
184
182
  "pytest-flakefinder==1.1.0",
185
183
  "pytest-timeout==2.3.1",
186
184
  "pytest-xdist==3.6.1",
187
- "pytest~=8.1",
185
+ "pytest==8.1.2",
188
186
  "rangehttpserver==1.4.0",
189
187
  "yappi==1.7.6",
190
188
  ]
@@ -206,8 +204,6 @@ colibri = "tinybird.colibri.cli:cli"
206
204
  members = [
207
205
  "chbackups",
208
206
  "data_connector",
209
- "gatherer",
210
- "tinybird_orchestrator",
211
207
  ]
212
208
 
213
209
  [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):
@@ -1386,16 +1385,16 @@ _namespace = {
1386
1385
  "close": None,
1387
1386
  "print": None,
1388
1387
  "input": None,
1388
+ # Keep customer parameters named `type`/`dir` usable without restoring the unsafe builtins.
1389
+ "type": None,
1390
+ "dir": None,
1389
1391
  }
1390
1392
 
1391
1393
 
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}
1394
+ reserved_vars = {"_tt_tmp", "_tt_append", "isinstance", "str", "error", "custom_error", *list(vars(builtins))}
1396
1395
  for p in DEFAULT_PARAM_NAMES: # we handle these in an specific manner
1397
1396
  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
1397
+ # Allow 'id' to be used as a template parameter - https://gitlab.com/tinybird/analytics/-/issues/19119
1399
1398
  reserved_vars.discard("id")
1400
1399
  error_vars = ["error", "custom_error"]
1401
1400
 
@@ -1472,7 +1471,8 @@ def generate(self, **kwargs) -> Tuple[str, TemplateExecutionResults]:
1472
1471
  return Expression(f"-- disable {feature}\n")
1473
1472
 
1474
1473
  namespace.update(_namespace)
1475
- # Default it here, not in _namespace, so it stays visible to variable extraction.
1474
+ # This is to fix the issue https://gitlab.com/tinybird/analytics/-/issues/19119
1475
+ # We need to do the override here because if we modify the _namespace, we would filter out parameters from the users
1476
1476
  namespace.update({"id": None})
1477
1477
  namespace.update(kwargs)
1478
1478
  namespace.update(
@@ -1822,7 +1822,7 @@ def get_var_names(t: Template):
1822
1822
  >>> [v['name'] for v in get_var_names(Template("{% for name in secret_names %}{{tb_secret(name)}}{% end %}"))]
1823
1823
  ['secret_names', 'name', 'tb_secret', 'name']
1824
1824
 
1825
- Type casting with date function in elif chain:
1825
+ Type casting with date function in elif chain (type is in reserved_vars):
1826
1826
  >>> t = Template("{% if kind == 'int' %}{{Int32(val, 0)}}{% elif kind == 'date' %}{{DateTime(val)}}{% elif kind == 'diff' %}{{date_diff_in_days(val, now)}}{% end %}")
1827
1827
  >>> [v['name'] for v in get_var_names(t)]
1828
1828
  ['kind', 'Int32', 'val', 'kind', 'DateTime', 'val', 'kind', 'date_diff_in_days', 'val', 'now']
@@ -2374,24 +2374,7 @@ def wrap_vars(t, escape_arrays: bool = False):
2374
2374
  return var
2375
2375
 
2376
2376
 
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]:
2377
+ def get_used_tables_in_template(sql):
2395
2378
  """
2396
2379
  >>> get_used_tables_in_template("select * from {{table('test')}}")
2397
2380
  ['test']
@@ -2405,42 +2388,30 @@ def get_used_tables_in_template(sql: str) -> List[str]:
2405
2388
  []
2406
2389
  >>> get_used_tables_in_template("select * from {{table('my.test')}}, {{table('another.one')}}")
2407
2390
  ['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
2391
  """
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
2392
  try:
2421
2393
  t = Template(sql)
2422
2394
 
2423
2395
  def _n(chunks, tables):
2424
2396
  for x in chunks:
2425
2397
  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)
2398
+ c = compile(x.expression, "<string>", "exec", dont_inherit=True)
2399
+ v = [x.lower() for x in c.co_names if x not in _namespace and x not in reserved_vars]
2400
+ if "table" in v:
2401
+
2402
+ def _t(*args, **kwargs):
2403
+ return str(args[0])
2404
+
2405
+ n = {"table": _t, "TABLE": _t}
2406
+ e = "_tt_tmp = %s" % x.expression
2407
+ exec_in(e, n)
2408
+ tables += [n["_tt_tmp"]]
2438
2409
  elif type(x).__name__ == "_ControlBlock":
2439
2410
  _n(x.body.chunks, tables)
2440
2411
 
2441
- tables: List[str] = []
2412
+ tables = []
2442
2413
  _n(t.file.body.chunks, tables)
2443
- return tuple(tables)
2414
+ return tables
2444
2415
  except SecurityException as e:
2445
2416
  raise SQLTemplateException(e)
2446
2417
 
@@ -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.22.dev0'
8
+ __revision__ = '3a75e0ef'
@@ -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",
@@ -335,12 +335,13 @@ def discard_deployment(host: Optional[str], headers: dict, wait: bool, request_f
335
335
  click.echo(FeedbackManager.error(message="Only one deployment found. Cannot discard the only deployment."))
336
336
  return
337
337
 
338
- live_deployment = next((deployment for deployment in deployments if deployment.get("live")), deployments[0])
339
- deployment_to_discard = next(deployment for deployment in deployments if deployment is not live_deployment)
338
+ current_deployment, deployment_to_discard = deployments[0], deployments[1]
340
339
 
341
- if live_deployment.get("status") != "data_ready":
340
+ # NOTE(eclbg): we never get here. We wrote this code when we though we'd enable promoting back and forth between
341
+ # staging and live, but the current CLI commands don't allow getting in that state
342
+ if current_deployment.get("status") != "data_ready":
342
343
  click.echo(FeedbackManager.error(message="Previous deployment is not ready"))
343
- deploy_errors = live_deployment.get("errors", [])
344
+ deploy_errors = current_deployment.get("errors", [])
344
345
  for deploy_error in deploy_errors:
345
346
  click.echo(FeedbackManager.error(message=f"* {deploy_error}"))
346
347
  return
@@ -358,6 +359,7 @@ def discard_deployment(host: Optional[str], headers: dict, wait: bool, request_f
358
359
  click.echo(FeedbackManager.error(message=result.get("error")))
359
360
  sys_exit("deployment_error", result.get("error", "Unknown error"))
360
361
 
362
+ deployment_to_discard = deployments[1]
361
363
  click.echo(FeedbackManager.success(message="Discard process successfully started"))
362
364
 
363
365
  if 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