data-sourcerer 0.2.1__py3-none-any.whl → 0.2.3__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.
Files changed (39) hide show
  1. {data_sourcerer-0.2.1.dist-info → data_sourcerer-0.2.3.dist-info}/METADATA +4 -1
  2. {data_sourcerer-0.2.1.dist-info → data_sourcerer-0.2.3.dist-info}/RECORD +39 -35
  3. sourcerer/__init__.py +1 -1
  4. sourcerer/domain/access_credentials/entities.py +4 -7
  5. sourcerer/domain/access_credentials/repositories.py +12 -0
  6. sourcerer/domain/access_credentials/services.py +2 -1
  7. sourcerer/domain/file_system/entities.py +5 -7
  8. sourcerer/domain/storage_provider/entities.py +7 -11
  9. sourcerer/infrastructure/access_credentials/registry.py +1 -1
  10. sourcerer/infrastructure/access_credentials/repositories.py +17 -0
  11. sourcerer/infrastructure/access_credentials/services.py +30 -14
  12. sourcerer/infrastructure/db/config.py +1 -1
  13. sourcerer/infrastructure/storage_provider/services/azure.py +5 -3
  14. sourcerer/infrastructure/utils.py +115 -1
  15. sourcerer/presentation/screens/critical_error/main.py +4 -4
  16. sourcerer/presentation/screens/file_system_finder/main.py +7 -3
  17. sourcerer/presentation/screens/file_system_finder/widgets/file_system_navigator.py +1 -1
  18. sourcerer/presentation/screens/main/main.py +37 -6
  19. sourcerer/presentation/screens/main/messages/refresh_storages_list_request.py +8 -0
  20. sourcerer/presentation/screens/main/widgets/gradient.py +3 -3
  21. sourcerer/presentation/screens/main/widgets/resizing_rule.py +3 -1
  22. sourcerer/presentation/screens/main/widgets/storage_content.py +43 -18
  23. sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +38 -6
  24. sourcerer/presentation/screens/preview_content/main.py +5 -5
  25. sourcerer/presentation/screens/provider_creds_list/main.py +44 -0
  26. sourcerer/presentation/screens/provider_creds_list/messages/__init__.py +0 -0
  27. sourcerer/presentation/screens/provider_creds_list/messages/reload_credentials_request.py +8 -0
  28. sourcerer/presentation/screens/provider_creds_list/styles.tcss +5 -5
  29. sourcerer/presentation/screens/provider_creds_registration/main.py +6 -2
  30. sourcerer/presentation/screens/question/main.py +4 -3
  31. sourcerer/presentation/screens/question/styles.tcss +2 -8
  32. sourcerer/presentation/screens/shared/widgets/button.py +1 -1
  33. sourcerer/presentation/screens/shared/widgets/labeled_input.py +5 -1
  34. sourcerer/presentation/screens/shared/widgets/loader.py +31 -0
  35. sourcerer/presentation/screens/storage_action_progress/main.py +29 -29
  36. sourcerer/utils.py +1 -1
  37. {data_sourcerer-0.2.1.dist-info → data_sourcerer-0.2.3.dist-info}/WHEEL +0 -0
  38. {data_sourcerer-0.2.1.dist-info → data_sourcerer-0.2.3.dist-info}/entry_points.txt +0 -0
  39. {data_sourcerer-0.2.1.dist-info → data_sourcerer-0.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -76,5 +76,9 @@ class LabeledInput(Container):
76
76
 
77
77
  """
78
78
  input_area = self.query_one(".form_input")
79
- text = input_area.document.text if isinstance(input_area, TextArea) else input_area.value # type: ignore
79
+ text = (
80
+ input_area.document.text
81
+ if isinstance(input_area, TextArea)
82
+ else input_area.value # type: ignore
83
+ )
80
84
  return self.Value(name=self.key, value=text)
@@ -0,0 +1,31 @@
1
+ from textual.app import ComposeResult
2
+ from textual.containers import Container
3
+ from textual.widgets import Static
4
+
5
+
6
+ class Loader(Container):
7
+ stops = "⣷⣯⣟⡿⢿⣻⣽⣾"
8
+ index = 0
9
+
10
+ DEFAULT_CSS = """
11
+ Loader {
12
+ color: #9E53E0;
13
+ }
14
+ """
15
+
16
+ def __init__(self, *args, **kwargs):
17
+ self.label = Static(self.stops[self.index])
18
+ super().__init__(*args, **kwargs)
19
+
20
+ def compose(self) -> ComposeResult:
21
+ yield self.label
22
+
23
+ def on_mount(self) -> None:
24
+ self.auto_refresh = 1 / 10
25
+
26
+ def automatic_refresh(self):
27
+ self.index += 1
28
+ if self.index >= len(self.stops):
29
+ self.index = 0
30
+ value = self.stops[self.index]
31
+ self.label.update(value)
@@ -1,9 +1,9 @@
1
1
  import contextlib
2
2
  import os
3
3
  from concurrent.futures import ThreadPoolExecutor, as_completed
4
- from dataclasses import dataclass
5
4
  from pathlib import Path
6
5
 
6
+ from msgspec._core import Struct
7
7
  from rich.text import Text
8
8
  from textual import on
9
9
  from textual.app import ComposeResult
@@ -44,8 +44,7 @@ gradient2 = Gradient.from_colors(
44
44
  )
45
45
 
46
46
 
47
- @dataclass
48
- class Key:
47
+ class Key(Struct):
49
48
  """
50
49
  Base class for representing a key in storage operations.
51
50
 
@@ -76,7 +75,6 @@ class DeleteKey(Key):
76
75
  """
77
76
 
78
77
 
79
- @dataclass
80
78
  class UploadKey(Key):
81
79
  """
82
80
  Represents a key for upload operations.
@@ -187,9 +185,9 @@ class StorageActionProgressScreen(ModalScreen):
187
185
  Sets the border title and starts the appropriate worker thread based on the action type
188
186
  (download, delete, or upload).
189
187
  """
190
- self.query_one("#StorageActionProgress").border_title = (
191
- f"{self.action.capitalize()} {len(self.keys)} files from {self.storage_name}"
192
- )
188
+ self.query_one(
189
+ "#StorageActionProgress"
190
+ ).border_title = f"{self.action.capitalize()} {len(self.keys)} files from {self.storage_name}"
193
191
 
194
192
  if self.action == "download":
195
193
  self.active_worker = self.run_worker(self.download_files, thread=True)
@@ -245,7 +243,7 @@ class StorageActionProgressScreen(ModalScreen):
245
243
  This method handles the download of multiple files, updating progress bars
246
244
  and handling various error conditions that might occur during the process.
247
245
  """
248
- main_progress_bar = self.query_one("#progress_bar")
246
+ main_progress_bar = self.query_one("#progress_bar", ProgressBar)
249
247
  failed_downloads = []
250
248
 
251
249
  with ThreadPoolExecutor(max_workers=MAX_PARALLEL_DOWNLOADS) as executor:
@@ -291,13 +289,13 @@ class StorageActionProgressScreen(ModalScreen):
291
289
  def progress_callback(progress_bar, chunk):
292
290
  progress_bar.advance(chunk)
293
291
 
294
- progress_bar = self.query_one(f"#progress_bar_{uuid}")
292
+ progress_bar = self.query_one(f"#progress_bar_{uuid}", ProgressBar)
295
293
 
296
294
  try:
297
295
  # Step 1: Get file size
298
296
  try:
299
297
  file_size = self.provider_service.get_file_size(self.storage_name, key)
300
- progress_bar.total = file_size # type: ignore
298
+ progress_bar.total = file_size
301
299
  except Exception as ex:
302
300
  self.notify(
303
301
  f"Failed to get file size for {key}: {str(ex)}", severity="error"
@@ -318,9 +316,9 @@ class StorageActionProgressScreen(ModalScreen):
318
316
  return
319
317
 
320
318
  # Step 3: Ensure progress bar is complete
321
- if progress_bar.progress != progress_bar.total: # type: ignore
319
+ if progress_bar.progress != progress_bar.total:
322
320
  try:
323
- progress_bar.progress = file_size # type: ignore
321
+ progress_bar.progress = file_size
324
322
  except Exception as ex:
325
323
  self.log.error(f"Error updating progress bar: {ex}")
326
324
  # Non-critical error, continue execution
@@ -340,7 +338,7 @@ class StorageActionProgressScreen(ModalScreen):
340
338
  This method handles the deletion of multiple files, updating progress bars
341
339
  and handling various error conditions that might occur during the process.
342
340
  """
343
- main_progress_bar = self.query_one("#progress_bar")
341
+ main_progress_bar = self.query_one("#progress_bar", ProgressBar)
344
342
  failed_downloads = []
345
343
 
346
344
  with ThreadPoolExecutor(max_workers=MAX_PARALLEL_DOWNLOADS) as executor:
@@ -379,11 +377,11 @@ class StorageActionProgressScreen(ModalScreen):
379
377
  main_progress_bar.advance(1)
380
378
  return
381
379
 
382
- progress_bar = self.query_one(f"#progress_bar_{uuid}")
380
+ progress_bar = self.query_one(f"#progress_bar_{uuid}", ProgressBar)
383
381
  try:
384
- progress_bar.total = 1 # type: ignore
382
+ progress_bar.total = 1
385
383
  self.provider_service.delete_storage_item(self.storage_name, key)
386
- progress_bar.advance(1) # type: ignore
384
+ progress_bar.advance(1)
387
385
  except Exception:
388
386
  self.notify(f"Failed to delete {key}", severity="error")
389
387
  raise
@@ -397,7 +395,7 @@ class StorageActionProgressScreen(ModalScreen):
397
395
  This method handles the upload of files, updating progress bars and
398
396
  handling various error conditions that might occur during the process.
399
397
  """
400
- main_progress_bar = self.query_one("#progress_bar")
398
+ main_progress_bar = self.query_one("#progress_bar", ProgressBar)
401
399
  failed_downloads = []
402
400
  if not self.provider_service:
403
401
  self.notify("Failed to upload files", severity="error")
@@ -411,10 +409,12 @@ class StorageActionProgressScreen(ModalScreen):
411
409
  storage=self.storage_name,
412
410
  storage_path=self.path,
413
411
  source_path=key.path,
414
- dest_path=key.dest_path, # type: ignore
412
+ dest_path=key.dest_path,
413
+ )
414
+ progress_bar = self.query_one(
415
+ f"#progress_bar_{key.uuid}", ProgressBar
415
416
  )
416
- progress_bar = self.query_one(f"#progress_bar_{key.uuid}")
417
- progress_bar.advance(1) # type: ignore
417
+ progress_bar.advance(1)
418
418
  except UploadStorageItemsError as e:
419
419
  self.notify(f"Failed to upload {key.path}: {e}", severity="error")
420
420
  finally:
@@ -422,8 +422,8 @@ class StorageActionProgressScreen(ModalScreen):
422
422
  elif source_path.is_dir():
423
423
 
424
424
  files_n = len([i for i in source_path.rglob("*") if i.is_file()])
425
- progress_bar = self.query_one(f"#progress_bar_{key.uuid}")
426
- progress_bar.total = files_n # type: ignore
425
+ progress_bar = self.query_one(f"#progress_bar_{key.uuid}", ProgressBar)
426
+ progress_bar.total = files_n
427
427
  with ThreadPoolExecutor(max_workers=MAX_PARALLEL_DOWNLOADS) as executor:
428
428
  self.active_executor = executor
429
429
  futures = [
@@ -447,10 +447,10 @@ class StorageActionProgressScreen(ModalScreen):
447
447
  self.files_has_been_processed = True
448
448
  self.active_executor = None
449
449
  try:
450
- self.query_one(f"#progress_file_details_{key.uuid}").remove()
451
- except Exception:
450
+ self.query_one(f"#progress_file_details_{key.uuid}", Label).remove()
451
+ except NoMatches:
452
452
  self.log(f"Failed to remove progress details for {key.uuid}")
453
- main_progress_bar.advance(1) # type: ignore
453
+ main_progress_bar.advance(1)
454
454
 
455
455
  def upload_file(self, source, rel_source, destination, uuid):
456
456
  """
@@ -467,12 +467,12 @@ class StorageActionProgressScreen(ModalScreen):
467
467
  if not self.provider_service:
468
468
  self.notify(f"Failed to upload {source}", severity="error")
469
469
  return
470
- progress_bar = self.query_one(f"#progress_bar_{uuid}")
470
+ progress_bar = self.query_one(f"#progress_bar_{uuid}", ProgressBar)
471
471
  details_container = None
472
472
  with contextlib.suppress(NoMatches):
473
- details_container = self.query_one(f"#progress_file_details_{uuid}")
473
+ details_container = self.query_one(f"#progress_file_details_{uuid}", Label)
474
474
  if details_container:
475
- details_container.update(Text(f"({rel_source})", overflow="ellipsis")) # type: ignore
475
+ details_container.update(Text(f"({rel_source})", overflow="ellipsis"))
476
476
  try:
477
477
  self.provider_service.upload_storage_item(
478
478
  storage=self.storage_name,
@@ -480,7 +480,7 @@ class StorageActionProgressScreen(ModalScreen):
480
480
  source_path=source,
481
481
  dest_path=destination,
482
482
  )
483
- progress_bar.advance(1) # type: ignore
483
+ progress_bar.advance(1)
484
484
  except UploadStorageItemsError as e:
485
485
  self.notify(f"Failed to upload {source}: {e}", severity="error")
486
486
 
sourcerer/utils.py CHANGED
@@ -4,7 +4,7 @@ import uuid
4
4
  from pathlib import Path
5
5
 
6
6
 
7
- def get_encryption_key(path: Path):
7
+ def get_encryption_key(path: Path) -> str:
8
8
  """
9
9
  Get the encryption key from a file or generate a new one if the file doesn't exist.
10
10