tinybird 0.0.1.dev71__tar.gz → 0.0.1.dev73__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.dev71 → tinybird-0.0.1.dev73}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/client.py +7 -5
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/feedback_manager.py +2 -2
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/prompts.py +56 -8
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/cli.py +1 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/build.py +2 -2
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/cicd.py +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/cli.py +12 -12
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/common.py +3 -4
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/config.py +3 -3
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/copy.py +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/build_pipe.py +35 -186
- tinybird-0.0.1.dev73/tinybird/tb/modules/datafile/playground.py +1400 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datasource.py +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/deployment.py +10 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/endpoint.py +10 -6
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/feedback_manager.py +2 -2
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/fmt.py +2 -2
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/local.py +2 -2
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/local_common.py +3 -3
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/materialization.py +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/mock.py +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/pipe.py +1 -1
- tinybird-0.0.1.dev73/tinybird/tb/modules/playground.py +135 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/shell.py +6 -5
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/token.py +17 -3
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/watch.py +105 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/workspace.py +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird.egg-info/SOURCES.txt +2 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/setup.cfg +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/config.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/connectors.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/context.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/datafile.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/sql.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/auth.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/create.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/build.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/common.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/login.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/project.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/tag.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/test.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird/tornado_template.py +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-0.0.1.dev71 → tinybird-0.0.1.dev73}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -93,7 +93,7 @@ class TinyB:
|
|
|
93
93
|
send_telemetry: bool = False,
|
|
94
94
|
semver: Optional[str] = None,
|
|
95
95
|
env: Optional[str] = "production",
|
|
96
|
-
|
|
96
|
+
staging: bool = False,
|
|
97
97
|
):
|
|
98
98
|
ctx = ssl.create_default_context()
|
|
99
99
|
ctx.check_hostname = False
|
|
@@ -106,7 +106,7 @@ class TinyB:
|
|
|
106
106
|
self.send_telemetry = send_telemetry
|
|
107
107
|
self.semver = semver
|
|
108
108
|
self.env = env
|
|
109
|
-
self.
|
|
109
|
+
self.staging = staging
|
|
110
110
|
|
|
111
111
|
async def _req_raw(
|
|
112
112
|
self,
|
|
@@ -127,8 +127,8 @@ class TinyB:
|
|
|
127
127
|
url += ("&" if "?" in url else "?") + "cli_version=" + quote(self.version)
|
|
128
128
|
if self.semver:
|
|
129
129
|
url += ("&" if "?" in url else "?") + "__tb__semver=" + self.semver
|
|
130
|
-
if self.
|
|
131
|
-
url += ("&" if "?" in url else "?") + "__tb__deployment=
|
|
130
|
+
if self.staging:
|
|
131
|
+
url += ("&" if "?" in url else "?") + "__tb__deployment=staging"
|
|
132
132
|
|
|
133
133
|
verify_ssl = not self.disable_ssl_checks
|
|
134
134
|
try:
|
|
@@ -669,10 +669,12 @@ class TinyB:
|
|
|
669
669
|
async def pipe_unlink_materialized(self, pipe_name: str, node_id: str):
|
|
670
670
|
return await self._req(f"/v0/pipes/{pipe_name}/nodes/{node_id}/materialization", method="DELETE")
|
|
671
671
|
|
|
672
|
-
async def query(self, sql: str, pipeline: Optional[str] = None):
|
|
672
|
+
async def query(self, sql: str, pipeline: Optional[str] = None, playground: Optional[str] = None):
|
|
673
673
|
params = {}
|
|
674
674
|
if pipeline:
|
|
675
675
|
params = {"pipeline": pipeline}
|
|
676
|
+
if playground:
|
|
677
|
+
params = {"playground": playground}
|
|
676
678
|
params.update({"release_replacements": "true"})
|
|
677
679
|
|
|
678
680
|
if len(sql) > TinyB.MAX_GET_LENGTH:
|
|
@@ -458,7 +458,7 @@ class FeedbackManager:
|
|
|
458
458
|
info_releases_detected = info_message("** Live Release: {current_semver} => New Release: {semver}")
|
|
459
459
|
info_dry_releases_detected = info_message("** [DRY RUN] Live Release: {current_semver} => New Release: {semver}")
|
|
460
460
|
info_pre_prompt_auth_login_user_token = info_message(
|
|
461
|
-
"ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here."
|
|
461
|
+
"ℹ️ In order to log into Tinybird, you need your user token. Please, go to {host}/tokens/ and paste your User Token here." # noqa: RUF001
|
|
462
462
|
)
|
|
463
463
|
prompt_auth_login_user_token = prompt_message("❓ User token:")
|
|
464
464
|
|
|
@@ -609,7 +609,7 @@ Ready? """
|
|
|
609
609
|
)
|
|
610
610
|
warning_datasource_sync = warning_message("** Warning: Do you want to sync the Data Source {datasource}?")
|
|
611
611
|
warning_datasource_sync_bucket = warning_message(
|
|
612
|
-
"** Warning: Do you want to ingest all the selected files (new and previous) from the {datasource} bucket? Be aware that data might be duplicated if
|
|
612
|
+
"** Warning: Do you want to ingest all the selected files (new and previous) from the {datasource} bucket? Be aware that data might be duplicated if you have previously ingested those files.\n"
|
|
613
613
|
)
|
|
614
614
|
warning_users_dont_exist = warning_message(
|
|
615
615
|
"** Warning: The following users do not exist in the workspace {workspace}: {users}"
|
|
@@ -634,20 +634,42 @@ materialized_pipe_instructions = """
|
|
|
634
634
|
<materialized_pipe_instructions>
|
|
635
635
|
- Do not create materialized pipes by default, unless the user asks for it.
|
|
636
636
|
- In a .pipe file you can define how to materialize each row ingested in the earliest Data Source in the Pipe query to a materialized Data Source. Materialization happens at ingest.
|
|
637
|
-
- DATASOURCE: Required when TYPE is MATERIALIZED. Sets the
|
|
637
|
+
- DATASOURCE: Required when TYPE is MATERIALIZED. Sets the target Data Source for materialized nodes.
|
|
638
638
|
- TYPE MATERIALIZED is the type of the pipe and it is mandatory for materialized pipes.
|
|
639
|
-
- The content of the .pipe file must follow
|
|
640
|
-
|
|
641
|
-
|
|
639
|
+
- The content of the .pipe file must follow the materialized_pipe_content format.
|
|
640
|
+
- Use State modifier for the aggregated columns in the pipe.
|
|
641
|
+
- Keep the SQL query simple and avoid using complex queries with joins, subqueries, etc.
|
|
642
|
+
</materialized_pipe_instructions>
|
|
643
|
+
<materialized_pipe_content>
|
|
642
644
|
NODE daily_sales
|
|
643
645
|
SQL >
|
|
644
|
-
SELECT toStartOfDay(starting_date) day, country,
|
|
646
|
+
SELECT toStartOfDay(starting_date) day, country, sumState(sales) as total_sales
|
|
645
647
|
FROM teams
|
|
646
648
|
GROUP BY day, country
|
|
647
649
|
|
|
648
650
|
TYPE MATERIALIZED
|
|
649
651
|
DATASOURCE sales_by_hour
|
|
650
|
-
</
|
|
652
|
+
</materialized_pipe_content>
|
|
653
|
+
<target_datasource_instructions>
|
|
654
|
+
- The target datasource of a materialized pipe must have an AggregatingMergeTree engine.
|
|
655
|
+
- Use AggregateFunction for the aggregated columns in the pipe.
|
|
656
|
+
- Pipes using a materialized data source must use the Merge modifier in the SQL query for the aggregated columns. Example: sumMerge(total_sales)
|
|
657
|
+
- Put all dimensions in the ENGINE_SORTING_KEY, sorted from least to most cardinality.
|
|
658
|
+
</target_datasource_instructions>
|
|
659
|
+
<target_datasource_content>
|
|
660
|
+
SCHEMA >
|
|
661
|
+
`total_sales` AggregateFunction(sum, Float64),
|
|
662
|
+
`sales_count` AggregateFunction(count, UInt64),
|
|
663
|
+
`column_name_2` AggregateFunction(avg, Float64),
|
|
664
|
+
`dimension_1` String,
|
|
665
|
+
`dimension_2` String,
|
|
666
|
+
...
|
|
667
|
+
`date` DateTime
|
|
668
|
+
|
|
669
|
+
ENGINE "AggregatingMergeTree"
|
|
670
|
+
ENGINE_PARTITION_KEY "toYYYYMM(date)"
|
|
671
|
+
ENGINE_SORTING_KEY "date, dimension_1, dimension_2, ..."
|
|
672
|
+
</target_datasource_content>
|
|
651
673
|
"""
|
|
652
674
|
|
|
653
675
|
|
|
@@ -790,10 +812,10 @@ When you need to work with resources or data in cloud, add always the --cloud fl
|
|
|
790
812
|
├── materializations
|
|
791
813
|
├── pipes
|
|
792
814
|
└── tests
|
|
793
|
-
- The local development server will be available at http://localhost:
|
|
815
|
+
- The local development server will be available at http://localhost:7181. Even if some response uses another base url, use always http://localhost:7181.
|
|
794
816
|
- After every change in your .datasource, .pipe or .ndjson files, run `{base_command} build` to build the project locally.
|
|
795
817
|
- When you need to ingest data locally in a datasource, create a .ndjson file with the same name of the datasource and the data you want and run `{base_command} build` so the data is ingested.
|
|
796
|
-
- The format of the generated api endpoint urls is: http://localhost:
|
|
818
|
+
- The format of the generated api endpoint urls is: http://localhost:7181/v0/pipe/<pipe_name>.json?token=<token>
|
|
797
819
|
- Before running the tests, remember to have the project built with `{base_command} build` with the latest changes.
|
|
798
820
|
</development_instructions>
|
|
799
821
|
When asking for ingesting data, adding data or appending data do the following depending on the environment you want to work with:
|
|
@@ -821,6 +843,10 @@ Follow these instructions when creating or updating .pipe files:
|
|
|
821
843
|
Follow these instructions when creating or updating .yaml files for tests:
|
|
822
844
|
{test_instructions}
|
|
823
845
|
</test_file_instructions>
|
|
846
|
+
<deployment_instruction>
|
|
847
|
+
Follow these instructions when evolving a datasource schema:
|
|
848
|
+
{deployment_instructions}
|
|
849
|
+
</deployment_instruction>
|
|
824
850
|
""".format(
|
|
825
851
|
base_command=base_command,
|
|
826
852
|
datasource_instructions=datasource_instructions,
|
|
@@ -831,6 +857,7 @@ Follow these instructions when creating or updating .yaml files for tests:
|
|
|
831
857
|
copy_pipe_instructions=copy_pipe_instructions,
|
|
832
858
|
materialized_pipe_instructions=materialized_pipe_instructions,
|
|
833
859
|
test_instructions=test_instructions,
|
|
860
|
+
deployment_instructions=deployment_instructions,
|
|
834
861
|
)
|
|
835
862
|
|
|
836
863
|
|
|
@@ -879,3 +906,24 @@ test_instructions = """
|
|
|
879
906
|
|
|
880
907
|
</test_file_format>
|
|
881
908
|
"""
|
|
909
|
+
|
|
910
|
+
deployment_instructions = """
|
|
911
|
+
- When you make schema changes that are incompatible with the old schema, you must use a forward query in your data source. Forward queries are necessary when introducing breaking changes. Otherwise, your deployment will fail due to a schema mismatch.
|
|
912
|
+
- Forward queries translate the old schema to a new one that you define in the .datasource file. This helps you evolve your schema while continuing to ingest data.
|
|
913
|
+
Follow these steps to evolve your schema using a forward query:
|
|
914
|
+
- Edit the .datasource file to add a forward query.
|
|
915
|
+
- Run tb deploy --check to validate the deployment before creating it.
|
|
916
|
+
- Deploy and promote your changes in Tinybird Cloud using {base_command} --cloud deploy.
|
|
917
|
+
<forward_query_example>
|
|
918
|
+
SCHEMA >
|
|
919
|
+
`timestamp` DateTime `json:$.timestamp`,
|
|
920
|
+
`session_id` UUID `json:$.session_id`,
|
|
921
|
+
`action` String `json:$.action`,
|
|
922
|
+
`version` String `json:$.version`,
|
|
923
|
+
`payload` String `json:$.payload`
|
|
924
|
+
|
|
925
|
+
FORWARD_QUERY >
|
|
926
|
+
select timestamp, toUUID(session_id) as session_id, action, version, payload
|
|
927
|
+
</forward_query_example>
|
|
928
|
+
</deployment_instruction>
|
|
929
|
+
"""
|
|
@@ -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.dev73'
|
|
8
|
+
__revision__ = 'a843588'
|
|
@@ -20,6 +20,7 @@ import tinybird.tb.modules.login
|
|
|
20
20
|
import tinybird.tb.modules.materialization
|
|
21
21
|
import tinybird.tb.modules.mock
|
|
22
22
|
import tinybird.tb.modules.pipe
|
|
23
|
+
import tinybird.tb.modules.playground
|
|
23
24
|
import tinybird.tb.modules.tag
|
|
24
25
|
import tinybird.tb.modules.test
|
|
25
26
|
import tinybird.tb.modules.token
|
|
@@ -41,7 +41,7 @@ def build(ctx: click.Context, watch: bool) -> None:
|
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
@cli.command("dev", help="Build the project server side and watch for changes")
|
|
44
|
+
@cli.command("dev", help="Build the project server side and watch for changes.")
|
|
45
45
|
@click.pass_context
|
|
46
46
|
def dev(ctx: click.Context) -> None:
|
|
47
47
|
project: Project = ctx.ensure_object(dict)["project"]
|
|
@@ -240,7 +240,7 @@ def process(
|
|
|
240
240
|
def run_watch(
|
|
241
241
|
project: Project, tb_client: TinyB, process: Callable[[bool, Optional[str], Optional[str]], None]
|
|
242
242
|
) -> None:
|
|
243
|
-
shell = Shell(project=project, tb_client=tb_client)
|
|
243
|
+
shell = Shell(project=project, tb_client=tb_client, playground=False)
|
|
244
244
|
click.echo(FeedbackManager.gray(message="\nWatching for changes..."))
|
|
245
245
|
watcher_thread = threading.Thread(
|
|
246
246
|
target=watch_project,
|
|
@@ -52,12 +52,12 @@ VERSION = f"{__cli__.__version__} (rev {__cli__.__revision__})"
|
|
|
52
52
|
default=False,
|
|
53
53
|
help="Prints internal representation, can be combined with any command to get more information.",
|
|
54
54
|
)
|
|
55
|
-
@click.option("--token", help="Use auth token, defaults to TB_TOKEN envvar, then to the .tinyb file")
|
|
55
|
+
@click.option("--token", help="Use auth token, defaults to TB_TOKEN envvar, then to the .tinyb file.")
|
|
56
56
|
@click.option("--host", help="Use custom host, defaults to TB_HOST envvar, then to https://api.tinybird.co")
|
|
57
|
-
@click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens")
|
|
58
|
-
@click.option("--cloud/--local", is_flag=True, default=False, help="Run against cloud or local")
|
|
59
|
-
@click.option("--build", is_flag=True, default=False, help="Run against build mode")
|
|
60
|
-
@click.option("--
|
|
57
|
+
@click.option("--show-tokens", is_flag=True, default=False, help="Enable the output of tokens.")
|
|
58
|
+
@click.option("--cloud/--local", is_flag=True, default=False, help="Run against cloud or local.")
|
|
59
|
+
@click.option("--build", is_flag=True, default=False, help="Run against build mode.")
|
|
60
|
+
@click.option("--staging", is_flag=True, default=False, help="Run against a staging deployment.")
|
|
61
61
|
@click.version_option(version=VERSION)
|
|
62
62
|
@click.pass_context
|
|
63
63
|
@coro
|
|
@@ -69,7 +69,7 @@ async def cli(
|
|
|
69
69
|
show_tokens: bool,
|
|
70
70
|
cloud: bool,
|
|
71
71
|
build: bool,
|
|
72
|
-
|
|
72
|
+
staging: bool,
|
|
73
73
|
) -> None:
|
|
74
74
|
"""
|
|
75
75
|
Use `OBFUSCATE_REGEX_PATTERN` and `OBFUSCATE_PATTERN_SEPARATOR` environment variables to define a regex pattern and a separator (in case of a single string with multiple regex) to obfuscate secrets in the CLI output.
|
|
@@ -123,7 +123,7 @@ async def cli(
|
|
|
123
123
|
|
|
124
124
|
logging.debug("debug enabled")
|
|
125
125
|
|
|
126
|
-
client = await create_ctx_client(ctx, config, cloud, build,
|
|
126
|
+
client = await create_ctx_client(ctx, config, cloud, build, staging)
|
|
127
127
|
|
|
128
128
|
if client:
|
|
129
129
|
ctx.ensure_object(dict)["client"] = client
|
|
@@ -189,7 +189,7 @@ async def dependencies(
|
|
|
189
189
|
|
|
190
190
|
@cli.command(
|
|
191
191
|
name="diff",
|
|
192
|
-
short_help="Diff local datafiles to the corresponding remote files in the workspace.
|
|
192
|
+
short_help="Diff local datafiles to the corresponding remote files in the workspace. Only diffs VERSION and SCHEMA for .datasource files.",
|
|
193
193
|
)
|
|
194
194
|
@click.argument("filename", type=click.Path(exists=True), nargs=-1, required=False)
|
|
195
195
|
@click.option(
|
|
@@ -388,13 +388,13 @@ def __unpatch_click_output():
|
|
|
388
388
|
click.secho = __old_click_secho
|
|
389
389
|
|
|
390
390
|
|
|
391
|
-
async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, build: bool,
|
|
391
|
+
async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, build: bool, staging: bool):
|
|
392
392
|
commands_without_ctx_client = ["auth", "check", "login", "local", "upgrade"]
|
|
393
393
|
command = ctx.invoked_subcommand
|
|
394
394
|
if command in commands_without_ctx_client:
|
|
395
395
|
return None
|
|
396
396
|
|
|
397
|
-
commands_always_cloud = ["pull"]
|
|
397
|
+
commands_always_cloud = ["pull", "playground"]
|
|
398
398
|
commands_always_build = ["build", "test", "dev"]
|
|
399
399
|
commands_always_local = ["create"]
|
|
400
400
|
if (
|
|
@@ -405,11 +405,11 @@ async def create_ctx_client(ctx: Context, config: Dict[str, Any], cloud: bool, b
|
|
|
405
405
|
click.echo(
|
|
406
406
|
FeedbackManager.gray(message=f"Running against Tinybird Cloud: Workspace {config.get('name', 'default')}")
|
|
407
407
|
)
|
|
408
|
-
return _get_tb_client(config.get("token", None), config["host"],
|
|
408
|
+
return _get_tb_client(config.get("token", None), config["host"], staging=staging)
|
|
409
409
|
build = command in commands_always_build or build
|
|
410
410
|
if not build and command not in commands_always_local and command not in commands_always_build:
|
|
411
411
|
click.echo(FeedbackManager.gray(message="Running against Tinybird Local\n"))
|
|
412
|
-
return await get_tinybird_local_client(config, build=build,
|
|
412
|
+
return await get_tinybird_local_client(config, build=build, staging=staging)
|
|
413
413
|
|
|
414
414
|
|
|
415
415
|
def get_target_env(cloud: bool, build: bool) -> str:
|
|
@@ -244,8 +244,7 @@ class CatchAuthExceptions(AliasedGroup):
|
|
|
244
244
|
formatter.write_text(
|
|
245
245
|
"""
|
|
246
246
|
Tinybird collects anonymous usage data and errors to improve the command
|
|
247
|
-
line experience. To opt-out, set TB_CLI_TELEMETRY_OPTOUT
|
|
248
|
-
variable to '1' or 'true'."""
|
|
247
|
+
line experience. To opt-out, set TB_CLI_TELEMETRY_OPTOUT to '1' or 'true'."""
|
|
249
248
|
)
|
|
250
249
|
formatter.write_paragraph()
|
|
251
250
|
|
|
@@ -375,9 +374,9 @@ def getenv_bool(key: str, default: bool) -> bool:
|
|
|
375
374
|
return v.lower() == "true" or v == "1"
|
|
376
375
|
|
|
377
376
|
|
|
378
|
-
def _get_tb_client(token: str, host: str,
|
|
377
|
+
def _get_tb_client(token: str, host: str, staging: bool = False) -> TinyB:
|
|
379
378
|
disable_ssl: bool = getenv_bool("TB_DISABLE_SSL_CHECKS", False)
|
|
380
|
-
return TinyB(token, host, version=VERSION, disable_ssl_checks=disable_ssl, send_telemetry=True,
|
|
379
|
+
return TinyB(token, host, version=VERSION, disable_ssl_checks=disable_ssl, send_telemetry=True, staging=staging)
|
|
381
380
|
|
|
382
381
|
|
|
383
382
|
def create_tb_client(ctx: Context) -> TinyB:
|
|
@@ -77,7 +77,7 @@ class CLIConfig:
|
|
|
77
77
|
_global: Optional["CLIConfig"] = None
|
|
78
78
|
_projects: Dict[str, "CLIConfig"] = {}
|
|
79
79
|
|
|
80
|
-
def __init__(self, path: Optional[str], parent: Optional["CLIConfig"] = None) -> None:
|
|
80
|
+
def __init__(self, path: Optional[str] = None, parent: Optional["CLIConfig"] = None) -> None:
|
|
81
81
|
self._path = path
|
|
82
82
|
self._parent = parent
|
|
83
83
|
self._values: Dict[str, ConfigValue] = {}
|
|
@@ -219,7 +219,7 @@ class CLIConfig:
|
|
|
219
219
|
return CLIConfig.DEFAULTS["host"]
|
|
220
220
|
return None
|
|
221
221
|
|
|
222
|
-
def get_client(self, token: Optional[str] = None, host: Optional[str] = None,
|
|
222
|
+
def get_client(self, token: Optional[str] = None, host: Optional[str] = None, staging: bool = False) -> tbc.TinyB:
|
|
223
223
|
"""Returns a new TinyB client configured with:
|
|
224
224
|
|
|
225
225
|
- token:
|
|
@@ -242,7 +242,7 @@ class CLIConfig:
|
|
|
242
242
|
version=CURRENT_VERSION,
|
|
243
243
|
disable_ssl_checks=FeatureFlags.ignore_ssl_errors(),
|
|
244
244
|
send_telemetry=FeatureFlags.send_telemetry(),
|
|
245
|
-
|
|
245
|
+
staging=staging,
|
|
246
246
|
)
|
|
247
247
|
|
|
248
248
|
def get_user_client(self, host: Optional[str] = None) -> tbc.TinyB:
|
|
@@ -9,12 +9,11 @@ import requests
|
|
|
9
9
|
from croniter import croniter
|
|
10
10
|
|
|
11
11
|
from tinybird.client import DoesNotExistException, TinyB
|
|
12
|
-
from tinybird.tb.modules.common import
|
|
12
|
+
from tinybird.tb.modules.common import requests_delete, requests_get, wait_job
|
|
13
|
+
from tinybird.tb.modules.config import CLIConfig
|
|
13
14
|
from tinybird.tb.modules.datafile.common import ON_DEMAND, CopyModes, CopyParameters, PipeNodeTypes, PipeTypes
|
|
14
|
-
from tinybird.tb.modules.datafile.pipe_checker import PipeCheckerRunner
|
|
15
15
|
from tinybird.tb.modules.exceptions import CLIPipeException
|
|
16
16
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
17
|
-
from tinybird.tb.modules.table import format_pretty_table
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
async def new_pipe(
|
|
@@ -47,7 +46,8 @@ async def new_pipe(
|
|
|
47
46
|
):
|
|
48
47
|
# TODO use tb_client instead of calling the urls directly.
|
|
49
48
|
host = tb_client.host
|
|
50
|
-
|
|
49
|
+
config = CLIConfig().get_project_config()
|
|
50
|
+
token = config.get_user_token()
|
|
51
51
|
|
|
52
52
|
headers = {"Authorization": f"Bearer {token}"}
|
|
53
53
|
|
|
@@ -55,11 +55,16 @@ async def new_pipe(
|
|
|
55
55
|
cli_params["cli_version"] = tb_client.version
|
|
56
56
|
cli_params["description"] = p.get("description", "")
|
|
57
57
|
cli_params["ignore_sql_errors"] = "true" if ignore_sql_errors else "false"
|
|
58
|
+
cli_params["workspace_id"] = config.get("id", None)
|
|
58
59
|
|
|
59
|
-
r: requests.Response = await requests_get(f"{host}/v0/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
r: requests.Response = await requests_get(f"{host}/v0/playgrounds?{urlencode(cli_params)}", headers=headers)
|
|
61
|
+
current_pipe = None
|
|
62
|
+
pipe_exists = False
|
|
63
|
+
playgrounds_response = r.json() if r.status_code == 200 else None
|
|
64
|
+
if playgrounds_response:
|
|
65
|
+
playgrounds = playgrounds_response["playgrounds"]
|
|
66
|
+
current_pipe = next((play for play in playgrounds if play["name"] == p["name"] + "__tb__playground"), None)
|
|
67
|
+
pipe_exists = current_pipe is not None
|
|
63
68
|
|
|
64
69
|
is_materialized = any([node.get("params", {}).get("type", None) == "materialized" for node in p["nodes"]])
|
|
65
70
|
copy_node = next((node for node in p["nodes"] if node.get("params", {}).get("type", None) == "copy"), None)
|
|
@@ -75,27 +80,7 @@ async def new_pipe(
|
|
|
75
80
|
# TODO: this should create a different node and rename it to the final one on success
|
|
76
81
|
if check and not populate:
|
|
77
82
|
if not is_materialized and not copy_node and not sink_node and not stream_node:
|
|
78
|
-
|
|
79
|
-
p,
|
|
80
|
-
host,
|
|
81
|
-
token,
|
|
82
|
-
populate,
|
|
83
|
-
tb_client,
|
|
84
|
-
only_response_times=only_response_times,
|
|
85
|
-
limit=tests_to_run,
|
|
86
|
-
relative_change=tests_relative_change,
|
|
87
|
-
sample_by_params=tests_to_sample_by_params,
|
|
88
|
-
matches=tests_filter_by,
|
|
89
|
-
failfast=tests_failfast,
|
|
90
|
-
validate_processed_bytes=tests_validate_processed_bytes,
|
|
91
|
-
ignore_order=tests_ignore_order,
|
|
92
|
-
token_for_requests_to_check=(
|
|
93
|
-
await get_token_from_main_branch(tb_client)
|
|
94
|
-
if not tests_check_requests_from_branch
|
|
95
|
-
else None
|
|
96
|
-
),
|
|
97
|
-
current_pipe=current_pipe,
|
|
98
|
-
)
|
|
83
|
+
pass
|
|
99
84
|
else:
|
|
100
85
|
if is_materialized:
|
|
101
86
|
await check_materialized(
|
|
@@ -167,9 +152,27 @@ async def new_pipe(
|
|
|
167
152
|
post_headers.update(headers)
|
|
168
153
|
|
|
169
154
|
try:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
155
|
+
user_client = deepcopy(tb_client)
|
|
156
|
+
config = CLIConfig().get_project_config()
|
|
157
|
+
user_client.token = config.get_user_token()
|
|
158
|
+
params["workspace_id"] = config.get("id", None)
|
|
159
|
+
body["name"] = p["name"] + "__tb__playground"
|
|
160
|
+
|
|
161
|
+
if pipe_exists and current_pipe:
|
|
162
|
+
data = await user_client._req(
|
|
163
|
+
f"/v0/playgrounds/{current_pipe['id']}?{urlencode(params)}",
|
|
164
|
+
method="PUT",
|
|
165
|
+
headers=post_headers,
|
|
166
|
+
data=json.dumps(body),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
else:
|
|
170
|
+
data = await user_client._req(
|
|
171
|
+
f"/v0/playgrounds?{urlencode(params)}",
|
|
172
|
+
method="POST",
|
|
173
|
+
headers=post_headers,
|
|
174
|
+
data=json.dumps(body),
|
|
175
|
+
)
|
|
173
176
|
except Exception as e:
|
|
174
177
|
raise click.ClickException(FeedbackManager.error_pushing_pipe(pipe=p["name"], error=str(e)))
|
|
175
178
|
|
|
@@ -296,160 +299,6 @@ async def get_token_from_main_branch(branch_tb_client: TinyB) -> Optional[str]:
|
|
|
296
299
|
return token_from_main_branch
|
|
297
300
|
|
|
298
301
|
|
|
299
|
-
async def check_pipe(
|
|
300
|
-
pipe,
|
|
301
|
-
host: str,
|
|
302
|
-
token: str,
|
|
303
|
-
populate: bool,
|
|
304
|
-
cl: TinyB,
|
|
305
|
-
limit: int = 0,
|
|
306
|
-
relative_change: float = 0.01,
|
|
307
|
-
sample_by_params: int = 0,
|
|
308
|
-
only_response_times=False,
|
|
309
|
-
matches: Optional[List[str]] = None,
|
|
310
|
-
failfast: bool = False,
|
|
311
|
-
validate_processed_bytes: bool = False,
|
|
312
|
-
ignore_order: bool = False,
|
|
313
|
-
token_for_requests_to_check: Optional[str] = None,
|
|
314
|
-
current_pipe: Optional[Dict[str, Any]] = None,
|
|
315
|
-
):
|
|
316
|
-
checker_pipe = deepcopy(pipe)
|
|
317
|
-
checker_pipe["name"] = f"{checker_pipe['name']}__checker"
|
|
318
|
-
|
|
319
|
-
if current_pipe:
|
|
320
|
-
pipe_type = current_pipe["type"]
|
|
321
|
-
if pipe_type == PipeTypes.COPY:
|
|
322
|
-
await cl.pipe_remove_copy(current_pipe["id"], current_pipe["copy_node"])
|
|
323
|
-
if pipe_type == PipeTypes.DATA_SINK:
|
|
324
|
-
await cl.pipe_remove_sink(current_pipe["id"], current_pipe["sink_node"])
|
|
325
|
-
if pipe_type == PipeTypes.STREAM:
|
|
326
|
-
await cl.pipe_remove_stream(current_pipe["id"], current_pipe["stream_node"])
|
|
327
|
-
|
|
328
|
-
# In case of doing --force for a materialized view, checker is being created as standard pipe
|
|
329
|
-
for node in checker_pipe["nodes"]:
|
|
330
|
-
node["params"]["type"] = PipeNodeTypes.STANDARD
|
|
331
|
-
|
|
332
|
-
if populate:
|
|
333
|
-
raise click.ClickException(FeedbackManager.error_check_pipes_populate())
|
|
334
|
-
|
|
335
|
-
runner = PipeCheckerRunner(pipe["name"], host)
|
|
336
|
-
headers = (
|
|
337
|
-
{"Authorization": f"Bearer {token_for_requests_to_check}"}
|
|
338
|
-
if token_for_requests_to_check
|
|
339
|
-
else {"Authorization": f"Bearer {token}"}
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
sql_for_coverage, sql_latest_requests = runner.get_sqls_for_requests_to_check(
|
|
343
|
-
matches or [], sample_by_params, limit
|
|
344
|
-
)
|
|
345
|
-
|
|
346
|
-
params = {"q": sql_for_coverage if limit == 0 and sample_by_params > 0 else sql_latest_requests}
|
|
347
|
-
r: requests.Response = await requests_get(
|
|
348
|
-
f"{host}/v0/sql?{urlencode(params)}", headers=headers, verify=not getenv_bool("TB_DISABLE_SSL_CHECKS", False)
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
# If we get a timeout, fallback to just the last requests
|
|
352
|
-
|
|
353
|
-
if not r or r.status_code == 408:
|
|
354
|
-
params = {"q": sql_latest_requests}
|
|
355
|
-
r = await requests_get(
|
|
356
|
-
f"{host}/v0/sql?{urlencode(params)}",
|
|
357
|
-
headers=headers,
|
|
358
|
-
verify=not getenv_bool("TB_DISABLE_SSL_CHECKS", False),
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
if not r or r.status_code != 200:
|
|
362
|
-
raise click.ClickException(FeedbackManager.error_check_pipes_api(pipe=pipe["name"]))
|
|
363
|
-
|
|
364
|
-
pipe_requests_to_check: List[Dict[str, Any]] = []
|
|
365
|
-
for row in r.json().get("data", []):
|
|
366
|
-
for i in range(len(row["endpoint_url"])):
|
|
367
|
-
pipe_requests_to_check += [
|
|
368
|
-
{
|
|
369
|
-
"endpoint_url": f"{host}{row['endpoint_url'][i]}",
|
|
370
|
-
"pipe_request_params": row["pipe_request_params"][i],
|
|
371
|
-
"http_method": row["http_method"],
|
|
372
|
-
}
|
|
373
|
-
]
|
|
374
|
-
|
|
375
|
-
if not pipe_requests_to_check:
|
|
376
|
-
return
|
|
377
|
-
|
|
378
|
-
await new_pipe(checker_pipe, cl, force=True, check=False, populate=populate)
|
|
379
|
-
|
|
380
|
-
runner_response = runner.run_pipe_checker(
|
|
381
|
-
pipe_requests_to_check,
|
|
382
|
-
checker_pipe["name"],
|
|
383
|
-
token,
|
|
384
|
-
only_response_times,
|
|
385
|
-
ignore_order,
|
|
386
|
-
validate_processed_bytes,
|
|
387
|
-
relative_change,
|
|
388
|
-
failfast,
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
try:
|
|
392
|
-
if runner_response.metrics_summary and runner_response.metrics_timing:
|
|
393
|
-
column_names_tests = ["Test Run", "Test Passed", "Test Failed", "% Test Passed", "% Test Failed"]
|
|
394
|
-
click.echo("\n==== Test Metrics ====\n")
|
|
395
|
-
click.echo(
|
|
396
|
-
format_pretty_table(
|
|
397
|
-
[
|
|
398
|
-
[
|
|
399
|
-
runner_response.metrics_summary["run"],
|
|
400
|
-
runner_response.metrics_summary["passed"],
|
|
401
|
-
runner_response.metrics_summary["failed"],
|
|
402
|
-
runner_response.metrics_summary["percentage_passed"],
|
|
403
|
-
runner_response.metrics_summary["percentage_failed"],
|
|
404
|
-
]
|
|
405
|
-
],
|
|
406
|
-
column_names=column_names_tests,
|
|
407
|
-
)
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
column_names_timing = ["Timing Metric (s)", "Current", "New"]
|
|
411
|
-
click.echo("\n==== Response Time Metrics ====\n")
|
|
412
|
-
click.echo(
|
|
413
|
-
format_pretty_table(
|
|
414
|
-
[
|
|
415
|
-
[metric, runner_response.metrics_timing[metric][0], runner_response.metrics_timing[metric][1]]
|
|
416
|
-
for metric in [
|
|
417
|
-
"min response time",
|
|
418
|
-
"max response time",
|
|
419
|
-
"mean response time",
|
|
420
|
-
"median response time",
|
|
421
|
-
"p90 response time",
|
|
422
|
-
"min read bytes",
|
|
423
|
-
"max read bytes",
|
|
424
|
-
"mean read bytes",
|
|
425
|
-
"median read bytes",
|
|
426
|
-
"p90 read bytes",
|
|
427
|
-
]
|
|
428
|
-
],
|
|
429
|
-
column_names=column_names_timing,
|
|
430
|
-
)
|
|
431
|
-
)
|
|
432
|
-
except Exception:
|
|
433
|
-
pass
|
|
434
|
-
|
|
435
|
-
if not runner_response.was_successfull:
|
|
436
|
-
for failure in runner_response.failed:
|
|
437
|
-
try:
|
|
438
|
-
click.echo("==== Test FAILED ====\n")
|
|
439
|
-
click.echo(failure["name"])
|
|
440
|
-
click.echo(FeedbackManager.error_check_pipe(error=failure["error"]))
|
|
441
|
-
click.echo("=====================\n\n\n")
|
|
442
|
-
except Exception:
|
|
443
|
-
pass
|
|
444
|
-
raise RuntimeError("Invalid results, you can bypass checks by running push with the --no-check flag")
|
|
445
|
-
|
|
446
|
-
# Only delete if no errors, so we can check results after failure
|
|
447
|
-
headers = {"Authorization": f"Bearer {token}"}
|
|
448
|
-
r = await requests_delete(f"{host}/v0/pipes/{checker_pipe['name']}", headers=headers)
|
|
449
|
-
if r.status_code != 204:
|
|
450
|
-
click.echo(FeedbackManager.warning_check_pipe(content=r.content))
|
|
451
|
-
|
|
452
|
-
|
|
453
302
|
async def check_materialized(pipe, host, token, cl, override_datasource=False, current_pipe=None):
|
|
454
303
|
checker_pipe = deepcopy(pipe)
|
|
455
304
|
checker_pipe["name"] = f"{checker_pipe['name']}__checker"
|