kleinkram 0.44.0.dev20250407065841__tar.gz → 0.44.0.dev20250409080103__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.

Potentially problematic release.


This version of kleinkram might be problematic. Click here for more details.

Files changed (57) hide show
  1. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/PKG-INFO +1 -1
  2. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/file_transfer.py +28 -12
  3. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_download.py +2 -1
  4. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/core.py +4 -4
  5. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/models.py +1 -1
  6. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/printing.py +2 -2
  7. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram.egg-info/PKG-INFO +1 -1
  8. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/setup.cfg +1 -1
  9. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_core.py +1 -1
  10. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/README.md +0 -0
  11. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/__init__.py +0 -0
  12. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/__main__.py +0 -0
  13. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/_version.py +0 -0
  14. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/__init__.py +0 -0
  15. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/client.py +0 -0
  16. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/deser.py +0 -0
  17. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/pagination.py +0 -0
  18. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/query.py +0 -0
  19. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/api/routes.py +0 -0
  20. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/auth.py +0 -0
  21. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/__init__.py +0 -0
  22. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_endpoint.py +0 -0
  23. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_file.py +0 -0
  24. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_list.py +0 -0
  25. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_mission.py +0 -0
  26. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_project.py +0 -0
  27. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_upload.py +0 -0
  28. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/_verify.py +0 -0
  29. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/app.py +0 -0
  30. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/cli/error_handling.py +0 -0
  31. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/config.py +0 -0
  32. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/errors.py +0 -0
  33. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/main.py +0 -0
  34. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/py.typed +0 -0
  35. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/types.py +0 -0
  36. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/utils.py +0 -0
  37. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram/wrappers.py +0 -0
  38. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram.egg-info/SOURCES.txt +0 -0
  39. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram.egg-info/dependency_links.txt +0 -0
  40. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram.egg-info/entry_points.txt +0 -0
  41. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram.egg-info/requires.txt +0 -0
  42. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/kleinkram.egg-info/top_level.txt +0 -0
  43. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/pyproject.toml +0 -0
  44. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/requirements.txt +0 -0
  45. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/setup.py +0 -0
  46. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/testing/__init__.py +0 -0
  47. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/testing/backend_fixtures.py +0 -0
  48. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/__init__.py +0 -0
  49. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/conftest.py +0 -0
  50. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_config.py +0 -0
  51. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_end_to_end.py +0 -0
  52. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_error_handling.py +0 -0
  53. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_fixtures.py +0 -0
  54. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_printing.py +0 -0
  55. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_query.py +0 -0
  56. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_utils.py +0 -0
  57. {kleinkram-0.44.0.dev20250407065841 → kleinkram-0.44.0.dev20250409080103}/tests/test_wrappers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kleinkram
3
- Version: 0.44.0.dev20250407065841
3
+ Version: 0.44.0.dev20250409080103
4
4
  Summary: give me your bags
5
5
  Author: Cyrill Püntener, Dominique Garmier, Johann Schwabe
6
6
  Author-email: pucyril@ethz.ch, dgarmier@ethz.ch, jschwab@ethz.ch
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import signal
4
3
  import logging
5
4
  import sys
6
5
  from concurrent.futures import Future
@@ -18,6 +17,9 @@ from uuid import UUID
18
17
  import boto3.s3.transfer
19
18
  import botocore.config
20
19
  import httpx
20
+ from rich.console import Console
21
+ from tqdm import tqdm
22
+
21
23
  from kleinkram.api.client import AuthenticatedClient
22
24
  from kleinkram.config import get_config
23
25
  from kleinkram.errors import AccessDenied
@@ -28,8 +30,6 @@ from kleinkram.utils import format_bytes
28
30
  from kleinkram.utils import format_error
29
31
  from kleinkram.utils import format_traceback
30
32
  from kleinkram.utils import styled_string
31
- from rich.console import Console
32
- from tqdm import tqdm
33
33
 
