kleinkram 0.13.1__py3-none-any.whl → 0.13.2__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 CHANGED
@@ -2,15 +2,91 @@ import glob
2
2
  import os
3
3
  import queue
4
4
  import threading
5
+ from functools import partial
5
6
  from typing import Dict
7
+ import boto3
6
8
 
7
- import httpx
8
9
  import tqdm
10
+ from boto3.s3.transfer import TransferConfig
11
+ from botocore.client import BaseClient
9
12
  from rich import print
10
13
 
11
14
  from kleinkram.api_client import AuthenticatedClient
12
15
 
13
16
 
17
+ class TransferCallback:
18
+ """
19
+ Handle callbacks from the transfer manager.
20
+
21
+ The transfer manager periodically calls the __call__ method throughout
22
+ the upload process so that it can take action, such as displaying progress
23
+ to the user and collecting data about the transfer.
24
+ """
25
+
26
+ def __init__(self):
27
+ """
28
+ Initialize the TransferCallback.
29
+
30
+ This initializes an empty dictionary to hold progress bars for each file.
31
+ """
32
+ self._lock = threading.Lock()
33
+ self.file_progress = {}
34
+
35
+ def add_file(self, file_id, target_size):
36
+ """
37
+ Add a new file to track.
38
+
39
+ :param file_id: A unique identifier for the file (e.g., file name or ID).
40
+ :param target_size: The total size of the file being transferred.
41
+ """
42
+ with self._lock:
43
+ tqdm_instance = tqdm.tqdm(
44
+ total=target_size,
45
+ unit="B",
46
+ unit_scale=True,
47
+ desc=f"Uploading {file_id}",
48
+ )
49
+ self.file_progress[file_id] = {
50
+ "tqdm": tqdm_instance,
51
+ "total_transferred": 0,
52
+ }
53
+
54
+ def __call__(self, file_id, bytes_transferred):
55
+ """
56
+ The callback method that is called by the transfer manager.
57
+
58
+ Display progress during file transfer and collect per-thread transfer
59
+ data. This method can be called by multiple threads, so shared instance
60
+ data is protected by a thread lock.
61
+
62
+ :param file_id: The identifier of the file being transferred.
63
+ :param bytes_transferred: The number of bytes transferred in this call.
64
+ """
65
+ with self._lock:
66
+ if file_id in self.file_progress:
67
+ progress = self.file_progress[file_id]
68
+ progress["total_transferred"] += bytes_transferred
69
+
70
+ # Update tqdm progress bar
71
+ progress["tqdm"].update(bytes_transferred)
72
+
73
+ def close(self):
74
+ """Close all tqdm progress bars."""
75
+ with self._lock:
76
+ for progress in self.file_progress.values():
77
+ progress["tqdm"].close()
78
+
79
+
80
+ def create_transfer_callback(callback_instance, file_id):
81
+ """
82
+ Factory function to create a partial function for TransferCallback.
83
+ :param callback_instance: Instance of TransferCallback.
84
+ :param file_id: The unique identifier for the file.
85
+ :return: A callable that can be passed as a callback to boto3's upload_file method.
86
+ """
87
+ return partial(callback_instance.__call__, file_id)
88
+
89
+
14
90
  def expand_and_match(path_pattern):
15
91
  expanded_path = os.path.expanduser(path_pattern)
16
92
  expanded_path = os.path.expandvars(expanded_path)
@@ -25,40 +101,59 @@ def expand_and_match(path_pattern):
25
101
  return file_list
26
102
 
27
103
 
28
- def uploadFiles(files: Dict[str, str], paths: Dict[str, str], nrThreads: int):
104
+ def uploadFiles(files: Dict[str, str], credentials: Dict[str, str], nrThreads: int):
105
+ client = AuthenticatedClient()
106
+
107
+ session = boto3.Session(
108
+ aws_access_key_id=credentials["accessKey"],
109
+ aws_secret_access_key=credentials["secretKey"],
110
+ aws_session_token=credentials["sessionToken"],
111
+ )
112
+ api_endpoint = client.tokenfile.endpoint
113
+ if api_endpoint == "http://localhost:3000":
114
+ minio_endpoint = "http://localhost:9000"
115
+ else:
116
+ minio_endpoint = api_endpoint.replace("api", "minio")
117
+ s3 = session.resource("s3", endpoint_url=minio_endpoint)
118
+
29
119
  _queue = queue.Queue()
30
120
  for file in files.items():
31
121
  _queue.put(file)
32
122
  threads = []
33
- pbar = tqdm.tqdm(total=len(files.items()) * 100)
123
+ transferCallback = TransferCallback()
124
+
34
125
  for i in range(nrThreads):
35
- thread = threading.Thread(target=uploadFile, args=(_queue, paths, pbar))
126
+ thread = threading.Thread(
127
+ target=uploadFile, args=(_queue, s3, transferCallback)
128
+ )
36
129
  thread.start()
37
130
  threads.append(thread)
38
131
  for thread in threads:
39
132
  thread.join()
40
133
 
41
134
 
42
- def uploadFile(_queue: queue.Queue, paths: Dict[str, str], pbar: tqdm):
135
+ def uploadFile(_queue: queue.Queue, s3: BaseClient, transferCallback: TransferCallback):
43
136
  while True:
44
137
  try:
45
- filename, info = _queue.get(timeout=3)
46
- url = info["url"]
47
- uuid = info["uuid"]
48
- filepath = paths[filename]
49
- headers = {"Content-Type": "application/octet-stream"}
138
+ filename, _file = _queue.get(timeout=3)
139
+ queueUUID = _file["queueUUID"]
140
+ filepath = _file["filepath"]
141
+ bucket = _file["bucket"]
142
+ target_location = _file["location"]
143
+ config = TransferConfig(
144
+ multipart_chunksize=10 * 1024 * 1024, max_concurrency=5
145
+ )
50
146
  with open(filepath, "rb") as f:
