data-sourcerer 0.1.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.1.0.dist-info/METADATA +52 -0
- data_sourcerer-0.1.0.dist-info/RECORD +95 -0
- data_sourcerer-0.1.0.dist-info/WHEEL +5 -0
- data_sourcerer-0.1.0.dist-info/entry_points.txt +2 -0
- data_sourcerer-0.1.0.dist-info/licenses/LICENSE +21 -0
- data_sourcerer-0.1.0.dist-info/top_level.txt +1 -0
- sourcerer/__init__.py +15 -0
- sourcerer/domain/__init__.py +13 -0
- sourcerer/domain/access_credentials/__init__.py +7 -0
- sourcerer/domain/access_credentials/entities.py +53 -0
- sourcerer/domain/access_credentials/exceptions.py +17 -0
- sourcerer/domain/access_credentials/repositories.py +84 -0
- sourcerer/domain/access_credentials/services.py +91 -0
- sourcerer/domain/file_system/__init__.py +7 -0
- sourcerer/domain/file_system/entities.py +70 -0
- sourcerer/domain/file_system/exceptions.py +17 -0
- sourcerer/domain/file_system/services.py +64 -0
- sourcerer/domain/shared/__init__.py +6 -0
- sourcerer/domain/shared/entities.py +18 -0
- sourcerer/domain/storage_provider/__init__.py +7 -0
- sourcerer/domain/storage_provider/entities.py +86 -0
- sourcerer/domain/storage_provider/exceptions.py +17 -0
- sourcerer/domain/storage_provider/services.py +130 -0
- sourcerer/infrastructure/__init__.py +13 -0
- sourcerer/infrastructure/access_credentials/__init__.py +7 -0
- sourcerer/infrastructure/access_credentials/exceptions.py +16 -0
- sourcerer/infrastructure/access_credentials/registry.py +120 -0
- sourcerer/infrastructure/access_credentials/repositories.py +119 -0
- sourcerer/infrastructure/access_credentials/services.py +396 -0
- sourcerer/infrastructure/db/__init__.py +6 -0
- sourcerer/infrastructure/db/config.py +73 -0
- sourcerer/infrastructure/db/models.py +47 -0
- sourcerer/infrastructure/file_system/__init__.py +7 -0
- sourcerer/infrastructure/file_system/exceptions.py +89 -0
- sourcerer/infrastructure/file_system/services.py +147 -0
- sourcerer/infrastructure/storage_provider/__init__.py +7 -0
- sourcerer/infrastructure/storage_provider/exceptions.py +78 -0
- sourcerer/infrastructure/storage_provider/registry.py +84 -0
- sourcerer/infrastructure/storage_provider/services.py +509 -0
- sourcerer/infrastructure/utils.py +106 -0
- sourcerer/presentation/__init__.py +12 -0
- sourcerer/presentation/app.py +36 -0
- sourcerer/presentation/di_container.py +46 -0
- sourcerer/presentation/screens/__init__.py +0 -0
- sourcerer/presentation/screens/critical_error/__init__.py +0 -0
- sourcerer/presentation/screens/critical_error/main.py +78 -0
- sourcerer/presentation/screens/critical_error/styles.tcss +41 -0
- sourcerer/presentation/screens/file_system_finder/main.py +248 -0
- sourcerer/presentation/screens/file_system_finder/styles.tcss +44 -0
- sourcerer/presentation/screens/file_system_finder/widgets/__init__.py +0 -0
- sourcerer/presentation/screens/file_system_finder/widgets/file_system_navigator.py +810 -0
- sourcerer/presentation/screens/main/__init__.py +0 -0
- sourcerer/presentation/screens/main/main.py +469 -0
- sourcerer/presentation/screens/main/messages/__init__.py +0 -0
- sourcerer/presentation/screens/main/messages/delete_request.py +12 -0
- sourcerer/presentation/screens/main/messages/download_request.py +12 -0
- sourcerer/presentation/screens/main/messages/preview_request.py +10 -0
- sourcerer/presentation/screens/main/messages/resizing_rule.py +21 -0
- sourcerer/presentation/screens/main/messages/select_storage_item.py +11 -0
- sourcerer/presentation/screens/main/messages/uncheck_files_request.py +8 -0
- sourcerer/presentation/screens/main/messages/upload_request.py +10 -0
- sourcerer/presentation/screens/main/mixins/__init__.py +0 -0
- sourcerer/presentation/screens/main/mixins/resize_containers_watcher_mixin.py +144 -0
- sourcerer/presentation/screens/main/styles.tcss +32 -0
- sourcerer/presentation/screens/main/widgets/__init__.py +0 -0
- sourcerer/presentation/screens/main/widgets/gradient.py +45 -0
- sourcerer/presentation/screens/main/widgets/resizing_rule.py +67 -0
- sourcerer/presentation/screens/main/widgets/storage_content.py +691 -0
- sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +143 -0
- sourcerer/presentation/screens/preview_content/__init__.py +0 -0
- sourcerer/presentation/screens/preview_content/main.py +59 -0
- sourcerer/presentation/screens/preview_content/styles.tcss +26 -0
- sourcerer/presentation/screens/provider_creds_list/__init__.py +0 -0
- sourcerer/presentation/screens/provider_creds_list/main.py +164 -0
- sourcerer/presentation/screens/provider_creds_list/styles.tcss +65 -0
- sourcerer/presentation/screens/provider_creds_registration/__init__.py +0 -0
- sourcerer/presentation/screens/provider_creds_registration/main.py +264 -0
- sourcerer/presentation/screens/provider_creds_registration/styles.tcss +42 -0
- sourcerer/presentation/screens/question/__init__.py +0 -0
- sourcerer/presentation/screens/question/main.py +31 -0
- sourcerer/presentation/screens/question/styles.tcss +33 -0
- sourcerer/presentation/screens/shared/__init__.py +0 -0
- sourcerer/presentation/screens/shared/containers.py +13 -0
- sourcerer/presentation/screens/shared/widgets/__init__.py +0 -0
- sourcerer/presentation/screens/shared/widgets/button.py +54 -0
- sourcerer/presentation/screens/shared/widgets/labeled_input.py +80 -0
- sourcerer/presentation/screens/storage_action_progress/__init__.py +0 -0
- sourcerer/presentation/screens/storage_action_progress/main.py +476 -0
- sourcerer/presentation/screens/storage_action_progress/styles.tcss +43 -0
- sourcerer/presentation/settings.py +31 -0
- sourcerer/presentation/themes/__init__.py +0 -0
- sourcerer/presentation/themes/github_dark.py +21 -0
- sourcerer/presentation/utils.py +69 -0
- sourcerer/settings.py +72 -0
- sourcerer/utils.py +32 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
"""
|
2
|
+
File system service implementation.
|
3
|
+
|
4
|
+
This module provides a concrete implementation of the BaseFileSystemService
|
5
|
+
interface for interacting with the local file system.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from pathlib import Path
|
9
|
+
|
10
|
+
from sourcerer.domain.file_system.entities import ListDirOutput
|
11
|
+
from sourcerer.domain.file_system.services import BaseFileSystemService
|
12
|
+
from sourcerer.infrastructure.file_system.exceptions import (
|
13
|
+
ReadFileException,
|
14
|
+
ListDirException,
|
15
|
+
)
|
16
|
+
from sourcerer.infrastructure.utils import custom_sort_key
|
17
|
+
|
18
|
+
|
19
|
+
class FileSystemService(BaseFileSystemService):
|
20
|
+
"""
|
21
|
+
Implementation of the file system service for local file operations.
|
22
|
+
|
23
|
+
This class provides methods for interacting with the local file system,
|
24
|
+
implementing the BaseFileSystemService interface. It handles operations
|
25
|
+
like reading, writing, listing, and searching files within a specified
|
26
|
+
working directory.
|
27
|
+
"""
|
28
|
+
|
29
|
+
ACCESS_DENIED_ERROR = "Access denied: Path outside work directory"
|
30
|
+
FILE_NOT_FOUND_ERROR = "File does not exist"
|
31
|
+
MOVING_FILE_ERROR = "Moving file error"
|
32
|
+
|
33
|
+
def __init__(self, work_dir: Path | str):
|
34
|
+
"""
|
35
|
+
Initialize a FileSystemService instance with the specified working directory.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
work_dir (Path or str): The path to the working directory. If a string is provided,
|
39
|
+
it will be converted to a Path object.
|
40
|
+
"""
|
41
|
+
self.work_dir = work_dir if isinstance(work_dir, Path) else Path(work_dir)
|
42
|
+
|
43
|
+
def read(self, path: Path) -> str:
|
44
|
+
"""
|
45
|
+
Reads and processes the contents of a file located at the specified path.
|
46
|
+
|
47
|
+
This method will attempt to open the file, read its content, and perform
|
48
|
+
any necessary processing on the data. It assumes that the file is in
|
49
|
+
a format appropriate for the specific application logic and that the
|
50
|
+
given path is accessible.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
path (Path): The path to the file to read.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
str: The processed data extracted from the file.
|
57
|
+
|
58
|
+
Raises:
|
59
|
+
ReadFileException: An error occurred during the file read operation.
|
60
|
+
"""
|
61
|
+
|
62
|
+
if not isinstance(path, Path):
|
63
|
+
raise ReadFileException("file_path must be a Path object")
|
64
|
+
if not path.exists():
|
65
|
+
raise ReadFileException(f"File not found: {path}")
|
66
|
+
self.validate_path_within_work_dir(path, ReadFileException)
|
67
|
+
try:
|
68
|
+
return path.read_text()
|
69
|
+
except Exception as e:
|
70
|
+
raise ReadFileException(f"Error reading file: {e}") from e
|
71
|
+
|
72
|
+
def list_dir(
|
73
|
+
self,
|
74
|
+
path: Path,
|
75
|
+
relative_paths: bool = False,
|
76
|
+
recursively=False,
|
77
|
+
max_items: int | None = None,
|
78
|
+
) -> ListDirOutput:
|
79
|
+
"""
|
80
|
+
List all files and directories within the specified directory.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
path (Path): The path to the directory.
|
84
|
+
relative_paths (bool): Whether to return relative paths or full paths.
|
85
|
+
recursively (bool): Whether iterate recursively over the content.
|
86
|
+
max_items (int | None): Maximum number of items to return.
|
87
|
+
|
88
|
+
Returns:
|
89
|
+
ListDirOutput: A data class containing the list of files and directories within the specified path.
|
90
|
+
- files (list[Path]): Sorted list of file paths
|
91
|
+
- directories (list[Path]): Sorted list of directory paths
|
92
|
+
|
93
|
+
Raises:
|
94
|
+
ListDirException: If the path is invalid, directory doesn't exist, or path is not a directory.
|
95
|
+
|
96
|
+
"""
|
97
|
+
if not isinstance(path, Path):
|
98
|
+
raise ListDirException("Path must be a Path object")
|
99
|
+
if not path.exists():
|
100
|
+
raise ListDirException(f"Directory not found: {path}")
|
101
|
+
if not path.is_dir():
|
102
|
+
raise ListDirException(f"Path is not a directory: {path}")
|
103
|
+
try:
|
104
|
+
path.relative_to(self.work_dir)
|
105
|
+
except ValueError as e:
|
106
|
+
raise ListDirException("Access denied: Path outside work directory") from e
|
107
|
+
try:
|
108
|
+
files = []
|
109
|
+
directories = []
|
110
|
+
|
111
|
+
entries = path.rglob("*") if recursively else path.iterdir()
|
112
|
+
items = 0
|
113
|
+
for entry in entries:
|
114
|
+
if max_items and items > max_items:
|
115
|
+
raise ListDirException(
|
116
|
+
f"Too many items, max processable dir size: {max_items}"
|
117
|
+
)
|
118
|
+
items += 1
|
119
|
+
target = files if entry.is_file() else directories
|
120
|
+
target.append(entry.relative_to(path) if relative_paths else entry)
|
121
|
+
return ListDirOutput(
|
122
|
+
files=sorted(files, key=custom_sort_key),
|
123
|
+
directories=sorted(directories, key=custom_sort_key),
|
124
|
+
)
|
125
|
+
except PermissionError as e:
|
126
|
+
raise ListDirException(f"Access denied: {e}") from e
|
127
|
+
except Exception as e:
|
128
|
+
raise ListDirException(f"Error listing directory: {e}") from e
|
129
|
+
|
130
|
+
def validate_path_within_work_dir(self, path: Path, exception_class: type) -> None:
|
131
|
+
"""
|
132
|
+
Validates if a path is within the working directory.
|
133
|
+
|
134
|
+
This method checks if the given path is contained within the working directory
|
135
|
+
to prevent unauthorized access to files outside the designated work area.
|
136
|
+
|
137
|
+
Args:
|
138
|
+
path (Path): The path to validate
|
139
|
+
exception_class (type): The exception class to raise if validation fails
|
140
|
+
|
141
|
+
Raises:
|
142
|
+
exception_class: If the path is outside the working directory
|
143
|
+
"""
|
144
|
+
try:
|
145
|
+
path.relative_to(self.work_dir)
|
146
|
+
except ValueError as e:
|
147
|
+
raise exception_class(self.ACCESS_DENIED_ERROR) from e
|
@@ -0,0 +1,78 @@
|
|
1
|
+
"""
|
2
|
+
Storage provider exception classes.
|
3
|
+
|
4
|
+
This module defines exception classes for handling errors that occur
|
5
|
+
during interactions with cloud storage providers.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from sourcerer.domain.storage_provider.exceptions import BaseStorageProviderException
|
9
|
+
|
10
|
+
|
11
|
+
class CredentialsNotFoundException(BaseStorageProviderException):
|
12
|
+
"""
|
13
|
+
Exception raised when credentials are not found for a cloud storage provider.
|
14
|
+
|
15
|
+
This exception is a specific case of BaseStorageProviderException
|
16
|
+
and should be used to indicate that the required credentials for
|
17
|
+
accessing a cloud storage service are missing or not configured.
|
18
|
+
"""
|
19
|
+
|
20
|
+
|
21
|
+
class ListStoragesException(BaseStorageProviderException):
|
22
|
+
"""
|
23
|
+
Exception raised for errors that occur during the listing of cloud storage services.
|
24
|
+
|
25
|
+
This exception is a specific case of BaseStorageProviderException
|
26
|
+
and is used to indicate issues encountered when attempting to retrieve
|
27
|
+
a list of available storage services from a cloud provider.
|
28
|
+
"""
|
29
|
+
|
30
|
+
|
31
|
+
class StoragePermissionException(BaseStorageProviderException):
|
32
|
+
"""
|
33
|
+
Exception raised for permission-related errors in cloud storage operations.
|
34
|
+
|
35
|
+
This exception is triggered when there is an issue with permissions
|
36
|
+
while accessing or modifying resources in a cloud storage service.
|
37
|
+
"""
|
38
|
+
|
39
|
+
|
40
|
+
class ListStorageItemsException(BaseStorageProviderException):
|
41
|
+
"""
|
42
|
+
Exception raised when an error occurs while listing items in cloud storage.
|
43
|
+
|
44
|
+
This exception is a specific case of BaseStorageProviderException
|
45
|
+
and is used to indicate issues encountered during the retrieval of
|
46
|
+
storage items from a cloud storage provider.
|
47
|
+
"""
|
48
|
+
|
49
|
+
|
50
|
+
class ReadStorageItemsException(BaseStorageProviderException):
|
51
|
+
"""
|
52
|
+
Exception raised for errors encountered while reading items from cloud storage.
|
53
|
+
|
54
|
+
This exception is a specific case of BaseStorageProviderException
|
55
|
+
and should be used to indicate issues that occur during the retrieval
|
56
|
+
of data from cloud storage services.
|
57
|
+
"""
|
58
|
+
|
59
|
+
|
60
|
+
class DeleteStorageItemsException(BaseStorageProviderException):
|
61
|
+
"""
|
62
|
+
Exception raised for errors that occur during the deletion of storage items.
|
63
|
+
|
64
|
+
This exception is a specific type of BaseStorageProviderException
|
65
|
+
and is used to indicate issues encountered when attempting to delete
|
66
|
+
items from a cloud storage service.
|
67
|
+
"""
|
68
|
+
|
69
|
+
|
70
|
+
class UploadStorageItemsException(BaseStorageProviderException):
|
71
|
+
"""
|
72
|
+
Exception raised for errors that occur during the upload of items
|
73
|
+
to cloud storage.
|
74
|
+
|
75
|
+
This exception is a specific case of BaseStorageProviderException
|
76
|
+
and is used to signal issues encountered while uploading data to
|
77
|
+
cloud storage services.
|
78
|
+
"""
|
@@ -0,0 +1,84 @@
|
|
1
|
+
"""
|
2
|
+
Registry for storage provider service implementations.
|
3
|
+
|
4
|
+
This module provides a registry system for managing different types of
|
5
|
+
storage provider services.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import functools
|
9
|
+
from typing import Type, Dict
|
10
|
+
|
11
|
+
from sourcerer.domain.storage_provider.services import BaseStorageProviderService
|
12
|
+
from sourcerer.infrastructure.utils import Singleton
|
13
|
+
|
14
|
+
|
15
|
+
class StorageProviderRegistry(metaclass=Singleton):
|
16
|
+
"""
|
17
|
+
Registry for storage provider service implementations.
|
18
|
+
|
19
|
+
This singleton class maintains a registry of storage provider service
|
20
|
+
implementations organized by provider identifier.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __init__(self, *args, **kwargs):
|
24
|
+
"""Initialize the registry with an empty dictionary."""
|
25
|
+
super().__init__(*args, **kwargs)
|
26
|
+
self._items_: Dict[str, type] = {}
|
27
|
+
|
28
|
+
def register(self, storage_provider: str, cls: Type[BaseStorageProviderService]):
|
29
|
+
"""
|
30
|
+
Register a storage provider service implementation.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
storage_provider (str): The provider identifier
|
34
|
+
cls (Type[BaseStorageProviderService]): The service class to register
|
35
|
+
"""
|
36
|
+
self._items_[storage_provider] = cls
|
37
|
+
|
38
|
+
def get(self):
|
39
|
+
"""
|
40
|
+
Get all registered storage provider services.
|
41
|
+
|
42
|
+
Returns:
|
43
|
+
dict: Dictionary of all registered storage provider services
|
44
|
+
"""
|
45
|
+
return self._items_
|
46
|
+
|
47
|
+
def get_by_provider(self, provider):
|
48
|
+
"""
|
49
|
+
Get a storage provider service by provider identifier.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
provider (str): The provider identifier
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
Type[BaseStorageProviderService]: The storage provider service class
|
56
|
+
"""
|
57
|
+
return self._items_.get(provider)
|
58
|
+
|
59
|
+
|
60
|
+
def storage_provider(provider: str):
|
61
|
+
"""
|
62
|
+
Decorator for registering storage provider service implementations.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
provider (str): The provider identifier
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
callable: Decorator function
|
69
|
+
"""
|
70
|
+
|
71
|
+
def wrapper(cls):
|
72
|
+
storage_provider_registry.register(provider, cls)
|
73
|
+
|
74
|
+
@functools.wraps(cls)
|
75
|
+
def wrapped(*args, **kwargs):
|
76
|
+
return cls(*args, **kwargs)
|
77
|
+
|
78
|
+
return wrapped
|
79
|
+
|
80
|
+
return wrapper
|
81
|
+
|
82
|
+
|
83
|
+
# Singleton registry instance
|
84
|
+
storage_provider_registry = StorageProviderRegistry()
|