data-sourcerer 0.3.0__py3-none-any.whl → 0.5.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.
- {data_sourcerer-0.3.0.dist-info → data_sourcerer-0.5.0.dist-info}/METADATA +11 -8
- {data_sourcerer-0.3.0.dist-info → data_sourcerer-0.5.0.dist-info}/RECORD +55 -34
- sourcerer/__init__.py +3 -1
- sourcerer/domain/package_meta/__init__.py +0 -0
- sourcerer/domain/package_meta/entities.py +9 -0
- sourcerer/domain/package_meta/services.py +9 -0
- sourcerer/domain/settings/__init__.py +0 -0
- sourcerer/domain/settings/entities.py +11 -0
- sourcerer/domain/settings/repositories.py +20 -0
- sourcerer/domain/settings/services.py +19 -0
- sourcerer/domain/storage_provider/entities.py +1 -1
- sourcerer/infrastructure/db/models.py +23 -0
- sourcerer/infrastructure/package_meta/__init__.py +0 -0
- sourcerer/infrastructure/package_meta/services.py +26 -0
- sourcerer/infrastructure/settings/__init__.py +0 -0
- sourcerer/infrastructure/settings/repositories.py +59 -0
- sourcerer/infrastructure/settings/services.py +16 -0
- sourcerer/infrastructure/storage_provider/services/azure.py +1 -3
- sourcerer/infrastructure/storage_provider/services/gcp.py +1 -3
- sourcerer/infrastructure/storage_provider/services/s3.py +1 -2
- sourcerer/infrastructure/utils.py +1 -0
- sourcerer/presentation/di_container.py +13 -0
- sourcerer/presentation/screens/about/__init__.py +0 -0
- sourcerer/presentation/screens/about/main.py +60 -0
- sourcerer/presentation/screens/about/styles.tcss +32 -0
- sourcerer/presentation/screens/file_system_finder/__init__.py +0 -0
- sourcerer/presentation/screens/file_system_finder/main.py +3 -9
- sourcerer/presentation/screens/main/main.py +116 -8
- sourcerer/presentation/screens/main/messages/preview_request.py +1 -0
- sourcerer/presentation/screens/main/styles.tcss +13 -4
- sourcerer/presentation/screens/main/widgets/storage_content.py +10 -3
- sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +102 -18
- sourcerer/presentation/screens/preview_content/main.py +202 -15
- sourcerer/presentation/screens/preview_content/styles.tcss +39 -4
- sourcerer/presentation/screens/preview_content/text_area_style.py +60 -0
- sourcerer/presentation/screens/provider_creds_list/main.py +23 -9
- sourcerer/presentation/screens/provider_creds_list/styles.tcss +9 -0
- sourcerer/presentation/screens/provider_creds_registration/main.py +3 -3
- sourcerer/presentation/screens/settings/__init__.py +0 -0
- sourcerer/presentation/screens/settings/main.py +70 -0
- sourcerer/presentation/screens/settings/styles.tcss +44 -0
- sourcerer/presentation/screens/shared/modal_screens.py +37 -0
- sourcerer/presentation/screens/shared/widgets/button.py +11 -0
- sourcerer/presentation/screens/shared/widgets/labeled_input.py +1 -3
- sourcerer/presentation/screens/storage_action_progress/main.py +1 -2
- sourcerer/presentation/screens/storages_list/main.py +24 -9
- sourcerer/presentation/screens/storages_list/styles.tcss +7 -0
- sourcerer/presentation/screens/storages_registration/main.py +3 -3
- sourcerer/presentation/settings.py +1 -0
- sourcerer/presentation/utils.py +1 -0
- sourcerer/settings.py +2 -0
- sourcerer/utils.py +19 -1
- {data_sourcerer-0.3.0.dist-info → data_sourcerer-0.5.0.dist-info}/WHEEL +0 -0
- {data_sourcerer-0.3.0.dist-info → data_sourcerer-0.5.0.dist-info}/entry_points.txt +0 -0
- {data_sourcerer-0.3.0.dist-info → data_sourcerer-0.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
from typing import ClassVar
|
2
|
+
|
3
|
+
from textual.binding import Binding, BindingType
|
4
|
+
from textual.screen import ModalScreen
|
5
|
+
|
6
|
+
|
7
|
+
class ExitBoundModalScreen(ModalScreen):
|
8
|
+
"""
|
9
|
+
A base class for modal screens that can be exited.
|
10
|
+
It provides a method to exit the screen and a flag to indicate if the screen should be exited.
|
11
|
+
"""
|
12
|
+
|
13
|
+
BINDINGS: ClassVar[list[BindingType]] = [
|
14
|
+
Binding("escape", "cancel_screen", "Pop screen"),
|
15
|
+
]
|
16
|
+
|
17
|
+
def action_cancel_screen(self):
|
18
|
+
"""
|
19
|
+
Action to exit the screen.
|
20
|
+
"""
|
21
|
+
self.dismiss()
|
22
|
+
|
23
|
+
|
24
|
+
class RefreshTriggerableModalScreen(ExitBoundModalScreen):
|
25
|
+
"""
|
26
|
+
A base class for modal screens that can be refreshed.
|
27
|
+
It provides a method to refresh the screen and a flag to indicate if the screen should be refreshed.
|
28
|
+
"""
|
29
|
+
|
30
|
+
def __init__(self, *args, **kwargs):
|
31
|
+
super().__init__(*args, **kwargs)
|
32
|
+
self._requires_storage_refresh = False
|
33
|
+
|
34
|
+
def action_cancel_screen(self):
|
35
|
+
requires_storage_refresh = self._requires_storage_refresh
|
36
|
+
self._requires_storage_refresh = False
|
37
|
+
self.dismiss(requires_storage_refresh)
|
@@ -28,6 +28,7 @@ class Button(Label):
|
|
28
28
|
}
|
29
29
|
}
|
30
30
|
"""
|
31
|
+
can_focus = True
|
31
32
|
|
32
33
|
@dataclass
|
33
34
|
class Click(Message):
|
@@ -52,3 +53,13 @@ class Button(Label):
|
|
52
53
|
_: An instance of events.Click representing the click event.
|
53
54
|
"""
|
54
55
|
self.post_message(self.Click(self.name)) # type: ignore
|
56
|
+
|
57
|
+
def on_key(self, event: events.Key) -> None:
|
58
|
+
"""
|
59
|
+
Handle key events to trigger click action when the button is focused and activated.
|
60
|
+
|
61
|
+
Args:
|
62
|
+
event (events.Key): The key event to handle.
|
63
|
+
"""
|
64
|
+
if event.key == "enter":
|
65
|
+
self.post_message(self.Click(self.name)) # type: ignore
|
@@ -77,8 +77,6 @@ class LabeledInput(Container):
|
|
77
77
|
"""
|
78
78
|
input_area = self.query_one(".form_input")
|
79
79
|
text = (
|
80
|
-
input_area.document.text
|
81
|
-
if isinstance(input_area, TextArea)
|
82
|
-
else input_area.value # type: ignore
|
80
|
+
input_area.document.text if isinstance(input_area, TextArea) else input_area.value # type: ignore
|
83
81
|
)
|
84
82
|
return self.Value(name=self.key, value=text)
|
@@ -369,7 +369,7 @@ class StorageActionProgressScreen(ModalScreen):
|
|
369
369
|
key (str): The key/path of the file to delete
|
370
370
|
uuid (str): Unique identifier for the file
|
371
371
|
main_progress_bar (ProgressBar): The main progress bar to update
|
372
|
-
"""
|
372
|
+
"""
|
373
373
|
if not self.provider_service:
|
374
374
|
self.notify(f"Failed to delete {key}", severity="error")
|
375
375
|
main_progress_bar.advance(1)
|
@@ -418,7 +418,6 @@ class StorageActionProgressScreen(ModalScreen):
|
|
418
418
|
finally:
|
419
419
|
self.files_has_been_processed = True
|
420
420
|
elif source_path.is_dir():
|
421
|
-
|
422
421
|
files_n = len([i for i in source_path.rglob("*") if i.is_file()])
|
423
422
|
progress_bar = self.query_one(f"#progress_bar_{key.uuid}", ProgressBar)
|
424
423
|
progress_bar.total = files_n
|
@@ -1,13 +1,14 @@
|
|
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
|
-
from textual.screen import ModalScreen
|
11
12
|
from textual.widgets import Label
|
12
13
|
|
13
14
|
from sourcerer.domain.storage.entities import Storage
|
@@ -15,6 +16,9 @@ from sourcerer.infrastructure.access_credentials.services import CredentialsServ
|
|
15
16
|
from sourcerer.infrastructure.storage.services import StoragesService
|
16
17
|
from sourcerer.presentation.di_container import DiContainer
|
17
18
|
from sourcerer.presentation.screens.question.main import QuestionScreen
|
19
|
+
from sourcerer.presentation.screens.shared.modal_screens import (
|
20
|
+
RefreshTriggerableModalScreen,
|
21
|
+
)
|
18
22
|
from sourcerer.presentation.screens.shared.widgets.button import Button
|
19
23
|
from sourcerer.presentation.screens.storages_list.messages.reload_storages_request import (
|
20
24
|
ReloadStoragesRequest,
|
@@ -74,12 +78,17 @@ class StorageRow(Horizontal):
|
|
74
78
|
self.post_message(ReloadStoragesRequest())
|
75
79
|
|
76
80
|
|
77
|
-
class StoragesListScreen(
|
81
|
+
class StoragesListScreen(RefreshTriggerableModalScreen):
|
78
82
|
CSS_PATH = "styles.tcss"
|
79
83
|
|
80
84
|
MAIN_CONTAINER_ID = "StoragesListScreen"
|
81
85
|
SETTINGS_CONTAINER_ID = "settings"
|
82
86
|
|
87
|
+
BINDINGS: ClassVar[list[BindingType]] = [
|
88
|
+
*RefreshTriggerableModalScreen.BINDINGS,
|
89
|
+
Binding("ctrl+n", "add_storage", "Add new storage"),
|
90
|
+
]
|
91
|
+
|
83
92
|
storages_list = reactive([], recompose=True)
|
84
93
|
|
85
94
|
def __init__(
|
@@ -102,6 +111,7 @@ class StoragesListScreen(ModalScreen):
|
|
102
111
|
"+Add new storage",
|
103
112
|
name=ControlsEnum.ADD_STORAGE.name,
|
104
113
|
classes="add_storage_button",
|
114
|
+
id="add_storage_button",
|
105
115
|
),
|
106
116
|
id="right-top",
|
107
117
|
)
|
@@ -119,13 +129,15 @@ class StoragesListScreen(ModalScreen):
|
|
119
129
|
"""
|
120
130
|
Initialize the screen by refreshing the credentials list when the screen is composed.
|
121
131
|
"""
|
122
|
-
self.refresh_storages_list()
|
132
|
+
self.refresh_storages_list(set_refresh_flag=False)
|
123
133
|
|
124
|
-
def refresh_storages_list(self):
|
134
|
+
def refresh_storages_list(self, set_refresh_flag: bool = True):
|
125
135
|
"""
|
126
136
|
Refresh the storages list by retrieving the latest storages from the storage service.
|
127
137
|
"""
|
128
138
|
self.storages_list = self.storage_service.list()
|
139
|
+
if set_refresh_flag:
|
140
|
+
self._requires_storage_refresh = True
|
129
141
|
|
130
142
|
@on(ReloadStoragesRequest)
|
131
143
|
def on_reload_storages_request(self, _: ReloadStoragesRequest):
|
@@ -149,12 +161,9 @@ class StoragesListScreen(ModalScreen):
|
|
149
161
|
event (Button.Click): The button click event.
|
150
162
|
"""
|
151
163
|
if event.action == ControlsEnum.CANCEL.name:
|
152
|
-
self.
|
164
|
+
self.action_cancel_screen()
|
153
165
|
if event.action == ControlsEnum.ADD_STORAGE.name:
|
154
|
-
self.
|
155
|
-
StoragesRegistrationScreen(),
|
156
|
-
callback=self.create_storage_entry, # type: ignore
|
157
|
-
)
|
166
|
+
self.action_add_storage()
|
158
167
|
|
159
168
|
def create_storage_entry(self, storage: StorageEntry | None):
|
160
169
|
"""
|
@@ -178,3 +187,9 @@ class StoragesListScreen(ModalScreen):
|
|
178
187
|
)
|
179
188
|
)
|
180
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
|
+
)
|
@@ -5,11 +5,11 @@ from dependency_injector.wiring import Provide
|
|
5
5
|
from textual import on
|
6
6
|
from textual.app import ComposeResult
|
7
7
|
from textual.containers import Container, Horizontal, VerticalScroll
|
8
|
-
from textual.screen import ModalScreen
|
9
8
|
from textual.widgets import Label, Select
|
10
9
|
|
11
10
|
from sourcerer.infrastructure.access_credentials.services import CredentialsService
|
12
11
|
from sourcerer.presentation.di_container import DiContainer
|
12
|
+
from sourcerer.presentation.screens.shared.modal_screens import ExitBoundModalScreen
|
13
13
|
from sourcerer.presentation.screens.shared.widgets.button import Button
|
14
14
|
from sourcerer.presentation.screens.shared.widgets.labeled_input import LabeledInput
|
15
15
|
|
@@ -25,7 +25,7 @@ class StorageEntry:
|
|
25
25
|
credentials_uuid: str
|
26
26
|
|
27
27
|
|
28
|
-
class StoragesRegistrationScreen(
|
28
|
+
class StoragesRegistrationScreen(ExitBoundModalScreen):
|
29
29
|
CSS_PATH = "styles.tcss"
|
30
30
|
|
31
31
|
MAIN_CONTAINER_ID = "StoragesRegistrationScreen"
|
@@ -84,7 +84,7 @@ class StoragesRegistrationScreen(ModalScreen):
|
|
84
84
|
collected authentication fields.
|
85
85
|
"""
|
86
86
|
if event.action == ControlsEnum.CANCEL.name:
|
87
|
-
self.
|
87
|
+
self.action_cancel_screen()
|
88
88
|
elif event.action == ControlsEnum.CREATE.name:
|
89
89
|
storage_name = self.query_one("#storage_name", LabeledInput).get().value
|
90
90
|
if not storage_name:
|
sourcerer/presentation/utils.py
CHANGED
@@ -4,6 +4,7 @@ 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
|
+
|
7
8
|
from dependency_injector.wiring import Provide
|
8
9
|
|
9
10
|
from sourcerer.domain.access_credentials.repositories import BaseCredentialsRepository
|
sourcerer/settings.py
CHANGED
sourcerer/utils.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
|
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
|
File without changes
|
File without changes
|
File without changes
|