data-sourcerer 0.1.1__tar.gz → 0.2.1__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.
Files changed (142) hide show
  1. {data_sourcerer-0.1.1 → data_sourcerer-0.2.1}/PKG-INFO +29 -10
  2. {data_sourcerer-0.1.1 → data_sourcerer-0.2.1}/README.md +10 -3
  3. data_sourcerer-0.2.1/pyproject.toml +102 -0
  4. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/__init__.py +1 -1
  5. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/access_credentials/entities.py +17 -0
  6. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/access_credentials/exceptions.py +1 -1
  7. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/access_credentials/repositories.py +1 -1
  8. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/access_credentials/services.py +14 -2
  9. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/file_system/exceptions.py +1 -1
  10. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/file_system/services.py +2 -2
  11. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/shared/entities.py +1 -0
  12. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/storage_provider/entities.py +3 -4
  13. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/storage_provider/exceptions.py +1 -1
  14. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/storage_provider/services.py +13 -9
  15. data_sourcerer-0.2.1/sourcerer/infrastructure/access_credentials/exceptions.py +29 -0
  16. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/access_credentials/registry.py +3 -4
  17. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/access_credentials/services.py +141 -44
  18. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/db/models.py +1 -1
  19. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/file_system/exceptions.py +9 -9
  20. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/file_system/services.py +16 -16
  21. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/storage_provider/exceptions.py +28 -8
  22. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/storage_provider/registry.py +2 -3
  23. data_sourcerer-0.2.1/sourcerer/infrastructure/storage_provider/services/azure.py +261 -0
  24. data_sourcerer-0.2.1/sourcerer/infrastructure/storage_provider/services/gcp.py +277 -0
  25. data_sourcerer-0.2.1/sourcerer/infrastructure/storage_provider/services/s3.py +290 -0
  26. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/utils.py +2 -4
  27. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/critical_error/main.py +3 -4
  28. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/file_system_finder/main.py +4 -4
  29. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/file_system_finder/widgets/file_system_navigator.py +12 -12
  30. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/main.py +57 -33
  31. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/delete_request.py +1 -2
  32. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/download_request.py +1 -2
  33. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/widgets/gradient.py +2 -5
  34. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/widgets/storage_content.py +12 -13
  35. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/widgets/storage_list_sidebar.py +8 -6
  36. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/preview_content/main.py +15 -4
  37. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/preview_content/styles.tcss +2 -1
  38. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/provider_creds_list/main.py +2 -2
  39. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/provider_creds_registration/main.py +26 -11
  40. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/question/main.py +1 -1
  41. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/shared/containers.py +1 -1
  42. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/shared/widgets/labeled_input.py +1 -1
  43. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/storage_action_progress/main.py +34 -20
  44. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/storage_action_progress/styles.tcss +11 -0
  45. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/utils.py +7 -3
  46. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/settings.py +4 -0
  47. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/utils.py +2 -2
  48. data_sourcerer-0.1.1/.github/workflows/bandit.yml +0 -27
  49. data_sourcerer-0.1.1/.github/workflows/pylint.yml +0 -28
  50. data_sourcerer-0.1.1/.github/workflows/pyright.yml +0 -26
  51. data_sourcerer-0.1.1/.github/workflows/ruff.yml +0 -25
  52. data_sourcerer-0.1.1/.pylintrc +0 -644
  53. data_sourcerer-0.1.1/docs/assets/billie-holiday.png +0 -0
  54. data_sourcerer-0.1.1/docs/assets/creds_registration.gif +0 -0
  55. data_sourcerer-0.1.1/docs/assets/keys_operations.gif +0 -0
  56. data_sourcerer-0.1.1/docs/assets/layer-1.png +0 -0
  57. data_sourcerer-0.1.1/docs/assets/layer-2.png +0 -0
  58. data_sourcerer-0.1.1/docs/assets/layer-3.png +0 -0
  59. data_sourcerer-0.1.1/docs/assets/layer-4.png +0 -0
  60. data_sourcerer-0.1.1/docs/assets/layer-5.png +0 -0
  61. data_sourcerer-0.1.1/docs/guides/register_credentials.md +0 -1
  62. data_sourcerer-0.1.1/docs/index.md +0 -4
  63. data_sourcerer-0.1.1/docs/js/parallax.js +0 -33
  64. data_sourcerer-0.1.1/docs/overrides/home.html +0 -294
  65. data_sourcerer-0.1.1/docs/roadmap.md +0 -49
  66. data_sourcerer-0.1.1/docs/styles/styles.css +0 -0
  67. data_sourcerer-0.1.1/media/creds_registration.gif +0 -0
  68. data_sourcerer-0.1.1/media/keys_operations.gif +0 -0
  69. data_sourcerer-0.1.1/mkdocs.yml +0 -63
  70. data_sourcerer-0.1.1/pyproject.toml +0 -44
  71. data_sourcerer-0.1.1/setup.cfg +0 -4
  72. data_sourcerer-0.1.1/src/data_sourcerer.egg-info/PKG-INFO +0 -53
  73. data_sourcerer-0.1.1/src/data_sourcerer.egg-info/SOURCES.txt +0 -135
  74. data_sourcerer-0.1.1/src/data_sourcerer.egg-info/dependency_links.txt +0 -1
  75. data_sourcerer-0.1.1/src/data_sourcerer.egg-info/entry_points.txt +0 -2
  76. data_sourcerer-0.1.1/src/data_sourcerer.egg-info/requires.txt +0 -11
  77. data_sourcerer-0.1.1/src/data_sourcerer.egg-info/top_level.txt +0 -1
  78. data_sourcerer-0.1.1/src/sourcerer/infrastructure/access_credentials/exceptions.py +0 -16
  79. data_sourcerer-0.1.1/src/sourcerer/infrastructure/storage_provider/services.py +0 -509
  80. data_sourcerer-0.1.1/tests/README.md +0 -57
  81. data_sourcerer-0.1.1/tests/sourcerer/__init__.py +0 -0
  82. data_sourcerer-0.1.1/tests/sourcerer/access_credentials/__init__.py +0 -0
  83. data_sourcerer-0.1.1/tests/sourcerer/access_credentials/test_registry.py +0 -119
  84. data_sourcerer-0.1.1/tests/sourcerer/access_credentials/test_repositories.py +0 -131
  85. data_sourcerer-0.1.1/tests/sourcerer/db/__init__.py +0 -0
  86. data_sourcerer-0.1.1/tests/sourcerer/db/test_models.py +0 -66
  87. data_sourcerer-0.1.1/tests/sourcerer/file_system/__init__.py +0 -0
  88. data_sourcerer-0.1.1/tests/sourcerer/file_system/test_services.py +0 -99
  89. data_sourcerer-0.1.1/tests/sourcerer/storage_provider/__init__.py +0 -0
  90. data_sourcerer-0.1.1/tests/sourcerer/storage_provider/test_registry.py +0 -82
  91. data_sourcerer-0.1.1/tests/sourcerer/storage_provider/test_services.py +0 -619
  92. data_sourcerer-0.1.1/uv.lock +0 -1794
  93. {data_sourcerer-0.1.1 → data_sourcerer-0.2.1}/.gitignore +0 -0
  94. {data_sourcerer-0.1.1 → data_sourcerer-0.2.1}/LICENSE +0 -0
  95. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/__init__.py +0 -0
  96. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/access_credentials/__init__.py +0 -0
  97. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/file_system/__init__.py +0 -0
  98. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/file_system/entities.py +0 -0
  99. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/shared/__init__.py +0 -0
  100. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/domain/storage_provider/__init__.py +0 -0
  101. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/__init__.py +0 -0
  102. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/access_credentials/__init__.py +0 -0
  103. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/access_credentials/repositories.py +0 -0
  104. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/db/__init__.py +0 -0
  105. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/db/config.py +0 -0
  106. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/file_system/__init__.py +0 -0
  107. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/infrastructure/storage_provider/__init__.py +0 -0
  108. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens → data_sourcerer-0.2.1/sourcerer/infrastructure/storage_provider/services}/__init__.py +0 -0
  109. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/__init__.py +0 -0
  110. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/app.py +0 -0
  111. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/di_container.py +0 -0
  112. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/critical_error → data_sourcerer-0.2.1/sourcerer/presentation/screens}/__init__.py +0 -0
  113. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/file_system_finder/widgets → data_sourcerer-0.2.1/sourcerer/presentation/screens/critical_error}/__init__.py +0 -0
  114. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/critical_error/styles.tcss +0 -0
  115. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/file_system_finder/styles.tcss +0 -0
  116. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/main → data_sourcerer-0.2.1/sourcerer/presentation/screens/file_system_finder/widgets}/__init__.py +0 -0
  117. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/main/messages → data_sourcerer-0.2.1/sourcerer/presentation/screens/main}/__init__.py +0 -0
  118. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/main/mixins → data_sourcerer-0.2.1/sourcerer/presentation/screens/main/messages}/__init__.py +0 -0
  119. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/preview_request.py +0 -0
  120. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/resizing_rule.py +0 -0
  121. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/select_storage_item.py +0 -0
  122. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/uncheck_files_request.py +0 -0
  123. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/messages/upload_request.py +0 -0
  124. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/main/widgets → data_sourcerer-0.2.1/sourcerer/presentation/screens/main/mixins}/__init__.py +0 -0
  125. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/mixins/resize_containers_watcher_mixin.py +3 -3
  126. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/styles.tcss +0 -0
  127. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/preview_content → data_sourcerer-0.2.1/sourcerer/presentation/screens/main/widgets}/__init__.py +0 -0
  128. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/main/widgets/resizing_rule.py +1 -1
  129. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/provider_creds_list → data_sourcerer-0.2.1/sourcerer/presentation/screens/preview_content}/__init__.py +0 -0
  130. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/provider_creds_registration → data_sourcerer-0.2.1/sourcerer/presentation/screens/provider_creds_list}/__init__.py +0 -0
  131. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/provider_creds_list/styles.tcss +0 -0
  132. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/question → data_sourcerer-0.2.1/sourcerer/presentation/screens/provider_creds_registration}/__init__.py +0 -0
  133. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/provider_creds_registration/styles.tcss +0 -0
  134. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/shared → data_sourcerer-0.2.1/sourcerer/presentation/screens/question}/__init__.py +0 -0
  135. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/question/styles.tcss +0 -0
  136. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/shared/widgets → data_sourcerer-0.2.1/sourcerer/presentation/screens/shared}/__init__.py +0 -0
  137. {data_sourcerer-0.1.1/src/sourcerer/presentation/screens/storage_action_progress → data_sourcerer-0.2.1/sourcerer/presentation/screens/shared/widgets}/__init__.py +0 -0
  138. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/screens/shared/widgets/button.py +0 -0
  139. {data_sourcerer-0.1.1/src/sourcerer/presentation/themes → data_sourcerer-0.2.1/sourcerer/presentation/screens/storage_action_progress}/__init__.py +0 -0
  140. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/settings.py +0 -0
  141. {data_sourcerer-0.1.1/tests → data_sourcerer-0.2.1/sourcerer/presentation/themes}/__init__.py +0 -0
  142. {data_sourcerer-0.1.1/src → data_sourcerer-0.2.1}/sourcerer/presentation/themes/github_dark.py +0 -0
