tinybird 0.0.1.dev0__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.

Files changed (45) hide show
  1. tinybird/__cli__.py +8 -0
  2. tinybird/ch_utils/constants.py +244 -0
  3. tinybird/ch_utils/engine.py +855 -0
  4. tinybird/check_pypi.py +25 -0
  5. tinybird/client.py +1281 -0
  6. tinybird/config.py +117 -0
  7. tinybird/connectors.py +428 -0
  8. tinybird/context.py +23 -0
  9. tinybird/datafile.py +5589 -0
  10. tinybird/datatypes.py +434 -0
  11. tinybird/feedback_manager.py +1022 -0
  12. tinybird/git_settings.py +145 -0
  13. tinybird/sql.py +865 -0
  14. tinybird/sql_template.py +2343 -0
  15. tinybird/sql_template_fmt.py +281 -0
  16. tinybird/sql_toolset.py +350 -0
  17. tinybird/syncasync.py +682 -0
  18. tinybird/tb_cli.py +25 -0
  19. tinybird/tb_cli_modules/auth.py +252 -0
  20. tinybird/tb_cli_modules/branch.py +1043 -0
  21. tinybird/tb_cli_modules/cicd.py +434 -0
  22. tinybird/tb_cli_modules/cli.py +1571 -0
  23. tinybird/tb_cli_modules/common.py +2082 -0
  24. tinybird/tb_cli_modules/config.py +344 -0
  25. tinybird/tb_cli_modules/connection.py +803 -0
  26. tinybird/tb_cli_modules/datasource.py +900 -0
  27. tinybird/tb_cli_modules/exceptions.py +91 -0
  28. tinybird/tb_cli_modules/fmt.py +91 -0
  29. tinybird/tb_cli_modules/job.py +85 -0
  30. tinybird/tb_cli_modules/pipe.py +858 -0
  31. tinybird/tb_cli_modules/regions.py +9 -0
  32. tinybird/tb_cli_modules/tag.py +100 -0
  33. tinybird/tb_cli_modules/telemetry.py +310 -0
  34. tinybird/tb_cli_modules/test.py +107 -0
  35. tinybird/tb_cli_modules/tinyunit/tinyunit.py +340 -0
  36. tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +71 -0
  37. tinybird/tb_cli_modules/token.py +349 -0
  38. tinybird/tb_cli_modules/workspace.py +269 -0
  39. tinybird/tb_cli_modules/workspace_members.py +212 -0
  40. tinybird/tornado_template.py +1194 -0
  41. tinybird-0.0.1.dev0.dist-info/METADATA +2815 -0
  42. tinybird-0.0.1.dev0.dist-info/RECORD +45 -0
  43. tinybird-0.0.1.dev0.dist-info/WHEEL +5 -0
  44. tinybird-0.0.1.dev0.dist-info/entry_points.txt +2 -0
  45. tinybird-0.0.1.dev0.dist-info/top_level.txt +4 -0
