data-sourcerer 0.4.0__py3-none-any.whl → 0.6.0__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 (45) hide show
  1. {data_sourcerer-0.4.0.dist-info → data_sourcerer-0.6.0.dist-info}/METADATA +13 -8
  2. {data_sourcerer-0.4.0.dist-info → data_sourcerer-0.6.0.dist-info}/RECORD +45 -26
  3. sourcerer/__init__.py +3 -1
  4. sourcerer/domain/package_meta/__init__.py +0 -0
  5. sourcerer/domain/package_meta/entities.py +9 -0
  6. sourcerer/domain/package_meta/services.py +9 -0
  7. sourcerer/domain/settings/__init__.py +0 -0
  8. sourcerer/domain/settings/entities.py +11 -0
  9. sourcerer/domain/settings/repositories.py +20 -0
  10. sourcerer/domain/settings/services.py +19 -0
  11. sourcerer/infrastructure/db/models.py +23 -0
  12. sourcerer/infrastructure/package_meta/__init__.py +0 -0
  13. sourcerer/infrastructure/package_meta/services.py +26 -0
  14. sourcerer/infrastructure/settings/__init__.py +0 -0
  15. sourcerer/infrastructure/settings/repositories.py +59 -0
  16. sourcerer/infrastructure/settings/services.py +16 -0
  17. sourcerer/infrastructure/storage_provider/services/azure.py +25 -2
  18. sourcerer/infrastructure/storage_provider/services/gcp.py +0 -1
  19. sourcerer/infrastructure/utils.py +1 -0
  20. sourcerer/presentation/di_container.py +13 -0
  21. sourcerer/presentation/screens/about/__init__.py +0 -0
  22. sourcerer/presentation/screens/about/main.py +60 -0
  23. sourcerer/presentation/screens/about/styles.tcss +32 -0
  24. sourcerer/presentation/screens/file_system_finder/__init__.py +0 -0
  25. sourcerer/presentation/screens/main/main.py +89 -6
  26. sourcerer/presentation/screens/main/styles.tcss +13 -4
  27. sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +102 -18
  28. sourcerer/presentation/screens/provider_creds_list/main.py +14 -4
  29. sourcerer/presentation/screens/provider_creds_list/styles.tcss +9 -0
  30. sourcerer/presentation/screens/question/styles.tcss +1 -1
  31. sourcerer/presentation/screens/settings/__init__.py +0 -0
  32. sourcerer/presentation/screens/settings/main.py +70 -0
  33. sourcerer/presentation/screens/settings/styles.tcss +44 -0
  34. sourcerer/presentation/screens/shared/widgets/button.py +11 -0
  35. sourcerer/presentation/screens/shared/widgets/labeled_input.py +1 -3
  36. sourcerer/presentation/screens/storage_action_progress/main.py +1 -2
  37. sourcerer/presentation/screens/storages_list/main.py +15 -4
  38. sourcerer/presentation/screens/storages_list/styles.tcss +7 -0
  39. sourcerer/presentation/settings.py +1 -0
  40. sourcerer/presentation/utils.py +15 -1
  41. sourcerer/settings.py +2 -0
  42. sourcerer/utils.py +19 -1
  43. {data_sourcerer-0.4.0.dist-info → data_sourcerer-0.6.0.dist-info}/WHEEL +0 -0
  44. {data_sourcerer-0.4.0.dist-info → data_sourcerer-0.6.0.dist-info}/entry_points.txt +0 -0
  45. {data_sourcerer-0.4.0.dist-info → data_sourcerer-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,12 @@
1
1
  import datetime
2
2
  import uuid
3
3
  from enum import Enum
4
+ from typing import ClassVar
4
5
 
5
6
  from dependency_injector.wiring import Provide
6
7
  from textual import on
7
8
  from textual.app import ComposeResult
9
+ from textual.binding import Binding, BindingType
8
10
  from textual.containers import Container, Horizontal, VerticalScroll
9
11
  from textual.reactive import reactive
10
12
  from textual.widgets import Label
@@ -82,6 +84,11 @@ class StoragesListScreen(RefreshTriggerableModalScreen):
82
84
  MAIN_CONTAINER_ID = "StoragesListScreen"
83
85
  SETTINGS_CONTAINER_ID = "settings"
84
86
 
87
+ BINDINGS: ClassVar[list[BindingType]] = [
88
+ *RefreshTriggerableModalScreen.BINDINGS,
89
+ Binding("ctrl+n", "add_storage", "Add new storage"),
90
+ ]
91
+
85
92
  storages_list = reactive([], recompose=True)
86
93
 
87
94
  def __init__(
@@ -104,6 +111,7 @@ class StoragesListScreen(RefreshTriggerableModalScreen):
104
111
  "+Add new storage",
105
112
  name=ControlsEnum.ADD_STORAGE.name,
106
113
  classes="add_storage_button",
114
+ id="add_storage_button",
107
115
  ),
108
116
  id="right-top",
109
117
  )