51
- with httpx.Client() as cli:
52
- # Using PUT method directly for the upload
53
- response = cli.put(url, content=f, headers=headers)
54
- if response.status_code == 200:
55
- pbar.update(100) # Update progress for each file
56
- client = AuthenticatedClient()
57
- client.post("/queue/confirmUpload", json={"uuid": uuid})
58
- else:
59
- print(
60
- f"Failed to upload {filename}. HTTP status: {response.status_code}"
61
- )
147
+ size = os.path.getsize(filepath)
148
+ transferCallback.add_file(filename, size)
149
+ callback_function = create_transfer_callback(transferCallback, filename)
150
+ s3.Bucket(bucket).upload_file(
151
+ filepath, target_location, Config=config, Callback=callback_function
152
+ )
153
+
154
+ client = AuthenticatedClient()
155
+ res = client.post("/queue/confirmUpload", json={"uuid": queueUUID})
156
+ res.raise_for_status()
62
157
  _queue.task_done()
63
158
  except queue.Empty:
64
159
  break
kleinkram/main.py CHANGED
@@ -179,23 +179,25 @@ def upload(
179
179
  )
180
180
  new_mission.raise_for_status()
181
181
  new_mission_data = new_mission.json()
182
- print(f"Created mission: {new_mission_data['name']}")
183
182
 
184
- get_presigned_url = "/queue/createPreSignedURLS"
183
+ get_temporary_credentials = "/file/temporaryAccess"
185
184
 
186
185
  response_2 = client.post(
187
- get_presigned_url,
186
+ get_temporary_credentials,
188
187
  json={"filenames": filenames, "missionUUID": new_mission_data["uuid"]},
189
188
  )
190
189
  response_2.raise_for_status()
191
- presigned_urls = response_2.json()
192
- for file in filenames:
193
- if not file in presigned_urls.keys():
190
+ temp_credentials = response_2.json()
191
+ credential = temp_credentials["credentials"]
192
+ confirmed_files = temp_credentials["files"]
193
+ for _file in filenames:
194
+ if not _file in confirmed_files.keys():
194
195
  raise Exception(
195
196
  "Could not upload File '" + file + "'. Is the filename unique? "
196
197
  )
197
- if len(presigned_urls) > 0:
198
- uploadFiles(presigned_urls, filepaths, 4)
198
+ confirmed_files[_file]["filepath"] = filepaths[_file]
199
+ if len(confirmed_files.keys()) > 0:
200
+ uploadFiles(confirmed_files, credential, 4)
199
201
 
200
202
  except httpx.HTTPError as e:
201
203
  print(e)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: kleinkram
3
- Version: 0.13.1
3
+ Version: 0.13.2
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
@@ -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=9YUuCH0pfj7gK88XRtR0SD-cfdcbR-4g0DdAcUfwdm4,2334
6
- kleinkram/main.py,sha256=LIhlsepSWm_cl_VN0TuvPYtdKX_2Mz7d3Q-piebj3O8,7983
5
+ kleinkram/helper.py,sha256=PNx6h7eTFZ10Ul7BqK2PTMXlKjHMKkQtANsceNZmAe8,5579
6
+ kleinkram/main.py,sha256=ofSs0hFmi05A5gwa5t_ioVS6-aI0h27J8I1ENIxkZKk,8118
7
7
  kleinkram/auth/auth.py,sha256=bROptCsE0r5D416_7l1lfw52IX_mSVEnjaKiU2_b1Ms,4980
8
8
  kleinkram/endpoint/endpoint.py,sha256=KAYQgK8J6Et8V_ho2wBUIAdg25Mps6l_glCfC1vvC2g,1372
9
9
  kleinkram/file/file.py,sha256=HsKzg8xn-AHJJIF11H6c0Gy61cRX3MyTMYdcyypUxWo,3195
@@ -13,8 +13,8 @@ kleinkram/queue/queue.py,sha256=MaLBjAu8asi9BkPvbbT-5AobCcpy3ex5rxM1kHpRINA,181
13
13
  kleinkram/tag/tag.py,sha256=TZHh1GIV4LhwhqEGKdTJkM5mCIoLXAopBgWdLX1AEz8,1819
14
14
  kleinkram/topic/topic.py,sha256=qit-DECI19QocXEkkkBC0FAlzpZnotAtX8mylA9zqAA,1630
15
15
  kleinkram/user/user.py,sha256=i_QfsctjhImvKKjuDPfOIyDr322SXgV-KxJo-a7qNZw,1368
16
- kleinkram-0.13.1.dist-info/METADATA,sha256=hSkr3cBsUq6jdaTYGbvDZDOcbc1eqGMMkRcL0P5irNQ,756
17
- kleinkram-0.13.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
- kleinkram-0.13.1.dist-info/entry_points.txt,sha256=RHXtRzcreVHImatgjhQwZQ6GdJThElYjHEWcR1BPXUI,45
19
- kleinkram-0.13.1.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
20
- kleinkram-0.13.1.dist-info/RECORD,,
16
+ kleinkram-0.13.2.dist-info/METADATA,sha256=ba5y3Udzl4-bZyf3MMu-qyCzRgI1wlJU2x5npP17TFc,756
17
+ kleinkram-0.13.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
+ kleinkram-0.13.2.dist-info/entry_points.txt,sha256=RHXtRzcreVHImatgjhQwZQ6GdJThElYjHEWcR1BPXUI,45
19
+ kleinkram-0.13.2.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
20
+ kleinkram-0.13.2.dist-info/RECORD,,