@@ -1,29 +1,41 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-sourcerer
3
- Version: 0.1.1
3
+ Version: 0.2.1
4
4
  Summary: Sourcerer is a terminal cloud storage navigator.
5
5
  Author-email: Bohdana Kuzmenko <bohdana.kuzmenko.dev@gmail.com>
6
6
  License: MIT
7
- Keywords: cloud,s3,gcp,cli,termanal,storage,textual,ui
8
- Requires-Python: >=3.8
9
- Description-Content-Type: text/markdown
10
7
  License-File: LICENSE
8
+ Keywords: cli,cloud,gcp,s3,storage,terminal,textual,ui
9
+ Requires-Python: >=3.9
10
+ Requires-Dist: azure-identity<2.0.0,>=1.22.0
11
+ Requires-Dist: azure-mgmt-storage<23.0.0,>=22.2.0
12
+ Requires-Dist: azure-storage-blob<13.0.0,>=12.25.1
11
13
  Requires-Dist: boto3<2.0.0,>=1.26.0
12
14
  Requires-Dist: cryptography<45.0.0,>=44.0.2
13
15
  Requires-Dist: dependency-injector<5.0.0,>=4.43.0
14
16
  Requires-Dist: google-cloud-storage<4.0.0,>=3.1.0
15
17
  Requires-Dist: humanize<5.0.0,>=4.12.1