@@ -0,0 +1,91 @@
1
+ from typing import Any, Dict, Optional
2
+
3
+ import click
4
+
5
+ from tinybird.tb_cli_modules.telemetry import add_telemetry_event
6
+
7
+
8
+ class CLIException(click.exceptions.ClickException):
9
+ """Default exception for all exceptions raised in the CLI.
10
+
11
+ Allows to specift a custom telemetry event to be sent before
12
+ raising the exception (if not specified, it sends a generic
13
+ `error` beacon with the error message)
14
+ """
15
+
16
+ def __init__(self, message: str, telemetry_event: Optional[str] = None, **kw_telemetry_event_data: Any) -> None:
17
+ telemetry_event = telemetry_event or "error"
18
+ data: Dict[str, Any] = {"error": message}
19
+ data.update(kw_telemetry_event_data)
20
+ add_telemetry_event(telemetry_event, **data)
21
+ super().__init__(message)
22
+
23
+
24
+ class CLIAuthException(CLIException):
25
+ """Exceptions generated by the auth commands"""
26
+
27
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
28
+ super().__init__(message, "auth_error", **kw_telemetry_event_data)
29
+
30
+
31
+ class CLIReleaseException(CLIException):
32
+ """Exceptions generated by the release commands"""
33
+
34
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
35
+ super().__init__(message, "release_error", **kw_telemetry_event_data)
36
+
37
+
38
+ class CLIBranchException(CLIException):
39
+ """Exceptions generated by the branch commands"""
40
+
41
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
42
+ super().__init__(message, "branch_error", **kw_telemetry_event_data)
43
+
44
+
45
+ class CLIGitReleaseException(CLIException):
46
+ """Exceptions generated by the git release related commands"""
47
+
48
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
49
+ super().__init__(message, "git_release_error", **kw_telemetry_event_data)
50
+
51
+
52
+ class CLIConnectionException(CLIException):
53
+ """Exceptions generated by the connection commands"""
54
+
55
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
56
+ super().__init__(message, "connection_error", **kw_telemetry_event_data)
57
+
58
+
59
+ class CLIDatasourceException(CLIException):
60
+ """Exceptions generated by the datasource commands"""
61
+
62
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
63
+ super().__init__(message, "datasource_error", **kw_telemetry_event_data)
64
+
65
+
66
+ class CLIPipeException(CLIException):
67
+ """Exceptions generated by the pipe commands"""
68
+
69
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
70
+ super().__init__(message, "pipe_error", **kw_telemetry_event_data)
71
+
72
+
73
+ class CLIWorkspaceMembersException(CLIException):
74
+ """Exceptions generated by the workspace members commands"""
75
+
76
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
77
+ super().__init__(message, "workspace_members_error", **kw_telemetry_event_data)
78
+
79
+
80
+ class CLIWorkspaceException(CLIException):
81
+ """Exceptions generated by the workspace commands"""
82
+
83
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
84
+ super().__init__(message, "workspace_error", **kw_telemetry_event_data)
85
+
86
+
87
+ class CLITokenException(CLIException):
88
+ """Exceptions generated by the token commands"""
89
+
90
+ def __init__(self, message: str, **kw_telemetry_event_data: Any) -> None:
91
+ super().__init__(message, "token_error", **kw_telemetry_event_data)
@@ -0,0 +1,91 @@
1
+ import difflib
2
+ import sys
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+
6
+ import aiofiles
7
+ import click
8
+ from click import Context
9
+
10
+ from tinybird.datafile import color_diff, format_datasource, format_pipe, is_file_a_datasource, peek
11
+ from tinybird.feedback_manager import FeedbackManager
12
+ from tinybird.tb_cli_modules.cli import cli
13
+ from tinybird.tb_cli_modules.common import coro
14
+
15
+
16
+ @cli.command()
17
+ @click.argument("filenames", type=click.Path(exists=True), nargs=-1, required=True)
18
+ @click.option(
19
+ "--line-length",
20
+ is_flag=False,
21
+ default=100,
22
+ help="A number indicating the maximum characters per line in the node SQL, lines will be splitted based on the SQL syntax and the number of characters passed as a parameter",
23
+ )
24
+ @click.option("--dry-run", is_flag=True, default=False, help="Don't ask to override the local file")
25
+ @click.option("--yes", is_flag=True, default=False, help="Do not ask for confirmation to overwrite the local file")
26
+ @click.option(
27
+ "--diff",
28
+ is_flag=True,
29
+ default=False,
30
+ help="Formats local file, prints the diff and exits 1 if different, 0 if equal",
31
+ )
32
+ @click.pass_context
33
+ @coro
34
+ async def fmt(
35
+ ctx: Context, filenames: List[str], line_length: int, dry_run: bool, yes: bool, diff: bool
36
+ ) -> Optional[str]:
37
+ """
38
+ Formats a .datasource, .pipe or .incl file
39
+
40
+ This command removes comments starting with # from the file, use DESCRIPTION instead.
41
+
42
+ The format command tries to parse the datafile so syntax errors might rise.
43
+
44
+ .incl files must contain a NODE definition
45
+ """
46
+
47
+ result = ""
48
+ failed = []
49
+ for filename in filenames:
50
+ if not diff:
51
+ click.echo(filename)
52
+ extensions = Path(filename).suffixes
53
+ if is_file_a_datasource(filename):
54
+ result = await format_datasource(filename, skip_eval=True)
55
+ elif (".pipe" in extensions) or (".incl" in extensions):
56
+ result = await format_pipe(filename, line_length, skip_eval=True)
57
+ else:
58
+ click.echo("Unsupported file type. Supported files types are: .pipe, .incl and .datasource")
59
+ return None
60
+
61
+ if diff:
62
+ result = result.rstrip("\n")
63
+ lines_fmt = [f"{line}\n" for line in result.split("\n")]
64
+ async with aiofiles.open(filename, "r") as file:
65
+ lines_file = await file.readlines()
66
+ diff_result = difflib.unified_diff(
67
+ lines_file, lines_fmt, fromfile=f"{Path(filename).name} local", tofile="fmt datafile"
68
+ )
69
+ diff_result = color_diff(diff_result)
70
+ not_empty, diff_lines = peek(diff_result)
71
+ if not_empty:
72
+ sys.stdout.writelines(diff_lines)
73
+ failed.append(filename)
74
+ click.echo("")
75
+ else:
76
+ click.echo(result)
77
+ if dry_run:
78
+ return None
79
+
80
+ if yes or click.confirm(FeedbackManager.prompt_override_local_file(name=filename)):
81
+ async with aiofiles.open(f"{filename}", "w") as file:
82
+ await file.write(result)
83
+
84
+ click.echo(FeedbackManager.success_generated_local_file(file=filename))
85
+
86
+ if len(failed):
87
+ click.echo(FeedbackManager.error_failed_to_format_files(number=len(failed)))
88
+ for f in failed:
89
+ click.echo(f"tb fmt {f} --yes")
90
+ sys.exit(1)
91
+ return result
@@ -0,0 +1,85 @@
1
+ # This is a command file for our CLI. Please keep it clean.
2
+ #
3
+ # - If it makes sense and only when strictly necessary, you can create utility functions in this file.
4
+ # - But please, **do not** interleave utility functions and command definitions.
5
+
6
+ import click
7
+ from click import Context
8
+
9
+ from tinybird.client import DoesNotExistException, TinyB
10
+ from tinybird.feedback_manager import FeedbackManager
11
+ from tinybird.tb_cli_modules.cli import cli
12
+ from tinybird.tb_cli_modules.common import coro, echo_safe_humanfriendly_tables_format_smart_table
13
+ from tinybird.tb_cli_modules.exceptions import CLIException
14
+
15
+
16
+ @cli.group()
17
+ @click.pass_context
18
+ def job(ctx: Context) -> None:
19
+ """Jobs commands."""
20
+
21
+
22
+ @job.command(name="ls")
23
+ @click.option(
24
+ "-s",
25
+ "--status",
26
+ help="Show only jobs with this status",
27
+ type=click.Choice(["waiting", "working", "done", "error"], case_sensitive=False),
28
+ multiple=True,
29
+ default=None,
30
+ )
31
+ @click.pass_context
32
+ @coro
33
+ async def jobs_ls(ctx: Context, status: str) -> None:
34
+ """List jobs, up to 100 in the last 48h"""
35
+ client: TinyB = ctx.ensure_object(dict)["client"]
36
+ jobs = await client.jobs(status=status)
37
+ columns = ["id", "kind", "status", "created at", "updated at", "job url"]
38
+ click.echo(FeedbackManager.info_jobs())
39
+ table = []
40
+ for j in jobs:
41
+ table.append([j[c.replace(" ", "_")] for c in columns])
42
+ echo_safe_humanfriendly_tables_format_smart_table(table, column_names=columns)
43
+ click.echo("\n")
44
+
45
+
46
+ @job.command(name="details")
47
+ @click.argument("job_id")
48
+ @click.pass_context
49
+ @coro
50
+ async def job_details(ctx: Context, job_id: str) -> None:
51
+ """Get details for any job created in the last 48h"""
52
+ client: TinyB = ctx.ensure_object(dict)["client"]
53
+ job = await client.job(job_id)
54
+ columns = []
55
+ click.echo(FeedbackManager.info_job(job=job_id))
56
+ table = []
57
+ columns = job.keys()
58
+ table = [job.values()]
59
+ echo_safe_humanfriendly_tables_format_smart_table(table, column_names=columns)
60
+ click.echo("\n")
61
+
62
+
63
+ @job.command(name="cancel")
64
+ @click.argument("job_id")
65
+ @click.pass_context
66
+ @coro
67
+ async def job_cancel(ctx: Context, job_id: str) -> None:
68
+ """Try to cancel a job"""
69
+ client = ctx.ensure_object(dict)["client"]
70
+
71
+ try:
72
+ result = await client.job_cancel(job_id)
73
+ except DoesNotExistException:
74
+ raise CLIException(FeedbackManager.error_job_does_not_exist(job_id=job_id))
75
+ except Exception as e:
76
+ raise CLIException(FeedbackManager.error_exception(error=e))
77
+ else:
78
+ current_job_status = result["status"]
79
+ if current_job_status == "cancelling":
80
+ click.echo(FeedbackManager.success_job_cancellation_cancelling(job_id=job_id))
81
+ elif current_job_status == "cancelled":
82
+ click.echo(FeedbackManager.success_job_cancellation_cancelled(job_id=job_id))
83
+ else:
84
+ raise CLIException(FeedbackManager.error_job_cancelled_but_status_unknown(job_id=job_id))
85
+ click.echo("\n")