kleinkram 0.21.7.dev20240919182750__py3-none-any.whl → 0.21.8.dev20240920104547__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/helper.py +16 -1
- kleinkram/main.py +64 -23
- {kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/METADATA +1 -1
- {kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/RECORD +7 -7
- {kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/WHEEL +0 -0
- {kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/entry_points.txt +0 -0
- {kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/licenses/LICENSE +0 -0
kleinkram/helper.py
CHANGED
|
@@ -3,6 +3,8 @@ import os
|
|
|
3
3
|
import queue
|
|
4
4
|
import threading
|
|
5
5
|
from functools import partial
|
|
6
|
+
|
|
7
|
+
from botocore.config import Config
|
|
6
8
|
from typing_extensions import Dict
|
|
7
9
|
import boto3
|
|
8
10
|
|
|
@@ -114,7 +116,12 @@ def uploadFiles(files: Dict[str, str], credentials: Dict[str, str], nrThreads: i
|
|
|
114
116
|
minio_endpoint = "http://localhost:9000"
|
|
115
117
|
else:
|
|
116
118
|
minio_endpoint = api_endpoint.replace("api", "minio")
|
|
117
|
-
|
|
119
|
+
|
|
120
|
+
config = Config(retries = {
|
|
121
|
+
'max_attempts': 10,
|
|
122
|
+
'mode': 'standard'
|
|
123
|
+
})
|
|
124
|
+
s3 = session.resource("s3", endpoint_url=minio_endpoint, config=config)
|
|
118
125
|
|
|
119
126
|
_queue = queue.Queue()
|
|
120
127
|
for file in files.items():
|
|
@@ -161,6 +168,14 @@ def uploadFile(_queue: queue.Queue, s3: BaseClient, transferCallback: TransferCa
|
|
|
161
168
|
print(f"Error uploading {filename}: {e}")
|
|
162
169
|
_queue.task_done()
|
|
163
170
|
|
|
171
|
+
def canUploadMission(client: AuthenticatedClient, project_uuid: str):
|
|
172
|
+
permissions = client.get("/user/permissions")
|
|
173
|
+
permissions.raise_for_status()
|
|
174
|
+
permissions_json = permissions.json()
|
|
175
|
+
for_project = filter(lambda x: x["uuid"] == project_uuid, permissions_json["projects"])
|
|
176
|
+
max_for_project = max(map(lambda x: x["access"], for_project))
|
|
177
|
+
return max_for_project >= 10
|
|
178
|
+
|
|
164
179
|
|
|
165
180
|
if __name__ == "__main__":
|
|
166
181
|
res = expand_and_match(
|
kleinkram/main.py
CHANGED
|
@@ -9,7 +9,7 @@ from rich import print
|
|
|
9
9
|
from rich.table import Table
|
|
10
10
|
from typer.core import TyperGroup
|
|
11
11
|
from typer.models import Context
|
|
12
|
-
from typing_extensions import Annotated, List
|
|
12
|
+
from typing_extensions import Annotated, List, Optional
|
|
13
13
|
|
|
14
14
|
from kleinkram.api_client import AuthenticatedClient
|
|
15
15
|
from kleinkram.auth.auth import login, setCliKey, logout
|
|
@@ -22,7 +22,7 @@ from kleinkram.queue.queue import queue
|
|
|
22
22
|
from kleinkram.tag.tag import tag
|
|
23
23
|
from kleinkram.topic.topic import topic
|
|
24
24
|
from kleinkram.user.user import user
|
|
25
|
-
from .helper import uploadFiles, expand_and_match
|
|
25
|
+
from .helper import uploadFiles, expand_and_match, canUploadMission
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class CommandPanel(str, Enum):
|
|
@@ -75,14 +75,14 @@ app = ErrorHandledTyper(
|
|
|
75
75
|
|
|
76
76
|
@app.callback()
|
|
77
77
|
def version(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
version: bool = typer.Option(
|
|
79
|
+
None,
|
|
80
|
+
"--version",
|
|
81
|
+
"-v",
|
|
82
|
+
callback=version_callback,
|
|
83
|
+
is_eager=True,
|
|
84
|
+
help="Print the version and exit",
|
|
85
|
+
)
|
|
86
86
|
):
|
|
87
87
|
pass
|
|
88
88
|
|
|
@@ -109,20 +109,21 @@ def download():
|
|
|
109
109
|
|
|
110
110
|
@app.command("upload", rich_help_panel=CommandPanel.CoreCommands)
|
|
111
111
|
def upload(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
path: Annotated[
|
|
113
|
+
str, typer.Option(prompt=True, help="Path to files to upload, Regex supported")
|
|
114
|
+
],
|
|
115
|
+
project: Annotated[str, typer.Option(prompt=True, help="Name of Project")],
|
|
116
|
+
mission: Annotated[
|
|
117
|
+
str, typer.Option(prompt=True, help="Name of Mission to create")
|
|
118
|
+
],
|
|
119
|
+
tags: Annotated[Optional[List[str]], typer.Option(prompt=False, help="Tags to add to the mission")] = None,
|
|
119
120
|
):
|
|
120
121
|
"""
|
|
121
122
|
Upload files matching the path to a mission in a project.
|
|
122
123
|
|
|
123
124
|
The mission name must be unique within the project and not yet created.\n
|
|
124
125
|
Examples:\n
|
|
125
|
-
- 'klein upload --path "~/data/**/*.bag" --project "Project 1" --mission "Mission 1"'\n
|
|
126
|
+
- 'klein upload --path "~/data/**/*.bag" --project "Project 1" --mission "Mission 1" --tags "0700946d-1d6a-4520-b263-0e177f49c35b:LEE-H" --tags "1565118d-593c-4517-8c2d-9658452d9319:Dodo"'\n
|
|
126
127
|
|
|
127
128
|
"""
|
|
128
129
|
files = expand_and_match(path)
|
|
@@ -147,7 +148,6 @@ def upload(
|
|
|
147
148
|
get_project_url = "/project/byName"
|
|
148
149
|
project_response = client.get(get_project_url, params={"name": project})
|
|
149
150
|
if project_response.status_code >= 400:
|
|
150
|
-
|
|
151
151
|
raise AccessDeniedException(
|
|
152
152
|
f"The project '{project}' does not exist or you do not have access to it.\n"
|
|
153
153
|
f"Consider using the following command to create a project: 'klein project create'\n",
|
|
@@ -159,6 +159,42 @@ def upload(
|
|
|
159
159
|
print(f"Project not found: '{project}'")
|
|
160
160
|
return
|
|
161
161
|
|
|
162
|
+
can_upload = canUploadMission(client, project_json['uuid'])
|
|
163
|
+
if not can_upload:
|
|
164
|
+
raise AccessDeniedException(
|
|
165
|
+
f"You do not have the required permissions to upload to project '{project}'\n", "Access Denied")
|
|
166
|
+
|
|
167
|
+
if not tags:
|
|
168
|
+
tags = []
|
|
169
|
+
tags_dict = {item.split(":")[0]: item.split(":")[1] for item in tags}
|
|
170
|
+
|
|
171
|
+
for required_tag in project_json["requiredTags"]:
|
|
172
|
+
if required_tag["name"] not in tags_dict:
|
|
173
|
+
while True:
|
|
174
|
+
if required_tag["datatype"] in ["LOCATION", "STRING", "LINK"]:
|
|
175
|
+
tag_value = typer.prompt("Provide value for required tag " + required_tag["name"])
|
|
176
|
+
if tag_value != "":
|
|
177
|
+
break
|
|
178
|
+
elif required_tag["datatype"] == "BOOLEAN":
|
|
179
|
+
tag_value = typer.confirm("Provide (y/N) for required tag " + required_tag["name"])
|
|
180
|
+
break
|
|
181
|
+
elif required_tag["datatype"] == "NUMBER":
|
|
182
|
+
tag_value = typer.prompt("Provide number for required tag " + required_tag["name"])
|
|
183
|
+
try:
|
|
184
|
+
tag_value = float(tag_value)
|
|
185
|
+
break
|
|
186
|
+
except ValueError:
|
|
187
|
+
typer.echo("Invalid number format. Please provide a number.")
|
|
188
|
+
elif required_tag["datatype"] == "DATE":
|
|
189
|
+
tag_value = typer.prompt("Provide date for required tag " + required_tag["name"])
|
|
190
|
+
try:
|
|
191
|
+
tag_value = datetime.strptime(tag_value, "%Y-%m-%d %H:%M:%S")
|
|
192
|
+
break
|
|
193
|
+
except ValueError:
|
|
194
|
+
print("Invalid date format. Please use 'YYYY-MM-DD HH:MM:SS'")
|
|
195
|
+
|
|
196
|
+
tags_dict[required_tag["uuid"]] = tag_value
|
|
197
|
+
|
|
162
198
|
get_mission_url = "/mission/byName"
|
|
163
199
|
mission_response = client.get(get_mission_url, params={"name": mission})
|
|
164
200
|
mission_response.raise_for_status()
|
|
@@ -174,18 +210,23 @@ def upload(
|
|
|
174
210
|
create_mission_url = "/mission/create"
|
|
175
211
|
new_mission = client.post(
|
|
176
212
|
create_mission_url,
|
|
177
|
-
json={"name": mission, "projectUUID": project_json["uuid"], "tags":
|
|
213
|
+
json={"name": mission, "projectUUID": project_json["uuid"], "tags": tags_dict},
|
|
178
214
|
)
|
|
179
|
-
new_mission.
|
|
215
|
+
if new_mission.status_code >= 400:
|
|
216
|
+
raise ValueError(
|
|
217
|
+
"Failed to create mission. Status Code: " + str(new_mission.status_code) + "\n" + new_mission.json()[
|
|
218
|
+
"message"])
|
|
180
219
|
new_mission_data = new_mission.json()
|
|
181
220
|
|
|
182
221
|
get_temporary_credentials = "/file/temporaryAccess"
|
|
183
|
-
|
|
184
222
|
response_2 = client.post(
|
|
185
223
|
get_temporary_credentials,
|
|
186
224
|
json={"filenames": filenames, "missionUUID": new_mission_data["uuid"]},
|
|
187
225
|
)
|
|
188
|
-
response_2.
|
|
226
|
+
if response_2.status_code >= 400:
|
|
227
|
+
raise ValueError(
|
|
228
|
+
"Failed to get temporary credentials. Status Code: " + str(response_2.status_code) + "\n" + response_2.json()[
|
|
229
|
+
"message"])
|
|
189
230
|
temp_credentials = response_2.json()
|
|
190
231
|
credential = temp_credentials["credentials"]
|
|
191
232
|
confirmed_files = temp_credentials["files"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: kleinkram
|
|
3
|
-
Version: 0.21.
|
|
3
|
+
Version: 0.21.8.dev20240920104547
|
|
4
4
|
Summary: A CLI for the ETH project kleinkram
|
|
5
5
|
Project-URL: Homepage, https://github.com/leggedrobotics/kleinkram
|
|
6
6
|
Project-URL: Issues, https://github.com/leggedrobotics/kleinkram/issues
|
{kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/RECORD
RENAMED
|
@@ -2,8 +2,8 @@ kleinkram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
2
2
|
kleinkram/api_client.py,sha256=1GPsM-XFbPYEKP7RfWmzMTwxRqnVh4wtHVuW25KT8kA,2264
|
|
3
3
|
kleinkram/consts.py,sha256=pm_6OuQcO-tYcRhwauTtyRRsuYY0y0yb6EGuIl49LnI,50
|
|
4
4
|
kleinkram/error_handling.py,sha256=Nm3tUtc4blQylJLNChSLgkDLFDHg3Xza0CghRrd_SYE,4015
|
|
5
|
-
kleinkram/helper.py,sha256=
|
|
6
|
-
kleinkram/main.py,sha256=
|
|
5
|
+
kleinkram/helper.py,sha256=t-6Il0mLAuEei8m37alJ8kkI5UARisRcXjcVSD42V6E,6126
|
|
6
|
+
kleinkram/main.py,sha256=C27P6hUcY12W3G8avYQBTftICP4stDjZTkhB3Jft9FE,10734
|
|
7
7
|
kleinkram/auth/auth.py,sha256=w3-TsxWxURzLQ3_p43zgV4Rlh4dVL_WqI6HG2aes-b4,4991
|
|
8
8
|
kleinkram/endpoint/endpoint.py,sha256=neyW1lR7RNiRj8nwCl77StQrofwRCbnCY0mqLJkqW84,1419
|
|
9
9
|
kleinkram/file/file.py,sha256=8CCYu9MdG24Rh0aEcNB3OEMUzpLMSoV4VIhdeq2n8iA,3206
|
|
@@ -13,8 +13,8 @@ kleinkram/queue/queue.py,sha256=MaLBjAu8asi9BkPvbbT-5AobCcpy3ex5rxM1kHpRINA,181
|
|
|
13
13
|
kleinkram/tag/tag.py,sha256=JSHbDPVfsvP34MuQhw__DPQk-Bah5G9BgwYsj_K_JGc,1805
|
|
14
14
|
kleinkram/topic/topic.py,sha256=IaXhrIHcJ3FSIr0WC-N7u9fkz-lAvSBgQklTX67t0Yc,1641
|
|
15
15
|
kleinkram/user/user.py,sha256=hDrbWeFPPnh2sswDd445SwcIFGyAbfXXWpYq1VqrK0g,1379
|
|
16
|
-
kleinkram-0.21.
|
|
17
|
-
kleinkram-0.21.
|
|
18
|
-
kleinkram-0.21.
|
|
19
|
-
kleinkram-0.21.
|
|
20
|
-
kleinkram-0.21.
|
|
16
|
+
kleinkram-0.21.8.dev20240920104547.dist-info/METADATA,sha256=QPwfxdoZjBkmrQv4laK-VH1K-eTMMNZIHABqSBXVRtg,845
|
|
17
|
+
kleinkram-0.21.8.dev20240920104547.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
18
|
+
kleinkram-0.21.8.dev20240920104547.dist-info/entry_points.txt,sha256=RHXtRzcreVHImatgjhQwZQ6GdJThElYjHEWcR1BPXUI,45
|
|
19
|
+
kleinkram-0.21.8.dev20240920104547.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
|
20
|
+
kleinkram-0.21.8.dev20240920104547.dist-info/RECORD,,
|
{kleinkram-0.21.7.dev20240919182750.dist-info → kleinkram-0.21.8.dev20240920104547.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|