16
- Requires-Dist: sqlalchemy<3.0.0,>=2.0.38
18
+ Requires-Dist: pyopenssl>=22.1.0; sys_platform == 'linux'
17
19
  Requires-Dist: sqlalchemy-utils<1.0.0,>=0.41.2
20
+ Requires-Dist: sqlalchemy<3.0.0,>=2.0.38
18
21
  Requires-Dist: textual[syntax]<4.0.0,>=2.0.0
19
- Requires-Dist: pyOpenSSL>=22.1.0; sys_platform == "linux"
20
- Dynamic: license-file
22
+ Provides-Extra: dev
23
+ Requires-Dist: bandit>=1.8.3; extra == 'dev'
24
+ Requires-Dist: black>=25.1.0; extra == 'dev'
25
+ Requires-Dist: coverage>=7.8.0; extra == 'dev'
26
+ Requires-Dist: mkdocs-material>=9.6.12; extra == 'dev'
27
+ Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
28
+ Requires-Dist: pylint>=3.3.6; extra == 'dev'
29
+ Requires-Dist: pyright>=1.1.400; extra == 'dev'
30
+ Requires-Dist: ruff>=0.11.7; extra == 'dev'
31
+ Requires-Dist: textual-dev>=1.7.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
21
33
 
22
34
  # 🧙‍♂️ Sourcerer
