tracktolib 0.48.1__py3-none-any.whl → 0.49.0__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.
- tracktolib/api.py +1 -1
- tracktolib/http_utils.py +2 -4
- tracktolib/logs.py +2 -4
- tracktolib/pg/query.py +5 -10
- tracktolib/pg_sync.py +5 -8
- tracktolib/s3/minio.py +8 -2
- tracktolib/tests.py +0 -6
- tracktolib/utils.py +7 -14
- {tracktolib-0.48.1.dist-info → tracktolib-0.49.0.dist-info}/METADATA +15 -15
- tracktolib-0.49.0.dist-info/RECORD +19 -0
- {tracktolib-0.48.1.dist-info → tracktolib-0.49.0.dist-info}/WHEEL +1 -1
- tracktolib-0.48.1.dist-info/RECORD +0 -19
- {tracktolib-0.48.1.dist-info → tracktolib-0.49.0.dist-info}/LICENSE +0 -0
tracktolib/api.py
CHANGED
|
@@ -44,7 +44,7 @@ def Depends(
|
|
|
44
44
|
use_cache: bool = True,
|
|
45
45
|
) -> D:
|
|
46
46
|
"""TODO: add support for __call__ (maybe see https://github.com/python/typing/discussions/1106 ?)"""
|
|
47
|
-
return params.Depends(dependency, use_cache=use_cache) # pyright: ignore [
|
|
47
|
+
return params.Depends(dependency, use_cache=use_cache) # pyright: ignore [reportReturnType]
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
B = TypeVar("B", bound=BaseModel | None | Sequence[BaseModel])
|
tracktolib/http_utils.py
CHANGED
|
@@ -22,8 +22,7 @@ async def download_file(
|
|
|
22
22
|
on_response: Callable[[httpx.Response], None] | None = None,
|
|
23
23
|
params: QueryParamTypes | None = None,
|
|
24
24
|
headers: dict[str, str] | None = None,
|
|
25
|
-
):
|
|
26
|
-
...
|
|
25
|
+
): ...
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
@typing.overload
|
|
@@ -37,8 +36,7 @@ async def download_file(
|
|
|
37
36
|
on_response: Callable[[httpx.Response], None] | None = None,
|
|
38
37
|
params: QueryParamTypes | None = None,
|
|
39
38
|
headers: dict[str, str] | None = None,
|
|
40
|
-
):
|
|
41
|
-
...
|
|
39
|
+
): ...
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
async def download_file(
|
tracktolib/logs.py
CHANGED
|
@@ -33,8 +33,7 @@ def init_logging(
|
|
|
33
33
|
version: str,
|
|
34
34
|
*,
|
|
35
35
|
stream_handler: logging.StreamHandler | None = None,
|
|
36
|
-
) -> tuple[CustomJsonFormatter, logging.StreamHandler]:
|
|
37
|
-
...
|
|
36
|
+
) -> tuple[CustomJsonFormatter, logging.StreamHandler]: ...
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
@overload
|
|
@@ -44,8 +43,7 @@ def init_logging(
|
|
|
44
43
|
version: str,
|
|
45
44
|
*,
|
|
46
45
|
stream_handler: logging.StreamHandler | None = None,
|
|
47
|
-
) -> tuple[logging.Formatter, logging.StreamHandler]:
|
|
48
|
-
...
|
|
46
|
+
) -> tuple[logging.Formatter, logging.StreamHandler]: ...
|
|
49
47
|
|
|
50
48
|
|
|
51
49
|
def init_logging(
|
tracktolib/pg/query.py
CHANGED
|
@@ -321,8 +321,7 @@ async def insert_many(
|
|
|
321
321
|
@overload
|
|
322
322
|
async def insert_returning(
|
|
323
323
|
conn: _Connection, table: str, item: dict, returning: str, on_conflict: OnConflict | None = None, fill: bool = False
|
|
324
|
-
) -> Any | None:
|
|
325
|
-
...
|
|
324
|
+
) -> Any | None: ...
|
|
326
325
|
|
|
327
326
|
|
|
328
327
|
@overload
|
|
@@ -333,8 +332,7 @@ async def insert_returning(
|
|
|
333
332
|
returning: list[str],
|
|
334
333
|
on_conflict: OnConflict | None = None,
|
|
335
334
|
fill: bool = False,
|
|
336
|
-
) -> asyncpg.Record | None:
|
|
337
|
-
...
|
|
335
|
+
) -> asyncpg.Record | None: ...
|
|
338
336
|
|
|
339
337
|
|
|
340
338
|
async def insert_returning(
|
|
@@ -388,8 +386,7 @@ async def update_returning(
|
|
|
388
386
|
where: str | None = None,
|
|
389
387
|
keys: list[str] | None = None,
|
|
390
388
|
start_from: int | None = None,
|
|
391
|
-
) -> Any | None:
|
|
392
|
-
...
|
|
389
|
+
) -> Any | None: ...
|
|
393
390
|
|
|
394
391
|
|
|
395
392
|
@overload
|
|
@@ -403,8 +400,7 @@ async def update_returning(
|
|
|
403
400
|
where: str | None = None,
|
|
404
401
|
keys: list[str] | None = None,
|
|
405
402
|
start_from: int | None = None,
|
|
406
|
-
) -> asyncpg.Record | None:
|
|
407
|
-
...
|
|
403
|
+
) -> asyncpg.Record | None: ...
|
|
408
404
|
|
|
409
405
|
|
|
410
406
|
@overload
|
|
@@ -418,8 +414,7 @@ async def update_returning(
|
|
|
418
414
|
where: str | None = None,
|
|
419
415
|
keys: list[str] | None = None,
|
|
420
416
|
start_from: int | None = None,
|
|
421
|
-
) -> asyncpg.Record | None:
|
|
422
|
-
...
|
|
417
|
+
) -> asyncpg.Record | None: ...
|
|
423
418
|
|
|
424
419
|
|
|
425
420
|
async def update_returning(
|
tracktolib/pg_sync.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Iterable, Any, overload, Literal, cast
|
|
2
|
+
from typing import Iterable, Any, overload, Literal, cast, Optional
|
|
3
3
|
|
|
4
4
|
from typing_extensions import LiteralString
|
|
5
5
|
|
|
@@ -32,18 +32,15 @@ def fetch_count(engine: Connection, table: str, *args, where: str | None = None)
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
@overload
|
|
35
|
-
def fetch_one(engine: Connection, query: Query, *args, required: Literal[False]) -> dict | None:
|
|
36
|
-
...
|
|
35
|
+
def fetch_one(engine: Connection, query: Query, *args, required: Literal[False]) -> dict | None: ...
|
|
37
36
|
|
|
38
37
|
|
|
39
38
|
@overload
|
|
40
|
-
def fetch_one(engine: Connection, query: Query, *args, required: Literal[True]) -> dict:
|
|
41
|
-
...
|
|
39
|
+
def fetch_one(engine: Connection, query: Query, *args, required: Literal[True]) -> dict: ...
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
@overload
|
|
45
|
-
def fetch_one(engine: Connection, query: Query, *args) -> dict | None:
|
|
46
|
-
...
|
|
43
|
+
def fetch_one(engine: Connection, query: Query, *args) -> dict | None: ...
|
|
47
44
|
|
|
48
45
|
|
|
49
46
|
def fetch_one(engine: Connection, query: Query, *args, required: bool = False) -> dict | None:
|
|
@@ -121,7 +118,7 @@ def insert_csv(
|
|
|
121
118
|
schema: LiteralString,
|
|
122
119
|
table: LiteralString,
|
|
123
120
|
csv_path: Path,
|
|
124
|
-
query: Query
|
|
121
|
+
query: Optional[Query] = None,
|
|
125
122
|
*,
|
|
126
123
|
exclude_columns: Iterable[str] | None = None,
|
|
127
124
|
delimiter: LiteralString = ",",
|
tracktolib/s3/minio.py
CHANGED
|
@@ -10,6 +10,8 @@ except ImportError:
|
|
|
10
10
|
def download_bucket(minio: Minio, bucket_name: str, output_dir: Path) -> list[Path]:
|
|
11
11
|
files = []
|
|
12
12
|
for obj in minio.list_objects(bucket_name, recursive=True):
|
|
13
|
+
if obj.object_name is None:
|
|
14
|
+
raise ValueError("object_name is empty")
|
|
13
15
|
data = minio.get_object(bucket_name, obj.object_name)
|
|
14
16
|
_file = output_dir / obj.object_name
|
|
15
17
|
_file.parent.mkdir(exist_ok=True, parents=True)
|
|
@@ -22,7 +24,11 @@ def download_bucket(minio: Minio, bucket_name: str, output_dir: Path) -> list[Pa
|
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
def bucket_rm(minio: Minio, bucket_name: str):
|
|
25
|
-
names = [
|
|
27
|
+
names = [
|
|
28
|
+
DeleteObject(x.object_name)
|
|
29
|
+
for x in minio.list_objects(bucket_name, recursive=True)
|
|
30
|
+
if x.object_name is not None
|
|
31
|
+
]
|
|
26
32
|
errors = minio.remove_objects(bucket_name, names)
|
|
27
33
|
errors = list(errors)
|
|
28
34
|
if errors:
|
|
@@ -31,4 +37,4 @@ def bucket_rm(minio: Minio, bucket_name: str):
|
|
|
31
37
|
|
|
32
38
|
|
|
33
39
|
def upload_object(minio: Minio, bucket_name: str, object_name: str, path: Path):
|
|
34
|
-
minio.fput_object(bucket_name, object_name, path.absolute())
|
|
40
|
+
minio.fput_object(bucket_name, object_name, str(path.absolute()))
|
tracktolib/tests.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import pprint
|
|
2
2
|
from typing import Iterable
|
|
3
|
-
import warnings
|
|
4
3
|
|
|
5
4
|
try:
|
|
6
5
|
import deepdiff
|
|
@@ -8,11 +7,6 @@ except ImportError:
|
|
|
8
7
|
raise ImportError('Please install deepdiff or tracktolib with "tests" to use this module')
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
def get_uuid(i: int = 0):
|
|
12
|
-
warnings.warn("Please use uuid.UUID(int=i) instead", DeprecationWarning)
|
|
13
|
-
return f"00000000-0000-0000-0000-000000{i:06}"
|
|
14
|
-
|
|
15
|
-
|
|
16
10
|
def assert_equals(d1: dict | Iterable, d2: dict | Iterable, *, ignore_order: bool = False):
|
|
17
11
|
diff = deepdiff.DeepDiff(d1, d2, ignore_order=ignore_order)
|
|
18
12
|
assert not diff, pprint.pprint(diff)
|
tracktolib/utils.py
CHANGED
|
@@ -58,18 +58,15 @@ def import_module(path: Path):
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
@overload
|
|
61
|
-
def get_chunks(it: Iterable[T], size: int, *, as_list: Literal[False]) -> Iterator[Iterable[T]]:
|
|
62
|
-
...
|
|
61
|
+
def get_chunks(it: Iterable[T], size: int, *, as_list: Literal[False]) -> Iterator[Iterable[T]]: ...
|
|
63
62
|
|
|
64
63
|
|
|
65
64
|
@overload
|
|
66
|
-
def get_chunks(it: Iterable[T], size: int, *, as_list: Literal[True]) -> Iterator[list[T]]:
|
|
67
|
-
...
|
|
65
|
+
def get_chunks(it: Iterable[T], size: int, *, as_list: Literal[True]) -> Iterator[list[T]]: ...
|
|
68
66
|
|
|
69
67
|
|
|
70
68
|
@overload
|
|
71
|
-
def get_chunks(it: Iterable[T], size: int) -> Iterator[list[T]]:
|
|
72
|
-
...
|
|
69
|
+
def get_chunks(it: Iterable[T], size: int) -> Iterator[list[T]]: ...
|
|
73
70
|
|
|
74
71
|
|
|
75
72
|
def get_chunks(it: Iterable[T], size: int, *, as_list: bool = True) -> Iterator[Iterable[T]]:
|
|
@@ -125,13 +122,11 @@ def to_camel_case(string: str) -> str:
|
|
|
125
122
|
|
|
126
123
|
|
|
127
124
|
@overload
|
|
128
|
-
def dict_to_camel(d: dict) -> dict:
|
|
129
|
-
...
|
|
125
|
+
def dict_to_camel(d: dict) -> dict: ...
|
|
130
126
|
|
|
131
127
|
|
|
132
128
|
@overload
|
|
133
|
-
def dict_to_camel(d: list[dict]) -> list[dict]:
|
|
134
|
-
...
|
|
129
|
+
def dict_to_camel(d: list[dict]) -> list[dict]: ...
|
|
135
130
|
|
|
136
131
|
|
|
137
132
|
def dict_to_camel(d: dict | list):
|
|
@@ -152,13 +147,11 @@ def dict_to_camel(d: dict | list):
|
|
|
152
147
|
|
|
153
148
|
|
|
154
149
|
@overload
|
|
155
|
-
def rm_keys(data: dict, keys: list[str]) -> dict:
|
|
156
|
-
...
|
|
150
|
+
def rm_keys(data: dict, keys: list[str]) -> dict: ...
|
|
157
151
|
|
|
158
152
|
|
|
159
153
|
@overload
|
|
160
|
-
def rm_keys(data: list[dict], keys: list[str]) -> list[dict]:
|
|
161
|
-
...
|
|
154
|
+
def rm_keys(data: list[dict], keys: list[str]) -> list[dict]: ...
|
|
162
155
|
|
|
163
156
|
|
|
164
157
|
def rm_keys(data: dict | list[dict], keys: list[str]):
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tracktolib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.49.0
|
|
4
4
|
Summary: Utility library for python
|
|
5
5
|
Home-page: https://github.com/tracktor/tracktolib
|
|
6
6
|
License: MIT
|
|
7
7
|
Keywords: utility
|
|
8
8
|
Author: Julien Brayere
|
|
9
9
|
Author-email: julien.brayere@tracktor.fr
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.12,<4.0
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
15
|
Provides-Extra: api
|
|
17
16
|
Provides-Extra: http
|
|
18
17
|
Provides-Extra: logs
|
|
@@ -21,16 +20,17 @@ Provides-Extra: pg-sync
|
|
|
21
20
|
Provides-Extra: s3
|
|
22
21
|
Provides-Extra: s3-minio
|
|
23
22
|
Provides-Extra: tests
|
|
24
|
-
Requires-Dist: aiobotocore (>=2.9.0); extra == "s3"
|
|
25
|
-
Requires-Dist: asyncpg (>=0.27.0); extra == "pg"
|
|
26
|
-
Requires-Dist: deepdiff (>=6.6.0); extra == "tests"
|
|
27
|
-
Requires-Dist: fastapi (>=0.103.2); extra == "api"
|
|
28
|
-
Requires-Dist: httpx (>=0.25.0); extra == "http"
|
|
29
|
-
Requires-Dist: minio (>=7.2.0); extra == "s3-minio"
|
|
30
|
-
Requires-Dist: psycopg (>=3.1.12); extra == "pg-sync"
|
|
31
|
-
Requires-Dist:
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: aiobotocore (>=2.9.0) ; extra == "s3"
|
|
24
|
+
Requires-Dist: asyncpg (>=0.27.0) ; extra == "pg"
|
|
25
|
+
Requires-Dist: deepdiff (>=6.6.0) ; extra == "tests"
|
|
26
|
+
Requires-Dist: fastapi (>=0.103.2) ; extra == "api"
|
|
27
|
+
Requires-Dist: httpx (>=0.25.0) ; extra == "http"
|
|
28
|
+
Requires-Dist: minio (>=7.2.0) ; extra == "s3-minio"
|
|
29
|
+
Requires-Dist: psycopg (>=3.1.12) ; extra == "pg-sync"
|
|
30
|
+
Requires-Dist: pycryptodome (>=3.20.0) ; extra == "s3-minio"
|
|
31
|
+
Requires-Dist: pydantic (>=2) ; extra == "api"
|
|
32
|
+
Requires-Dist: python-json-logger (>=2.0.4) ; extra == "logs"
|
|
33
|
+
Requires-Dist: rich (>=13.6.0) ; extra == "pg"
|
|
34
34
|
Project-URL: Repository, https://github.com/tracktor/tracktolib
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
36
36
|
|
|
@@ -80,7 +80,7 @@ To use the functions, create a `Connection` using psycopg: `conn = psycopg2.conn
|
|
|
80
80
|
*fetch_one*
|
|
81
81
|
|
|
82
82
|
```python
|
|
83
|
-
from pg.pg_sync import (
|
|
83
|
+
from tracktolib.pg.pg_sync import (
|
|
84
84
|
insert_many, fetch_one, fetch_count, fetch_all
|
|
85
85
|
)
|
|
86
86
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
LICENSE,sha256=uUanH0X7SeZEPdsRTHegMSMTiIHMurt9H0jSwEwKE1Y,1081
|
|
2
|
+
tracktolib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
tracktolib/api.py,sha256=xArVgRj_g7bw2tEDbjC9qs9f55b9X0-kJoc8-s1rsYo,9616
|
|
4
|
+
tracktolib/http_utils.py,sha256=c10JGmHaBw3VSDMYhz2dvVw2lo4PUAq1xMub74I7xDc,2625
|
|
5
|
+
tracktolib/logs.py,sha256=M5RZ8OYKgLEBJeC1AwUCSRbFAH09hwdTjjs-AQ9QGg8,2204
|
|
6
|
+
tracktolib/pg/__init__.py,sha256=32kKBJzIDyppszZMAOSMgM3ggz7Ow0TaNKiMs740gyw,333
|
|
7
|
+
tracktolib/pg/query.py,sha256=KESY4g0XePUrRIakygmzhPP2vIOfJGWc2PAZsIj_PfI,13580
|
|
8
|
+
tracktolib/pg/utils.py,sha256=cL24KEt4SWJQ7LJPzaO3c8Xg0ZLmjhn22DtTWg86nwc,6324
|
|
9
|
+
tracktolib/pg_sync.py,sha256=OsmEbFzqlJDm1jfuxpFi2Lhjj9nEGxGlnNmZCnqWZ6c,5106
|
|
10
|
+
tracktolib/pg_utils.py,sha256=8DDlZVSgfNie9M-zL7wilFufXMMvSPw5d7aIDs_pQCM,1976
|
|
11
|
+
tracktolib/s3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
tracktolib/s3/minio.py,sha256=wMEjkSes9Fp39fD17IctALpD6zB2xwDRQEmO7Vzan3g,1387
|
|
13
|
+
tracktolib/s3/s3.py,sha256=d0Q63Zb62ef4jAt05zQwpgYvAoxHC9kSQuHzzK90VvE,4825
|
|
14
|
+
tracktolib/tests.py,sha256=Pbc4yGQrIWFLBEgX-kDBxhMCqH-bfOJtkH2agvaM6ZQ,382
|
|
15
|
+
tracktolib/utils.py,sha256=jwLww8bqDu8zEip9uN4yW0lE5_YMWfrAHYtagr8sYOA,5295
|
|
16
|
+
tracktolib-0.49.0.dist-info/LICENSE,sha256=uUanH0X7SeZEPdsRTHegMSMTiIHMurt9H0jSwEwKE1Y,1081
|
|
17
|
+
tracktolib-0.49.0.dist-info/METADATA,sha256=jwSGn-VdiGimYNLizSMhI_cLSyM8GgQDNkickFcfJ-4,3641
|
|
18
|
+
tracktolib-0.49.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
19
|
+
tracktolib-0.49.0.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
LICENSE,sha256=uUanH0X7SeZEPdsRTHegMSMTiIHMurt9H0jSwEwKE1Y,1081
|
|
2
|
-
tracktolib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
tracktolib/api.py,sha256=UaALaBPTbWICGVxzZIxvSVVWi_DjMzfjtB_vGc-K7sI,9623
|
|
4
|
-
tracktolib/http_utils.py,sha256=dqjRJTNCo1qDnvQBTcImw1ibi1LnqETrpWDAU5txBHs,2633
|
|
5
|
-
tracktolib/logs.py,sha256=enezPjBU4v2s8knG_V6kIbQsoyxfNIKEpKVSSkr_2U8,2212
|
|
6
|
-
tracktolib/pg/__init__.py,sha256=32kKBJzIDyppszZMAOSMgM3ggz7Ow0TaNKiMs740gyw,333
|
|
7
|
-
tracktolib/pg/query.py,sha256=cOmMhAjCDvcNJpIDh2OJP3AQK-Ax-dZQpNj5nZTk06Y,13600
|
|
8
|
-
tracktolib/pg/utils.py,sha256=cL24KEt4SWJQ7LJPzaO3c8Xg0ZLmjhn22DtTWg86nwc,6324
|
|
9
|
-
tracktolib/pg_sync.py,sha256=pjeHuLmBAkof16FhPXfFyK4nfThEnsISF3US5lzBw-0,5105
|
|
10
|
-
tracktolib/pg_utils.py,sha256=8DDlZVSgfNie9M-zL7wilFufXMMvSPw5d7aIDs_pQCM,1976
|
|
11
|
-
tracktolib/s3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
tracktolib/s3/minio.py,sha256=JaRpHOM6NqpMieplp58Fpc7uTh7PItyP8On7jMXhB-Q,1234
|
|
13
|
-
tracktolib/s3/s3.py,sha256=d0Q63Zb62ef4jAt05zQwpgYvAoxHC9kSQuHzzK90VvE,4825
|
|
14
|
-
tracktolib/tests.py,sha256=FS0uae3ShiiJOD7WE2WEv9h3QwRJCbLDHpe_8Ikc0j0,554
|
|
15
|
-
tracktolib/utils.py,sha256=usiUYVwMa43RvqpKJmQDmzhvfahSVMW0OAcyVWWfPkg,5323
|
|
16
|
-
tracktolib-0.48.1.dist-info/LICENSE,sha256=uUanH0X7SeZEPdsRTHegMSMTiIHMurt9H0jSwEwKE1Y,1081
|
|
17
|
-
tracktolib-0.48.1.dist-info/WHEEL,sha256=vxFmldFsRN_Hx10GDvsdv1wroKq8r5Lzvjp6GZ4OO8c,88
|
|
18
|
-
tracktolib-0.48.1.dist-info/METADATA,sha256=HbP82J7Y04AIb7oBa1WGbgUSUXBCNfkFe7QeQQoBSQo,3610
|
|
19
|
-
tracktolib-0.48.1.dist-info/RECORD,,
|
|
File without changes
|