tinybird-cli 1.2.1.dev1__tar.gz → 1.2.1.dev2__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-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/PKG-INFO +6 -1
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/__cli__.py +2 -2
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/client.py +1 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/datafile.py +73 -25
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/sql_template.py +139 -23
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/cli.py +48 -29
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/PKG-INFO +6 -1
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/setup.cfg +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/check_pypi.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/config.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/connector_settings.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/connectors.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/context.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/datatypes.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/feedback_manager.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/sql.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/sql_toolset.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/syncasync.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/token.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tornado_template.py +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/SOURCES.txt +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/dependency_links.txt +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/entry_points.txt +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/requires.txt +0 -0
- {tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 1.2.1.
|
|
3
|
+
Version: 1.2.1.dev2
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,6 +19,11 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
1.2.1.dev2
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Changed` Internal change
|
|
26
|
+
|
|
22
27
|
1.2.1.dev1
|
|
23
28
|
************
|
|
24
29
|
|
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://docs.tinybird.co/cli.html'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '1.2.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '1.2.1.dev2'
|
|
8
|
+
__revision__ = '06bf61e'
|
|
@@ -588,6 +588,7 @@ class TinyB(object):
|
|
|
588
588
|
params = {}
|
|
589
589
|
if pipeline:
|
|
590
590
|
params = {"pipeline": pipeline}
|
|
591
|
+
params.update({"release_replacements": "true"})
|
|
591
592
|
|
|
592
593
|
if len(sql) > TinyB.MAX_GET_LENGTH:
|
|
593
594
|
return await self._req(f"/v0/sql?{urlencode(params)}", data=sql, method="POST")
|
|
@@ -23,7 +23,7 @@ from operator import itemgetter
|
|
|
23
23
|
import shlex
|
|
24
24
|
import sys
|
|
25
25
|
import re
|
|
26
|
-
from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
|
|
26
|
+
from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
|
|
27
27
|
from enum import Enum
|
|
28
28
|
from mypy_extensions import VarArg, KwArg
|
|
29
29
|
import difflib
|
|
@@ -2297,6 +2297,7 @@ async def new_pipe(
|
|
|
2297
2297
|
tests_check_requests_from_branch: bool = False,
|
|
2298
2298
|
config: Any = None,
|
|
2299
2299
|
fork_downstream: Optional[bool] = False,
|
|
2300
|
+
fork: Optional[bool] = False,
|
|
2300
2301
|
): # noqa: C901
|
|
2301
2302
|
# TODO use tb_client instead of calling the urls directly.
|
|
2302
2303
|
host = tb_client.host
|
|
@@ -2382,7 +2383,7 @@ async def new_pipe(
|
|
|
2382
2383
|
if populate_subset:
|
|
2383
2384
|
params["populate_subset"] = populate_subset
|
|
2384
2385
|
params["unlink_on_populate_error"] = "true" if unlink_on_populate_error else "false"
|
|
2385
|
-
params["branch_mode"] = "fork" if fork_downstream else "None"
|
|
2386
|
+
params["branch_mode"] = "fork" if fork_downstream or fork else "None"
|
|
2386
2387
|
|
|
2387
2388
|
body = {"name": p["name"], "description": p.get("description", "")}
|
|
2388
2389
|
|
|
@@ -2610,6 +2611,7 @@ async def new_ds(
|
|
|
2610
2611
|
skip_confirmation: bool = False,
|
|
2611
2612
|
current_ws=None,
|
|
2612
2613
|
fork_downstream: Optional[bool] = False,
|
|
2614
|
+
fork: Optional[bool] = False,
|
|
2613
2615
|
git_release: Optional[bool] = False,
|
|
2614
2616
|
):
|
|
2615
2617
|
ds_name = ds["params"]["name"]
|
|
@@ -2641,9 +2643,9 @@ async def new_ds(
|
|
|
2641
2643
|
except DoesNotExistException:
|
|
2642
2644
|
datasource_exists = False
|
|
2643
2645
|
|
|
2644
|
-
if not datasource_exists or fork_downstream:
|
|
2646
|
+
if not datasource_exists or fork_downstream or fork:
|
|
2645
2647
|
params = ds["params"]
|
|
2646
|
-
params["branch_mode"] = "fork" if fork_downstream else "None"
|
|
2648
|
+
params["branch_mode"] = "fork" if fork_downstream or fork else "None"
|
|
2647
2649
|
|
|
2648
2650
|
try:
|
|
2649
2651
|
if (
|
|
@@ -2719,7 +2721,7 @@ async def new_ds(
|
|
|
2719
2721
|
ds["params"]["schema"].replace(" ", "") != existing_ds["schema"]["sql_schema"].replace(" ", "")
|
|
2720
2722
|
):
|
|
2721
2723
|
new_schema = ds["params"]["schema"]
|
|
2722
|
-
if new_description or new_schema or new_ttl and not fork_downstream:
|
|
2724
|
+
if new_description or new_schema or new_ttl and (not fork_downstream or not fork):
|
|
2723
2725
|
alter_response = await client.alter_datasource(
|
|
2724
2726
|
ds_name, new_schema=new_schema, description=new_description, ttl=new_ttl, dry_run=True
|
|
2725
2727
|
)
|
|
@@ -2899,6 +2901,7 @@ async def exec_file(
|
|
|
2899
2901
|
tests_check_requests_from_branch: bool = False,
|
|
2900
2902
|
current_ws: Optional[Dict[str, Any]] = None,
|
|
2901
2903
|
fork_downstream: Optional[bool] = False,
|
|
2904
|
+
fork: Optional[bool] = False,
|
|
2902
2905
|
git_release: Optional[bool] = False,
|
|
2903
2906
|
):
|
|
2904
2907
|
if debug:
|
|
@@ -2929,6 +2932,7 @@ async def exec_file(
|
|
|
2929
2932
|
override_datasource=override_datasource,
|
|
2930
2933
|
tests_check_requests_from_branch=tests_check_requests_from_branch,
|
|
2931
2934
|
fork_downstream=fork_downstream,
|
|
2935
|
+
fork=fork,
|
|
2932
2936
|
)
|
|
2933
2937
|
elif r["resource"] == "datasources":
|
|
2934
2938
|
await new_ds(
|
|
@@ -2939,6 +2943,7 @@ async def exec_file(
|
|
|
2939
2943
|
skip_confirmation=skip_confirmation,
|
|
2940
2944
|
current_ws=current_ws,
|
|
2941
2945
|
fork_downstream=fork_downstream,
|
|
2946
|
+
fork=fork,
|
|
2942
2947
|
git_release=git_release,
|
|
2943
2948
|
)
|
|
2944
2949
|
elif r["resource"] == "tokens":
|
|
@@ -3280,38 +3285,48 @@ async def build_graph(
|
|
|
3280
3285
|
|
|
3281
3286
|
return downstream_dependency_graph
|
|
3282
3287
|
|
|
3283
|
-
def update_dep_map_recursively(
|
|
3288
|
+
def update_dep_map_recursively(
|
|
3289
|
+
dep_map, downstream_dep_map, all_resources, to_run, dep_map_keys, key=None, visited=None
|
|
3290
|
+
):
|
|
3284
3291
|
"""
|
|
3285
3292
|
Given a downstream_dep_map obtained from create_downstream_dependency_graph this function updates each node recursively to complete the downstream dependency graph for each node
|
|
3286
3293
|
"""
|
|
3294
|
+
if not visited:
|
|
3295
|
+
visited = list()
|
|
3296
|
+
if not key and len(dep_map_keys) == 0:
|
|
3297
|
+
return
|
|
3298
|
+
if not key:
|
|
3299
|
+
key = dep_map_keys.pop()
|
|
3287
3300
|
if key not in dep_map:
|
|
3288
3301
|
dep_map[key] = set()
|
|
3289
|
-
elif key in external_visitor:
|
|
3290
|
-
return
|
|
3291
3302
|
else:
|
|
3292
|
-
|
|
3303
|
+
visited.append(key)
|
|
3304
|
+
return
|
|
3293
3305
|
|
|
3294
3306
|
for dep in downstream_dep_map.get(key, {}):
|
|
3295
3307
|
if dep not in downstream_dep_map:
|
|
3296
3308
|
continue
|
|
3297
3309
|
to_run[dep] = all_resources.get(dep)
|
|
3298
|
-
update_dep_map_recursively(
|
|
3310
|
+
update_dep_map_recursively(
|
|
3311
|
+
dep_map, downstream_dep_map, all_resources, to_run, dep_map_keys, key=dep, visited=visited
|
|
3312
|
+
)
|
|
3299
3313
|
dep_map[key].update(downstream_dep_map[dep])
|
|
3300
3314
|
dep_map[key].update({dep})
|
|
3301
3315
|
try:
|
|
3302
3316
|
dep_map[key].remove(key)
|
|
3303
3317
|
except KeyError:
|
|
3304
|
-
|
|
3318
|
+
pass
|
|
3305
3319
|
|
|
3306
3320
|
to_run[key] = all_resources.get(key)
|
|
3321
|
+
update_dep_map_recursively(
|
|
3322
|
+
dep_map, downstream_dep_map, all_resources, to_run, dep_map_keys, key=None, visited=visited
|
|
3323
|
+
)
|
|
3307
3324
|
|
|
3308
3325
|
new_dep_map = dep_map
|
|
3309
3326
|
if all_dep_map and fork_downstream:
|
|
3310
3327
|
downstream_dep_map = create_downstream_dependency_graph(all_dep_map, all_resources)
|
|
3311
3328
|
new_dep_map = {}
|
|
3312
|
-
|
|
3313
|
-
for key in list(dep_map.keys()):
|
|
3314
|
-
update_dep_map_recursively(new_dep_map, downstream_dep_map, all_resources, to_run, key, external_visitor)
|
|
3329
|
+
update_dep_map_recursively(new_dep_map, downstream_dep_map, all_resources, to_run, list(set(dep_map.keys())))
|
|
3315
3330
|
|
|
3316
3331
|
return to_run, new_dep_map
|
|
3317
3332
|
|
|
@@ -3396,6 +3411,7 @@ async def folder_push(
|
|
|
3396
3411
|
config: Optional[Dict[str, Any]] = None,
|
|
3397
3412
|
user_token: Optional[str] = None,
|
|
3398
3413
|
fork_downstream: Optional[bool] = False,
|
|
3414
|
+
fork: Optional[bool] = False,
|
|
3399
3415
|
is_internal: Optional[bool] = False,
|
|
3400
3416
|
): # noqa: C901
|
|
3401
3417
|
workspaces: List[Dict[str, Any]] = (await tb_client.user_workspaces_and_branches()).get("workspaces", [])
|
|
@@ -3535,6 +3551,7 @@ async def folder_push(
|
|
|
3535
3551
|
latest_datasource_versions: Dict[str, Any],
|
|
3536
3552
|
dry_run: bool,
|
|
3537
3553
|
fork_downstream: Optional[bool] = False,
|
|
3554
|
+
fork: Optional[bool] = False,
|
|
3538
3555
|
):
|
|
3539
3556
|
if name in to_run:
|
|
3540
3557
|
if not dry_run:
|
|
@@ -3583,6 +3600,7 @@ async def folder_push(
|
|
|
3583
3600
|
tests_check_requests_from_branch,
|
|
3584
3601
|
current_ws,
|
|
3585
3602
|
fork_downstream,
|
|
3603
|
+
fork,
|
|
3586
3604
|
git_release,
|
|
3587
3605
|
)
|
|
3588
3606
|
if not run_tests:
|
|
@@ -3632,6 +3650,7 @@ async def folder_push(
|
|
|
3632
3650
|
async def push_files(dry_run: bool = False):
|
|
3633
3651
|
endpoints_dep_map = dict()
|
|
3634
3652
|
pipes_dep_map = dict()
|
|
3653
|
+
mat_dep_map = dict()
|
|
3635
3654
|
processed = set()
|
|
3636
3655
|
|
|
3637
3656
|
groups = [group for group in toposort(dep_map)]
|
|
@@ -3643,24 +3662,44 @@ async def folder_push(
|
|
|
3643
3662
|
continue
|
|
3644
3663
|
# FIXME: name in dep_map?? that's wrong it should be there
|
|
3645
3664
|
if fork_downstream and not is_datasource(to_run.get(name)) and name in dep_map:
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3665
|
+
if is_materialized(to_run.get(name)):
|
|
3666
|
+
mat_dep_map[name] = dep_map[name]
|
|
3667
|
+
continue
|
|
3668
|
+
else:
|
|
3669
|
+
pipes_dep_map[name] = dep_map[name]
|
|
3670
|
+
continue
|
|
3671
|
+
await push(name, to_run, resource_versions, latest_datasource_versions, dry_run, fork_downstream, fork)
|
|
3649
3672
|
processed.add(name)
|
|
3650
3673
|
|
|
3674
|
+
# push endpoints with no dependencies or dependencies with other endpoints
|
|
3675
|
+
groups = [group for group in toposort(endpoints_dep_map)]
|
|
3676
|
+
for group in groups:
|
|
3677
|
+
for name in group:
|
|
3678
|
+
if name not in processed and not is_materialized(to_run[name]):
|
|
3679
|
+
await push(
|
|
3680
|
+
name, to_run, resource_versions, latest_datasource_versions, dry_run, fork_downstream, fork
|
|
3681
|
+
)
|
|
3682
|
+
processed.add(name)
|
|
3683
|
+
|
|
3684
|
+
# materialized pipes at the end
|
|
3651
3685
|
if fork_downstream:
|
|
3652
|
-
for group in toposort(pipes_dep_map)
|
|
3686
|
+
groups = [group for group in toposort(pipes_dep_map)]
|
|
3687
|
+
for group in groups:
|
|
3653
3688
|
for name in group:
|
|
3654
|
-
if name not in processed:
|
|
3689
|
+
if name not in processed and not is_materialized(to_run[name]):
|
|
3655
3690
|
await push(
|
|
3656
3691
|
name, to_run, resource_versions, latest_datasource_versions, dry_run, fork_downstream
|
|
3657
3692
|
)
|
|
3693
|
+
processed.add(name)
|
|
3658
3694
|
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3695
|
+
groups = [group for group in toposort(mat_dep_map)]
|
|
3696
|
+
for group in groups:
|
|
3697
|
+
for name in group:
|
|
3698
|
+
if name not in processed:
|
|
3699
|
+
await push(
|
|
3700
|
+
name, to_run, resource_versions, latest_datasource_versions, dry_run, fork_downstream
|
|
3701
|
+
)
|
|
3702
|
+
processed.add(name)
|
|
3664
3703
|
|
|
3665
3704
|
if deployment.is_git_release:
|
|
3666
3705
|
deployment.deploying_dry_run()
|
|
@@ -4365,6 +4404,15 @@ def is_endpoint(resource: Dict[str, Any]) -> bool:
|
|
|
4365
4404
|
return False
|
|
4366
4405
|
|
|
4367
4406
|
|
|
4407
|
+
def is_materialized(resource: Dict[str, Any]) -> bool:
|
|
4408
|
+
if not resource:
|
|
4409
|
+
return False
|
|
4410
|
+
is_materialized = any(
|
|
4411
|
+
[node.get("params", {}).get("type", None) == "materialized" for node in resource.get("nodes", []) or []]
|
|
4412
|
+
)
|
|
4413
|
+
return is_materialized
|
|
4414
|
+
|
|
4415
|
+
|
|
4368
4416
|
def is_endpoint_with_no_dependencies(resource: Dict[str, Any], dep_map: Dict[str, Any], to_run: Dict[str, Any]) -> bool:
|
|
4369
4417
|
if not resource or resource.get("resource") == "datasources":
|
|
4370
4418
|
return False
|
|
@@ -4388,7 +4436,7 @@ def is_endpoint_with_no_dependencies(resource: Dict[str, Any], dep_map: Dict[str
|
|
|
4388
4436
|
deps = dep_map.get(resource["resource_name"], None)
|
|
4389
4437
|
for dep in deps:
|
|
4390
4438
|
r = to_run.get(dep, None)
|
|
4391
|
-
if is_endpoint(r):
|
|
4439
|
+
if is_endpoint(r) or is_materialized(r):
|
|
4392
4440
|
return False
|
|
4393
4441
|
|
|
4394
4442
|
return True
|
|
@@ -423,7 +423,14 @@ def day_diff(d0, d1, default=None):
|
|
|
423
423
|
)
|
|
424
424
|
|
|
425
425
|
|
|
426
|
-
def date_diff_in_days(
|
|
426
|
+
def date_diff_in_days(
|
|
427
|
+
d0: Union[Placeholder, str],
|
|
428
|
+
d1: Union[Placeholder, str],
|
|
429
|
+
date_format: str = "%Y-%m-%d",
|
|
430
|
+
default=None,
|
|
431
|
+
backup_date_format=None,
|
|
432
|
+
none_if_error=False,
|
|
433
|
+
):
|
|
427
434
|
"""
|
|
428
435
|
>>> date_diff_in_days('2019-01-01', '2019-01-01')
|
|
429
436
|
0
|
|
@@ -441,13 +448,27 @@ def date_diff_in_days(d0, d1, date_format: str = "%Y-%m-%d", default=None):
|
|
|
441
448
|
0
|
|
442
449
|
>>> date_diff_in_days(Placeholder(), '')
|
|
443
450
|
0
|
|
451
|
+
>>> date_diff_in_days('2019-01-01', '2019/01/01', backup_date_format='%Y/%m/%d')
|
|
452
|
+
0
|
|
453
|
+
>>> date_diff_in_days('2019-01-01', '2019/01/04', backup_date_format='%Y/%m/%d')
|
|
454
|
+
3
|
|
455
|
+
>>> date_diff_in_days('2019/01/04', '2019-01-01', backup_date_format='%Y/%m/%d')
|
|
456
|
+
3
|
|
457
|
+
>>> date_diff_in_days('2019-02-01T20:00:00z', '2019-02-15', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d')
|
|
458
|
+
13
|
|
459
|
+
>>> date_diff_in_days('2019-02-01 20:00:00', '2019-02-15', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
460
|
+
True
|
|
461
|
+
>>> date_diff_in_days('2019-01-01', '2019-00-02', none_if_error=True) is None
|
|
462
|
+
True
|
|
463
|
+
>>> date_diff_in_days('2019-01-01 00:00:00', '2019-01-02 00:00:00', none_if_error=True) is None
|
|
464
|
+
True
|
|
444
465
|
"""
|
|
445
466
|
if isinstance(d0, Placeholder) or isinstance(d1, Placeholder):
|
|
446
467
|
if default:
|
|
447
468
|
return default
|
|
448
469
|
return 0
|
|
449
470
|
try:
|
|
450
|
-
return __date_diff(d0, d1, date_format, "days")
|
|
471
|
+
return __date_diff(d0, d1, date_format, backup_date_format, "days", none_if_error)
|
|
451
472
|
except Exception:
|
|
452
473
|
raise SQLTemplateException(
|
|
453
474
|
"invalid date format in function `date_diff_in_days`, it must be ISO format date YYYY-MM-DD, e.g. 2018-09-26",
|
|
@@ -456,7 +477,12 @@ def date_diff_in_days(d0, d1, date_format: str = "%Y-%m-%d", default=None):
|
|
|
456
477
|
|
|
457
478
|
|
|
458
479
|
def date_diff_in_hours(
|
|
459
|
-
d0: Union[Placeholder, str],
|
|
480
|
+
d0: Union[Placeholder, str],
|
|
481
|
+
d1: Union[Placeholder, str],
|
|
482
|
+
date_format: str = "%Y-%m-%d %H:%M:%S",
|
|
483
|
+
default=None,
|
|
484
|
+
backup_date_format=None,
|
|
485
|
+
none_if_error=False,
|
|
460
486
|
):
|
|
461
487
|
"""
|
|
462
488
|
>>> date_diff_in_hours('2022-12-19T18:42:23.521Z', '2022-12-19T18:42:23.521Z', date_format='%Y-%m-%dT%H:%M:%S.%fz')
|
|
@@ -471,13 +497,33 @@ def date_diff_in_hours(
|
|
|
471
497
|
0
|
|
472
498
|
>>> date_diff_in_hours(Placeholder(), '')
|
|
473
499
|
0
|
|
500
|
+
>>> date_diff_in_hours('2022-12-19T03:22:12.102Z', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d')
|
|
501
|
+
3
|
|
502
|
+
>>> date_diff_in_hours('2022-12-19', '2022-12-19', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d')
|
|
503
|
+
0
|
|
504
|
+
>>> date_diff_in_hours('2022-12-19', '2022-12-18', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d')
|
|
505
|
+
24
|
|
506
|
+
>>> date_diff_in_hours('2022-12-19', '2022-12-19 02:01:00', backup_date_format='%Y-%m-%d')
|
|
507
|
+
2
|
|
508
|
+
>>> date_diff_in_hours('2022-25-19T00:00:03.521Z', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
509
|
+
True
|
|
510
|
+
>>> date_diff_in_hours('2022-25-19 00:00:03', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
511
|
+
True
|
|
512
|
+
>>> date_diff_in_hours('2022-12-19', '2022-25-19', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
513
|
+
True
|
|
514
|
+
>>> date_diff_in_hours('2022-12-19', '2022-25-19 00:01:00', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
515
|
+
True
|
|
516
|
+
>>> date_diff_in_hours('2022-12-32 18:42:22', '2022-12-19 18:42:22', none_if_error=True) is None
|
|
517
|
+
True
|
|
518
|
+
>>> date_diff_in_hours('2022-12-18T18:42:22Z', '2022-12-19T18:42:22Z', none_if_error=True) is None
|
|
519
|
+
True
|
|
474
520
|
"""
|
|
475
521
|
if isinstance(d0, Placeholder) or isinstance(d1, Placeholder):
|
|
476
522
|
if default:
|
|
477
523
|
return default
|
|
478
524
|
return 0
|
|
479
525
|
try:
|
|
480
|
-
return __date_diff(d0, d1, date_format, "hours")
|
|
526
|
+
return __date_diff(d0, d1, date_format, backup_date_format, "hours", none_if_error)
|
|
481
527
|
except Exception:
|
|
482
528
|
raise SQLTemplateException(
|
|
483
529
|
"invalid date_format in function `date_diff_in_hours`, defaults to YYYY-MM-DD hh:mm:ss. Or %Y-%m-%d %H:%M:%S [.ssssss]Z, e.g. ms: 2022-12-19T18:42:22.591Z s:2022-12-19T18:42:22Z",
|
|
@@ -486,7 +532,12 @@ def date_diff_in_hours(
|
|
|
486
532
|
|
|
487
533
|
|
|
488
534
|
def date_diff_in_minutes(
|
|
489
|
-
d0: Union[Placeholder, str],
|
|
535
|
+
d0: Union[Placeholder, str],
|
|
536
|
+
d1: Union[Placeholder, str],
|
|
537
|
+
date_format: str = "%Y-%m-%d %H:%M:%S",
|
|
538
|
+
default=None,
|
|
539
|
+
backup_date_format=None,
|
|
540
|
+
none_if_error=False,
|
|
490
541
|
):
|
|
491
542
|
"""
|
|
492
543
|
>>> date_diff_in_minutes('2022-12-19T18:42:23.521Z', '2022-12-19T18:42:23.521Z', date_format='%Y-%m-%dT%H:%M:%S.%fz')
|
|
@@ -501,13 +552,33 @@ def date_diff_in_minutes(
|
|
|
501
552
|
0
|
|
502
553
|
>>> date_diff_in_minutes(Placeholder(), '')
|
|
503
554
|
0
|
|
555
|
+
>>> date_diff_in_minutes('2022-12-19T03:22:12.102Z', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d')
|
|
556
|
+
202
|
|
557
|
+
>>> date_diff_in_minutes('2022-12-19', '2022-12-19', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d')
|
|
558
|
+
0
|
|
559
|
+
>>> date_diff_in_minutes('2022-12-19', '2022-12-18', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d')
|
|
560
|
+
1440
|
|
561
|
+
>>> date_diff_in_minutes('2022-12-19', '2022-12-19 00:01:00', backup_date_format='%Y-%m-%d')
|
|
562
|
+
1
|
|
563
|
+
>>> date_diff_in_minutes('2022-25-19T00:00:03.521Z', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
564
|
+
True
|
|
565
|
+
>>> date_diff_in_minutes('2022-12-19', '2022-25-19', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
566
|
+
True
|
|
567
|
+
>>> date_diff_in_minutes('2022-12-19', '2022-25-19 00:01:00', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
568
|
+
True
|
|
569
|
+
>>> date_diff_in_minutes('2022-25-19T00:00:03.521Z', '2022-12-19 00:23:12', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
570
|
+
True
|
|
571
|
+
>>> date_diff_in_minutes('2022-12-14 18:42:22', '2022/12/19 18:42:22', none_if_error=True) is None
|
|
572
|
+
True
|
|
573
|
+
>>> date_diff_in_minutes('2022-12-14 18:42:22', '2022/12/19 18:42:22', date_format='%Y/%m/%dT%H:%M:%S.%fz', none_if_error=True) is None
|
|
574
|
+
True
|
|
504
575
|
"""
|
|
505
576
|
if isinstance(d0, Placeholder) or isinstance(d1, Placeholder):
|
|
506
577
|
if default:
|
|
507
578
|
return default
|
|
508
579
|
return 0
|
|
509
580
|
try:
|
|
510
|
-
return __date_diff(d0, d1, date_format, "minutes")
|
|
581
|
+
return __date_diff(d0, d1, date_format, backup_date_format, "minutes", none_if_error)
|
|
511
582
|
except Exception:
|
|
512
583
|
raise SQLTemplateException(
|
|
513
584
|
"invalid date_format in function `date_diff_in_seconds`, defaults to YYYY-MM-DD hh:mm:ss. Or %Y-%m-%d %H:%M:%S [.ssssss]Z, e.g. ms: 2022-12-19T18:42:22.591Z s:2022-12-19T18:42:22Z",
|
|
@@ -516,7 +587,12 @@ def date_diff_in_minutes(
|
|
|
516
587
|
|
|
517
588
|
|
|
518
589
|
def date_diff_in_seconds(
|
|
519
|
-
d0: Union[Placeholder, str],
|
|
590
|
+
d0: Union[Placeholder, str],
|
|
591
|
+
d1: Union[Placeholder, str],
|
|
592
|
+
date_format: str = "%Y-%m-%d %H:%M:%S",
|
|
593
|
+
default=None,
|
|
594
|
+
backup_date_format=None,
|
|
595
|
+
none_if_error=False,
|
|
520
596
|
):
|
|
521
597
|
"""
|
|
522
598
|
>>> date_diff_in_seconds('2022-12-19T18:42:23.521Z', '2022-12-19T18:42:23.521Z', date_format='%Y-%m-%dT%H:%M:%S.%fz')
|
|
@@ -537,13 +613,33 @@ def date_diff_in_seconds(
|
|
|
537
613
|
0
|
|
538
614
|
>>> date_diff_in_seconds(Placeholder(), '')
|
|
539
615
|
0
|
|
616
|
+
>>> date_diff_in_seconds('2022-12-19T00:00:03.521Z', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d')
|
|
617
|
+
3
|
|
618
|
+
>>> date_diff_in_seconds('2022-12-19', '2022-12-19', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d')
|
|
619
|
+
0
|
|
620
|
+
>>> date_diff_in_seconds('2022-12-19', '2022-12-19 00:01:00', backup_date_format='%Y-%m-%d')
|
|
621
|
+
60
|
|
622
|
+
>>> date_diff_in_seconds('2022-25-19T00:00:03.521Z', '2022-12-19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
623
|
+
True
|
|
624
|
+
>>> date_diff_in_seconds('2022-12-19', '2022-25-19', '%Y-%m-%dT%H:%M:%Sz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
625
|
+
True
|
|
626
|
+
>>> date_diff_in_seconds('2022-12-19', '2022-25-19 00:01:00', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
627
|
+
True
|
|
628
|
+
>>> date_diff_in_seconds('2022-10-19T00:00:03.521Z', '2022/12/19', date_format='%Y-%m-%dT%H:%M:%S.%fz', backup_date_format='%Y-%m-%d', none_if_error=True) is None
|
|
629
|
+
True
|
|
630
|
+
>>> date_diff_in_seconds('2022-10-19 00:00:03', '2022-10-19 00:05:03', date_format='%Y-%m-%dT%H:%M:%S.%fz', none_if_error=True) is None
|
|
631
|
+
True
|
|
632
|
+
>>> date_diff_in_seconds('2022/12/19 00:00:03', '2022-10-19 00:05:03', none_if_error=True) is None
|
|
633
|
+
True
|
|
634
|
+
>>> date_diff_in_seconds('2022-25-19 00:00:03', '2022-10-19 00:05:03', none_if_error=True) is None
|
|
635
|
+
True
|
|
540
636
|
"""
|
|
541
637
|
if isinstance(d0, Placeholder) or isinstance(d1, Placeholder):
|
|
542
638
|
if default:
|
|
543
639
|
return default
|
|
544
640
|
return 0
|
|
545
641
|
try:
|
|
546
|
-
return __date_diff(d0, d1, date_format, "seconds")
|
|
642
|
+
return __date_diff(d0, d1, date_format, backup_date_format, "seconds", none_if_error)
|
|
547
643
|
except Exception:
|
|
548
644
|
raise SQLTemplateException(
|
|
549
645
|
"invalid date_format in function `date_diff_in_seconds`, defaults to YYYY-MM-DD hh:mm:ss. Or %Y-%m-%d %H:%M:%S [.ssssss]Z, e.g. ms: 2022-12-19T18:42:22.591Z s:2022-12-19T18:42:22Z",
|
|
@@ -551,32 +647,52 @@ def date_diff_in_seconds(
|
|
|
551
647
|
)
|
|
552
648
|
|
|
553
649
|
|
|
554
|
-
def __date_diff(
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
650
|
+
def __date_diff(
|
|
651
|
+
d0: Union[Placeholder, str],
|
|
652
|
+
d1: Union[Placeholder, str],
|
|
653
|
+
date_format: str = "%Y-%m-%d %H:%M:%S",
|
|
654
|
+
backup_date_format=None,
|
|
655
|
+
unit: str = "seconds",
|
|
656
|
+
none_if_error=False,
|
|
657
|
+
):
|
|
559
658
|
try:
|
|
659
|
+
formatted_d0 = _parse_datetime(d0, date_format, backup_date_format)
|
|
660
|
+
formatted_d1 = _parse_datetime(d1, date_format, backup_date_format)
|
|
661
|
+
diff = abs(formatted_d1 - formatted_d0).total_seconds()
|
|
662
|
+
|
|
560
663
|
if unit == "days":
|
|
561
|
-
return int(
|
|
562
|
-
abs((datetime.strptime(d1, date_format) - datetime.strptime(d0, date_format)).total_seconds()) / 86400
|
|
563
|
-
)
|
|
664
|
+
return int(diff / 86400)
|
|
564
665
|
elif unit == "hours":
|
|
565
|
-
return int(
|
|
566
|
-
abs((datetime.strptime(d1, date_format) - datetime.strptime(d0, date_format)).total_seconds()) / 3600
|
|
567
|
-
)
|
|
666
|
+
return int(diff / 3600)
|
|
568
667
|
elif unit == "minutes":
|
|
569
|
-
return int(
|
|
570
|
-
abs((datetime.strptime(d1, date_format) - datetime.strptime(d0, date_format)).total_seconds()) / 60
|
|
571
|
-
)
|
|
668
|
+
return int(diff / 60)
|
|
572
669
|
else:
|
|
573
|
-
return int(
|
|
670
|
+
return int(diff)
|
|
574
671
|
except Exception:
|
|
672
|
+
if none_if_error:
|
|
673
|
+
return None
|
|
674
|
+
|
|
575
675
|
raise SQLTemplateException(
|
|
576
676
|
"invalid date_format in function date_diff_* function", documentation="/cli/advanced-templates.html"
|
|
577
677
|
)
|
|
578
678
|
|
|
579
679
|
|
|
680
|
+
def _parse_datetime(date_string, date_format, backup_date_format=None):
|
|
681
|
+
formats = [date_format]
|
|
682
|
+
if backup_date_format:
|
|
683
|
+
formats.append(backup_date_format)
|
|
684
|
+
|
|
685
|
+
for fmt in formats:
|
|
686
|
+
try:
|
|
687
|
+
return datetime.strptime(date_string, fmt)
|
|
688
|
+
except ValueError:
|
|
689
|
+
continue
|
|
690
|
+
|
|
691
|
+
raise SQLTemplateException(
|
|
692
|
+
"invalid date_format in function date_diff_* function", documentation="/cli/advanced-templates.html"
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
|
|
580
696
|
function_list = {
|
|
581
697
|
"columns": columns,
|
|
582
698
|
"table": table,
|
|
@@ -1542,6 +1542,13 @@ async def prompt(_ctx: Context) -> None:
|
|
|
1542
1542
|
help="Creates new versions of the dependent downstream resources to the changed resources.",
|
|
1543
1543
|
hidden=True,
|
|
1544
1544
|
)
|
|
1545
|
+
@click.option(
|
|
1546
|
+
"--fork",
|
|
1547
|
+
is_flag=True,
|
|
1548
|
+
default=False,
|
|
1549
|
+
help="Creates new versions of the changed resources. Use --fork-downstream to fork also the downstream dependencies of the changed resources.",
|
|
1550
|
+
hidden=True,
|
|
1551
|
+
)
|
|
1545
1552
|
@click.option(
|
|
1546
1553
|
"--is-internal",
|
|
1547
1554
|
is_flag=True,
|
|
@@ -1577,6 +1584,7 @@ async def deploy(
|
|
|
1577
1584
|
folder: str,
|
|
1578
1585
|
user_token: Optional[str],
|
|
1579
1586
|
fork_downstream: bool,
|
|
1587
|
+
fork: bool,
|
|
1580
1588
|
is_internal: bool,
|
|
1581
1589
|
only_changes: bool,
|
|
1582
1590
|
) -> None:
|
|
@@ -1584,32 +1592,43 @@ async def deploy(
|
|
|
1584
1592
|
|
|
1585
1593
|
ignore_sql_errors = FeatureFlags.ignore_sql_errors()
|
|
1586
1594
|
context.disable_template_security_validation.set(True)
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1595
|
+
try:
|
|
1596
|
+
await folder_push(
|
|
1597
|
+
tb_client=create_tb_client(ctx),
|
|
1598
|
+
dry_run=dry_run,
|
|
1599
|
+
check=False,
|
|
1600
|
+
push_deps=True,
|
|
1601
|
+
debug=debug,
|
|
1602
|
+
force=True,
|
|
1603
|
+
git_release=True,
|
|
1604
|
+
only_changes=only_changes,
|
|
1605
|
+
override_datasource=override_datasource,
|
|
1606
|
+
populate=populate,
|
|
1607
|
+
populate_subset=subset,
|
|
1608
|
+
populate_condition=sql_condition,
|
|
1609
|
+
unlink_on_populate_error=unlink_on_populate_error,
|
|
1610
|
+
upload_fixtures=fixtures,
|
|
1611
|
+
wait=wait,
|
|
1612
|
+
ignore_sql_errors=ignore_sql_errors,
|
|
1613
|
+
skip_confirmation=yes,
|
|
1614
|
+
workspace_map=dict(workspace_map),
|
|
1615
|
+
workspace_lib_paths=workspace,
|
|
1616
|
+
timeout=timeout,
|
|
1617
|
+
run_tests=False,
|
|
1618
|
+
folder=folder,
|
|
1619
|
+
config=ctx.ensure_object(dict)["config"],
|
|
1620
|
+
user_token=user_token,
|
|
1621
|
+
fork_downstream=fork_downstream,
|
|
1622
|
+
fork=fork,
|
|
1623
|
+
is_internal=is_internal,
|
|
1624
|
+
)
|
|
1625
|
+
except click.ClickException as e:
|
|
1626
|
+
# custom exceptions coming from the API for the git workflow
|
|
1627
|
+
# FIXME: change this in the API
|
|
1628
|
+
if "--override-datasource" in str(e):
|
|
1629
|
+
new_exception = type(e)(
|
|
1630
|
+
f"{str(e).replace('. If you want to try to force override the Materialized View, please use the `--override-datasource` flag', '')} If you are creating a new Release update the related .datasource files and use --fork-downstream"
|
|
1631
|
+
)
|
|
1632
|
+
raise new_exception
|
|
1633
|
+
else:
|
|
1634
|
+
raise e
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinybird-cli
|
|
3
|
-
Version: 1.2.1.
|
|
3
|
+
Version: 1.2.1.dev2
|
|
4
4
|
Summary: Tinybird Command Line Tool
|
|
5
5
|
Home-page: https://docs.tinybird.co/cli.html
|
|
6
6
|
Author: Tinybird
|
|
@@ -19,6 +19,11 @@ Changelog
|
|
|
19
19
|
|
|
20
20
|
---------
|
|
21
21
|
|
|
22
|
+
1.2.1.dev2
|
|
23
|
+
************
|
|
24
|
+
|
|
25
|
+
- `Changed` Internal change
|
|
26
|
+
|
|
22
27
|
1.2.1.dev1
|
|
23
28
|
************
|
|
24
29
|
|
|
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-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit.py
RENAMED
|
File without changes
|
{tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird/tb_cli_modules/workspace_members.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tinybird-cli-1.2.1.dev1 → tinybird-cli-1.2.1.dev2}/tinybird_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|