@@ -155,10 +163,7 @@ class StoragesListScreen(RefreshTriggerableModalScreen):
155
163
  if event.action == ControlsEnum.CANCEL.name:
156
164
  self.action_cancel_screen()
157
165
  if event.action == ControlsEnum.ADD_STORAGE.name:
158
- self.app.push_screen(
159
- StoragesRegistrationScreen(),
160
- callback=self.create_storage_entry, # type: ignore
161
- )
166
+ self.action_add_storage()
162
167
 
163
168
  def create_storage_entry(self, storage: StorageEntry | None):
164
169
  """
@@ -182,3 +187,9 @@ class StoragesListScreen(RefreshTriggerableModalScreen):
182
187
  )
183
188
  )
184
189
  self.refresh_storages_list()
190
+
191
+ def action_add_storage(self):
192
+ self.app.push_screen(
193
+ StoragesRegistrationScreen(),
194
+ callback=self.create_storage_entry, # type: ignore
195
+ )
@@ -23,6 +23,13 @@ StoragesListScreen {
23
23
 
24
24
  .add_storage_button {
25
25
  color: $success-darken-2;
26
+
27
+ &:hover {
28
+ color: $primary;
29
+ }
30
+ &:focus {
31
+ color: $primary;
32
+ }
26
33
  }
27
34
 
28
35
  margin-bottom: 1;
@@ -3,6 +3,7 @@
3
3
  This module contains various configuration constants and settings used throughout
4
4
  the application, including UI elements and display configurations.
5
5
  """
6
+
6
7
  from enum import Enum
7
8
 
8
9
  NO_DATA_LOGO = """
@@ -4,6 +4,9 @@ Utility functions for the presentation layer.
4
4
  This module provides helper functions for the presentation layer,
5
5
  particularly for retrieving and initializing storage provider services.
6
6
  """
7
+ from threading import Lock
8
+
9
+ from cachetools import LRUCache
7
10
  from dependency_injector.wiring import Provide
8
11
 
9
12
  from sourcerer.domain.access_credentials.repositories import BaseCredentialsRepository
@@ -14,6 +17,10 @@ from sourcerer.infrastructure.access_credentials.registry import (
14
17
  )
15
18
  from sourcerer.infrastructure.storage_provider.registry import storage_provider_registry
16
19
  from sourcerer.presentation.di_container import DiContainer
20
+ from sourcerer.settings import MAX_CREDENTIALS_CACHE_SIZE
21
+
22
+ _provider_service_cache: LRUCache = LRUCache(maxsize=MAX_CREDENTIALS_CACHE_SIZE)
23
+ _provider_service_cache_lock = Lock()
17
24
 
18
25
 
19
26
  def get_provider_service_by_access_uuid(
@@ -59,6 +66,10 @@ def get_provider_service_by_access_credentials(
59
66
  authenticated credentials.
60
67
  """
61
68
 
69
+ with _provider_service_cache_lock:
70
+ if credentials.uuid in _provider_service_cache:
71
+ return _provider_service_cache[credentials.uuid]
72
+
62
73
  credentials_service = access_credential_method_registry.get_by_provider_and_name(
63
74
  credentials.provider, credentials.credentials_type
64
75
  )
@@ -78,4 +89,7 @@ def get_provider_service_by_access_credentials(
78
89
  )
79
90
  except CredentialsAuthError:
80
91
  return None
81
- return provider_service_class(auth_credentials)
92
+ service = provider_service_class(auth_credentials)
93
+ with _provider_service_cache_lock:
94
+ _provider_service_cache[credentials.uuid] = service
95
+ return service
sourcerer/settings.py CHANGED
@@ -76,3 +76,5 @@ TEXT_EXTENSIONS = {
76
76
  PAGE_SIZE = 100
77
77
  PREVIEW_LENGTH_LIMIT = 10_000
78
78
  PREVIEW_LIMIT_SIZE = 2 * 1024 * 1024 # 2 MB
79
+
80
+ MAX_CREDENTIALS_CACHE_SIZE = 30
sourcerer/utils.py CHANGED
@@ -1,8 +1,10 @@
1
- # Generate and store encryption key in a file
1
+ import contextlib
2
2
  import os
3
3
  import uuid
4
4
  from pathlib import Path
5
5
 
6
+ import requests
7
+
6
8
 
7
9
  def get_encryption_key(path: Path) -> str:
8
10
  """
@@ -30,3 +32,19 @@ def get_encryption_key(path: Path) -> str:
30
32
  f.write(new_key)
31
33
 
32
34
  return new_key
35
+
36
+
37
+ def get_last_package_version(name):
38
+ """
39
+ Fetch the latest version of a package from PyPI.
40
+ Args:
41
+ name (str): The name of the package.
42
+ Returns:
43
+ str: The latest version of the package, or None if an error occurs.
44
+ """
45
+ with contextlib.suppress(Exception):
46
+ url = f"https://pypi.org/pypi/{name}/json"
47
+ response = requests.get(url, timeout=5)
48
+ response.raise_for_status()
49
+ return response.json()["info"]["version"]
50
+ return None