kleinkram 0.38.1.dev20241120100707__py3-none-any.whl → 0.38.1.dev20241125112529__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kleinkram might be problematic. Click here for more details.
- kleinkram/api/client.py +31 -23
- kleinkram/api/file_transfer.py +323 -203
- kleinkram/api/parsing.py +86 -0
- kleinkram/api/routes.py +77 -311
- kleinkram/app.py +20 -54
- kleinkram/auth.py +0 -2
- kleinkram/commands/download.py +60 -60
- kleinkram/commands/list.py +53 -48
- kleinkram/commands/mission.py +25 -13
- kleinkram/commands/upload.py +79 -53
- kleinkram/commands/verify.py +58 -35
- kleinkram/config.py +2 -3
- kleinkram/errors.py +48 -31
- kleinkram/models.py +2 -2
- kleinkram/resources.py +158 -0
- kleinkram/utils.py +16 -47
- {kleinkram-0.38.1.dev20241120100707.dist-info → kleinkram-0.38.1.dev20241125112529.dist-info}/METADATA +5 -3
- kleinkram-0.38.1.dev20241125112529.dist-info/RECORD +37 -0
- {kleinkram-0.38.1.dev20241120100707.dist-info → kleinkram-0.38.1.dev20241125112529.dist-info}/WHEEL +1 -1
- tests/test_end_to_end.py +105 -0
- tests/test_resources.py +137 -0
- tests/test_utils.py +13 -59
- kleinkram-0.38.1.dev20241120100707.dist-info/RECORD +0 -33
- {kleinkram-0.38.1.dev20241120100707.dist-info → kleinkram-0.38.1.dev20241125112529.dist-info}/LICENSE +0 -0
- {kleinkram-0.38.1.dev20241120100707.dist-info → kleinkram-0.38.1.dev20241125112529.dist-info}/entry_points.txt +0 -0
- {kleinkram-0.38.1.dev20241120100707.dist-info → kleinkram-0.38.1.dev20241125112529.dist-info}/top_level.txt +0 -0
kleinkram/utils.py
CHANGED
|
@@ -10,7 +10,6 @@ from pathlib import Path
|
|
|
10
10
|
from typing import Any
|
|
11
11
|
from typing import Dict
|
|
12
12
|
from typing import List
|
|
13
|
-
from typing import Optional
|
|
14
13
|
from typing import Sequence
|
|
15
14
|
from typing import Tuple
|
|
16
15
|
from typing import Union
|
|
@@ -19,18 +18,22 @@ from uuid import UUID
|
|
|
19
18
|
import yaml
|
|
20
19
|
from kleinkram._version import __version__
|
|
21
20
|
from kleinkram.errors import FileTypeNotSupported
|
|
22
|
-
from kleinkram.errors import InvalidFileSpec
|
|
23
|
-
from kleinkram.errors import InvalidMissionSpec
|
|
24
|
-
from kleinkram.models import FilesById
|
|
25
|
-
from kleinkram.models import FilesByMission
|
|
26
|
-
from kleinkram.models import MissionById
|
|
27
|
-
from kleinkram.models import MissionByName
|
|
28
21
|
from rich.console import Console
|
|
29
22
|
|
|
30
|
-
|
|
31
23
|
INTERNAL_ALLOWED_CHARS = string.ascii_letters + string.digits + "_" + "-"
|
|
32
24
|
|
|
33
25
|
|
|
26
|
+
def split_args(args: List[str]) -> Tuple[List[UUID], List[str]]:
|
|
27
|
+
uuids = []
|
|
28
|
+
names = []
|
|
29
|
+
for arg in args:
|
|
30
|
+
if is_valid_uuid4(arg):
|
|
31
|
+
uuids.append(UUID(arg, version=4))
|
|
32
|
+
else:
|
|
33
|
+
names.append(arg)
|
|
34
|
+
return uuids, names
|
|
35
|
+
|
|
36
|
+
|
|
34
37
|
def check_file_paths(files: Sequence[Path]) -> None:
|
|
35
38
|
for file in files:
|
|
36
39
|
if file.is_dir():
|
|
@@ -43,6 +46,11 @@ def check_file_paths(files: Sequence[Path]) -> None:
|
|
|
43
46
|
)
|
|
44
47
|
|
|
45
48
|
|
|
49
|
+
def noop(*args: Any, **kwargs: Any) -> None:
|
|
50
|
+
_ = args, kwargs # suppress unused variable warning
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
|
|
46
54
|
def format_error(msg: str, exc: Exception, *, verbose: bool = False) -> str:
|
|
47
55
|
if not verbose:
|
|
48
56
|
ret = f"{msg}: {type(exc).__name__}"
|
|
@@ -137,45 +145,6 @@ def b64_md5(file: Path) -> str:
|
|
|
137
145
|
return base64.b64encode(binary_digest).decode("utf-8")
|
|
138
146
|
|
|
139
147
|
|
|
140
|
-
def get_valid_mission_spec(
|
|
141
|
-
mission: Union[str, UUID],
|
|
142
|
-
project: Optional[Union[str, UUID]] = None,
|
|
143
|
-
) -> Union[MissionById, MissionByName]:
|
|
144
|
-
"""\
|
|
145
|
-
checks if:
|
|
146
|
-
- atleast one is speicifed
|
|
147
|
-
- if project is not specified then mission must be a valid uuid4
|
|
148
|
-
"""
|
|
149
|
-
|
|
150
|
-
if isinstance(mission, UUID):
|
|
151
|
-
return MissionById(id=mission)
|
|
152
|
-
if isinstance(mission, str) and project is not None:
|
|
153
|
-
return MissionByName(name=mission, project=project)
|
|
154
|
-
raise InvalidMissionSpec("must specify mission id or project name / id")
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def get_valid_file_spec(
|
|
158
|
-
files: Sequence[Union[str, UUID]],
|
|
159
|
-
mission: Optional[Union[str, UUID]] = None,
|
|
160
|
-
project: Optional[Union[str, UUID]] = None,
|
|
161
|
-
) -> Union[FilesById, FilesByMission]:
|
|
162
|
-
"""\
|
|
163
|
-
"""
|
|
164
|
-
if not any([project, mission, files]):
|
|
165
|
-
raise InvalidFileSpec("must specify `project`, `mission` or `files`")
|
|
166
|
-
|
|
167
|
-
# if only files are specified they must be valid uuid4
|
|
168
|
-
if project is None and mission is None:
|
|
169
|
-
if all(map(lambda file: isinstance(file, UUID), files)):
|
|
170
|
-
return FilesById(ids=files) # type: ignore
|
|
171
|
-
raise InvalidFileSpec("if no mission is specified files must be valid uuid4")
|
|
172
|
-
|
|
173
|
-
if mission is None:
|
|
174
|
-
raise InvalidMissionSpec("mission must be specified")
|
|
175
|
-
mission_spec = get_valid_mission_spec(mission, project)
|
|
176
|
-
return FilesByMission(mission=mission_spec, files=list(files))
|
|
177
|
-
|
|
178
|
-
|
|
179
148
|
def to_name_or_uuid(s: str) -> Union[UUID, str]:
|
|
180
149
|
if is_valid_uuid4(s):
|
|
181
150
|
return UUID(s)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kleinkram
|
|
3
|
-
Version: 0.38.1.
|
|
3
|
+
Version: 0.38.1.dev20241125112529
|
|
4
4
|
Summary: give me your bags
|
|
5
5
|
Author: Cyrill Püntener, Dominique Garmier, Johann Schwabe
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -109,5 +109,7 @@ klein --help
|
|
|
109
109
|
```bash
|
|
110
110
|
pytest .
|
|
111
111
|
```
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
or if you want to skip slow tests...
|
|
113
|
+
```bash
|
|
114
|
+
pytest -m "not slow" .
|
|
115
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
kleinkram/__init__.py,sha256=adI-FqfuuH56n8U-lJa3uZkH_saxi7dr4Hox_HBuf9A,107
|
|
2
|
+
kleinkram/__main__.py,sha256=B9RiZxfO4jpCmWPUHyKJ7_EoZlEG4sPpH-nz7T_YhhQ,125
|
|
3
|
+
kleinkram/_version.py,sha256=QYJyRTcqFcJj4qWYpqs7WcoOP6jxDMqyvxLY-cD6KcE,129
|
|
4
|
+
kleinkram/app.py,sha256=dhXHl9xYXnfahXKbkyNI_EpTvtmmsrEjxbpPOANI7SY,5584
|
|
5
|
+
kleinkram/auth.py,sha256=G1RRyJBMR1IFLL2lR3D2RjkYtlkHWXZwCHRP-bRKKmk,2857
|
|
6
|
+
kleinkram/config.py,sha256=-MEgsSAzQg7jUSr8czRj8Y2DxbqMIKPDy4HBvnZ2oaI,4373
|
|
7
|
+
kleinkram/consts.py,sha256=70GELDssDm-YeIbChBRTscnNRcyWRUDWWlYBjVWNLDk,205
|
|
8
|
+
kleinkram/core.py,sha256=XmNhg1i520w-9et8r0LSQRsVN09gJgSXfyHRV1tu2rM,227
|
|
9
|
+
kleinkram/enums.py,sha256=bX0H8_xkh_7DRycJYII8MTjHmjbcFW9ZJ3tzlzRhT2k,149
|
|
10
|
+
kleinkram/errors.py,sha256=PVwgUAIuPie8uufN1UuuEAGQR-K41jFSygE1bMdhCwo,1869
|
|
11
|
+
kleinkram/main.py,sha256=hmFuSnE2p-E4nZ2zDVToOsoELZhosLN0r4wsXnbmsas,168
|
|
12
|
+
kleinkram/models.py,sha256=FFsbgcWN6GH3dFcbRDN2IPiVZ1wQG-FbYGtM64JaI_E,4303
|
|
13
|
+
kleinkram/resources.py,sha256=LqSLU5WPQOZZGG6w6-8E_Uy3B2AOc6dRjyZYiTByunY,4684
|
|
14
|
+
kleinkram/utils.py,sha256=BG6BrNc5eNARQ0nG4J2_rEK28bX--8KwwA2eIdXZo3o,4619
|
|
15
|
+
kleinkram/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
kleinkram/api/client.py,sha256=L0e6-KxpEmhNH-Z0_FgAIFqhAERRphlpyffjky8umOA,3385
|
|
17
|
+
kleinkram/api/file_transfer.py,sha256=pI9QKSpZFeIPY6fFwWsBxQr0PE9UW97Dp8UlKRZ5owY,13144
|
|
18
|
+
kleinkram/api/parsing.py,sha256=bvUwrSrM9SnDs_TGRq-HHOvH9hu3aTAq5S_bNLHA3Wk,2549
|
|
19
|
+
kleinkram/api/routes.py,sha256=o-ZoQlK3pZ1jx-sD2-EXEXAa5XZ8BsIXa0jLQ0Ogst4,6062
|
|
20
|
+
kleinkram/commands/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
21
|
+
kleinkram/commands/download.py,sha256=LydLgo3MMBfp35eENOKxuvV8z3eTSmmANcMcSQpgB88,3368
|
|
22
|
+
kleinkram/commands/endpoint.py,sha256=VgaleKTev8Muu4OmS4tptbhrbl58u1UTAxEmoLBCQew,1642
|
|
23
|
+
kleinkram/commands/list.py,sha256=NmTI6j-w-pp4Xf-U02HgKayb2U5H_3TvUytudY1lMNg,3316
|
|
24
|
+
kleinkram/commands/mission.py,sha256=on1mYcYbixOSqhciqB2GugmO2WyzZN4jgoS0mA78BaU,2214
|
|
25
|
+
kleinkram/commands/project.py,sha256=q-kJ1YQr-Axo-Zl0qe2J7eGGgKlSbcdDjpAJIynRLaM,587
|
|
26
|
+
kleinkram/commands/upload.py,sha256=rKS7_zPfHpOm6UG595Wfn9AKEAJ0sr9aqScpyaKruwo,5102
|
|
27
|
+
kleinkram/commands/verify.py,sha256=96yBA7rpQRsAdSGPZXE6gpvnw7e_patex2XqvNeDJLc,4841
|
|
28
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
+
tests/test_end_to_end.py,sha256=uGNsNz9HszzKYSXMUcTYzjMuYJkCEWjE9yt3IszcsY0,2855
|
|
30
|
+
tests/test_resources.py,sha256=y6Ibi1fn7oBV19-XVtgwqLLOYKAGwi7DcimkG5CLPI8,3802
|
|
31
|
+
tests/test_utils.py,sha256=zFtr66_TV68xcGchX64jRS-08mwWE-WghS6F3GXRpIc,4018
|
|
32
|
+
kleinkram-0.38.1.dev20241125112529.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
33
|
+
kleinkram-0.38.1.dev20241125112529.dist-info/METADATA,sha256=NIoNLmkeTm4u4ap17SyRZ8yU96pqQvN5ciQjN1JBnO4,2324
|
|
34
|
+
kleinkram-0.38.1.dev20241125112529.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
35
|
+
kleinkram-0.38.1.dev20241125112529.dist-info/entry_points.txt,sha256=SaB2l5aqhSr8gmaMw2kvQU90a8Bnl7PedU8cWYxkfYo,46
|
|
36
|
+
kleinkram-0.38.1.dev20241125112529.dist-info/top_level.txt,sha256=G1Lj9vHAtZn402Ukkrfll-6BCmnDNy_HVtWeNvXzdDA,16
|
|
37
|
+
kleinkram-0.38.1.dev20241125112529.dist-info/RECORD,,
|
tests/test_end_to_end.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import secrets
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from kleinkram.api.routes import _get_api_version
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.text import Text
|
|
12
|
+
|
|
13
|
+
VERBOSE = True
|
|
14
|
+
|
|
15
|
+
CLI = "klein"
|
|
16
|
+
PROJECT_NAME = "automated-testing"
|
|
17
|
+
|
|
18
|
+
DATA_DIR = Path(__file__).parent.parent / "data" / "testing"
|
|
19
|
+
_IN_DIR = DATA_DIR / "in"
|
|
20
|
+
_OUT_DIR = DATA_DIR / "out"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture(scope="session")
|
|
24
|
+
def api():
|
|
25
|
+
try:
|
|
26
|
+
_get_api_version()
|
|
27
|
+
return True
|
|
28
|
+
except Exception:
|
|
29
|
+
print("API is not available")
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture(scope="session")
|
|
34
|
+
def in_dir():
|
|
35
|
+
return _IN_DIR
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.fixture(scope="session")
|
|
39
|
+
def out_dir():
|
|
40
|
+
try:
|
|
41
|
+
_OUT_DIR.mkdir(exist_ok=True)
|
|
42
|
+
yield _OUT_DIR
|
|
43
|
+
finally:
|
|
44
|
+
shutil.rmtree(_OUT_DIR)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.fixture(scope="session")
|
|
48
|
+
def name():
|
|
49
|
+
return secrets.token_hex(8)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run_cmd(command, *, verbose=VERBOSE):
|
|
53
|
+
msg = ("\n", "#" * 50, "\n\n", "running command:", Text(command, style="bold"))
|
|
54
|
+
Console().print(*msg)
|
|
55
|
+
|
|
56
|
+
if not verbose:
|
|
57
|
+
command += ">/dev/null 2>&1"
|
|
58
|
+
ret = os.system(command)
|
|
59
|
+
Console().print("got return code:", ret, style="bold red")
|
|
60
|
+
return ret
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@pytest.mark.slow
|
|
64
|
+
def test_upload_verify_update_download_mission(name, in_dir, out_dir, api):
|
|
65
|
+
assert api
|
|
66
|
+
|
|
67
|
+
upload = (
|
|
68
|
+
f"{CLI} upload -p {PROJECT_NAME} -m {name} --create {in_dir.absolute()}/*.bag"
|
|
69
|
+
)
|
|
70
|
+
verify = f"{CLI} verify -p {PROJECT_NAME} -m {name} {in_dir.absolute()}/*.bag"
|
|
71
|
+
update = f"{CLI} mission update -p {PROJECT_NAME} -m {name} --metadata {in_dir.absolute()}/metadata.yaml"
|
|
72
|
+
download = f"{CLI} download -p {PROJECT_NAME} -m {name} --dest {out_dir.absolute()}"
|
|
73
|
+
|
|
74
|
+
assert run_cmd(upload) == 0
|
|
75
|
+
assert run_cmd(verify) == 0
|
|
76
|
+
assert run_cmd(update) == 0
|
|
77
|
+
assert run_cmd(download) == 0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.mark.slow
|
|
81
|
+
def test_list_files(api):
|
|
82
|
+
assert api
|
|
83
|
+
assert run_cmd(f"{CLI} list files -p {PROJECT_NAME}") == 0
|
|
84
|
+
assert run_cmd(f"{CLI} list files -p {PROJECT_NAME} -m {secrets.token_hex(8)}") == 0
|
|
85
|
+
assert run_cmd(f"{CLI} list files") == 0
|
|
86
|
+
assert run_cmd(f"{CLI} list files -p {secrets.token_hex(8)}") == 0
|
|
87
|
+
assert run_cmd(f'{CLI} list files -p "*" -m "*" "*"') == 0
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@pytest.mark.slow
|
|
91
|
+
def test_list_missions(api):
|
|
92
|
+
assert api
|
|
93
|
+
assert run_cmd(f"{CLI} list missions -p {PROJECT_NAME}") == 0
|
|
94
|
+
assert run_cmd(f"{CLI} list missions -p {secrets.token_hex(8)}") == 0
|
|
95
|
+
assert run_cmd(f"{CLI} list missions") == 0
|
|
96
|
+
assert run_cmd(f'{CLI} list missions -p "*" "*"') == 0
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@pytest.mark.slow
|
|
100
|
+
def test_list_projects(api):
|
|
101
|
+
assert api
|
|
102
|
+
assert run_cmd(f"{CLI} list projects") == 0
|
|
103
|
+
assert run_cmd(f"{CLI} list projects {PROJECT_NAME}") == 0
|
|
104
|
+
assert run_cmd(f"{CLI} list projects {secrets.token_hex(8)}") == 0
|
|
105
|
+
assert run_cmd(f'{CLI} list projects "*"') == 0
|
tests/test_resources.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from kleinkram.resources import check_mission_spec_is_creatable
|
|
7
|
+
from kleinkram.resources import check_project_spec_is_creatable
|
|
8
|
+
from kleinkram.resources import InvalidMissionSpec
|
|
9
|
+
from kleinkram.resources import InvalidProjectSpec
|
|
10
|
+
from kleinkram.resources import mission_spec_is_unique
|
|
11
|
+
from kleinkram.resources import MissionSpec
|
|
12
|
+
from kleinkram.resources import project_spec_is_unique
|
|
13
|
+
from kleinkram.resources import ProjectSpec
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.parametrize(
|
|
17
|
+
"spec, expected",
|
|
18
|
+
[
|
|
19
|
+
pytest.param(MissionSpec(), False, id="match all"),
|
|
20
|
+
pytest.param(MissionSpec(patterns=["*"]), False, id="mission name match all"),
|
|
21
|
+
pytest.param(
|
|
22
|
+
MissionSpec(patterns=["test"]),
|
|
23
|
+
False,
|
|
24
|
+
id="mission name without project",
|
|
25
|
+
),
|
|
26
|
+
pytest.param(
|
|
27
|
+
MissionSpec(patterns=["test"], project_spec=ProjectSpec()),
|
|
28
|
+
False,
|
|
29
|
+
id="mission name with non-unique project",
|
|
30
|
+
),
|
|
31
|
+
pytest.param(
|
|
32
|
+
MissionSpec(
|
|
33
|
+
patterns=["test"],
|
|
34
|
+
project_spec=ProjectSpec(ids=[uuid4()]),
|
|
35
|
+
),
|
|
36
|
+
True,
|
|
37
|
+
id="mission name with unique project",
|
|
38
|
+
),
|
|
39
|
+
pytest.param(
|
|
40
|
+
MissionSpec(ids=[uuid4()]),
|
|
41
|
+
True,
|
|
42
|
+
id="mission by id",
|
|
43
|
+
),
|
|
44
|
+
pytest.param(
|
|
45
|
+
MissionSpec(ids=[uuid4(), uuid4()]),
|
|
46
|
+
False,
|
|
47
|
+
id="multiple mission ids",
|
|
48
|
+
),
|
|
49
|
+
],
|
|
50
|
+
)
|
|
51
|
+
def test_mission_spec_is_unique(spec, expected):
|
|
52
|
+
assert mission_spec_is_unique(spec) == expected
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize(
|
|
56
|
+
"spec, expected",
|
|
57
|
+
[
|
|
58
|
+
pytest.param(ProjectSpec(), False, id="match all"),
|
|
59
|
+
pytest.param(ProjectSpec(patterns=["*"]), False, id="project name match all"),
|
|
60
|
+
pytest.param(
|
|
61
|
+
ProjectSpec(patterns=["test"]),
|
|
62
|
+
True,
|
|
63
|
+
id="project name",
|
|
64
|
+
),
|
|
65
|
+
pytest.param(
|
|
66
|
+
ProjectSpec(ids=[uuid4()]),
|
|
67
|
+
True,
|
|
68
|
+
id="project by id",
|
|
69
|
+
),
|
|
70
|
+
pytest.param(
|
|
71
|
+
ProjectSpec(ids=[uuid4(), uuid4()]),
|
|
72
|
+
False,
|
|
73
|
+
id="multiple project ids",
|
|
74
|
+
),
|
|
75
|
+
],
|
|
76
|
+
)
|
|
77
|
+
def test_project_spec_is_unique(spec, expected):
|
|
78
|
+
assert project_spec_is_unique(spec) == expected
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.mark.parametrize(
|
|
82
|
+
"spec, valid",
|
|
83
|
+
[
|
|
84
|
+
pytest.param(
|
|
85
|
+
MissionSpec(patterns=["test"], project_spec=ProjectSpec()),
|
|
86
|
+
False,
|
|
87
|
+
id="non-unique project",
|
|
88
|
+
),
|
|
89
|
+
pytest.param(
|
|
90
|
+
MissionSpec(
|
|
91
|
+
patterns=["test"],
|
|
92
|
+
project_spec=ProjectSpec(ids=[uuid4()]),
|
|
93
|
+
),
|
|
94
|
+
True,
|
|
95
|
+
id="valid spec",
|
|
96
|
+
),
|
|
97
|
+
pytest.param(
|
|
98
|
+
MissionSpec(ids=[uuid4()]),
|
|
99
|
+
False,
|
|
100
|
+
id="mission by id",
|
|
101
|
+
),
|
|
102
|
+
],
|
|
103
|
+
)
|
|
104
|
+
def test_check_mission_spec_is_createable(spec, valid):
|
|
105
|
+
if not valid:
|
|
106
|
+
with pytest.raises(InvalidMissionSpec):
|
|
107
|
+
check_mission_spec_is_creatable(spec)
|
|
108
|
+
else:
|
|
109
|
+
check_mission_spec_is_creatable(spec)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@pytest.mark.parametrize(
|
|
113
|
+
"spec, valid",
|
|
114
|
+
[
|
|
115
|
+
pytest.param(
|
|
116
|
+
ProjectSpec(patterns=["test"]),
|
|
117
|
+
True,
|
|
118
|
+
id="project name",
|
|
119
|
+
),
|
|
120
|
+
pytest.param(
|
|
121
|
+
ProjectSpec(ids=[uuid4()]),
|
|
122
|
+
False,
|
|
123
|
+
id="project by id",
|
|
124
|
+
),
|
|
125
|
+
pytest.param(
|
|
126
|
+
ProjectSpec(ids=[uuid4(), uuid4()]),
|
|
127
|
+
False,
|
|
128
|
+
id="multiple project ids",
|
|
129
|
+
),
|
|
130
|
+
],
|
|
131
|
+
)
|
|
132
|
+
def test_check_project_spec_is_creatable(spec, valid):
|
|
133
|
+
if not valid:
|
|
134
|
+
with pytest.raises(InvalidProjectSpec):
|
|
135
|
+
check_project_spec_is_creatable(spec)
|
|
136
|
+
else:
|
|
137
|
+
check_project_spec_is_creatable(spec)
|
tests/test_utils.py
CHANGED
|
@@ -6,23 +6,28 @@ from uuid import uuid4
|
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
8
|
from kleinkram.errors import FileTypeNotSupported
|
|
9
|
-
from kleinkram.errors import InvalidFileSpec
|
|
10
|
-
from kleinkram.errors import InvalidMissionSpec
|
|
11
|
-
from kleinkram.models import FilesById
|
|
12
|
-
from kleinkram.models import FilesByMission
|
|
13
|
-
from kleinkram.models import MissionById
|
|
14
|
-
from kleinkram.models import MissionByName
|
|
15
9
|
from kleinkram.utils import b64_md5
|
|
16
10
|
from kleinkram.utils import check_file_paths
|
|
17
11
|
from kleinkram.utils import filtered_by_patterns
|
|
18
12
|
from kleinkram.utils import get_filename
|
|
19
13
|
from kleinkram.utils import get_filename_map
|
|
20
|
-
from kleinkram.utils import get_valid_file_spec
|
|
21
|
-
from kleinkram.utils import get_valid_mission_spec
|
|
22
14
|
from kleinkram.utils import is_valid_uuid4
|
|
15
|
+
from kleinkram.utils import split_args
|
|
23
16
|
from kleinkram.utils import to_name_or_uuid
|
|
24
17
|
|
|
25
18
|
|
|
19
|
+
def test_split_args():
|
|
20
|
+
uuid = uuid4()
|
|
21
|
+
assert split_args([str(uuid)]) == ([uuid], [])
|
|
22
|
+
assert split_args(["name"]) == ([], ["name"])
|
|
23
|
+
assert split_args([str(uuid), "name"]) == ([uuid], ["name"])
|
|
24
|
+
assert split_args(["name", str(uuid)]) == ([uuid], ["name"])
|
|
25
|
+
assert split_args(["name", "name"]) == ([], ["name", "name"])
|
|
26
|
+
assert split_args([str(uuid), str(uuid)]) == ([uuid, uuid], [])
|
|
27
|
+
assert split_args([]) == ([], [])
|
|
28
|
+
assert split_args(["*", str(uuid)]) == ([uuid], ["*"])
|
|
29
|
+
|
|
30
|
+
|
|
26
31
|
def test_check_file_paths():
|
|
27
32
|
with TemporaryDirectory() as temp_dir:
|
|
28
33
|
exits_txt = Path(temp_dir) / "exists.txt"
|
|
@@ -114,57 +119,6 @@ def test_b64_md5():
|
|
|
114
119
|
assert b64_md5(file) == "XrY7u+Ae7tCTyyK7j1rNww=="
|
|
115
120
|
|
|
116
121
|
|
|
117
|
-
def test_get_valid_mission_spec():
|
|
118
|
-
# only mission name
|
|
119
|
-
with pytest.raises(InvalidMissionSpec):
|
|
120
|
-
get_valid_mission_spec("mission")
|
|
121
|
-
|
|
122
|
-
# only mission id
|
|
123
|
-
id_ = uuid4()
|
|
124
|
-
assert get_valid_mission_spec(id_) == MissionById(id_)
|
|
125
|
-
|
|
126
|
-
# mission name and project name
|
|
127
|
-
assert get_valid_mission_spec("mission", "project") == MissionByName(
|
|
128
|
-
"mission", "project"
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
# mission name and project id
|
|
132
|
-
project_id = uuid4()
|
|
133
|
-
assert get_valid_mission_spec("mission", project_id) == MissionByName(
|
|
134
|
-
"mission", project_id
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
# mission id and project name
|
|
138
|
-
assert get_valid_mission_spec(id_, "project") == MissionById(id_)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def test_get_valid_file_spec():
|
|
142
|
-
# no information
|
|
143
|
-
with pytest.raises(InvalidFileSpec):
|
|
144
|
-
get_valid_file_spec([], None, None)
|
|
145
|
-
|
|
146
|
-
# only file ids
|
|
147
|
-
file_ids = [uuid4(), uuid4()]
|
|
148
|
-
assert get_valid_file_spec(file_ids, None, None) == FilesById(file_ids)
|
|
149
|
-
|
|
150
|
-
# only file names
|
|
151
|
-
with pytest.raises(InvalidFileSpec):
|
|
152
|
-
get_valid_file_spec(["foo"], None, None)
|
|
153
|
-
|
|
154
|
-
# missing mission
|
|
155
|
-
with pytest.raises(InvalidMissionSpec):
|
|
156
|
-
get_valid_file_spec([], None, "project")
|
|
157
|
-
|
|
158
|
-
# mission name and file names
|
|
159
|
-
assert get_valid_file_spec([], "mission", "project") == FilesByMission(
|
|
160
|
-
MissionByName("mission", "project"), []
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
assert get_valid_file_spec(
|
|
164
|
-
file_ids + ["name"], "mission", "project"
|
|
165
|
-
) == FilesByMission(MissionByName("mission", "project"), file_ids + ["name"])
|
|
166
|
-
|
|
167
|
-
|
|
168
122
|
def test_to_name_or_uuid():
|
|
169
123
|
id_ = uuid4()
|
|
170
124
|
not_id = "not an id"
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
kleinkram/__init__.py,sha256=adI-FqfuuH56n8U-lJa3uZkH_saxi7dr4Hox_HBuf9A,107
|
|
2
|
-
kleinkram/__main__.py,sha256=B9RiZxfO4jpCmWPUHyKJ7_EoZlEG4sPpH-nz7T_YhhQ,125
|
|
3
|
-
kleinkram/_version.py,sha256=QYJyRTcqFcJj4qWYpqs7WcoOP6jxDMqyvxLY-cD6KcE,129
|
|
4
|
-
kleinkram/app.py,sha256=DJpZjckTVlFgy5zvWdTxI2B5AzPJsqp-jo3TX9iT2Ic,6533
|
|
5
|
-
kleinkram/auth.py,sha256=QAwT3VWdHEv5cxNnRbZoVykYwdeaoZjtBQBBXfejFdQ,2953
|
|
6
|
-
kleinkram/config.py,sha256=QZWBXOCRjXa-wcSynJkCaYSE_0kU85j2zsdp-miR-eU,4447
|
|
7
|
-
kleinkram/consts.py,sha256=70GELDssDm-YeIbChBRTscnNRcyWRUDWWlYBjVWNLDk,205
|
|
8
|
-
kleinkram/core.py,sha256=XmNhg1i520w-9et8r0LSQRsVN09gJgSXfyHRV1tu2rM,227
|
|
9
|
-
kleinkram/enums.py,sha256=bX0H8_xkh_7DRycJYII8MTjHmjbcFW9ZJ3tzlzRhT2k,149
|
|
10
|
-
kleinkram/errors.py,sha256=m5WoLDfh4JngZ_tdqjVseHvgRQe1DmjHlQkkwme8z1U,1285
|
|
11
|
-
kleinkram/main.py,sha256=hmFuSnE2p-E4nZ2zDVToOsoELZhosLN0r4wsXnbmsas,168
|
|
12
|
-
kleinkram/models.py,sha256=dOrvK-H6cW8tPbZUbBeE6MROp17c5hp5FeULKZRpZ3s,4329
|
|
13
|
-
kleinkram/utils.py,sha256=Ot8Pd2JH59q-TSHroODqudQqir5iltYQayzZmzkMvns,5941
|
|
14
|
-
kleinkram/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
kleinkram/api/client.py,sha256=F7Z3IX0309Z_OJzTjTQkoDVXPDJJW_Fm092gorlnox0,3182
|
|
16
|
-
kleinkram/api/file_transfer.py,sha256=N_DhiJO2aaP9_VHy8P1Uoq40gZSQCUcEw-Hlur1Xxrc,9485
|
|
17
|
-
kleinkram/api/routes.py,sha256=_6dQChz4xlUgCJql0mpy513sX2oI-4HRDo-SuhMluyg,12878
|
|
18
|
-
kleinkram/commands/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
19
|
-
kleinkram/commands/download.py,sha256=393n9kaJJJmsAJGdPTrkd-H2giNsJuihr1JD1mdF6rk,3415
|
|
20
|
-
kleinkram/commands/endpoint.py,sha256=VgaleKTev8Muu4OmS4tptbhrbl58u1UTAxEmoLBCQew,1642
|
|
21
|
-
kleinkram/commands/list.py,sha256=bfuzWckZE46Y25EynOxZH0DPIXu_TJEBNFBoLbb4LfM,2926
|
|
22
|
-
kleinkram/commands/mission.py,sha256=BXnGUnOBTSHZipy50P2NtornXUAxDCdyqmGpVUMzfxc,1751
|
|
23
|
-
kleinkram/commands/project.py,sha256=q-kJ1YQr-Axo-Zl0qe2J7eGGgKlSbcdDjpAJIynRLaM,587
|
|
24
|
-
kleinkram/commands/upload.py,sha256=Wc3OkmdtbrloTA4FaE2i1BD2gBcsjkR4T8G9qlIqe-M,4450
|
|
25
|
-
kleinkram/commands/verify.py,sha256=-hCeCYGFSGqf4JYl2nlkpEIhbScRWnDYqS202SzCUnI,3719
|
|
26
|
-
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
tests/test_utils.py,sha256=ob-7lNHP20hnB8E8O242l1IbWqSWvFYqTdYuPAbBoLU,5331
|
|
28
|
-
kleinkram-0.38.1.dev20241120100707.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
29
|
-
kleinkram-0.38.1.dev20241120100707.dist-info/METADATA,sha256=9XzNgTy7F_zRrsWl5hQaHXxK5X9EZCxxmYjMeEge6fo,2335
|
|
30
|
-
kleinkram-0.38.1.dev20241120100707.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
|
31
|
-
kleinkram-0.38.1.dev20241120100707.dist-info/entry_points.txt,sha256=SaB2l5aqhSr8gmaMw2kvQU90a8Bnl7PedU8cWYxkfYo,46
|
|
32
|
-
kleinkram-0.38.1.dev20241120100707.dist-info/top_level.txt,sha256=G1Lj9vHAtZn402Ukkrfll-6BCmnDNy_HVtWeNvXzdDA,16
|
|
33
|
-
kleinkram-0.38.1.dev20241120100707.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|