tinybird 0.0.1.dev223__py3-none-any.whl → 0.0.1.dev225__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tinybird might be problematic. Click here for more details.
- tinybird/datafile/common.py +2 -0
- tinybird/prompts.py +59 -6
- tinybird/tb/__cli__.py +2 -2
- tinybird/tb/modules/common.py +1 -10
- tinybird/tb/modules/connection.py +10 -3
- tinybird/tb/modules/create.py +12 -1
- tinybird/tb/modules/feedback_manager.py +8 -1
- tinybird/tb/modules/login.py +88 -27
- {tinybird-0.0.1.dev223.dist-info → tinybird-0.0.1.dev225.dist-info}/METADATA +1 -1
- {tinybird-0.0.1.dev223.dist-info → tinybird-0.0.1.dev225.dist-info}/RECORD +13 -13
- {tinybird-0.0.1.dev223.dist-info → tinybird-0.0.1.dev225.dist-info}/WHEEL +0 -0
- {tinybird-0.0.1.dev223.dist-info → tinybird-0.0.1.dev225.dist-info}/entry_points.txt +0 -0
- {tinybird-0.0.1.dev223.dist-info → tinybird-0.0.1.dev225.dist-info}/top_level.txt +0 -0
tinybird/datafile/common.py
CHANGED
|
@@ -1710,6 +1710,8 @@ def parse(
|
|
|
1710
1710
|
"s3_access_key": assign_var("s3_access_key"),
|
|
1711
1711
|
"s3_secret": assign_var("s3_secret"),
|
|
1712
1712
|
"gcs_service_account_credentials_json": assign_var_json("gcs_service_account_credentials_json"),
|
|
1713
|
+
"gcs_access_id": assign_var("gcs_hmac_access_id"),
|
|
1714
|
+
"gcs_secret": assign_var("gcs_hmac_secret"),
|
|
1713
1715
|
"gcs_hmac_access_id": assign_var("gcs_hmac_access_id"),
|
|
1714
1716
|
"gcs_hmac_secret": assign_var("gcs_hmac_secret"),
|
|
1715
1717
|
"include": include,
|
tinybird/prompts.py
CHANGED
|
@@ -420,9 +420,11 @@ You are a Tinybird expert. You will be given a prompt to generate new or update
|
|
|
420
420
|
{pipe_example}
|
|
421
421
|
{copy_pipe_instructions}
|
|
422
422
|
{materialized_pipe_instructions}
|
|
423
|
+
{sink_pipe_instructions}
|
|
423
424
|
{connection_instructions}
|
|
424
425
|
{kafka_connection_example}
|
|
425
426
|
{gcs_connection_example}
|
|
427
|
+
{gcs_hmac_connection_example}
|
|
426
428
|
{s3_connection_example}
|
|
427
429
|
|
|
428
430
|
{feedback_history}
|
|
@@ -445,9 +447,11 @@ Use the following format to generate the response and do not wrap it in any othe
|
|
|
445
447
|
pipe_example=pipe_example,
|
|
446
448
|
copy_pipe_instructions=copy_pipe_instructions,
|
|
447
449
|
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
450
|
+
sink_pipe_instructions=sink_pipe_instructions,
|
|
448
451
|
connection_instructions=connection_instructions,
|
|
449
452
|
kafka_connection_example=kafka_connection_example,
|
|
450
453
|
gcs_connection_example=gcs_connection_example,
|
|
454
|
+
gcs_hmac_connection_example=gcs_hmac_connection_example,
|
|
451
455
|
s3_connection_example=s3_connection_example,
|
|
452
456
|
feedback_history=feedback_history,
|
|
453
457
|
)
|
|
@@ -639,6 +643,43 @@ COPY_SCHEDULE 0 * * * *
|
|
|
639
643
|
</copy_pipe_instructions>
|
|
640
644
|
"""
|
|
641
645
|
|
|
646
|
+
sink_pipe_instructions = """
|
|
647
|
+
<sink_pipe_instructions>
|
|
648
|
+
- Do not create sink pipes by default, unless the user asks for it.
|
|
649
|
+
- Sink pipes should be created in the /sinks folder.
|
|
650
|
+
- In a .pipe file you can define how to export the result of a Pipe to an external system, optionally with a schedule.
|
|
651
|
+
- Valid external systems are Kafka, S3, GCS.
|
|
652
|
+
- Sink pipes depend on a connection, if no connection is provided, search for an existing connection that suits the request. If none, create a new connection.
|
|
653
|
+
- Do not include EXPORT_SCHEDULE in the .pipe file unless is specifically requested by the user.
|
|
654
|
+
- EXPORT_SCHEDULE is a cron expression that defines the schedule of the sink pipe.
|
|
655
|
+
- EXPORT_SCHEDULE is optional and if not provided, the sink pipe will be executed only once.
|
|
656
|
+
- EXPORT_CONNECTION_NAME is the name of the connection used to export.
|
|
657
|
+
- TYPE SINK is the type of the pipe and it is mandatory for sink pipes.
|
|
658
|
+
- If the sink pipe uses parameters, you must include the % character and a newline on top of every query to be able to use the parameters.
|
|
659
|
+
- The content of the .pipe file must follow this format:
|
|
660
|
+
DESCRIPTION Sink Pipe to export sales hour every hour using my_connection
|
|
661
|
+
|
|
662
|
+
NODE daily_sales
|
|
663
|
+
SQL >
|
|
664
|
+
%
|
|
665
|
+
SELECT toStartOfDay(starting_date) day, country, sum(sales) as total_sales
|
|
666
|
+
FROM teams
|
|
667
|
+
WHERE
|
|
668
|
+
day BETWEEN toStartOfDay(now()) - interval 1 day AND toStartOfDay(now())
|
|
669
|
+
and country = {{ String(country, 'US')}}
|
|
670
|
+
GROUP BY day, country
|
|
671
|
+
|
|
672
|
+
TYPE sink
|
|
673
|
+
EXPORT_CONNECTION_NAME "my_connection"
|
|
674
|
+
EXPORT_BUCKET_URI "s3://tinybird-sinks"
|
|
675
|
+
EXPORT_FILE_TEMPLATE "daily_prices"
|
|
676
|
+
EXPORT_SCHEDULE "*/5 * * * *"
|
|
677
|
+
EXPORT_FORMAT "csv"
|
|
678
|
+
EXPORT_COMPRESSION "gz"
|
|
679
|
+
EXPORT_WRITE_STRATEGY "truncate"
|
|
680
|
+
</sink_pipe_instructions>
|
|
681
|
+
"""
|
|
682
|
+
|
|
642
683
|
materialized_pipe_instructions = """
|
|
643
684
|
<materialized_pipe_instructions>
|
|
644
685
|
- Do not create materialized pipes by default, unless the user asks for it.
|
|
@@ -709,6 +750,14 @@ GCS_SERVICE_ACCOUNT_CREDENTIALS_JSON {{ tb_secret("PRODUCTION_GCS_SERVICE_ACCOUN
|
|
|
709
750
|
</gcs_connection_content>
|
|
710
751
|
"""
|
|
711
752
|
|
|
753
|
+
gcs_hmac_connection_example = """
|
|
754
|
+
<gcs_hmac_connection_content>
|
|
755
|
+
TYPE gcs
|
|
756
|
+
GCS_HMAC_ACCESS_ID {{ tb_secret("gcs_hmac_access_id") }}
|
|
757
|
+
GCS_HMAC_SECRET {{ tb_secret("gcs_hmac_secret") }}
|
|
758
|
+
</gcs_hmac_connection_content>
|
|
759
|
+
"""
|
|
760
|
+
|
|
712
761
|
s3_connection_example = """
|
|
713
762
|
<s3_connection_content>
|
|
714
763
|
TYPE s3
|
|
@@ -767,7 +816,7 @@ pipe_instructions = """
|
|
|
767
816
|
- Nodes can't have the same exact name as the Pipe they belong to.
|
|
768
817
|
- Avoid more than one node per pipe unless it is really necessary or requested by the user.
|
|
769
818
|
- No indentation is allowed for property names: DESCRIPTION, NODE, SQL, TYPE, etc.
|
|
770
|
-
- Allowed TYPE values are: endpoint, copy, materialized.
|
|
819
|
+
- Allowed TYPE values are: endpoint, copy, materialized, sink.
|
|
771
820
|
- Add always the output node in the TYPE section or in the last node of the pipe.
|
|
772
821
|
</pipe_file_instructions>
|
|
773
822
|
"""
|
|
@@ -847,17 +896,17 @@ You have commands at your disposal to develop a tinybird project:
|
|
|
847
896
|
- {base_command} build: to build the project locally and check it works.
|
|
848
897
|
- {base_command} deployment create --wait --auto: to create a deployment and promote it automatically
|
|
849
898
|
- {base_command} test run: to run existing tests
|
|
850
|
-
- {base_command}
|
|
851
|
-
- {base_command}
|
|
852
|
-
- {base_command}
|
|
899
|
+
- {base_command} endpoint url <pipe_name>: to get the url of an endpoint, token included.
|
|
900
|
+
- {base_command} endpoint data <pipe_name>: to get the data of an endpoint. You can pass parameters to the endpoint like this: {base_command} endpoint data <pipe_name> --param1 value1 --param2 value2
|
|
901
|
+
- {base_command} token ls: to list all the tokens
|
|
853
902
|
There are other commands that you can use, but these are the most common ones. Run `{base_command} -h` to see all the commands if needed.
|
|
854
|
-
When you need to work with resources or data in the Tinybird environment that you updated with the build command, add always the --build flag before the command. Example: {base_command} --build datasource ls
|
|
855
903
|
When you need to work with resources or data in cloud, add always the --cloud flag before the command. Example: {base_command} --cloud datasource ls
|
|
856
904
|
</command_calling>
|
|
857
905
|
<development_instructions>
|
|
858
906
|
- When asking to create a tinybird data project, if the needed folders are not already created, use the following structure:
|
|
859
907
|
├── connections
|
|
860
908
|
├── copies
|
|
909
|
+
├── sinks
|
|
861
910
|
├── datasources
|
|
862
911
|
├── endpoints
|
|
863
912
|
├── fixtures
|
|
@@ -875,7 +924,7 @@ When asking for ingesting data, adding data or appending data do the following d
|
|
|
875
924
|
- When building locally, create a .ndjson file with the data you want to ingest and do `{base_command} build` to ingest the data in the build env.
|
|
876
925
|
- We call `cloud` the production environment.
|
|
877
926
|
- When appending data in cloud, use `{base_command} --cloud datasource append <datasource_name> <file_name>`
|
|
878
|
-
- When you have a response that says “there are rows in quarantine”, do `{base_command} --
|
|
927
|
+
- When you have a response that says “there are rows in quarantine”, do `{base_command} [--cloud] datasource data <datasource_name>_quarantine` to understand what is the problem.
|
|
879
928
|
</ingest_data_instructions>
|
|
880
929
|
<datasource_file_instructions>
|
|
881
930
|
Follow these instructions when creating or updating .datasource files:
|
|
@@ -890,9 +939,11 @@ Follow these instructions when creating or updating .pipe files:
|
|
|
890
939
|
{pipe_example}
|
|
891
940
|
{copy_pipe_instructions}
|
|
892
941
|
{materialized_pipe_instructions}
|
|
942
|
+
{sink_pipe_instructions}
|
|
893
943
|
{connection_instructions}
|
|
894
944
|
{kafka_connection_example}
|
|
895
945
|
{gcs_connection_example}
|
|
946
|
+
{gcs_hmac_connection_example}
|
|
896
947
|
{s3_connection_example}
|
|
897
948
|
</pipe_file_instructions>
|
|
898
949
|
<test_file_instructions>
|
|
@@ -912,11 +963,13 @@ Follow these instructions when evolving a datasource schema:
|
|
|
912
963
|
pipe_example=pipe_example,
|
|
913
964
|
copy_pipe_instructions=copy_pipe_instructions,
|
|
914
965
|
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
966
|
+
sink_pipe_instructions=sink_pipe_instructions,
|
|
915
967
|
test_instructions=test_instructions,
|
|
916
968
|
deployment_instructions=deployment_instructions,
|
|
917
969
|
connection_instructions=connection_instructions,
|
|
918
970
|
kafka_connection_example=kafka_connection_example,
|
|
919
971
|
gcs_connection_example=gcs_connection_example,
|
|
972
|
+
gcs_hmac_connection_example=gcs_hmac_connection_example,
|
|
920
973
|
s3_connection_example=s3_connection_example,
|
|
921
974
|
)
|
|
922
975
|
|
tinybird/tb/__cli__.py
CHANGED
|
@@ -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__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev225'
|
|
8
|
+
__revision__ = 'ddc2523'
|
tinybird/tb/modules/common.py
CHANGED
|
@@ -1761,18 +1761,11 @@ async def run_aws_iamrole_connection_flow(
|
|
|
1761
1761
|
|
|
1762
1762
|
async def run_gcp_svc_account_connection_flow(
|
|
1763
1763
|
environment: str,
|
|
1764
|
-
) ->
|
|
1765
|
-
bucket_name = click.prompt(
|
|
1766
|
-
"📦 Bucket name (specific name recommended, use '*' for unrestricted access in IAM policy)",
|
|
1767
|
-
prompt_suffix="\n> ",
|
|
1768
|
-
)
|
|
1769
|
-
validate_string_connector_param("Bucket", bucket_name)
|
|
1770
|
-
|
|
1764
|
+
) -> None:
|
|
1771
1765
|
click.echo(FeedbackManager.prompt_gcs_svc_account_login_gcp())
|
|
1772
1766
|
click.echo(FeedbackManager.click_enter_to_continue())
|
|
1773
1767
|
input()
|
|
1774
1768
|
|
|
1775
|
-
# Display message and wait for user to press Enter
|
|
1776
1769
|
click.echo(FeedbackManager.prompt_gcs_service_account_creation_flow(environment=environment))
|
|
1777
1770
|
click.echo(FeedbackManager.click_enter_to_continue())
|
|
1778
1771
|
input()
|
|
@@ -1781,8 +1774,6 @@ async def run_gcp_svc_account_connection_flow(
|
|
|
1781
1774
|
click.echo(FeedbackManager.click_enter_to_continue())
|
|
1782
1775
|
input()
|
|
1783
1776
|
|
|
1784
|
-
return bucket_name
|
|
1785
|
-
|
|
1786
1777
|
|
|
1787
1778
|
async def production_aws_iamrole_only(
|
|
1788
1779
|
prod_client: TinyB,
|
|
@@ -203,7 +203,10 @@ async def connection_create_s3(ctx: Context) -> None:
|
|
|
203
203
|
)
|
|
204
204
|
unique_suffix = uuid.uuid4().hex[:8] # Use first 8 chars of a UUID for brevity
|
|
205
205
|
secret_name = f"s3_role_arn_{connection_name}_{unique_suffix}"
|
|
206
|
-
|
|
206
|
+
if obj["env"] == "local":
|
|
207
|
+
save_secret_to_env_file(project=project, name=secret_name, value=role_arn)
|
|
208
|
+
else:
|
|
209
|
+
await client.create_secret(name=secret_name, value=role_arn)
|
|
207
210
|
|
|
208
211
|
create_in_cloud = (
|
|
209
212
|
click.confirm(FeedbackManager.prompt_connection_in_cloud_confirmation(), default=True)
|
|
@@ -267,15 +270,19 @@ async def connection_create_gcs(ctx: Context) -> None:
|
|
|
267
270
|
"""
|
|
268
271
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
269
272
|
obj: Dict[str, Any] = ctx.ensure_object(dict)
|
|
273
|
+
client: TinyB = obj["client"]
|
|
270
274
|
|
|
271
275
|
service = DataConnectorType.GCLOUD_STORAGE
|
|
272
276
|
click.echo(FeedbackManager.prompt_gcs_connection_header())
|
|
273
277
|
connection_name = get_gcs_connection_name(project.folder)
|
|
274
|
-
|
|
278
|
+
await run_gcp_svc_account_connection_flow(environment=obj["env"])
|
|
275
279
|
creds_json = get_gcs_svc_account_creds()
|
|
276
280
|
unique_suffix = uuid.uuid4().hex[:8] # Use first 8 chars of a UUID for brevity
|
|
277
281
|
secret_name = f"gcs_svc_account_creds_{connection_name}_{unique_suffix}"
|
|
278
|
-
|
|
282
|
+
if obj["env"] == "local":
|
|
283
|
+
save_secret_to_env_file(project=project, name=secret_name, value=creds_json)
|
|
284
|
+
else:
|
|
285
|
+
await client.create_secret(name=secret_name, value=creds_json)
|
|
279
286
|
|
|
280
287
|
connection_path = await generate_gcs_connection_file_with_secrets(
|
|
281
288
|
name=connection_name,
|
tinybird/tb/modules/create.py
CHANGED
|
@@ -197,7 +197,17 @@ async def create(
|
|
|
197
197
|
raise CLICreateException(FeedbackManager.error(message=str(e)))
|
|
198
198
|
|
|
199
199
|
|
|
200
|
-
PROJECT_PATHS = (
|
|
200
|
+
PROJECT_PATHS = (
|
|
201
|
+
"datasources",
|
|
202
|
+
"endpoints",
|
|
203
|
+
"materializations",
|
|
204
|
+
"copies",
|
|
205
|
+
"sinks",
|
|
206
|
+
"pipes",
|
|
207
|
+
"fixtures",
|
|
208
|
+
"tests",
|
|
209
|
+
"connections",
|
|
210
|
+
)
|
|
201
211
|
|
|
202
212
|
|
|
203
213
|
def validate_project_structure(project: Project) -> bool:
|
|
@@ -248,6 +258,7 @@ def create_project_structure(folder: str):
|
|
|
248
258
|
"endpoints →": "Expose real-time HTTP APIs of your transformed data.",
|
|
249
259
|
"materializations →": "Stream continuous updates of the result of a pipe into a new data source.",
|
|
250
260
|
"copies →": "Capture the result of a pipe at a moment in time and write it into a target data source.",
|
|
261
|
+
"sinks →": "Export your data to external systems on a scheduled or on-demand basis.",
|
|
251
262
|
"pipes →": "Transform your data and reuse the logic in endpoints, materializations and copies.",
|
|
252
263
|
"fixtures →": "Files with sample data for your project.",
|
|
253
264
|
"tests →": "Test your pipe files with data validation tests.",
|
|
@@ -631,7 +631,12 @@ STEP 2: CREATE GCP SERVICE ACCOUNT
|
|
|
631
631
|
1. Go to IAM & Admin > Service Accounts > + Create Service Account: https://console.cloud.google.com/iam-admin/serviceaccounts/create
|
|
632
632
|
2. Provide a service account name. Name the service account something meaningful (e.g., TinybirdGCS-{environment}-svc-account)
|
|
633
633
|
3. Click "Create and continue"
|
|
634
|
-
4. Click the "Select a role" drop down menu and select
|
|
634
|
+
4. Click the "Select a role" drop down menu and select:
|
|
635
|
+
- "Storage Object Viewer" for GCS Data Source (reading from GCS)
|
|
636
|
+
- For GCS Sink (writing to GCS), select all three roles:
|
|
637
|
+
• "Storage Object Creator" - Allows users to create objects
|
|
638
|
+
• "Storage Object Viewer" - Grants access to view objects and their metadata
|
|
639
|
+
(You can add IAM condition to provide access to selected buckets. More info in IAM Conditions: https://cloud.google.com/iam/docs/conditions-overview)
|
|
635
640
|
5. Click "Done"
|
|
636
641
|
"""
|
|
637
642
|
)
|
|
@@ -654,7 +659,9 @@ STEP 3: ADD KEY TO SERVICE ACCOUNT
|
|
|
654
659
|
|
|
655
660
|
• File created at: {connection_path}
|
|
656
661
|
• You can now use this connection in your Data Sources with: IMPORT_CONNECTION_NAME '{connection_name}'
|
|
662
|
+
• You can also use this connection in your Pipes with: EXPORT_CONNECTION_NAME '{connection_name}'
|
|
657
663
|
• Learn more about our GCS Connector: https://www.tinybird.co/docs/forward/get-data-in/connectors/gcs
|
|
664
|
+
• Learn more about our GCS Sinks: https://www.tinybird.co/docs/forward/work-with-data/publish-data/gcs-sinks
|
|
658
665
|
""")
|
|
659
666
|
|
|
660
667
|
prompt_init_git_release_pull = prompt_message(
|
tinybird/tb/modules/login.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import http.server
|
|
2
2
|
import os
|
|
3
3
|
import platform
|
|
4
|
+
import random
|
|
4
5
|
import shutil
|
|
5
6
|
import socketserver
|
|
7
|
+
import string
|
|
6
8
|
import subprocess
|
|
7
9
|
import sys
|
|
8
10
|
import threading
|
|
@@ -127,8 +129,14 @@ def start_server(auth_callback, auth_host):
|
|
|
127
129
|
default=False,
|
|
128
130
|
help="Show available regions and select where to authenticate to",
|
|
129
131
|
)
|
|
132
|
+
@click.option(
|
|
133
|
+
"--method",
|
|
134
|
+
type=click.Choice(["browser", "code"]),
|
|
135
|
+
default="browser",
|
|
136
|
+
help="Set the authentication method to use. Default: browser.",
|
|
137
|
+
)
|
|
130
138
|
@coro
|
|
131
|
-
async def login(host: Optional[str], auth_host: str, workspace: str, interactive: bool):
|
|
139
|
+
async def login(host: Optional[str], auth_host: str, workspace: str, interactive: bool, method: str):
|
|
132
140
|
"""Authenticate using the browser."""
|
|
133
141
|
try:
|
|
134
142
|
cli_config = CLIConfig.get_project_config()
|
|
@@ -154,6 +162,49 @@ async def login(host: Optional[str], auth_host: str, workspace: str, interactive
|
|
|
154
162
|
host = host.rstrip("/")
|
|
155
163
|
auth_host = auth_host.rstrip("/")
|
|
156
164
|
|
|
165
|
+
if method == "code":
|
|
166
|
+
display_code, one_time_code = create_one_time_code()
|
|
167
|
+
click.echo(FeedbackManager.info(message=f"First, copy your one-time code: {display_code}"))
|
|
168
|
+
click.echo(FeedbackManager.info(message="Press [Enter] to continue in the browser..."))
|
|
169
|
+
input()
|
|
170
|
+
click.echo(FeedbackManager.highlight(message="» Opening browser for authentication..."))
|
|
171
|
+
params = {
|
|
172
|
+
"apiHost": host,
|
|
173
|
+
"code": one_time_code,
|
|
174
|
+
"method": "code",
|
|
175
|
+
}
|
|
176
|
+
auth_url = f"{auth_host}/api/cli-login?{urlencode(params)}"
|
|
177
|
+
open_url(auth_url)
|
|
178
|
+
click.echo(
|
|
179
|
+
FeedbackManager.info(message="\nIf browser does not open, please open the following URL manually:")
|
|
180
|
+
)
|
|
181
|
+
click.echo(FeedbackManager.info(message=auth_url))
|
|
182
|
+
|
|
183
|
+
async def poll_for_tokens():
|
|
184
|
+
while True:
|
|
185
|
+
params = {
|
|
186
|
+
"apiHost": host,
|
|
187
|
+
"cliCode": one_time_code,
|
|
188
|
+
"method": "code",
|
|
189
|
+
}
|
|
190
|
+
response = requests.get(f"{auth_host}/api/cli-login?{urlencode(params)}") # noqa: ASYNC210
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
if response.status_code == 200:
|
|
194
|
+
data = response.json()
|
|
195
|
+
user_token = data.get("user_token", "")
|
|
196
|
+
workspace_token = data.get("workspace_token", "")
|
|
197
|
+
if user_token and workspace_token:
|
|
198
|
+
await authenticate_with_tokens(data, host, cli_config)
|
|
199
|
+
break
|
|
200
|
+
except Exception:
|
|
201
|
+
pass
|
|
202
|
+
|
|
203
|
+
time.sleep(2) # noqa: ASYNC251
|
|
204
|
+
|
|
205
|
+
await poll_for_tokens()
|
|
206
|
+
return
|
|
207
|
+
|
|
157
208
|
auth_event = threading.Event()
|
|
158
209
|
auth_code: list[str] = [] # Using a list to store the code, as it's mutable
|
|
159
210
|
|
|
@@ -190,32 +241,7 @@ async def login(host: Optional[str], auth_host: str, workspace: str, interactive
|
|
|
190
241
|
)
|
|
191
242
|
|
|
192
243
|
data = response.json()
|
|
193
|
-
|
|
194
|
-
cli_config.set_token_for_host(data.get("workspace_token", ""), host)
|
|
195
|
-
cli_config.set_user_token(data.get("user_token", ""))
|
|
196
|
-
host = data.get("api_host", host)
|
|
197
|
-
cli_config.set_host(host)
|
|
198
|
-
ws = await cli_config.get_client(token=data.get("workspace_token", ""), host=host).workspace_info(
|
|
199
|
-
version="v1"
|
|
200
|
-
)
|
|
201
|
-
for k in ("id", "name", "user_email", "user_id", "scope"):
|
|
202
|
-
if k in ws:
|
|
203
|
-
cli_config[k] = ws[k]
|
|
204
|
-
|
|
205
|
-
path = os.path.join(os.getcwd(), ".tinyb")
|
|
206
|
-
cli_config.persist_to_file(override_with_path=path)
|
|
207
|
-
|
|
208
|
-
auth_info: Dict[str, Any] = await cli_config.get_user_client().check_auth_login()
|
|
209
|
-
if not auth_info.get("is_valid", False):
|
|
210
|
-
raise Exception(FeedbackManager.error_auth_login_not_valid(host=cli_config.get_host()))
|
|
211
|
-
|
|
212
|
-
if not auth_info.get("is_user", False):
|
|
213
|
-
raise Exception(FeedbackManager.error_auth_login_not_user(host=cli_config.get_host()))
|
|
214
|
-
|
|
215
|
-
click.echo(FeedbackManager.gray(message="\nWorkspace: ") + FeedbackManager.info(message=ws["name"]))
|
|
216
|
-
click.echo(FeedbackManager.gray(message="User: ") + FeedbackManager.info(message=ws["user_email"]))
|
|
217
|
-
click.echo(FeedbackManager.gray(message="Host: ") + FeedbackManager.info(message=host))
|
|
218
|
-
click.echo(FeedbackManager.success(message="\n✓ Authentication successful!"))
|
|
244
|
+
await authenticate_with_tokens(data, host, cli_config)
|
|
219
245
|
else:
|
|
220
246
|
raise Exception("Authentication failed or timed out.")
|
|
221
247
|
except Exception as e:
|
|
@@ -272,3 +298,38 @@ def open_url(url: str, *, new_tab: bool = False) -> bool:
|
|
|
272
298
|
|
|
273
299
|
# 5. If everything failed, let the caller know.
|
|
274
300
|
return False
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def create_one_time_code():
|
|
304
|
+
"""Create a random one-time code for the authentication process in the format of A2C4-D2G4 (only uppercase letters and digits)"""
|
|
305
|
+
seperator = "-"
|
|
306
|
+
full_code = "".join(random.choices(string.ascii_uppercase + string.digits, k=8))
|
|
307
|
+
parts = [full_code[:4], full_code[4:]]
|
|
308
|
+
return seperator.join(parts), full_code
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
async def authenticate_with_tokens(data: Dict[str, Any], host: Optional[str], cli_config: CLIConfig):
|
|
312
|
+
cli_config.set_token(data.get("workspace_token", ""))
|
|
313
|
+
host = host or data.get("api_host", "")
|
|
314
|
+
cli_config.set_token_for_host(data.get("workspace_token", ""), host)
|
|
315
|
+
cli_config.set_user_token(data.get("user_token", ""))
|
|
316
|
+
cli_config.set_host(host)
|
|
317
|
+
ws = await cli_config.get_client(token=data.get("workspace_token", ""), host=host).workspace_info(version="v1")
|
|
318
|
+
for k in ("id", "name", "user_email", "user_id", "scope"):
|
|
319
|
+
if k in ws:
|
|
320
|
+
cli_config[k] = ws[k]
|
|
321
|
+
|
|
322
|
+
path = os.path.join(os.getcwd(), ".tinyb")
|
|
323
|
+
cli_config.persist_to_file(override_with_path=path)
|
|
324
|
+
|
|
325
|
+
auth_info: Dict[str, Any] = await cli_config.get_user_client().check_auth_login()
|
|
326
|
+
if not auth_info.get("is_valid", False):
|
|
327
|
+
raise Exception(FeedbackManager.error_auth_login_not_valid(host=cli_config.get_host()))
|
|
328
|
+
|
|
329
|
+
if not auth_info.get("is_user", False):
|
|
330
|
+
raise Exception(FeedbackManager.error_auth_login_not_user(host=cli_config.get_host()))
|
|
331
|
+
|
|
332
|
+
click.echo(FeedbackManager.gray(message="\nWorkspace: ") + FeedbackManager.info(message=ws["name"]))
|
|
333
|
+
click.echo(FeedbackManager.gray(message="User: ") + FeedbackManager.info(message=ws["user_email"]))
|
|
334
|
+
click.echo(FeedbackManager.gray(message="Host: ") + FeedbackManager.info(message=host))
|
|
335
|
+
click.echo(FeedbackManager.success(message="\n✓ Authentication successful!"))
|
|
@@ -3,7 +3,7 @@ tinybird/context.py,sha256=FfqYfrGX_I7PKGTQo93utaKPDNVYWelg4Hsp3evX5wM,1291
|
|
|
3
3
|
tinybird/datatypes.py,sha256=r4WCvspmrXTJHiPjjyOTiZyZl31FO3Ynkwq4LQsYm6E,11059
|
|
4
4
|
tinybird/feedback_manager.py,sha256=1INQFfRfuMCb9lfB8KNf4r6qC2khW568hoHjtk-wshI,69305
|
|
5
5
|
tinybird/git_settings.py,sha256=Sw_8rGmribEFJ4Z_6idrVytxpFYk7ez8ei0qHULzs3E,3934
|
|
6
|
-
tinybird/prompts.py,sha256=
|
|
6
|
+
tinybird/prompts.py,sha256=VELVeJzSyGJULFML9eXytMG_3Ett0xKwNVRLBNP6TIs,40954
|
|
7
7
|
tinybird/sql.py,sha256=BufnOgclQokDyihtuXesOwHBsebN6wRXIxO5wKRkOwE,48299
|
|
8
8
|
tinybird/sql_template.py,sha256=WjsTBjpQLVBHGZbY2dZuhZUurFR-rbJ_KRRy5vx4Y5E,99967
|
|
9
9
|
tinybird/sql_template_fmt.py,sha256=KUHdj5rYCYm_rKKdXYSJAE9vIyXUQLB0YSZnUXHeBlY,10196
|
|
@@ -12,12 +12,12 @@ tinybird/syncasync.py,sha256=IPnOx6lMbf9SNddN1eBtssg8vCLHMt76SuZ6YNYm-Yk,27761
|
|
|
12
12
|
tinybird/tornado_template.py,sha256=jjNVDMnkYFWXflmT8KU_Ssbo5vR8KQq3EJMk5vYgXRw,41959
|
|
13
13
|
tinybird/ch_utils/constants.py,sha256=yEKR11gLCL-irEXXF9QwShaR0JLXiBTlaxfolcCIoqY,4097
|
|
14
14
|
tinybird/ch_utils/engine.py,sha256=X4tE9OrfaUy6kO9cqVEzyI9cDcmOF3IAssRRzsTsfEQ,40781
|
|
15
|
-
tinybird/datafile/common.py,sha256=
|
|
15
|
+
tinybird/datafile/common.py,sha256=W8HtbKVLe8Fr8Q1x3xw2DA-vroi8EZfvDJptAxiJVzQ,91784
|
|
16
16
|
tinybird/datafile/exceptions.py,sha256=8rw2umdZjtby85QbuRKFO5ETz_eRHwUY5l7eHsy1wnI,556
|
|
17
17
|
tinybird/datafile/parse_connection.py,sha256=tRyn2Rpr1TeWet5BXmMoQgaotbGdYep1qiTak_OqC5E,1825
|
|
18
18
|
tinybird/datafile/parse_datasource.py,sha256=ssW8QeFSgglVFi3sDZj_HgkJiTJ2069v2JgqnH3CkDE,1825
|
|
19
19
|
tinybird/datafile/parse_pipe.py,sha256=xf4m0Tw44QWJzHzAm7Z7FwUoUUtr7noMYjU1NiWnX0k,3880
|
|
20
|
-
tinybird/tb/__cli__.py,sha256=
|
|
20
|
+
tinybird/tb/__cli__.py,sha256=yoNIdYpjihCJBWlrVYhBKJ8YPmuz0F1l8T1UsPRwrqQ,247
|
|
21
21
|
tinybird/tb/check_pypi.py,sha256=i3l2L8IajeB7sreikR7oPlYJki9MtS3c_M4crnmbByc,760
|
|
22
22
|
tinybird/tb/cli.py,sha256=0xYk2Ip4vb3nNFbxfTdG3VoIgdRvUKVbUVU_mviErPA,1107
|
|
23
23
|
tinybird/tb/client.py,sha256=FKj61vY9STPW03kfVcxYuY1_csI-kP-mc1ERQfqJtg8,56505
|
|
@@ -25,18 +25,18 @@ tinybird/tb/config.py,sha256=jT9xndpeCY_g0HdB5qE2EquC0TFRRnkPnQFWZWd04jo,3998
|
|
|
25
25
|
tinybird/tb/modules/build.py,sha256=T36msoBK5g9AZlrJnFRPvlZbrdE265LY1q3Y4YqvS3w,20067
|
|
26
26
|
tinybird/tb/modules/cicd.py,sha256=Njb6eZOHHbUkoJJx6KoixO9PsfA_T-3Ybkya9-50Ca8,7328
|
|
27
27
|
tinybird/tb/modules/cli.py,sha256=zTUob6oSZszCx-lk6MJbQ_VuNOXBo8b0DOHPWezzMOg,15997
|
|
28
|
-
tinybird/tb/modules/common.py,sha256=
|
|
28
|
+
tinybird/tb/modules/common.py,sha256=F6oaoFZ3aBxEMjiDKYhthsEIUqSFPkcdlMJ7h7A49Ac,83114
|
|
29
29
|
tinybird/tb/modules/config.py,sha256=VnzYVUo4q1RBEEMMce4_OCrKp4erhgkRPHElydVlKj0,11488
|
|
30
|
-
tinybird/tb/modules/connection.py,sha256=
|
|
30
|
+
tinybird/tb/modules/connection.py,sha256=dAOv8z3ym9Tt62j7AI8R9PgFwgiCIFdgIMpUiMdtxaQ,18906
|
|
31
31
|
tinybird/tb/modules/copy.py,sha256=zHN1d5NA-MFsgbk2kKJq2P9qA8dNOnIsIa60QpVnSwc,4458
|
|
32
|
-
tinybird/tb/modules/create.py,sha256=
|
|
32
|
+
tinybird/tb/modules/create.py,sha256=dRpzwv1GWqu1BqZtl1-AkFbap52adA-GwY-xf0qxIcw,22262
|
|
33
33
|
tinybird/tb/modules/datasource.py,sha256=4a50A_qwB-3FUEUeB3ps6tUCJvn02rMUUwW-vHaMjTw,40846
|
|
34
34
|
tinybird/tb/modules/deployment.py,sha256=ByXIgEvwxB49pJEKKj0EJIfORWyflCYr04k8961nBkA,28391
|
|
35
35
|
tinybird/tb/modules/deprecations.py,sha256=rrszC1f_JJeJ8mUxGoCxckQTJFBCR8wREf4XXXN-PRc,4507
|
|
36
36
|
tinybird/tb/modules/dev_server.py,sha256=57FCKuWpErwYUYgHspYDkLWEm9F4pbvVOtMrFXX1fVU,10129
|
|
37
37
|
tinybird/tb/modules/endpoint.py,sha256=rC1CZiEZDMb5chByf4xZhv5PsfkoLeIVDScHQ-QcBsE,12072
|
|
38
38
|
tinybird/tb/modules/exceptions.py,sha256=5jK91w1LPmtqIUfDpHe_Op5OxGz8-p1BPgtLREMIni0,5217
|
|
39
|
-
tinybird/tb/modules/feedback_manager.py,sha256=
|
|
39
|
+
tinybird/tb/modules/feedback_manager.py,sha256=AR7spZdOO_ya_5C8cGN3zb3vzAeu--HvAfj6pFGuw5k,77882
|
|
40
40
|
tinybird/tb/modules/info.py,sha256=NqSsoyzFqbtUEGH_tSowNOI_jSsNuixibln6-plsfOY,6810
|
|
41
41
|
tinybird/tb/modules/infra.py,sha256=fve30Gj3mG9zbquGxS2e4ipcOYOxviWQCpNFfEzJN_Q,33195
|
|
42
42
|
tinybird/tb/modules/job.py,sha256=AsUCRNzy7HG5oJ4fyk9NpIm5NtNJgBZSy8MtJdXBe5A,3167
|
|
@@ -44,7 +44,7 @@ tinybird/tb/modules/llm.py,sha256=KfsCYmKeW1VQz0iDZhGKCRkQv_Y3kTHh6JuxvofOguE,10
|
|
|
44
44
|
tinybird/tb/modules/llm_utils.py,sha256=nS9r4FAElJw8yXtmdYrx-rtI2zXR8qXfi1QqUDCfxvg,3469
|
|
45
45
|
tinybird/tb/modules/local.py,sha256=TWT7pGXQ3cOy0M_piyw7WhrzoxZE18PmfOLzHD5CoEc,6096
|
|
46
46
|
tinybird/tb/modules/local_common.py,sha256=8CSEVygFi0fIISatYxCStcHizugXCA9WNTLO_zDKmXw,17195
|
|
47
|
-
tinybird/tb/modules/login.py,sha256=
|
|
47
|
+
tinybird/tb/modules/login.py,sha256=VxxCzyjG5dpFm1lmlNPVcM-0-jqURAFp4HEkMMBdiGo,12617
|
|
48
48
|
tinybird/tb/modules/logout.py,sha256=sniI4JNxpTrVeRCp0oGJuQ3yRerG4hH5uz6oBmjv724,1009
|
|
49
49
|
tinybird/tb/modules/materialization.py,sha256=neugOziGfh50GSOgfZJX8giVPKgauoE313LUw6kXowo,5467
|
|
50
50
|
tinybird/tb/modules/mock.py,sha256=IyHweMUM6bUH8IhyiX2tTMpdVpTFUeAJ41lZ5P42-HQ,5303
|
|
@@ -82,8 +82,8 @@ tinybird/tb_cli_modules/config.py,sha256=IsgdtFRnUrkY8-Zo32lmk6O7u3bHie1QCxLwgp4
|
|
|
82
82
|
tinybird/tb_cli_modules/exceptions.py,sha256=pmucP4kTF4irIt7dXiG-FcnI-o3mvDusPmch1L8RCWk,3367
|
|
83
83
|
tinybird/tb_cli_modules/regions.py,sha256=QjsL5H6Kg-qr0aYVLrvb1STeJ5Sx_sjvbOYO0LrEGMk,166
|
|
84
84
|
tinybird/tb_cli_modules/telemetry.py,sha256=Hh2Io8ZPROSunbOLuMvuIFU4TqwWPmQTqal4WS09K1A,10449
|
|
85
|
-
tinybird-0.0.1.
|
|
86
|
-
tinybird-0.0.1.
|
|
87
|
-
tinybird-0.0.1.
|
|
88
|
-
tinybird-0.0.1.
|
|
89
|
-
tinybird-0.0.1.
|
|
85
|
+
tinybird-0.0.1.dev225.dist-info/METADATA,sha256=tYgd7QaNE9_KOU6StAufP4rIYWwLAcZ7hHWI1vL8pro,1682
|
|
86
|
+
tinybird-0.0.1.dev225.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
87
|
+
tinybird-0.0.1.dev225.dist-info/entry_points.txt,sha256=LwdHU6TfKx4Qs7BqqtaczEZbImgU7Abe9Lp920zb_fo,43
|
|
88
|
+
tinybird-0.0.1.dev225.dist-info/top_level.txt,sha256=VqqqEmkAy7UNaD8-V51FCoMMWXjLUlR0IstvK7tJYVY,54
|
|
89
|
+
tinybird-0.0.1.dev225.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|