tinybird-cli 3.3.1.dev8__tar.gz → 3.6.1.dev9__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.
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/PKG-INFO +65 -20
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/__cli__.py +3 -3
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/ch_utils/engine.py +52 -2
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/client.py +3 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/context.py +1 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/datafile.py +224 -66
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/feedback_manager.py +67 -15
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/git_settings.py +13 -1
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/sql.py +91 -3
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/sql_template.py +50 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/sql_template_fmt.py +22 -1
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/auth.py +1 -1
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/cicd.py +37 -21
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/cli.py +67 -18
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/common.py +1 -6
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/connection.py +1 -3
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/pipe.py +15 -4
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/workspace_members.py +3 -3
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tornado_template.py +1 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/PKG-INFO +65 -20
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/top_level.txt +1 -1
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/setup.cfg +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/check_pypi.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/config.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/connector_settings.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/connectors.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/data_connectors/credentials.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/datatypes.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/syncasync.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/SOURCES.txt +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/entry_points.txt +0 -0
- {tinybird-cli-3.3.1.dev8 → tinybird-cli-3.6.1.dev9}/tinybird_cli.egg-info/requires.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.1.dev9
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
|
-
Home-page: https://
|
|
5
|
+
Home-page: https://www.tinybird.co/docs/cli/introduction.html
|
|
6
6
|
Author: Tinybird
|
|
7
7
|
Author-email: support@tinybird.co
|
|
8
8
|
Requires-Python: >=3.8, <3.12
|
|
@@ -11,7 +11,7 @@ Provides-Extra: bigquery
|
|
|
11
11
|
Provides-Extra: snowflake
|
|
12
12
|
|
|
13
13
|
Tinybird CLI
|
|
14
|
-
|
|
14
|
+
=============
|
|
15
15
|
|
|
16
16
|
The Tinybird command-line tool allows you to use all the Tinybird functionality directly from the command line. Additionally, it includes several functions to create and manage data projects easily.
|
|
17
17
|
|
|
@@ -19,48 +19,93 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
-
3.
|
|
22
|
+
3.6.1.dev9
|
|
23
23
|
************
|
|
24
24
|
|
|
25
|
-
- `
|
|
25
|
+
- `Fixed` Added correct URL for checking available regions
|
|
26
|
+
|
|
26
27
|
|
|
27
|
-
3.
|
|
28
|
+
3.6.1.dev8
|
|
28
29
|
************
|
|
29
30
|
|
|
30
|
-
- `
|
|
31
|
+
- `Fixed` Report better error message on `tb diff` when two Datafiles have the same name
|
|
31
32
|
|
|
32
|
-
3.
|
|
33
|
+
3.6.1.dev7
|
|
33
34
|
************
|
|
34
35
|
|
|
35
|
-
- `Fixed` `tb deploy`
|
|
36
|
+
- `Fixed` `tb deploy` supports deployment when a `.incl` file is removed
|
|
36
37
|
|
|
37
|
-
3.
|
|
38
|
+
3.6.1.dev6
|
|
38
39
|
************
|
|
39
40
|
|
|
40
|
-
- `Fixed` `
|
|
41
|
+
- `Fixed` Some issues when using `--fmt: off` with `CASE` in the sql
|
|
41
42
|
|
|
42
|
-
3.
|
|
43
|
+
3.6.1.dev5
|
|
43
44
|
************
|
|
44
45
|
|
|
45
|
-
- `
|
|
46
|
+
- `Fixed` Avoid `tb fmt` to error if there's a `CASE` in the sql
|
|
47
|
+
|
|
48
|
+
3.6.1.dev4
|
|
49
|
+
************
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
***********
|
|
51
|
+
- `Fixed` regression tests query when filtering by specific parameter
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
3.6.1.dev3
|
|
54
|
+
************
|
|
55
|
+
|
|
56
|
+
- `Changed` behavior when running `tb deploy` on a branch to push the connection settings to the backend. This change is the backend that decides what to do.
|
|
51
57
|
|
|
52
|
-
3.
|
|
58
|
+
3.6.1.dev2
|
|
53
59
|
************
|
|
54
60
|
|
|
55
|
-
- `Changed`
|
|
61
|
+
- `Changed` fixed major version of tinybird-cli to lower than 4 when using `tb init --git`
|
|
62
|
+
|
|
63
|
+
3.6.0
|
|
64
|
+
************
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
- `Added` Add new envvar `TB_INCL_RELATIVE_PATH` in .tinyenv to look for Datafiles out of the Data Project directory
|
|
67
|
+
- `Changed` On-demand Sink run checks the pipe type instead of checking the workspace connectors
|
|
68
|
+
|
|
69
|
+
3.5.0
|
|
58
70
|
************
|
|
59
71
|
|
|
60
|
-
-
|
|
72
|
+
- `Added` Token management in Copy pipes datafiles
|
|
73
|
+
- `Added` Better error report on `tb push` when trying to push a pipe with bad templating
|
|
74
|
+
- `Added` credential validation for S3 connections
|
|
75
|
+
- `Added` `tb connection create` now supports `s3_iamrole` as service type
|
|
76
|
+
- `Changed` error message when trying to modify a datasource without bumping the major semver version to add a link to the documentation.
|
|
77
|
+
- `Changed` GH workflow files and secret includes the workspace name when generated from the UI and CLI
|
|
78
|
+
- `Changed` rename `INDICES` to `INDEXES`
|
|
79
|
+
- `Changed` Save git commit to workspace on `tb push --only-changes`
|
|
80
|
+
- `Fixed` Fix error message when deleting an `.incl` file with the git workflow
|
|
81
|
+
- `Fixed` support `tb deploy --dry-run`
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
3.4.0
|
|
85
|
+
************
|
|
86
|
+
|
|
87
|
+
- `Added` Support `tb deploy` .datasource with `INDEXES`
|
|
88
|
+
- `Added` Support `tb push` .datasource with `INDEXES`
|
|
89
|
+
- `Added` Support `tb deploy` in a post release of a .datasource with `INDEXES`
|
|
90
|
+
- `Added` Check backfill on preview is required when `tb deploy` modified datasources. Disable check with `TB_CHECK_BACKFILL_REQUIRED=0`.
|
|
91
|
+
- `Changed` Allow spaces when managing multiple Workspace members
|
|
92
|
+
- `Changed` `tb deploy` to not allow pushing materialized views with datasource definition in the same datafile. We are blocking this as has unsupported behavior and it misleading and less flexible than having 2 files one for the datasource and one for the materialized view.
|
|
93
|
+
- `Changed` `tb deploy` to deploy the datasources from top to bottom to make sure that if we modified the column in some datasource in the top. It will be deployed before the datasources that depend on it.
|
|
94
|
+
- `Changed` Post-release required when deploying changes that include changing a Copy Pipe.
|
|
95
|
+
- `Changed` script `exec_test.sh` from `tb init --git` to run retries to avoid flakiness in tests
|
|
96
|
+
- `Changed` Update `tb release rm --oldest-rollback` to use new API
|
|
97
|
+
- `Fixed` Post-release recommended instead of required when deploying changes that include changing a Copy Pipe. Displays a warning when other number of the semver is increased.
|
|
98
|
+
- `Fixed` Fixed bug when a Data Source was created using an INDEX
|
|
99
|
+
- `Fixed` Avoid None git diff change type
|
|
100
|
+
- `Fixed` `tb deploy` to deploy the endpoints in the correct order when there are endpoints depending on other endpoints.
|
|
101
|
+
- `Fixed` `tb push` pipe with multiple tokens
|
|
102
|
+
- `Fixed` `IMPORT` and `ENGINE` changes were not detected `tb deploy`
|
|
103
|
+
- `Removed` part of the code supporting python 3.6 as we stopped giving support 18 month ago
|
|
104
|
+
|
|
61
105
|
|
|
62
106
|
3.3.0
|
|
63
107
|
************
|
|
108
|
+
|
|
64
109
|
- `Added` Show warning when doing data or pipe operations directly against Live.
|
|
65
110
|
- `Added` `bi_stats`, `bi_stats_rt` and `endpoint_errors` to the list of service data sources that the CLI ignore when looking for dependencies of pipes being pushed.
|
|
66
111
|
- `Added` S3 Iam Role connection creation
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
__name__ = 'tinybird-cli'
|
|
3
3
|
__description__ = 'Tinybird Command Line Tool'
|
|
4
|
-
__url__ = 'https://
|
|
4
|
+
__url__ = 'https://www.tinybird.co/docs/cli/introduction.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '3.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '3.6.1.dev9'
|
|
8
|
+
__revision__ = 'ff22a5b'
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import re
|
|
3
3
|
from collections import defaultdict
|
|
4
|
+
from dataclasses import asdict
|
|
4
5
|
from typing import Any, Callable, Dict, Iterable, List, Optional
|
|
5
6
|
|
|
6
|
-
from ..sql import col_name, engine_replicated_to_local, parse_table_structure
|
|
7
|
+
from ..sql import TableIndex, col_name, engine_replicated_to_local, parse_indexes_structure, parse_table_structure
|
|
7
8
|
|
|
8
9
|
DEFAULT_EMPTY_PARAMETERS = ["ttl", "partition_key", "sorting_key"]
|
|
9
10
|
DEFAULT_JOIN_EMPTY_PARAMETERS = ["join_strictness", "join_type", "key_columns"]
|
|
@@ -31,7 +32,20 @@ class TableDetails:
|
|
|
31
32
|
>>> ed.to_datafile()
|
|
32
33
|
''
|
|
33
34
|
|
|
35
|
+
>>> ed = TableDetails({ "engine_full": "MergeTree() PARTITION BY toYear(timestamp) ORDER BY (timestamp, cityHash64(location)) SAMPLE BY cityHash64(location) SETTINGS index_granularity = 32, index_granularity_bytes = 2048", "engine": "MergeTree", "partition_key": "toYear(timestamp)", "sorting_key": "timestamp, cityHash64(location)", "primary_key": "timestamp, cityHash64(location)", "sampling_key": "cityHash64(location)", "settings": "index_granularity = 32, index_granularity_bytes = 2048", "ttl": None })
|
|
36
|
+
>>> ed.diff_ttl("toDate(timestamp) + toIntervalDay(1)")
|
|
37
|
+
True
|
|
34
38
|
>>> ed = TableDetails({ "engine_full": "MergeTree() PARTITION BY toYear(timestamp) ORDER BY (timestamp, cityHash64(location)) SAMPLE BY cityHash64(location) SETTINGS index_granularity = 32, index_granularity_bytes = 2048 TTL toDate(timestamp) + INTERVAL 1 DAY", "engine": "MergeTree", "partition_key": "toYear(timestamp)", "sorting_key": "timestamp, cityHash64(location)", "primary_key": "timestamp, cityHash64(location)", "sampling_key": "cityHash64(location)", "settings": "index_granularity = 32, index_granularity_bytes = 2048", "ttl": "toDate(timestamp) + INTERVAL 1 DAY" })
|
|
39
|
+
>>> ed.diff_ttl("toDate(timestamp) + toIntervalDay(1)")
|
|
40
|
+
False
|
|
41
|
+
>>> ed.diff_ttl("toDate(timestamp) + toIntervalDay(2)")
|
|
42
|
+
True
|
|
43
|
+
>>> ed.diff_ttl("toDate(timestamp) + INTERVAL DAY 2")
|
|
44
|
+
True
|
|
45
|
+
>>> ed.diff_ttl("toDate(timestamp) + INTERVAL 1 DAY")
|
|
46
|
+
False
|
|
47
|
+
>>> ed.diff_ttl("")
|
|
48
|
+
True
|
|
35
49
|
>>> ed.engine_full
|
|
36
50
|
'MergeTree() PARTITION BY toYear(timestamp) ORDER BY (timestamp, cityHash64(location)) SAMPLE BY cityHash64(location) SETTINGS index_granularity = 32, index_granularity_bytes = 2048 TTL toDate(timestamp) + INTERVAL 1 DAY'
|
|
37
51
|
>>> ed.engine
|
|
@@ -131,6 +145,16 @@ class TableDetails:
|
|
|
131
145
|
return is_aggregating or is_replacing or is_collapsing
|
|
132
146
|
return False
|
|
133
147
|
|
|
148
|
+
def diff_ttl(self, new_ttl: str) -> bool:
|
|
149
|
+
try:
|
|
150
|
+
from tinybird.sql_toolset import format_sql
|
|
151
|
+
|
|
152
|
+
current_ttl = format_sql(f"select {self.ttl}")[7:]
|
|
153
|
+
new_ttl = format_sql(f"select {new_ttl}")[7:]
|
|
154
|
+
return current_ttl != new_ttl
|
|
155
|
+
except Exception:
|
|
156
|
+
return self.ttl != new_ttl
|
|
157
|
+
|
|
134
158
|
@property
|
|
135
159
|
def partition_key(self) -> Optional[str]:
|
|
136
160
|
return self.details.get("partition_key", None)
|
|
@@ -204,6 +228,10 @@ class TableDetails:
|
|
|
204
228
|
"row_count": self.details.get("total_rows", None),
|
|
205
229
|
}
|
|
206
230
|
|
|
231
|
+
@property
|
|
232
|
+
def indexes(self) -> List[TableIndex]:
|
|
233
|
+
return _parse_indexes(str(self.details.get("create_table_query", "")))
|
|
234
|
+
|
|
207
235
|
def to_json(self, exclude: Optional[List[str]] = None, include_empty_details: bool = False):
|
|
208
236
|
# name, database are not exported since they are not part of the engine
|
|
209
237
|
d: Dict[str, Any] = {
|
|
@@ -234,6 +262,8 @@ class TableDetails:
|
|
|
234
262
|
d["version"] = self.version
|
|
235
263
|
if self.ttl:
|
|
236
264
|
d["ttl"] = self.ttl.strip()
|
|
265
|
+
if self.indexes:
|
|
266
|
+
d["indexes"] = [asdict(index) for index in self.indexes]
|
|
237
267
|
|
|
238
268
|
if self.engine_full:
|
|
239
269
|
engine_params = engine_params_from_engine_full(self.engine_full)
|
|
@@ -253,7 +283,9 @@ class TableDetails:
|
|
|
253
283
|
return d
|
|
254
284
|
|
|
255
285
|
def to_datafile(self, include_empty_details: bool = False) -> str:
|
|
256
|
-
d: Dict[str, Any] = self.to_json(
|
|
286
|
+
d: Dict[str, Any] = self.to_json(
|
|
287
|
+
exclude=["engine", "engine_full", "indexes"], include_empty_details=include_empty_details
|
|
288
|
+
)
|
|
257
289
|
engine: str = self.engine
|
|
258
290
|
|
|
259
291
|
datafile: str = ""
|
|
@@ -774,3 +806,21 @@ def ttl_condition_from_engine_full(engine_full: Optional[str]) -> Optional[str]:
|
|
|
774
806
|
except Exception as e:
|
|
775
807
|
logging.error(str(e))
|
|
776
808
|
return None
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
def _parse_indexes(create_table_query_expr: str) -> List[TableIndex]:
|
|
812
|
+
if create_table_query_expr == "":
|
|
813
|
+
return []
|
|
814
|
+
try:
|
|
815
|
+
from tinybird.sql_toolset import format_sql
|
|
816
|
+
|
|
817
|
+
indexes = [
|
|
818
|
+
line.strip()
|
|
819
|
+
for line in format_sql(create_table_query_expr).splitlines()
|
|
820
|
+
if line.strip().startswith("INDEX")
|
|
821
|
+
]
|
|
822
|
+
except ModuleNotFoundError:
|
|
823
|
+
# this is not needed from CLI
|
|
824
|
+
return []
|
|
825
|
+
|
|
826
|
+
return parse_indexes_structure(indexes)
|
|
@@ -306,6 +306,7 @@ class TinyB(object):
|
|
|
306
306
|
description: Optional[str] = None,
|
|
307
307
|
ttl: Optional[str] = None,
|
|
308
308
|
dry_run: bool = False,
|
|
309
|
+
indexes: Optional[str] = None,
|
|
309
310
|
):
|
|
310
311
|
params = {"dry": "true" if dry_run else "false"}
|
|
311
312
|
if new_schema:
|
|
@@ -314,6 +315,8 @@ class TinyB(object):
|
|
|
314
315
|
params.update({"description": description})
|
|
315
316
|
if ttl:
|
|
316
317
|
params.update({"ttl": ttl})
|
|
318
|
+
if indexes:
|
|
319
|
+
params.update({"indexes": indexes})
|
|
317
320
|
res = await self._req(f"/v0/datasources/{ds_name}/alter", method="POST", data=params)
|
|
318
321
|
|
|
319
322
|
if "Error" in res:
|
|
@@ -6,6 +6,7 @@ table_id: ContextVar[str] = ContextVar("table_id")
|
|
|
6
6
|
hfi_frequency: ContextVar[float] = ContextVar("hfi_frequency")
|
|
7
7
|
hfi_frequency_gatherer: ContextVar[float] = ContextVar("hfi_frequency_gatherer")
|
|
8
8
|
hfi_use_gatherer: ContextVar[bool] = ContextVar("hfi_use_gatherer")
|
|
9
|
+
use_gatherer: ContextVar[bool] = ContextVar("use_gatherer")
|
|
9
10
|
disable_template_security_validation: ContextVar[bool] = ContextVar("disable_template_security_validation")
|
|
10
11
|
origin: ContextVar[str] = ContextVar("origin")
|
|
11
12
|
request_id: ContextVar[str] = ContextVar("request_id")
|