tinybird 0.0.1.dev87__tar.gz → 0.0.1.dev89__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of tinybird might be problematic. Click here for more details.
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/ch_utils/engine.py +12 -6
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/client.py +16 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/config.py +2 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/context.py +1 -1
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/common.py +196 -6
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/config.py +3 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/deployment.py +11 -9
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/feedback_manager.py +14 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/workspace.py +54 -19
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/setup.cfg +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/connectors.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/datafile.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/prompts.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/sql.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/cli.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/auth.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/build.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/cicd.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/cli.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/copy.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/create.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/build.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/common.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/playground.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datasource.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/endpoint.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/fmt.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/local.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/local_common.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/login.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/logout.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/materialization.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/mock.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/pipe.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/playground.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/project.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/shell.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/tag.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/test.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/token.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/watch.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tornado_template.py +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird.egg-info/SOURCES.txt +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -761,6 +761,16 @@ def engine_local_to_replicated(engine: str, database: str, name: str) -> str:
|
|
|
761
761
|
return re.sub(r"(.*)MergeTree(\(([^\)]*)\))*(.*)", _replace, engine.strip())
|
|
762
762
|
|
|
763
763
|
|
|
764
|
+
def ttl_from_engine(engine: str) -> Optional[str]:
|
|
765
|
+
ttl_array = engine.split(" TTL ")
|
|
766
|
+
if len(ttl_array) <= 1:
|
|
767
|
+
return None
|
|
768
|
+
settings_array = engine.split(" SETTINGS ")
|
|
769
|
+
settings = " SETTINGS " + settings_array[1] if len(settings_array) > 1 else None
|
|
770
|
+
ttl = ttl_array[1][: -(len(settings))] if settings else ttl_array[1]
|
|
771
|
+
return ttl
|
|
772
|
+
|
|
773
|
+
|
|
764
774
|
def ttl_condition_from_engine_full(engine_full: Optional[str]) -> Optional[str]:
|
|
765
775
|
"""
|
|
766
776
|
>>> ttl_condition_from_engine_full(None)
|
|
@@ -808,13 +818,9 @@ def ttl_condition_from_engine_full(engine_full: Optional[str]) -> Optional[str]:
|
|
|
808
818
|
return None
|
|
809
819
|
|
|
810
820
|
try:
|
|
811
|
-
|
|
812
|
-
if
|
|
821
|
+
ttl = ttl_from_engine(engine_full)
|
|
822
|
+
if not ttl:
|
|
813
823
|
return None
|
|
814
|
-
settings_array = engine_full.split(" SETTINGS ")
|
|
815
|
-
settings = " SETTINGS " + settings_array[1] if len(settings_array) > 1 else None
|
|
816
|
-
ttl = ttl_array[1][: -(len(settings))] if settings else ttl_array[1]
|
|
817
|
-
|
|
818
824
|
groups = SIMPLE_TTL_DEFINITION.search(ttl)
|
|
819
825
|
if not groups:
|
|
820
826
|
return None
|
|
@@ -871,6 +871,22 @@ class TinyB:
|
|
|
871
871
|
async def organization(self, organization_id: str):
|
|
872
872
|
return await self._req(f"/v0/organizations/{organization_id}")
|
|
873
873
|
|
|
874
|
+
async def create_organization(
|
|
875
|
+
self,
|
|
876
|
+
name: str,
|
|
877
|
+
):
|
|
878
|
+
url = f"/v0/organizations?name={name}"
|
|
879
|
+
return await self._req(url, method="POST", data=b"")
|
|
880
|
+
|
|
881
|
+
async def add_workspaces_to_organization(self, organization_id: str, workspace_ids: List[str]):
|
|
882
|
+
if not workspace_ids:
|
|
883
|
+
return
|
|
884
|
+
return await self._req(
|
|
885
|
+
f"/v0/organizations/{organization_id}/workspaces",
|
|
886
|
+
method="PUT",
|
|
887
|
+
data=json.dumps({"workspace_ids": ",".join(workspace_ids)}),
|
|
888
|
+
)
|
|
889
|
+
|
|
874
890
|
async def wait_for_job(
|
|
875
891
|
self,
|
|
876
892
|
job_id: str,
|
|
@@ -30,6 +30,7 @@ LEGACY_HOSTS = {
|
|
|
30
30
|
"https://api.us-west-2.aws.tinybird.co": "https://app.tinybird.co/aws/us-west-2",
|
|
31
31
|
"https://api.eu-central-1.aws.tinybird.co": "https://app.tinybird.co/aws/eu-central-1",
|
|
32
32
|
"https://api.eu-west-1.aws.tinybird.co": "https://app.tinybird.co/aws/eu-west-1",
|
|
33
|
+
"https://api.europe-west2.gcp.tinybird.co": "https://cloud.tinybird.co/gcp/europe-west2",
|
|
33
34
|
"https://api.ap-east.aws.tinybird.co": "https://app.tinybird.co/aws/ap-east",
|
|
34
35
|
"https://api.wadus1.gcp.tinybird.co": "https://app.wadus.tinybird.co/gcp/wadus1",
|
|
35
36
|
"https://api.wadus2.gcp.tinybird.co": "https://app.wadus.tinybird.co/gcp/wadus2",
|
|
@@ -48,6 +49,7 @@ LEGACY_HOSTS = {
|
|
|
48
49
|
"https://ui.us-east.aws.tinybird.co": "https://app.tinybird.co/aws/us-east-1",
|
|
49
50
|
"https://ui.us-west-2.aws.tinybird.co": "https://app.tinybird.co/aws/us-west-2",
|
|
50
51
|
"https://ui.eu-central-1.aws.tinybird.co": "https://app.tinybird.co/aws/eu-central-1",
|
|
52
|
+
"https://ui.europe-west2.gcp.tinybird.co": "https://cloud.tinybird.co/gcp/europe-west2",
|
|
51
53
|
"https://ui.ap-east.aws.tinybird.co": "https://app.tinybird.co/aws/ap-east",
|
|
52
54
|
"https://ui.split.tinybird.co": "https://app.tinybird.co/aws/split-us-east",
|
|
53
55
|
"https://ui.split.us-west-2.aws.tinybird.co": "https://app.tinybird.co/aws/split-us-west-2",
|
|
@@ -7,7 +7,7 @@ if TYPE_CHECKING:
|
|
|
7
7
|
|
|
8
8
|
workspace_id: ContextVar[str] = ContextVar("workspace_id")
|
|
9
9
|
workspace: ContextVar["User"] = ContextVar("workspace")
|
|
10
|
-
|
|
10
|
+
table_id: ContextVar[str] = ContextVar("table_id")
|
|
11
11
|
hfi_frequency: ContextVar[float] = ContextVar("hfi_frequency")
|
|
12
12
|
hfi_frequency_gatherer: ContextVar[float] = ContextVar("hfi_frequency_gatherer")
|
|
13
13
|
use_gatherer: ContextVar[bool] = ContextVar("use_gatherer")
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev89'
|
|
8
|
+
__revision__ = '6153af6'
|
|
@@ -19,7 +19,7 @@ from enum import Enum
|
|
|
19
19
|
from functools import wraps
|
|
20
20
|
from os import environ, getcwd, getenv
|
|
21
21
|
from pathlib import Path
|
|
22
|
-
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Union
|
|
22
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Literal, Optional, Set, Tuple, TypedDict, Union
|
|
23
23
|
from urllib.parse import urlparse
|
|
24
24
|
|
|
25
25
|
import aiofiles
|
|
@@ -683,7 +683,13 @@ async def fork_workspace(client: TinyB, user_client: TinyB, created_workspace):
|
|
|
683
683
|
|
|
684
684
|
|
|
685
685
|
async def create_workspace_non_interactive(
|
|
686
|
-
ctx: Context,
|
|
686
|
+
ctx: Context,
|
|
687
|
+
workspace_name: str,
|
|
688
|
+
starterkit: Optional[str],
|
|
689
|
+
user_token: str,
|
|
690
|
+
fork: bool,
|
|
691
|
+
organization_id: Optional[str],
|
|
692
|
+
organization_name: Optional[str],
|
|
687
693
|
):
|
|
688
694
|
"""Creates a workspace using the provided name and starterkit"""
|
|
689
695
|
client: TinyB = ctx.ensure_object(dict)["client"]
|
|
@@ -692,8 +698,15 @@ async def create_workspace_non_interactive(
|
|
|
692
698
|
user_client: TinyB = deepcopy(client)
|
|
693
699
|
user_client.token = user_token
|
|
694
700
|
|
|
695
|
-
created_workspace = await user_client.create_workspace(workspace_name, starterkit)
|
|
696
|
-
|
|
701
|
+
created_workspace = await user_client.create_workspace(workspace_name, starterkit, organization_id)
|
|
702
|
+
if organization_id and organization_name:
|
|
703
|
+
click.echo(
|
|
704
|
+
FeedbackManager.success_workspace_created_with_organization(
|
|
705
|
+
workspace_name=workspace_name, organization_name=organization_name, organization_id=organization_id
|
|
706
|
+
)
|
|
707
|
+
)
|
|
708
|
+
else:
|
|
709
|
+
click.echo(FeedbackManager.success_workspace_created(workspace_name=workspace_name))
|
|
697
710
|
|
|
698
711
|
if fork:
|
|
699
712
|
await fork_workspace(client, user_client, created_workspace)
|
|
@@ -703,7 +716,13 @@ async def create_workspace_non_interactive(
|
|
|
703
716
|
|
|
704
717
|
|
|
705
718
|
async def create_workspace_interactive(
|
|
706
|
-
ctx: Context,
|
|
719
|
+
ctx: Context,
|
|
720
|
+
workspace_name: Optional[str],
|
|
721
|
+
starterkit: Optional[str],
|
|
722
|
+
user_token: str,
|
|
723
|
+
fork: bool,
|
|
724
|
+
organization_id: Optional[str],
|
|
725
|
+
organization_name: Optional[str],
|
|
707
726
|
):
|
|
708
727
|
if not starterkit and not is_ci_environment():
|
|
709
728
|
click.echo("\n")
|
|
@@ -721,7 +740,18 @@ async def create_workspace_interactive(
|
|
|
721
740
|
default_name = f"new_workspace_{uuid.uuid4().hex[0:4]}"
|
|
722
741
|
workspace_name = click.prompt("\nWorkspace name", default=default_name, err=True, type=str)
|
|
723
742
|
|
|
724
|
-
|
|
743
|
+
if not workspace_name:
|
|
744
|
+
raise CLIException(FeedbackManager.error_workspace_name_required())
|
|
745
|
+
|
|
746
|
+
await create_workspace_non_interactive(
|
|
747
|
+
ctx,
|
|
748
|
+
workspace_name,
|
|
749
|
+
starterkit,
|
|
750
|
+
user_token,
|
|
751
|
+
fork,
|
|
752
|
+
organization_id,
|
|
753
|
+
organization_name,
|
|
754
|
+
)
|
|
725
755
|
|
|
726
756
|
|
|
727
757
|
async def print_data_branch_summary(client, job_id, response=None):
|
|
@@ -1948,3 +1978,163 @@ async def send_batch_events(
|
|
|
1948
1978
|
elapsed_time = time_end - time_start
|
|
1949
1979
|
cols = len(data[0].keys()) if len(data) > 0 else 0
|
|
1950
1980
|
click.echo(FeedbackManager.highlight(message=f"» {rows} rows x {cols} cols in {elapsed_time:.1f}s"))
|
|
1981
|
+
|
|
1982
|
+
|
|
1983
|
+
async def get_organizations_by_user(config: CLIConfig, user_token: str) -> List[Dict[str, Any]]:
|
|
1984
|
+
"""Fetches all organizations by user using the provided user token"""
|
|
1985
|
+
organizations = []
|
|
1986
|
+
|
|
1987
|
+
try:
|
|
1988
|
+
user_client = config.get_client(token=user_token)
|
|
1989
|
+
user_workspaces = await user_client.user_workspaces_with_organization()
|
|
1990
|
+
admin_org_id = user_workspaces.get("organization_id")
|
|
1991
|
+
seen_org_ids = set()
|
|
1992
|
+
|
|
1993
|
+
for workspace in user_workspaces.get("workspaces"):
|
|
1994
|
+
org = workspace.get("organization")
|
|
1995
|
+
if org and org.get("id") not in seen_org_ids:
|
|
1996
|
+
org["is_admin"] = org.get("id") == admin_org_id
|
|
1997
|
+
organizations.append(org)
|
|
1998
|
+
seen_org_ids.add(org.get("id"))
|
|
1999
|
+
|
|
2000
|
+
# Case: user is admin of an organization but not a member of any workspace in it
|
|
2001
|
+
if admin_org_id and admin_org_id not in seen_org_ids:
|
|
2002
|
+
org = await user_client.organization(admin_org_id)
|
|
2003
|
+
org["id"] = admin_org_id
|
|
2004
|
+
org["is_admin"] = True
|
|
2005
|
+
organizations.append(org)
|
|
2006
|
+
|
|
2007
|
+
except Exception as e:
|
|
2008
|
+
raise CLIWorkspaceException(FeedbackManager.error_while_fetching_orgs(error=str(e)))
|
|
2009
|
+
return organizations
|
|
2010
|
+
|
|
2011
|
+
|
|
2012
|
+
OrgType = Literal["tinybird", "domain", "admin", "member"]
|
|
2013
|
+
|
|
2014
|
+
|
|
2015
|
+
class Organization(TypedDict):
|
|
2016
|
+
id: str
|
|
2017
|
+
name: str
|
|
2018
|
+
role: str
|
|
2019
|
+
domains: Optional[List[str]]
|
|
2020
|
+
type: OrgType
|
|
2021
|
+
|
|
2022
|
+
|
|
2023
|
+
def sort_organizations_by_user(organizations: List[Dict[str, Any]], user_email: Optional[str]) -> List[Organization]:
|
|
2024
|
+
"""Sort organizations based on type: tinybird > domain > admin > member"""
|
|
2025
|
+
sorted_organizations: List[Organization] = []
|
|
2026
|
+
user_domain = user_email.split("@")[1] if user_email else None
|
|
2027
|
+
is_tinybird_user = user_domain == "tinybird.co"
|
|
2028
|
+
|
|
2029
|
+
for org in organizations:
|
|
2030
|
+
domain = org.get("domain") or ""
|
|
2031
|
+
domains = domain.split(",") if domain else None
|
|
2032
|
+
role: OrgType = "admin" if org.get("is_admin") else "member"
|
|
2033
|
+
type = role
|
|
2034
|
+
if domains and user_domain and user_domain in domains:
|
|
2035
|
+
type = "domain"
|
|
2036
|
+
if org.get("name") == "Tinybird" and is_tinybird_user:
|
|
2037
|
+
type = "tinybird"
|
|
2038
|
+
|
|
2039
|
+
sorted_organizations.append(
|
|
2040
|
+
{
|
|
2041
|
+
"id": org.get("id") or "",
|
|
2042
|
+
"name": org.get("name") or "",
|
|
2043
|
+
"role": role,
|
|
2044
|
+
"domains": [domain.strip() for domain in domains] if domains else None,
|
|
2045
|
+
"type": type,
|
|
2046
|
+
}
|
|
2047
|
+
)
|
|
2048
|
+
|
|
2049
|
+
type_priority: Dict[OrgType, int] = {"tinybird": 0, "domain": 1, "admin": 2, "member": 3}
|
|
2050
|
+
|
|
2051
|
+
sorted_organizations.sort(key=lambda x: type_priority[x["type"]])
|
|
2052
|
+
|
|
2053
|
+
return sorted_organizations
|
|
2054
|
+
|
|
2055
|
+
|
|
2056
|
+
async def ask_for_organization_interactively(organizations: List[Organization]) -> Optional[Organization]:
|
|
2057
|
+
rows = [(index + 1, org["name"], org["role"], org["id"]) for index, org in enumerate(organizations)]
|
|
2058
|
+
|
|
2059
|
+
echo_safe_humanfriendly_tables_format_smart_table(rows, column_names=["Idx", "Name", "Role", "Id"])
|
|
2060
|
+
click.echo("")
|
|
2061
|
+
click.echo(" [0] to cancel")
|
|
2062
|
+
|
|
2063
|
+
org_index = -1
|
|
2064
|
+
while org_index == -1:
|
|
2065
|
+
org_index = click.prompt("\nSelect an organization to include the workspace in", default=1)
|
|
2066
|
+
if org_index < 0 or org_index > len(organizations):
|
|
2067
|
+
click.echo(FeedbackManager.error_organization_index(organization_index=org_index))
|
|
2068
|
+
org_index = -1
|
|
2069
|
+
|
|
2070
|
+
if org_index == 0:
|
|
2071
|
+
click.echo(FeedbackManager.info_cancelled_by_user())
|
|
2072
|
+
return None
|
|
2073
|
+
|
|
2074
|
+
return organizations[org_index - 1]
|
|
2075
|
+
|
|
2076
|
+
|
|
2077
|
+
async def ask_for_organization_name(config: CLIConfig) -> str:
|
|
2078
|
+
user_email = config.get_user_email()
|
|
2079
|
+
default_organization_name = (
|
|
2080
|
+
user_email.split("@")[1].split(".")[0] if user_email else None
|
|
2081
|
+
) # Example: "jane.doe@tinybird.com" -> "tinybird"
|
|
2082
|
+
# check if domain is a common domain
|
|
2083
|
+
if default_organization_name in ["gmail", "yahoo", "hotmail", "outlook"]:
|
|
2084
|
+
default_organization_name = (
|
|
2085
|
+
user_email.split("@")[0] if user_email else None
|
|
2086
|
+
) # Example: "jane.doe@gmail.com" -> "jane.doe"
|
|
2087
|
+
return click.prompt(
|
|
2088
|
+
"\nYou need to create an organization to continue. We will include your existing workspaces in it.\nThis operation will only happen once and then your new workspaces will be automatically included in your organization.\n\nEnter organization name",
|
|
2089
|
+
hide_input=False,
|
|
2090
|
+
show_default=True,
|
|
2091
|
+
default=default_organization_name,
|
|
2092
|
+
)
|
|
2093
|
+
|
|
2094
|
+
|
|
2095
|
+
async def create_organization_and_add_workspaces(
|
|
2096
|
+
config: CLIConfig, organization_name: str, user_token: str
|
|
2097
|
+
) -> Dict[str, Any]:
|
|
2098
|
+
client: TinyB = config.get_client(token=user_token)
|
|
2099
|
+
try:
|
|
2100
|
+
organization = await client.create_organization(organization_name)
|
|
2101
|
+
click.echo(FeedbackManager.success_organization_created(organization_name=organization_name))
|
|
2102
|
+
except Exception as e:
|
|
2103
|
+
raise CLIWorkspaceException(FeedbackManager.error_organization_creation(error=str(e)))
|
|
2104
|
+
|
|
2105
|
+
# Add existing orphan workspaces to the organization - this is only needed for backwards compatibility
|
|
2106
|
+
user_workspaces = await client.user_workspaces_with_organization()
|
|
2107
|
+
workspaces_to_migrate = []
|
|
2108
|
+
for workspace in user_workspaces["workspaces"]:
|
|
2109
|
+
if workspace.get("organization") is None and workspace.get("role") == "admin":
|
|
2110
|
+
workspaces_to_migrate.append(workspace["id"])
|
|
2111
|
+
await client.add_workspaces_to_organization(organization["id"], workspaces_to_migrate)
|
|
2112
|
+
|
|
2113
|
+
return organization
|
|
2114
|
+
|
|
2115
|
+
|
|
2116
|
+
async def get_user_token(config: CLIConfig, user_token: Optional[str] = None) -> str:
|
|
2117
|
+
client = config.get_client()
|
|
2118
|
+
host = config.get_host() or CLIConfig.DEFAULTS["host"]
|
|
2119
|
+
ui_host = get_display_host(host)
|
|
2120
|
+
|
|
2121
|
+
if not user_token:
|
|
2122
|
+
user_token = config.get_user_token()
|
|
2123
|
+
if user_token:
|
|
2124
|
+
try:
|
|
2125
|
+
await check_user_token_with_client(client, user_token)
|
|
2126
|
+
except Exception:
|
|
2127
|
+
user_token = None
|
|
2128
|
+
pass
|
|
2129
|
+
if not user_token:
|
|
2130
|
+
user_token = ask_for_user_token("delete a workspace", ui_host)
|
|
2131
|
+
if not user_token:
|
|
2132
|
+
raise CLIWorkspaceException(
|
|
2133
|
+
FeedbackManager.error_exception(
|
|
2134
|
+
error='Invalid user authentication. Make sure you are using the "user token" instead of the "admin your@email" token.'
|
|
2135
|
+
)
|
|
2136
|
+
)
|
|
2137
|
+
|
|
2138
|
+
await check_user_token_with_client(client, user_token)
|
|
2139
|
+
|
|
2140
|
+
return user_token
|
|
@@ -247,6 +247,9 @@ class CLIConfig:
|
|
|
247
247
|
def get_user_client(self, host: Optional[str] = None) -> tbc.TinyB:
|
|
248
248
|
return self.get_client(self.get_user_token(), host)
|
|
249
249
|
|
|
250
|
+
def get_user_email(self) -> Optional[str]:
|
|
251
|
+
return self["user_email"]
|
|
252
|
+
|
|
250
253
|
def set_workspace_token(self, workspace_id: str, token: str) -> None:
|
|
251
254
|
pass
|
|
252
255
|
|
|
@@ -191,17 +191,19 @@ def deployment_group() -> None:
|
|
|
191
191
|
help="Validate the deployment before creating it. Disabled by default.",
|
|
192
192
|
)
|
|
193
193
|
@click.option(
|
|
194
|
-
"--allow-
|
|
194
|
+
"--allow-destructive-operations/--no-allow-destructive-operations",
|
|
195
195
|
is_flag=True,
|
|
196
196
|
default=False,
|
|
197
197
|
help="Allow removing datasources. Disabled by default.",
|
|
198
198
|
)
|
|
199
199
|
@click.pass_context
|
|
200
|
-
def deployment_create(
|
|
200
|
+
def deployment_create(
|
|
201
|
+
ctx: click.Context, wait: bool, auto: bool, check: bool, allow_destructive_operations: bool
|
|
202
|
+
) -> None:
|
|
201
203
|
"""
|
|
202
204
|
Validate and deploy the project server side.
|
|
203
205
|
"""
|
|
204
|
-
create_deployment(ctx, wait, auto, check,
|
|
206
|
+
create_deployment(ctx, wait, auto, check, allow_destructive_operations)
|
|
205
207
|
|
|
206
208
|
|
|
207
209
|
@deployment_group.command(name="ls")
|
|
@@ -298,17 +300,17 @@ def deployment_rollback(ctx: click.Context, wait: bool) -> None:
|
|
|
298
300
|
help="Validate the deployment before creating it. Disabled by default.",
|
|
299
301
|
)
|
|
300
302
|
@click.option(
|
|
301
|
-
"--allow-
|
|
303
|
+
"--allow-destructive-operations/--no-allow-destructive-operations",
|
|
302
304
|
is_flag=True,
|
|
303
305
|
default=False,
|
|
304
306
|
help="Allow removing datasources. Disabled by default.",
|
|
305
307
|
)
|
|
306
308
|
@click.pass_context
|
|
307
|
-
def deploy(ctx: click.Context, wait: bool, auto: bool, check: bool,
|
|
309
|
+
def deploy(ctx: click.Context, wait: bool, auto: bool, check: bool, allow_destructive_operations: bool) -> None:
|
|
308
310
|
"""
|
|
309
311
|
Deploy the project.
|
|
310
312
|
"""
|
|
311
|
-
create_deployment(ctx, wait, auto, check,
|
|
313
|
+
create_deployment(ctx, wait, auto, check, allow_destructive_operations)
|
|
312
314
|
|
|
313
315
|
|
|
314
316
|
def create_deployment(
|
|
@@ -316,7 +318,7 @@ def create_deployment(
|
|
|
316
318
|
wait: bool,
|
|
317
319
|
auto: bool,
|
|
318
320
|
check: Optional[bool] = None,
|
|
319
|
-
|
|
321
|
+
allow_destructive_operations: Optional[bool] = None,
|
|
320
322
|
) -> None:
|
|
321
323
|
# TODO: This code is duplicated in build_server.py
|
|
322
324
|
# Should be refactored to be shared
|
|
@@ -350,8 +352,8 @@ def create_deployment(
|
|
|
350
352
|
if check:
|
|
351
353
|
click.echo(FeedbackManager.highlight(message="\n» Validating deployment...\n"))
|
|
352
354
|
params["check"] = "true"
|
|
353
|
-
if
|
|
354
|
-
params["
|
|
355
|
+
if allow_destructive_operations:
|
|
356
|
+
params["allow_destructive_operations"] = "true"
|
|
355
357
|
r = requests.post(TINYBIRD_API_URL, files=files, headers=HEADERS, params=params)
|
|
356
358
|
result = r.json()
|
|
357
359
|
logging.debug(json.dumps(result, indent=2))
|
|
@@ -257,6 +257,16 @@ class FeedbackManager:
|
|
|
257
257
|
error_connection_invalid_ca_pem = error_message("Invalid CA certificate in PEM format")
|
|
258
258
|
error_connection_ca_pem_not_found = error_message("CA certificate in PEM format not found at {ca_pem}")
|
|
259
259
|
error_workspace = error_message("Workspace {workspace} not found. use 'tb workspace ls' to list your workspaces")
|
|
260
|
+
error_workspace_name_required = error_message("Workspace name is required")
|
|
261
|
+
error_organization_not_found = error_message("Organization with id '{organization_id}' not found")
|
|
262
|
+
error_organization_index = error_message(
|
|
263
|
+
"Error selecting organization '{organization_index}'. Select a valid index or 0 to cancel"
|
|
264
|
+
)
|
|
265
|
+
error_organization_creation = error_message("Error creating organization: {error}")
|
|
266
|
+
warning_none_organization = warning_message(
|
|
267
|
+
"Tinybird is now based on organizations. Please, go to the UI ({ui_host}) to follow the migration process. \nYour workspace will be created any way."
|
|
268
|
+
)
|
|
269
|
+
error_while_fetching_orgs = error_message("Error while fetching organizations: {error}")
|
|
260
270
|
error_deleted_include = error_message(
|
|
261
271
|
"Related include file {include_file} was deleted and it's used in {filename}. Delete or remove dependency from {filename}."
|
|
262
272
|
)
|
|
@@ -991,6 +1001,10 @@ Ready? """
|
|
|
991
1001
|
success_connection_using = success_message("** Using connection '{connection_name}'")
|
|
992
1002
|
success_using_host = success_message("** Using host: {host} ({name})")
|
|
993
1003
|
success_workspace_created = success_message("** Workspace '{workspace_name}' has been created")
|
|
1004
|
+
success_organization_created = success_message("** Organization '{organization_name}' has been created")
|
|
1005
|
+
success_workspace_created_with_organization = success_message(
|
|
1006
|
+
"** Workspace '{workspace_name}' has been created in Organization '{organization_name}' (id: '{organization_id}')"
|
|
1007
|
+
)
|
|
994
1008
|
success_workspace_branch_created = success_message(
|
|
995
1009
|
"** Branch '{branch_name}' from '{workspace_name}' has been created"
|
|
996
1010
|
)
|
|
@@ -9,19 +9,22 @@ import click
|
|
|
9
9
|
from click import Context
|
|
10
10
|
|
|
11
11
|
from tinybird.client import TinyB
|
|
12
|
-
from tinybird.config import get_display_host
|
|
13
12
|
from tinybird.tb.modules.cli import cli
|
|
14
13
|
from tinybird.tb.modules.common import (
|
|
15
14
|
_get_workspace_plan_name,
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
ask_for_organization_interactively,
|
|
16
|
+
ask_for_organization_name,
|
|
18
17
|
coro,
|
|
18
|
+
create_organization_and_add_workspaces,
|
|
19
19
|
create_workspace_interactive,
|
|
20
20
|
create_workspace_non_interactive,
|
|
21
21
|
echo_safe_humanfriendly_tables_format_smart_table,
|
|
22
22
|
get_current_main_workspace,
|
|
23
|
+
get_organizations_by_user,
|
|
24
|
+
get_user_token,
|
|
23
25
|
is_valid_starterkit,
|
|
24
26
|
print_current_workspace,
|
|
27
|
+
sort_organizations_by_user,
|
|
25
28
|
switch_workspace,
|
|
26
29
|
)
|
|
27
30
|
from tinybird.tb.modules.config import CLIConfig
|
|
@@ -98,29 +101,65 @@ async def workspace_current():
|
|
|
98
101
|
default=False,
|
|
99
102
|
help="When enabled, tb will share all data sources from the current workspace with the new one",
|
|
100
103
|
)
|
|
104
|
+
@click.option(
|
|
105
|
+
"--organization-id",
|
|
106
|
+
"organization_id",
|
|
107
|
+
type=str,
|
|
108
|
+
required=False,
|
|
109
|
+
help="When passed, the workspace will be created in the specified organization",
|
|
110
|
+
)
|
|
101
111
|
@click.pass_context
|
|
102
112
|
@coro
|
|
103
113
|
async def create_workspace(
|
|
104
|
-
ctx: Context,
|
|
114
|
+
ctx: Context,
|
|
115
|
+
workspace_name: str,
|
|
116
|
+
starter_kit: str,
|
|
117
|
+
user_token: Optional[str],
|
|
118
|
+
fork: bool,
|
|
119
|
+
organization_id: Optional[str],
|
|
105
120
|
) -> None:
|
|
106
121
|
if starter_kit and not await is_valid_starterkit(ctx, starter_kit):
|
|
107
122
|
raise CLIWorkspaceException(FeedbackManager.error_starterkit_name(starterkit_name=starter_kit))
|
|
108
123
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
config = CLIConfig.get_project_config()
|
|
125
|
+
|
|
126
|
+
user_token = await get_user_token(config, user_token)
|
|
127
|
+
|
|
128
|
+
organization_name = None
|
|
129
|
+
organizations = await get_organizations_by_user(config, user_token)
|
|
130
|
+
|
|
131
|
+
if organization_id:
|
|
132
|
+
organization = next((org for org in organizations if org.get("id") == organization_id), None)
|
|
133
|
+
if not organization:
|
|
134
|
+
raise CLIWorkspaceException(FeedbackManager.error_organization_not_found(organization_id=organization_id))
|
|
135
|
+
organization_name = organization.get("name")
|
|
136
|
+
else:
|
|
137
|
+
if len(organizations) == 0:
|
|
138
|
+
organization_name = await ask_for_organization_name(config)
|
|
139
|
+
organization = await create_organization_and_add_workspaces(config, organization_name, user_token)
|
|
140
|
+
organization_id = organization.get("id")
|
|
141
|
+
elif len(organizations) == 1:
|
|
142
|
+
organization_id = organizations[0].get("id")
|
|
143
|
+
organization_name = organizations[0].get("name")
|
|
144
|
+
else:
|
|
145
|
+
sorted_organizations = sort_organizations_by_user(organizations, user_email=config.get_user_email())
|
|
146
|
+
current_organization = await ask_for_organization_interactively(sorted_organizations)
|
|
147
|
+
if current_organization:
|
|
148
|
+
organization_id = current_organization.get("id")
|
|
149
|
+
organization_name = current_organization.get("name")
|
|
150
|
+
else:
|
|
151
|
+
return
|
|
117
152
|
|
|
118
153
|
# If we have at least workspace_name, we start the non interactive
|
|
119
154
|
# process, creating an empty workspace
|
|
120
155
|
if workspace_name:
|
|
121
|
-
await create_workspace_non_interactive(
|
|
156
|
+
await create_workspace_non_interactive(
|
|
157
|
+
ctx, workspace_name, starter_kit, user_token, fork, organization_id, organization_name
|
|
158
|
+
)
|
|
122
159
|
else:
|
|
123
|
-
await create_workspace_interactive(
|
|
160
|
+
await create_workspace_interactive(
|
|
161
|
+
ctx, workspace_name, starter_kit, user_token, fork, organization_id, organization_name
|
|
162
|
+
)
|
|
124
163
|
|
|
125
164
|
|
|
126
165
|
@workspace.command(name="delete", short_help="Delete a workspace for your Tinybird user")
|
|
@@ -142,12 +181,8 @@ async def delete_workspace(
|
|
|
142
181
|
|
|
143
182
|
config = CLIConfig.get_project_config()
|
|
144
183
|
client = config.get_client()
|
|
145
|
-
host = config.get_host() or CLIConfig.DEFAULTS["host"]
|
|
146
|
-
ui_host = get_display_host(host)
|
|
147
184
|
|
|
148
|
-
|
|
149
|
-
user_token = ask_for_user_token("delete a workspace", ui_host)
|
|
150
|
-
await check_user_token(ctx, user_token)
|
|
185
|
+
user_token = await get_user_token(config, user_token)
|
|
151
186
|
|
|
152
187
|
workspaces = (await client.user_workspaces()).get("workspaces", [])
|
|
153
188
|
workspace_to_delete = next(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/build_datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/format_datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb/modules/datafile/parse_datasource.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-0.0.1.dev87 → tinybird-0.0.1.dev89}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|