34
34
  logger = logging.getLogger(__name__)
35
35
 
@@ -267,7 +267,7 @@ def _url_download(
267
267
  if path.exists() and not overwrite:
268
268
  raise FileExistsError(f"file already exists: {path}")
269
269
 
270
- with httpx.stream("GET", url) as response:
270
+ with httpx.stream("GET", url, timeout=S3_READ_TIMEOUT) as response:
271
271
  response.raise_for_status()
272
272
  with open(path, "wb") as f:
273
273
  with tqdm(
@@ -289,6 +289,7 @@ class DownloadState(Enum):
289
289
  DOWNLOADED_INVALID_HASH = 3
290
290
  SKIPPED_INVALID_HASH = 4
291
291
  SKIPPED_INVALID_REMOTE_STATE = 5
292
+ SKIPPED_FILE_SIZE_MISMATCH = 6
292
293
 
293
294
 
294
295
  def download_file(
@@ -307,17 +308,29 @@ def download_file(
307
308
  return DownloadState.SKIPPED_INVALID_REMOTE_STATE, 0
308
309
 
309
310
  if path.exists():
310
- local_hash = b64_md5(path)
311
- if local_hash != file.hash and not overwrite and file.hash is not None:
312
- return DownloadState.SKIPPED_INVALID_HASH, 0
313
311
 
314
- elif local_hash == file.hash:
315
- return DownloadState.SKIPPED_OK, 0
312
+ # compare file size
313
+ if file.size == path.stat().st_size:
314
+ local_hash = b64_md5(path)
315
+ if local_hash != file.hash and not overwrite and file.hash is not None:
316
+ return DownloadState.SKIPPED_INVALID_HASH, 0
316
317
 
317
- # this has to be here
318
- if verbose:
318
+ elif local_hash == file.hash:
319
+ return DownloadState.SKIPPED_OK, 0
320
+
321
+ elif verbose:
322
+ tqdm.write(
323
+ styled_string(f"overwriting {path}, hash missmatch", style="yellow")
324
+ )
325
+
326
+ elif not overwrite and file.size is not None:
327
+ return DownloadState.SKIPPED_FILE_SIZE_MISMATCH, 0
328
+
329
+ elif verbose:
319
330
  tqdm.write(
320
- styled_string(f"overwriting {path}, hash missmatch", style="yellow")
331
+ styled_string(
332
+ f"overwriting {path}, file size missmatch", style="yellow"
333
+ )
321
334
  )
322
335
 
323
336
  # request a download url
@@ -400,6 +413,7 @@ DOWNLOAD_STATE_COLOR = {
400
413
  DownloadState.SKIPPED_OK: "green",
401
414
  DownloadState.DOWNLOADED_INVALID_HASH: "red",
402
415
  DownloadState.SKIPPED_INVALID_HASH: "yellow",
416
+ DownloadState.SKIPPED_FILE_SIZE_MISMATCH: "yellow",
403
417
  DownloadState.SKIPPED_INVALID_REMOTE_STATE: "purple",
404
418
  }
405
419
 
@@ -432,6 +446,8 @@ def _download_handler(
432
446
  msg = f"skipped {path} already downloaded (hash ok)"
433
447
  elif state == DownloadState.SKIPPED_INVALID_HASH:
434
448
  msg = f"skipped {path}, exists with hash mismatch (use --overwrite?)"
449
+ elif state == DownloadState.SKIPPED_FILE_SIZE_MISMATCH:
450
+ msg = f"skipped {path}, exists with file size mismatch (use --overwrite?)"
435
451
  elif state == DownloadState.SKIPPED_INVALID_REMOTE_STATE:
436
452
  msg = f"skipped {path}, remote file has invalid state ({file.state.value})"
437
453
  else:
@@ -43,7 +43,8 @@ def download(
43
43
  False, help="save files in nested directories, project-name/mission-name"
44
44
  ),
45
45
  overwrite: bool = typer.Option(
46
- False, help="overwrite files if they already exist and don't match the filehash"
46
+ False,
47
+ help="overwrite files if they already exist and don't match the file size or file hash",
47
48
  ),
48
49
  ) -> None:
49
50
  # create destionation directory
@@ -180,22 +180,22 @@ def verify(
180
180
  elif remote_file.state == FileState.OK:
181
181
 
182
182
  # default case, will be overwritten if we find a mismatch
183
- file_status[file] = FileVerificationStatus.UPLAODED
183
+ file_status[file] = FileVerificationStatus.UPLOADED
184
184
 
185
185
  if check_file_size:
186
186
  if remote_file.size == file.stat().st_size:
187
- file_status[file] = FileVerificationStatus.UPLAODED
187
+ file_status[file] = FileVerificationStatus.UPLOADED
188
188
  else:
189
189
  file_status[file] = FileVerificationStatus.MISMATCHED_SIZE
190
190
 
191
- if file_status[file] != FileVerificationStatus.UPLAODED:
191
+ if file_status[file] != FileVerificationStatus.UPLOADED:
192
192
  continue # abort if we already found a mismatch
193
193
 
194
194
  if check_file_hash:
195
195
  if remote_file.hash is None:
196
196
  file_status[file] = FileVerificationStatus.COMPUTING_HASH
197
197
  elif remote_file.hash == b64_md5(file):
198
- file_status[file] = FileVerificationStatus.UPLAODED
198
+ file_status[file] = FileVerificationStatus.UPLOADED
199
199
  else:
200
200
  file_status[file] = FileVerificationStatus.MISMATCHED_HASH
201
201
 
@@ -77,7 +77,7 @@ class File:
77
77
 
78
78
  # this is the file state for the verify command
79
79
  class FileVerificationStatus(str, Enum):
80
- UPLAODED = "uploaded"
80
+ UPLOADED = "uploaded"
81
81
  UPLOADING = "uploading"
82
82
  COMPUTING_HASH = "computing hash"
83
83
  MISSING = "missing"
@@ -38,7 +38,7 @@ FILE_STATE_COLOR = {
38
38
 
39
39
 
40
40
  FILE_VERIFICATION_STATUS_STYLES = {
41
- FileVerificationStatus.UPLAODED: "green",
41
+ FileVerificationStatus.UPLOADED: "green",
42
42
  FileVerificationStatus.UPLOADING: "yellow",
43
43
  FileVerificationStatus.MISSING: "yellow",
44
44
  FileVerificationStatus.MISMATCHED_HASH: "red",
@@ -297,7 +297,7 @@ def print_file_verification_status(
297
297
  else:
298
298
  for path, status in file_status.items():
299
299
  stream = (
300
- sys.stdout if status == FileVerificationStatus.UPLAODED else sys.stderr
300
+ sys.stdout if status == FileVerificationStatus.UPLOADED else sys.stderr
301
301
  )
302
302
  print(path, file=stream, flush=True)
303
303
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kleinkram
3
- Version: 0.44.0.dev20250407065841
3
+ Version: 0.44.0.dev20250409080103
4
4
  Summary: give me your bags
5
5
  Author: Cyrill Püntener, Dominique Garmier, Johann Schwabe
6
6
  Author-email: pucyril@ethz.ch, dgarmier@ethz.ch, jschwab@ethz.ch
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = kleinkram
3
- version = 0.44.0-dev20250407065841
3
+ version = 0.44.0-dev20250409080103
4
4
  description = give me your bags
5
5
  long_description = file: README.md
6
6
  long_description_content_type = text/markdown
@@ -167,7 +167,7 @@ def test_verify(mission):
167
167
  )
168
168
 
169
169
  assert all(
170
- status == FileVerificationStatus.UPLAODED for status in verify_status.values()
170
+ status == FileVerificationStatus.UPLOADED for status in verify_status.values()
171
171
  )
172
172
 
173
173