23
35
 
24
36
  **Sourcerer** is a CLI-based cloud storage explorer that provides a unified interface for developers and DevOps
25
37
  engineers to view and manage files across multiple cloud providers like
26
- **GCP**, **AWS S3**, and **S3-compatible services**.
38
+ **GCP Storage**, **Azure Storage**, **AWS S3**, and **S3-compatible services**.
27
39
 
28
40
  > Your terminal. Your storages. Your control.
29
41
 
@@ -31,7 +43,7 @@ engineers to view and manage files across multiple cloud providers like
31
43
 
32
44
  ## ✨ Features
33
45
 
34
- - 🔍 Unified file browser for GCP, AWS S3, and S3-compatible services
46
+ - 🔍 Unified file browser for GCP Storage, Azure Storage, AWS S3, and S3-compatible services
35
47
  - 🧭 Terminal UI (TUI) built with [Textual](https://github.com/Textualize/textual)
36
48
  - 🗂️ Explore buckets and objects seamlessly
37
49
  - 🔄 Upload, download, and delete files
@@ -42,7 +54,14 @@ engineers to view and manage files across multiple cloud providers like
42
54
  ## 🪄 Installation
43
55
 
44
56
  ```bash
45
- pip install sourcerer
57
+ pip install data-sourcerer
58
+ ```
59
+ --
60
+
61
+ ## 🪄 Run
62
+
63
+ ```bash
64
+ sourcerer
46
65
  ```
47
66
 
48
67
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Sourcerer** is a CLI-based cloud storage explorer that provides a unified interface for developers and DevOps
4
4
  engineers to view and manage files across multiple cloud providers like
5
- **GCP**, **AWS S3**, and **S3-compatible services**.
5
+ **GCP Storage**, **Azure Storage**, **AWS S3**, and **S3-compatible services**.
6
6
 
7
7
  > Your terminal. Your storages. Your control.
8
8
 
@@ -10,7 +10,7 @@ engineers to view and manage files across multiple cloud providers like
10
10
 
11
11
  ## ✨ Features
12
12
 
13
- - 🔍 Unified file browser for GCP, AWS S3, and S3-compatible services
13
+ - 🔍 Unified file browser for GCP Storage, Azure Storage, AWS S3, and S3-compatible services
14
14
  - 🧭 Terminal UI (TUI) built with [Textual](https://github.com/Textualize/textual)
15
15
  - 🗂️ Explore buckets and objects seamlessly
16
16
  - 🔄 Upload, download, and delete files
@@ -21,7 +21,14 @@ engineers to view and manage files across multiple cloud providers like
21
21
  ## 🪄 Installation
22
22
 
23
23
  ```bash
24
- pip install sourcerer
24
+ pip install data-sourcerer
25
+ ```
26
+ --
27
+
28
+ ## 🪄 Run
29
+
30
+ ```bash
31
+ sourcerer
25
32
  ```
26
33
 
27
34
 
@@ -0,0 +1,102 @@
1
+ [project]
2
+
3
+ name = "data-sourcerer"
4
+ version = "0.2.1"
5
+ description = "Sourcerer is a terminal cloud storage navigator."
6
+ requires-python = ">=3.9"
7
+
8
+ keywords = ["cloud", "s3", "gcp", "cli", "terminal", "storage", "textual", "ui"]
9
+ license = {text = "MIT"}
10
+
11
+ authors = [
12
+ {name = "Bohdana Kuzmenko", email = "bohdana.kuzmenko.dev@gmail.com"},
13
+ ]
14
+
15
+ readme = {file = "README.md", content-type = "text/markdown"}
16
+
17
+ dependencies = [
18
+ "boto3>=1.26.0,<2.0.0",
19
+ "cryptography>=44.0.2,<45.0.0",
20
+ "dependency-injector>=4.43.0,<5.0.0",
21
+ "google-cloud-storage>=3.1.0,<4.0.0",
22
+ "humanize>=4.12.1,<5.0.0",
23
+ "sqlalchemy>=2.0.38,<3.0.0",
24
+ "sqlalchemy-utils>=0.41.2,<1.0.0",
25
+ "textual[syntax]>=2.0.0,<4.0.0",
26
+ "pyOpenSSL>=22.1.0; sys_platform == 'linux'",
27
+ "azure-storage-blob>=12.25.1,<13.0.0",
28
+ "azure-identity>=1.22.0,<2.0.0",
29
+ "azure-mgmt-storage>=22.2.0,<23.0.0",
30
+ ]
31
+
32
+ [project.scripts]
33
+ sourcerer = "sourcerer.presentation.app:main"
34
+
35
+ [build-system]
36
+ requires = ["hatchling"]
37
+ build-backend = "hatchling.build"
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "bandit>=1.8.3",
42
+ "black>=25.1.0",
43
+ "coverage>=7.8.0",
44
+ "mkdocs-material>=9.6.12",
45
+ "pre-commit>=4.2.0",
46
+ "pylint>=3.3.6",
47
+ "pyright>=1.1.400",
48
+ "ruff>=0.11.7",
49
+ "textual-dev>=1.7.0",
50
+ ]
51
+
52
+ [project.optional-dependencies]
53
+ dev = [
54
+ "bandit>=1.8.3",
55
+ "black>=25.1.0",
56
+ "coverage>=7.8.0",
57
+ "mkdocs-material>=9.6.12",
58
+ "pre-commit>=4.2.0",
59
+ "pylint>=3.3.6",
60
+ "pyright>=1.1.400",
61
+ "ruff>=0.11.7",
62
+ "textual-dev>=1.7.0",
63
+ ]
64
+
65
+ [tool.coverage.run]
66
+ branch = true
67
+ source = [
68
+ "src/sourcerer/infrastructure",
69
+ ]
70
+
71
+ [tool.coverage.report]
72
+ fail_under = 75
73
+
74
+ [tool.ruff]
75
+ line-length = 120
76
+ target-version = "py312"
77
+
78
+ # Enable these rules
79
+ select = [
80
+ "E", # pycodestyle
81
+ "F", # pyflakes
82
+ "I", # isort
83
+ "N", # pep8-naming
84
+ "UP", # pyupgrade
85
+ "C90", # mccabe (complexity)
86
+ "B", # flake8-bugbear
87
+ "SIM", # flake8-simplify
88
+ ]
89
+
90
+ # Allow autofix for these rule sets
91
+ fixable = ["ALL"]
92
+
93
+ # Disallow autofix for these
94
+ unfixable = ["F401"] # unused imports - maybe you want to catch it manually
95
+
96
+
97
+ [tool.ruff.mccabe]
98
+ max-complexity = 10
99
+
100
+ [tool.hatch.build]
101
+ include = ["src"]
102
+ sources = ["src"]
@@ -12,4 +12,4 @@ The application is structured using a clean architecture approach with:
12
12
  - Presentation layer: User interface components
13
13
  """
14
14
 
15
- __version__ = "0.1.0"
15
+ __version__ = "0.2.1"
@@ -9,6 +9,7 @@ from dataclasses import dataclass
9
9
  from datetime import datetime
10
10
 
11
11
  import boto3
12
+ from azure.identity import ClientSecretCredential
12
13
 
13
14
 
14
15
  @dataclass
@@ -51,3 +52,19 @@ class Boto3Credentials:
51
52
  session: boto3.Session
52
53
  endpoint_url: str | None = None
53
54
  signature_version: str | None = None
55
+
56
+
57
+ @dataclass
58
+ class AzureCredentials:
59
+ """
60
+ Represents Azure credentials.
61
+
62
+ Attributes:
63
+ credentials (ClientSecretCredential): Azure identity credential object for authentication.
64
+ subscription_id (str): The Azure subscription ID.
65
+ cloud_suffix (str): The Azure cloud storage suffix (e.g., blob.core.windows.net).
66
+ """
67
+
68
+ credentials: ClientSecretCredential
69
+ subscription_id: str
70
+ cloud_suffix: str
@@ -6,7 +6,7 @@ access credentials operations.
6
6
  """
7
7
 
8
8
 
9
- class BaseAccessCredentialsException(Exception):
9
+ class BaseAccessCredentialsError(Exception):
10
10
  """
11
11
  Base exception class for access credentials-related errors.
12
12
 
@@ -5,7 +5,7 @@ This module defines the abstract base class for credentials repositories,
5
5
  providing a common interface for different storage implementations.
6
6
  """
7
7
 
8
- from abc import abstractmethod, ABCMeta
8
+ from abc import ABCMeta, abstractmethod
9
9
 
10
10
  from sourcerer.domain.access_credentials.entities import Credentials
11
11
 
@@ -8,7 +8,6 @@ authentication methods.
8
8
 
9
9
  from abc import abstractmethod
10
10
  from dataclasses import dataclass
11
- from typing import List
12
11
 
13
12
  from sourcerer.domain.access_credentials.repositories import BaseCredentialsRepository
14
13
 
@@ -82,10 +81,23 @@ class BaseAccessCredentialsService:
82
81
 
83
82
  @classmethod
84
83
  @abstractmethod
85
- def auth_fields(cls) -> List[AuthField]:
84
+ def auth_fields(cls) -> list[AuthField]:
86
85
  """
87
86
  Get list of authentication fields.
88
87
 
89
88
  Returns:
90
89
  List[AuthField]: List of authentication field definitions
91
90
  """
91
+
92
+ @classmethod
93
+ def validate_auth_fields_values(cls, auth_fields: dict) -> None:
94
+ """
95
+ Validate authentication fields.
96
+
97
+ Args:
98
+ auth_fields (dict): Dictionary containing authentication field,
99
+ where keys are field names and values are field values
100
+
101
+ Raises:
102
+ MissingAuthFieldsError: If any required authentication fields are missing
103
+ """
@@ -6,7 +6,7 @@ file system operations.
6
6
  """
7
7
 
8
8
 
9
- class BaseFileSystemException(Exception):
9
+ class BaseFileSystemError(Exception):
10
10
  """
11
11
  Base exception class for filesystem-related errors.
12
12
 
@@ -37,7 +37,7 @@ class BaseFileSystemService(metaclass=abc.ABCMeta):
37
37
  str: The processed data extracted from the file.
38
38
 
39
39
  Raises:
40
- ReadFileException: An error occurred during the file read operation.
40
+ ReadFileError: An error occurred during the file read operation.
41
41
  """
42
42
  raise NotImplementedError
43
43
 
@@ -59,6 +59,6 @@ class BaseFileSystemService(metaclass=abc.ABCMeta):
59
59
  - directories (list[Path]): Sorted list of directory paths
60
60
 
61
61
  Raises:
62
- ListDirException: If the path is invalid, directory doesn't exist, or path is not a directory.
62
+ ListDirError: If the path is invalid, directory doesn't exist, or path is not a directory.
63
63
  """
64
64
  raise NotImplementedError
@@ -16,3 +16,4 @@ class StorageProvider:
16
16
 
17
17
  S3 = "S3"
18
18
  GoogleCloudStorage = "Google Cloud Storage"
19
+ AzureStorage = "Azure Storage"
@@ -7,7 +7,6 @@ such as storage containers, files, folders, and permissions.
7
7
 
8
8
  from dataclasses import dataclass
9
9
  from datetime import datetime
10
- from typing import List
11
10
 
12
11
 
13
12
  @dataclass
@@ -37,7 +36,7 @@ class StoragePermissions:
37
36
  """
38
37
 
39
38
  user: str
40
- permissions: List[str]
39
+ permissions: list[str]
41
40
 
42
41
 
43
42
  @dataclass
@@ -82,5 +81,5 @@ class StorageContent:
82
81
  folders (List[Folder]): List of folders in the location
83
82
  """
84
83
 
85
- files: List[File]
86
- folders: List[Folder]
84
+ files: list[File]
85
+ folders: list[Folder]
@@ -6,7 +6,7 @@ cloud storage provider operations.
6
6
  """
7
7
 
8
8
 
9
- class BaseStorageProviderException(Exception):
9
+ class BaseStorageProviderError(Exception):
10
10
  """
11
11
  Base exception class for cloud storage provider-related errors.
12
12
 
@@ -6,13 +6,13 @@ providing a common interface for cloud storage operations.
6
6
  """
7
7
 
8
8
  from abc import ABC, abstractmethod
9
+ from collections.abc import Callable
9
10
  from pathlib import Path
10
- from typing import List, Callable
11
11
 
12
12
  from sourcerer.domain.storage_provider.entities import (
13
- StoragePermissions,
14
- StorageContent,
15
13
  Storage,
14
+ StorageContent,
15
+ StoragePermissions,
16
16
  )
17
17
 
18
18
 
@@ -27,7 +27,7 @@ class BaseStorageProviderService(ABC):
27
27
  """
28
28
 
29
29
  @abstractmethod
30
- def list_storages(self) -> List[Storage]:
30
+ def list_storages(self) -> list[Storage]:
31
31
  """
32
32
  Return a list of available storages.
33
33
 
@@ -36,7 +36,7 @@ class BaseStorageProviderService(ABC):
36
36
  """
37
37
 
38
38
  @abstractmethod
39
- def get_storage_permissions(self, storage: str) -> List[StoragePermissions]:
39
+ def get_storage_permissions(self, storage: str) -> list[StoragePermissions]:
40
40
  """
41
41
  Return the permissions for the specified storage.
42
42
 
@@ -75,7 +75,6 @@ class BaseStorageProviderService(ABC):
75
75
  Returns:
76
76
  bytes: The content of the storage item
77
77
  """
78
- pass
79
78
 
80
79
  @abstractmethod
81
80
  def delete_storage_item(self, storage: str, key: str) -> None:
@@ -89,13 +88,18 @@ class BaseStorageProviderService(ABC):
89
88
 
90
89
  @abstractmethod
91
90
  def upload_storage_item(
92
- self, storage: str, source_path: Path, dest_path: str | None = None
91
+ self,
92
+ storage: str,
93
+ storage_path: str,
94
+ source_path: Path,
95
+ dest_path: str | None = None,
93
96
  ) -> None:
94
97
  """
95
98
  Upload a file to the specified storage path.
96
99
 
97
100
  Args:
98
101
  storage (str): The storage identifier
102
+ storage_path (str): The path within the storage to upload
99
103
  source_path (Path): Local file path to upload
100
104
  dest_path (str, optional): Destination path in storage. Defaults to None.
101
105
  """
@@ -117,7 +121,7 @@ class BaseStorageProviderService(ABC):
117
121
  """
118
122
 
119
123
  @abstractmethod
120
- def get_file_size(self, storage: str, key: str) -> dict:
124
+ def get_file_size(self, storage: str, key: str) -> int:
121
125
  """
122
126
  Get metadata for a storage item without downloading content.
123
127
 
@@ -126,5 +130,5 @@ class BaseStorageProviderService(ABC):
126
130
  key (str): The key/path of the item
127
131
 
128
132
  Returns:
129
- dict: Metadata for the specified item
133
+ int: Size of the storage item in bytes
130
134
  """
@@ -0,0 +1,29 @@
1
+ from sourcerer.domain.access_credentials.exceptions import (
2
+ BaseAccessCredentialsError,
3
+ )
4
+
5
+
6
+ class CredentialsAuthError(BaseAccessCredentialsError):
7
+ """
8
+ Exception raised when there is an error parsing access credentials.
9
+
10
+ This exception is raised when the access credentials cannot be
11
+ authenticated or parsed correctly. It indicates that the provided
12
+ credentials are invalid or not in the expected format.
13
+ This can occur during operations such as login, token validation,
14
+ or any other authentication process that relies on the provided
15
+ credentials.
16
+ """
17
+
18
+
19
+ class MissingAuthFieldsError(CredentialsAuthError):
20
+ """
21
+ Exception raised when there are missing authentication fields.
22
+
23
+ This exception is raised when the required authentication fields
24
+ are missing from the provided credentials. It indicates that the
25
+ authentication process cannot proceed without the necessary
26
+ credentials. This can occur during operations such as login,
27
+ token validation, or any other authentication process that relies
28
+ on the provided credentials.
29
+ """
@@ -7,7 +7,6 @@ access credential services for various cloud providers.
7
7
 
8
8
  import functools
9
9
  from dataclasses import dataclass
10
- from typing import Type, Dict
11
10
 
12
11
  from sourcerer.domain.access_credentials.services import BaseAccessCredentialsService
13
12
  from sourcerer.infrastructure.utils import Singleton
@@ -38,19 +37,19 @@ class AccessCredentialsRegistry(metaclass=Singleton):
38
37
  def __init__(self, *args, **kwargs):
39
38
  """Initialize the registry with an empty dictionary."""
40
39
  super().__init__(*args, **kwargs)
41
- self._items_: Dict[str, Dict[str, type]] = {} # type: ignore
40
+ self._items_: dict[str, dict[str, type]] = {} # type: ignore
42
41
 
43
42
  def register(
44
43
  self,
45
44
  access_credentials_method: AccessCredentialsMethod,
46
- cls: Type[BaseAccessCredentialsService],
45
+ cls: type[BaseAccessCredentialsService],
47
46
  ):
48
47
  """
49
48
  Register a credential service implementation.
50
49
 
51
50
  Args:
52
51
  access_credentials_method (AccessCredentialsMethod): The method descriptor
53
- cls (Type[BaseAccessCredentialsService]): The service class to register
52
+ cls (type[BaseAccessCredentialsService]): The service class to register
54
53
  """
55
54
  if access_credentials_method.provider not in self._items_:
56
55
  self._items_[access_credentials_method.provider] = {}