persistence-kit 3.0.2__tar.gz → 3.3.0__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.
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/PKG-INFO +141 -5
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/README.md +128 -2
- persistence_kit-3.3.0/persistence_kit/__init__.py +233 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/api/__init__.py +3 -0
- persistence_kit-3.3.0/persistence_kit/api/rate_limit.py +103 -0
- persistence_kit-3.3.0/persistence_kit/authenticated_user.py +37 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_engine.py +1 -1
- persistence_kit-3.3.0/persistence_kit/security/__init__.py +82 -0
- persistence_kit-3.3.0/persistence_kit/security/factory.py +156 -0
- persistence_kit-3.3.0/persistence_kit/security/ports.py +123 -0
- persistence_kit-3.3.0/persistence_kit/security/providers/__init__.py +23 -0
- persistence_kit-3.3.0/persistence_kit/security/providers/cognito_identity_provider.py +1232 -0
- persistence_kit-3.3.0/persistence_kit/security/providers/memory_security_provider.py +570 -0
- persistence_kit-3.3.0/persistence_kit/security/registration.py +100 -0
- persistence_kit-3.3.0/persistence_kit/security/token_verifiers/__init__.py +23 -0
- persistence_kit-3.3.0/persistence_kit/security/token_verifiers/cognito_jwt_verifier.py +60 -0
- persistence_kit-3.3.0/persistence_kit/security/token_verifiers/memory_jwt_verifier.py +44 -0
- persistence_kit-3.3.0/persistence_kit/settings/__init__.py +29 -0
- persistence_kit-3.3.0/persistence_kit/settings/app_settings.py +125 -0
- persistence_kit-3.3.0/persistence_kit/storage/__init__.py +80 -0
- persistence_kit-3.3.0/persistence_kit/storage/contracts.py +30 -0
- persistence_kit-3.3.0/persistence_kit/storage/errors.py +18 -0
- persistence_kit-3.3.0/persistence_kit/storage/factory.py +140 -0
- persistence_kit-3.3.0/persistence_kit/storage/local.py +148 -0
- persistence_kit-3.3.0/persistence_kit/storage/media.py +107 -0
- persistence_kit-3.3.0/persistence_kit/storage/routes.py +119 -0
- persistence_kit-3.3.0/persistence_kit/storage/s3.py +125 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/pyproject.toml +15 -3
- persistence_kit-3.0.2/persistence_kit/__init__.py +0 -46
- persistence_kit-3.0.2/persistence_kit/settings/__init__.py +0 -5
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/LICENSE +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/api/common.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/api/error_handlers.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/api/exceptions.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/api/route_loader.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/bootstrap/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/bootstrap/configuration.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/bootstrap/seeders.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/bootstrap/startup.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/contracts/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/contracts/repository.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/contracts/view_repository.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/py.typed +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/dynamodb_repo/dynamodb_mapper.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/dynamodb_repo/dynamodb_repo.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/filter_ops.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/memory_repo/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/memory_repo/memory_repo.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/mongo_repo/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/mongo_repo/mongo_mapper.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/mongo_repo/mongo_repo.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/sqlalchemy_repo/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/sqlalchemy_repo/schema_evolve.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_dataclass_mapper.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_repo.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository/sqlalchemy_repo/table_factory.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/factory/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/factory/repository_factory.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/registry/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/registry/entity_registry.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/view/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/repository_factory/view/populating_repository.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/settings/constants.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/settings/parsers.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/settings/repo_settings.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/utils/__init__.py +0 -0
- {persistence_kit-3.0.2 → persistence_kit-3.3.0}/persistence_kit/utils/upsert.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: persistence-kit
|
|
3
|
-
Version: 3.0
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Reusable persistence and repository toolkit
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -18,11 +18,21 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
19
|
Classifier: Topic :: Database
|
|
20
20
|
Classifier: Typing :: Typed
|
|
21
|
+
Provides-Extra: all
|
|
22
|
+
Provides-Extra: api
|
|
23
|
+
Provides-Extra: dynamodb
|
|
24
|
+
Provides-Extra: security
|
|
25
|
+
Provides-Extra: security-cognito
|
|
26
|
+
Provides-Extra: storage-routes
|
|
27
|
+
Provides-Extra: storage-s3
|
|
28
|
+
Provides-Extra: testing
|
|
21
29
|
Requires-Dist: asyncpg (>=0.30.0,<0.31.0)
|
|
22
|
-
Requires-Dist: boto3 (>=1.35.0,<2.0.0)
|
|
23
|
-
Requires-Dist: fastapi (>=0.115.0,<0.116.0)
|
|
30
|
+
Requires-Dist: boto3 (>=1.35.0,<2.0.0) ; extra == "storage-s3" or extra == "security-cognito" or extra == "dynamodb" or extra == "all"
|
|
31
|
+
Requires-Dist: fastapi (>=0.115.0,<0.116.0) ; extra == "api" or extra == "storage-routes" or extra == "security" or extra == "security-cognito" or extra == "testing" or extra == "all"
|
|
24
32
|
Requires-Dist: motor (>=3.7.1,<4.0.0)
|
|
25
33
|
Requires-Dist: pydantic-settings (>=2.3.0,<3.0.0)
|
|
34
|
+
Requires-Dist: pyjwt[crypto] (>=2.10.1,<3.0.0) ; extra == "security" or extra == "security-cognito" or extra == "testing" or extra == "all"
|
|
35
|
+
Requires-Dist: python-multipart (>=0.0.20,<0.0.21) ; extra == "api" or extra == "storage-routes" or extra == "security" or extra == "security-cognito" or extra == "testing" or extra == "all"
|
|
26
36
|
Requires-Dist: sqlalchemy[asyncio] (>=2.0.43,<3.0.0)
|
|
27
37
|
Requires-Dist: typing-extensions (>=4.12.0,<5.0.0)
|
|
28
38
|
Project-URL: Documentation, https://github.com/andresfserrano/persistence-kit#readme
|
|
@@ -53,6 +63,8 @@ Author: Andres Felipe Serrano Barrios
|
|
|
53
63
|
- `api/`: reusable API exceptions, handlers, and route loading helpers
|
|
54
64
|
- `bootstrap/`: startup helpers, configuration registry, and seed orchestration
|
|
55
65
|
- `utils/`: transversal helpers such as upsert utilities
|
|
66
|
+
- `storage/`: reusable object storage contracts and local/S3 adapters
|
|
67
|
+
- `security/`: reusable identity provider contracts, Cognito/memory adapters, and JWT verifiers
|
|
56
68
|
- `repository/`: concrete repository implementations by backend
|
|
57
69
|
- `repository_factory/`: entity registry, repository creation, and populated view repository
|
|
58
70
|
|
|
@@ -67,6 +79,28 @@ Recommended rule:
|
|
|
67
79
|
pip install persistence-kit
|
|
68
80
|
```
|
|
69
81
|
|
|
82
|
+
The base install keeps optional capabilities out of the dependency graph. Enable
|
|
83
|
+
only what the host project uses:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install "persistence-kit[api]"
|
|
87
|
+
pip install "persistence-kit[security]"
|
|
88
|
+
pip install "persistence-kit[security-cognito]"
|
|
89
|
+
pip install "persistence-kit[storage-s3]"
|
|
90
|
+
pip install "persistence-kit[storage-routes]"
|
|
91
|
+
pip install "persistence-kit[dynamodb]"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Available capabilities:
|
|
95
|
+
|
|
96
|
+
- `api`: FastAPI exceptions, pagination helpers, route loading, and error handlers.
|
|
97
|
+
- `security`: memory identity provider and JWT verifier.
|
|
98
|
+
- `security-cognito`: security plus Cognito and AWS/JWKS dependencies.
|
|
99
|
+
- `storage-s3`: S3 object storage adapter.
|
|
100
|
+
- `storage-routes`: FastAPI local export download router.
|
|
101
|
+
- `dynamodb`: DynamoDB repository backend.
|
|
102
|
+
- `all`: every optional capability.
|
|
103
|
+
|
|
70
104
|
## Quick Start
|
|
71
105
|
|
|
72
106
|
```python
|
|
@@ -96,10 +130,25 @@ from persistence_kit import (
|
|
|
96
130
|
Repository,
|
|
97
131
|
ViewRepository,
|
|
98
132
|
RepoSettings,
|
|
133
|
+
PersistenceKitSettings,
|
|
134
|
+
AuthProvider,
|
|
135
|
+
ExportStorageProvider,
|
|
99
136
|
Database,
|
|
100
137
|
ConfigRegistry,
|
|
101
138
|
configuration,
|
|
102
139
|
SeederProvider,
|
|
140
|
+
ObjectStorage,
|
|
141
|
+
LocalObjectStorage,
|
|
142
|
+
S3ObjectStorage,
|
|
143
|
+
get_export_storage,
|
|
144
|
+
build_local_export_storage_router,
|
|
145
|
+
IdentityProvider,
|
|
146
|
+
MemorySecurityProvider,
|
|
147
|
+
CognitoIdentityProvider,
|
|
148
|
+
MemoryJwtVerifier,
|
|
149
|
+
CognitoJwtVerifier,
|
|
150
|
+
get_identity_provider,
|
|
151
|
+
get_token_verifier,
|
|
103
152
|
build_api_router,
|
|
104
153
|
handle_service_errors,
|
|
105
154
|
handle_repository_errors,
|
|
@@ -125,6 +174,93 @@ Use internal paths only for implementation details, for example:
|
|
|
125
174
|
- `persistence_kit.repository_factory.registry.entity_registry`
|
|
126
175
|
- `persistence_kit.repository_factory.view.populating_repository`
|
|
127
176
|
|
|
177
|
+
## Object Storage
|
|
178
|
+
|
|
179
|
+
`persistence_kit.storage` provides driven adapters for storing generated files or
|
|
180
|
+
binary objects outside the domain layer:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from persistence_kit.storage import LocalObjectStorage
|
|
184
|
+
|
|
185
|
+
storage = LocalObjectStorage(
|
|
186
|
+
base_dir=".local",
|
|
187
|
+
public_base_url="http://localhost:8000",
|
|
188
|
+
signing_secret="dev-secret",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
key = await storage.upload("exports/report.csv", b"id,name\n1,Ada\n", "text/csv")
|
|
192
|
+
url = await storage.generate_presigned_url(key)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Available adapters:
|
|
196
|
+
|
|
197
|
+
- `LocalObjectStorage`: stores files under a configured local directory and signs download URLs.
|
|
198
|
+
- `S3ObjectStorage`: uploads objects to S3 and returns AWS presigned URLs.
|
|
199
|
+
|
|
200
|
+
Backward-compatible aliases are exported for applications that previously used
|
|
201
|
+
`LocalExportStorageProvider` and `S3ExportStorageProvider`.
|
|
202
|
+
|
|
203
|
+
`get_export_storage(settings)` builds and caches the configured adapter from a
|
|
204
|
+
`PersistenceKitSettings` instance or a subclass inherited by the host app.
|
|
205
|
+
|
|
206
|
+
For FastAPI applications, `build_local_export_storage_router(...)` exposes a
|
|
207
|
+
reusable local download route. The host app passes its settings provider,
|
|
208
|
+
optional-current-user dependency, and product authorization callback.
|
|
209
|
+
|
|
210
|
+
Install `persistence-kit[storage-s3]` before using `S3ObjectStorage` and
|
|
211
|
+
`persistence-kit[storage-routes]` before using the FastAPI export route.
|
|
212
|
+
|
|
213
|
+
## Security
|
|
214
|
+
|
|
215
|
+
`persistence_kit.security` provides reusable driven adapters for application
|
|
216
|
+
authentication flows:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from persistence_kit.security import MemorySecurityProvider, MemoryJwtVerifier
|
|
220
|
+
|
|
221
|
+
identity = MemorySecurityProvider(
|
|
222
|
+
jwt_secret="dev-secret-with-enough-length",
|
|
223
|
+
jwt_issuer="local-sandbox",
|
|
224
|
+
seed_role_users=True,
|
|
225
|
+
seed_role_codes=("admin", "operator"),
|
|
226
|
+
seed_user_domain="example.org",
|
|
227
|
+
)
|
|
228
|
+
verifier = MemoryJwtVerifier(secret="dev-secret-with-enough-length", issuer="local-sandbox")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Available pieces:
|
|
232
|
+
|
|
233
|
+
- `IdentityProvider` and `TokenVerifier`: application-facing protocols.
|
|
234
|
+
- `MemorySecurityProvider`: local identity provider for tests/sandbox environments.
|
|
235
|
+
- `CognitoIdentityProvider`: AWS Cognito identity provider adapter.
|
|
236
|
+
- `MemoryJwtVerifier` and `CognitoJwtVerifier`: JWT token verifiers.
|
|
237
|
+
- Registration/login/password-reset result dataclasses and helper functions such as `unique_roles`.
|
|
238
|
+
|
|
239
|
+
Host applications should keep domain-specific roles, authorization policies,
|
|
240
|
+
scope rules, and route permission matrices outside the kit.
|
|
241
|
+
|
|
242
|
+
Install `persistence-kit[security]` for the memory provider/JWT verifier and
|
|
243
|
+
`persistence-kit[security-cognito]` for Cognito support.
|
|
244
|
+
|
|
245
|
+
`PersistenceKitSettings` centralizes common auth, storage, observability, AWS,
|
|
246
|
+
and job-service settings. Host applications can inherit from it and override
|
|
247
|
+
only product-specific defaults:
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
from persistence_kit import Database, PersistenceKitSettings
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class Settings(PersistenceKitSettings):
|
|
254
|
+
service_name: str = "my-api"
|
|
255
|
+
key_status_history_database: Database = Database.MONGO
|
|
256
|
+
memory_seed_role_codes: tuple[str, ...] = ("admin", "operator")
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`persistence_kit.security.factory` can build the identity provider and token
|
|
260
|
+
verifier from that inherited settings object. `persistence_kit.storage.factory`
|
|
261
|
+
does the same for export storage, and `persistence_kit.storage.routes` exposes
|
|
262
|
+
the reusable FastAPI local export route.
|
|
263
|
+
|
|
128
264
|
## Typical Host Application Flow
|
|
129
265
|
|
|
130
266
|
1. Define your entities as dataclasses.
|
|
@@ -150,13 +286,13 @@ Create the local environment and run tests from the library root:
|
|
|
150
286
|
|
|
151
287
|
```bash
|
|
152
288
|
poetry lock
|
|
153
|
-
poetry install --with dev
|
|
289
|
+
poetry install --with dev --all-extras
|
|
154
290
|
poetry run pytest -q
|
|
155
291
|
```
|
|
156
292
|
|
|
157
293
|
Current validation baseline:
|
|
158
294
|
|
|
159
|
-
- `persistence_kit`: `
|
|
295
|
+
- `persistence_kit`: `335 passed`
|
|
160
296
|
|
|
161
297
|
## Publish to PyPI (Manual)
|
|
162
298
|
|
|
@@ -21,6 +21,8 @@ Author: Andres Felipe Serrano Barrios
|
|
|
21
21
|
- `api/`: reusable API exceptions, handlers, and route loading helpers
|
|
22
22
|
- `bootstrap/`: startup helpers, configuration registry, and seed orchestration
|
|
23
23
|
- `utils/`: transversal helpers such as upsert utilities
|
|
24
|
+
- `storage/`: reusable object storage contracts and local/S3 adapters
|
|
25
|
+
- `security/`: reusable identity provider contracts, Cognito/memory adapters, and JWT verifiers
|
|
24
26
|
- `repository/`: concrete repository implementations by backend
|
|
25
27
|
- `repository_factory/`: entity registry, repository creation, and populated view repository
|
|
26
28
|
|
|
@@ -35,6 +37,28 @@ Recommended rule:
|
|
|
35
37
|
pip install persistence-kit
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
The base install keeps optional capabilities out of the dependency graph. Enable
|
|
41
|
+
only what the host project uses:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install "persistence-kit[api]"
|
|
45
|
+
pip install "persistence-kit[security]"
|
|
46
|
+
pip install "persistence-kit[security-cognito]"
|
|
47
|
+
pip install "persistence-kit[storage-s3]"
|
|
48
|
+
pip install "persistence-kit[storage-routes]"
|
|
49
|
+
pip install "persistence-kit[dynamodb]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Available capabilities:
|
|
53
|
+
|
|
54
|
+
- `api`: FastAPI exceptions, pagination helpers, route loading, and error handlers.
|
|
55
|
+
- `security`: memory identity provider and JWT verifier.
|
|
56
|
+
- `security-cognito`: security plus Cognito and AWS/JWKS dependencies.
|
|
57
|
+
- `storage-s3`: S3 object storage adapter.
|
|
58
|
+
- `storage-routes`: FastAPI local export download router.
|
|
59
|
+
- `dynamodb`: DynamoDB repository backend.
|
|
60
|
+
- `all`: every optional capability.
|
|
61
|
+
|
|
38
62
|
## Quick Start
|
|
39
63
|
|
|
40
64
|
```python
|
|
@@ -64,10 +88,25 @@ from persistence_kit import (
|
|
|
64
88
|
Repository,
|
|
65
89
|
ViewRepository,
|
|
66
90
|
RepoSettings,
|
|
91
|
+
PersistenceKitSettings,
|
|
92
|
+
AuthProvider,
|
|
93
|
+
ExportStorageProvider,
|
|
67
94
|
Database,
|
|
68
95
|
ConfigRegistry,
|
|
69
96
|
configuration,
|
|
70
97
|
SeederProvider,
|
|
98
|
+
ObjectStorage,
|
|
99
|
+
LocalObjectStorage,
|
|
100
|
+
S3ObjectStorage,
|
|
101
|
+
get_export_storage,
|
|
102
|
+
build_local_export_storage_router,
|
|
103
|
+
IdentityProvider,
|
|
104
|
+
MemorySecurityProvider,
|
|
105
|
+
CognitoIdentityProvider,
|
|
106
|
+
MemoryJwtVerifier,
|
|
107
|
+
CognitoJwtVerifier,
|
|
108
|
+
get_identity_provider,
|
|
109
|
+
get_token_verifier,
|
|
71
110
|
build_api_router,
|
|
72
111
|
handle_service_errors,
|
|
73
112
|
handle_repository_errors,
|
|
@@ -93,6 +132,93 @@ Use internal paths only for implementation details, for example:
|
|
|
93
132
|
- `persistence_kit.repository_factory.registry.entity_registry`
|
|
94
133
|
- `persistence_kit.repository_factory.view.populating_repository`
|
|
95
134
|
|
|
135
|
+
## Object Storage
|
|
136
|
+
|
|
137
|
+
`persistence_kit.storage` provides driven adapters for storing generated files or
|
|
138
|
+
binary objects outside the domain layer:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from persistence_kit.storage import LocalObjectStorage
|
|
142
|
+
|
|
143
|
+
storage = LocalObjectStorage(
|
|
144
|
+
base_dir=".local",
|
|
145
|
+
public_base_url="http://localhost:8000",
|
|
146
|
+
signing_secret="dev-secret",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
key = await storage.upload("exports/report.csv", b"id,name\n1,Ada\n", "text/csv")
|
|
150
|
+
url = await storage.generate_presigned_url(key)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Available adapters:
|
|
154
|
+
|
|
155
|
+
- `LocalObjectStorage`: stores files under a configured local directory and signs download URLs.
|
|
156
|
+
- `S3ObjectStorage`: uploads objects to S3 and returns AWS presigned URLs.
|
|
157
|
+
|
|
158
|
+
Backward-compatible aliases are exported for applications that previously used
|
|
159
|
+
`LocalExportStorageProvider` and `S3ExportStorageProvider`.
|
|
160
|
+
|
|
161
|
+
`get_export_storage(settings)` builds and caches the configured adapter from a
|
|
162
|
+
`PersistenceKitSettings` instance or a subclass inherited by the host app.
|
|
163
|
+
|
|
164
|
+
For FastAPI applications, `build_local_export_storage_router(...)` exposes a
|
|
165
|
+
reusable local download route. The host app passes its settings provider,
|
|
166
|
+
optional-current-user dependency, and product authorization callback.
|
|
167
|
+
|
|
168
|
+
Install `persistence-kit[storage-s3]` before using `S3ObjectStorage` and
|
|
169
|
+
`persistence-kit[storage-routes]` before using the FastAPI export route.
|
|
170
|
+
|
|
171
|
+
## Security
|
|
172
|
+
|
|
173
|
+
`persistence_kit.security` provides reusable driven adapters for application
|
|
174
|
+
authentication flows:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from persistence_kit.security import MemorySecurityProvider, MemoryJwtVerifier
|
|
178
|
+
|
|
179
|
+
identity = MemorySecurityProvider(
|
|
180
|
+
jwt_secret="dev-secret-with-enough-length",
|
|
181
|
+
jwt_issuer="local-sandbox",
|
|
182
|
+
seed_role_users=True,
|
|
183
|
+
seed_role_codes=("admin", "operator"),
|
|
184
|
+
seed_user_domain="example.org",
|
|
185
|
+
)
|
|
186
|
+
verifier = MemoryJwtVerifier(secret="dev-secret-with-enough-length", issuer="local-sandbox")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Available pieces:
|
|
190
|
+
|
|
191
|
+
- `IdentityProvider` and `TokenVerifier`: application-facing protocols.
|
|
192
|
+
- `MemorySecurityProvider`: local identity provider for tests/sandbox environments.
|
|
193
|
+
- `CognitoIdentityProvider`: AWS Cognito identity provider adapter.
|
|
194
|
+
- `MemoryJwtVerifier` and `CognitoJwtVerifier`: JWT token verifiers.
|
|
195
|
+
- Registration/login/password-reset result dataclasses and helper functions such as `unique_roles`.
|
|
196
|
+
|
|
197
|
+
Host applications should keep domain-specific roles, authorization policies,
|
|
198
|
+
scope rules, and route permission matrices outside the kit.
|
|
199
|
+
|
|
200
|
+
Install `persistence-kit[security]` for the memory provider/JWT verifier and
|
|
201
|
+
`persistence-kit[security-cognito]` for Cognito support.
|
|
202
|
+
|
|
203
|
+
`PersistenceKitSettings` centralizes common auth, storage, observability, AWS,
|
|
204
|
+
and job-service settings. Host applications can inherit from it and override
|
|
205
|
+
only product-specific defaults:
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from persistence_kit import Database, PersistenceKitSettings
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class Settings(PersistenceKitSettings):
|
|
212
|
+
service_name: str = "my-api"
|
|
213
|
+
key_status_history_database: Database = Database.MONGO
|
|
214
|
+
memory_seed_role_codes: tuple[str, ...] = ("admin", "operator")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`persistence_kit.security.factory` can build the identity provider and token
|
|
218
|
+
verifier from that inherited settings object. `persistence_kit.storage.factory`
|
|
219
|
+
does the same for export storage, and `persistence_kit.storage.routes` exposes
|
|
220
|
+
the reusable FastAPI local export route.
|
|
221
|
+
|
|
96
222
|
## Typical Host Application Flow
|
|
97
223
|
|
|
98
224
|
1. Define your entities as dataclasses.
|
|
@@ -118,13 +244,13 @@ Create the local environment and run tests from the library root:
|
|
|
118
244
|
|
|
119
245
|
```bash
|
|
120
246
|
poetry lock
|
|
121
|
-
poetry install --with dev
|
|
247
|
+
poetry install --with dev --all-extras
|
|
122
248
|
poetry run pytest -q
|
|
123
249
|
```
|
|
124
250
|
|
|
125
251
|
Current validation baseline:
|
|
126
252
|
|
|
127
|
-
- `persistence_kit`: `
|
|
253
|
+
- `persistence_kit`: `335 passed`
|
|
128
254
|
|
|
129
255
|
## Publish to PyPI (Manual)
|
|
130
256
|
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
from importlib import import_module
|
|
2
|
+
|
|
3
|
+
from .bootstrap.configuration import ConfigRegistry, configuration, set_config_package
|
|
4
|
+
from .bootstrap.seeders import Seeder, SeederProvider
|
|
5
|
+
from .bootstrap.startup import is_duplicate_startup_error, run_startup_bootstrap
|
|
6
|
+
from .contracts.repository import Repository
|
|
7
|
+
from .contracts.view_repository import ViewRepository
|
|
8
|
+
from .settings import (
|
|
9
|
+
DEFAULT_MEMORY_JWT_ISSUER,
|
|
10
|
+
DEFAULT_MEMORY_JWT_SECRET,
|
|
11
|
+
DEFAULT_MEMORY_JWT_TTL_SECONDS,
|
|
12
|
+
LOCAL_DEFAULT_JOB_SERVICE_API_KEY,
|
|
13
|
+
AuthProvider,
|
|
14
|
+
DeploymentStage,
|
|
15
|
+
ExportStorageProvider,
|
|
16
|
+
MediaStorageProvider,
|
|
17
|
+
PersistenceKitSettings,
|
|
18
|
+
)
|
|
19
|
+
from .settings.constants import Database
|
|
20
|
+
from .settings.parsers import split_csv_list
|
|
21
|
+
from .settings.repo_settings import RepoSettings
|
|
22
|
+
from .storage import (
|
|
23
|
+
EXPORT_STORAGE_BUILDERS,
|
|
24
|
+
ExportStorage,
|
|
25
|
+
ExportStorageBuilder,
|
|
26
|
+
ObjectStorage,
|
|
27
|
+
StorageConfigError,
|
|
28
|
+
StorageError,
|
|
29
|
+
StoragePathError,
|
|
30
|
+
StoragePresignError,
|
|
31
|
+
StorageUploadError,
|
|
32
|
+
get_export_storage,
|
|
33
|
+
)
|
|
34
|
+
from .authenticated_user import AuthenticatedUser
|
|
35
|
+
from .utils.upsert import dataclass_field_names, upsert_entity
|
|
36
|
+
|
|
37
|
+
_OPTIONAL_EXPORTS = {
|
|
38
|
+
"ApiError": ("persistence_kit.api.common", "ApiError", "api"),
|
|
39
|
+
"pagination_params": ("persistence_kit.api.common", "pagination_params", "api"),
|
|
40
|
+
"BaseAPIException": ("persistence_kit.api.exceptions", "BaseAPIException", "api"),
|
|
41
|
+
"NotFoundException": ("persistence_kit.api.exceptions", "NotFoundException", "api"),
|
|
42
|
+
"ValidationException": ("persistence_kit.api.exceptions", "ValidationException", "api"),
|
|
43
|
+
"BusinessRuleException": (
|
|
44
|
+
"persistence_kit.api.exceptions",
|
|
45
|
+
"BusinessRuleException",
|
|
46
|
+
"api",
|
|
47
|
+
),
|
|
48
|
+
"DatabaseException": ("persistence_kit.api.exceptions", "DatabaseException", "api"),
|
|
49
|
+
"handle_service_errors": (
|
|
50
|
+
"persistence_kit.api.error_handlers",
|
|
51
|
+
"handle_service_errors",
|
|
52
|
+
"api",
|
|
53
|
+
),
|
|
54
|
+
"handle_repository_errors": (
|
|
55
|
+
"persistence_kit.api.error_handlers",
|
|
56
|
+
"handle_repository_errors",
|
|
57
|
+
"api",
|
|
58
|
+
),
|
|
59
|
+
"build_api_router": ("persistence_kit.api.route_loader", "build_api_router", "api"),
|
|
60
|
+
"InMemoryRateLimiter": ("persistence_kit.api.rate_limit", "InMemoryRateLimiter", "api"),
|
|
61
|
+
"build_auth_rate_limit_dependency": (
|
|
62
|
+
"persistence_kit.api.rate_limit",
|
|
63
|
+
"build_auth_rate_limit_dependency",
|
|
64
|
+
"api",
|
|
65
|
+
),
|
|
66
|
+
"IdentityProvider": ("persistence_kit.security.ports", "IdentityProvider", "security"),
|
|
67
|
+
"TokenVerifier": ("persistence_kit.security.ports", "TokenVerifier", "security"),
|
|
68
|
+
"CognitoIdentityProvider": (
|
|
69
|
+
"persistence_kit.security.providers",
|
|
70
|
+
"CognitoIdentityProvider",
|
|
71
|
+
"security-cognito",
|
|
72
|
+
),
|
|
73
|
+
"MemorySecurityProvider": (
|
|
74
|
+
"persistence_kit.security.providers",
|
|
75
|
+
"MemorySecurityProvider",
|
|
76
|
+
"testing",
|
|
77
|
+
),
|
|
78
|
+
"CognitoJwtVerifier": (
|
|
79
|
+
"persistence_kit.security.token_verifiers",
|
|
80
|
+
"CognitoJwtVerifier",
|
|
81
|
+
"security-cognito",
|
|
82
|
+
),
|
|
83
|
+
"MemoryJwtVerifier": (
|
|
84
|
+
"persistence_kit.security.token_verifiers",
|
|
85
|
+
"MemoryJwtVerifier",
|
|
86
|
+
"testing",
|
|
87
|
+
),
|
|
88
|
+
"get_identity_provider": (
|
|
89
|
+
"persistence_kit.security.factory",
|
|
90
|
+
"get_identity_provider",
|
|
91
|
+
"security",
|
|
92
|
+
),
|
|
93
|
+
"get_token_verifier": (
|
|
94
|
+
"persistence_kit.security.factory",
|
|
95
|
+
"get_token_verifier",
|
|
96
|
+
"security",
|
|
97
|
+
),
|
|
98
|
+
"RegistrationResult": (
|
|
99
|
+
"persistence_kit.security.registration",
|
|
100
|
+
"RegistrationResult",
|
|
101
|
+
"security",
|
|
102
|
+
),
|
|
103
|
+
"RoleAssignmentResult": (
|
|
104
|
+
"persistence_kit.security.registration",
|
|
105
|
+
"RoleAssignmentResult",
|
|
106
|
+
"security",
|
|
107
|
+
),
|
|
108
|
+
"UserStatusUpdateResult": (
|
|
109
|
+
"persistence_kit.security.registration",
|
|
110
|
+
"UserStatusUpdateResult",
|
|
111
|
+
"security",
|
|
112
|
+
),
|
|
113
|
+
"LoginResult": ("persistence_kit.security.registration", "LoginResult", "security"),
|
|
114
|
+
"RefreshTokensResult": (
|
|
115
|
+
"persistence_kit.security.registration",
|
|
116
|
+
"RefreshTokensResult",
|
|
117
|
+
"security",
|
|
118
|
+
),
|
|
119
|
+
"LogoutResult": ("persistence_kit.security.registration", "LogoutResult", "security"),
|
|
120
|
+
"PasswordResetCodeRequestResult": (
|
|
121
|
+
"persistence_kit.security.registration",
|
|
122
|
+
"PasswordResetCodeRequestResult",
|
|
123
|
+
"security",
|
|
124
|
+
),
|
|
125
|
+
"PasswordResetConfirmResult": (
|
|
126
|
+
"persistence_kit.security.registration",
|
|
127
|
+
"PasswordResetConfirmResult",
|
|
128
|
+
"security",
|
|
129
|
+
),
|
|
130
|
+
"PasswordResetResult": (
|
|
131
|
+
"persistence_kit.security.registration",
|
|
132
|
+
"PasswordResetResult",
|
|
133
|
+
"security",
|
|
134
|
+
),
|
|
135
|
+
"RegisteredUserResult": (
|
|
136
|
+
"persistence_kit.security.registration",
|
|
137
|
+
"RegisteredUserResult",
|
|
138
|
+
"security",
|
|
139
|
+
),
|
|
140
|
+
"RegisteredUsersPageResult": (
|
|
141
|
+
"persistence_kit.security.registration",
|
|
142
|
+
"RegisteredUsersPageResult",
|
|
143
|
+
"security",
|
|
144
|
+
),
|
|
145
|
+
"validate_allowed_email_domain": (
|
|
146
|
+
"persistence_kit.security.registration",
|
|
147
|
+
"validate_allowed_email_domain",
|
|
148
|
+
"security",
|
|
149
|
+
),
|
|
150
|
+
"unique_roles": ("persistence_kit.security.registration", "unique_roles", "security"),
|
|
151
|
+
"LocalObjectStorage": ("persistence_kit.storage.local", "LocalObjectStorage", "testing"),
|
|
152
|
+
"LocalExportStorageProvider": (
|
|
153
|
+
"persistence_kit.storage.local",
|
|
154
|
+
"LocalExportStorageProvider",
|
|
155
|
+
"testing",
|
|
156
|
+
),
|
|
157
|
+
"S3ObjectStorage": ("persistence_kit.storage.s3", "S3ObjectStorage", "storage-s3"),
|
|
158
|
+
"S3ExportStorageProvider": (
|
|
159
|
+
"persistence_kit.storage.s3",
|
|
160
|
+
"S3ExportStorageProvider",
|
|
161
|
+
"storage-s3",
|
|
162
|
+
),
|
|
163
|
+
"build_local_export_storage_router": (
|
|
164
|
+
"persistence_kit.storage.routes",
|
|
165
|
+
"build_local_export_storage_router",
|
|
166
|
+
"storage-routes",
|
|
167
|
+
),
|
|
168
|
+
"serve_local_export": (
|
|
169
|
+
"persistence_kit.storage.routes",
|
|
170
|
+
"serve_local_export",
|
|
171
|
+
"storage-routes",
|
|
172
|
+
),
|
|
173
|
+
"guess_export_media_type": (
|
|
174
|
+
"persistence_kit.storage.routes",
|
|
175
|
+
"guess_export_media_type",
|
|
176
|
+
"storage-routes",
|
|
177
|
+
),
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
__all__ = [
|
|
181
|
+
"Repository",
|
|
182
|
+
"ViewRepository",
|
|
183
|
+
"split_csv_list",
|
|
184
|
+
"ConfigRegistry",
|
|
185
|
+
"configuration",
|
|
186
|
+
"Database",
|
|
187
|
+
"RepoSettings",
|
|
188
|
+
"AuthProvider",
|
|
189
|
+
"ExportStorageProvider",
|
|
190
|
+
"MediaStorageProvider",
|
|
191
|
+
"DeploymentStage",
|
|
192
|
+
"LOCAL_DEFAULT_JOB_SERVICE_API_KEY",
|
|
193
|
+
"DEFAULT_MEMORY_JWT_SECRET",
|
|
194
|
+
"DEFAULT_MEMORY_JWT_ISSUER",
|
|
195
|
+
"DEFAULT_MEMORY_JWT_TTL_SECONDS",
|
|
196
|
+
"PersistenceKitSettings",
|
|
197
|
+
"Seeder",
|
|
198
|
+
"SeederProvider",
|
|
199
|
+
"set_config_package",
|
|
200
|
+
"is_duplicate_startup_error",
|
|
201
|
+
"run_startup_bootstrap",
|
|
202
|
+
"AuthenticatedUser",
|
|
203
|
+
"dataclass_field_names",
|
|
204
|
+
"upsert_entity",
|
|
205
|
+
"ObjectStorage",
|
|
206
|
+
"StorageError",
|
|
207
|
+
"StorageConfigError",
|
|
208
|
+
"StoragePathError",
|
|
209
|
+
"StorageUploadError",
|
|
210
|
+
"StoragePresignError",
|
|
211
|
+
"ExportStorage",
|
|
212
|
+
"ExportStorageBuilder",
|
|
213
|
+
"EXPORT_STORAGE_BUILDERS",
|
|
214
|
+
"get_export_storage",
|
|
215
|
+
*_OPTIONAL_EXPORTS,
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def __getattr__(name: str):
|
|
220
|
+
if name not in _OPTIONAL_EXPORTS:
|
|
221
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
222
|
+
|
|
223
|
+
module_name, attr_name, extra_name = _OPTIONAL_EXPORTS[name]
|
|
224
|
+
try:
|
|
225
|
+
module = import_module(module_name)
|
|
226
|
+
except ModuleNotFoundError as exc:
|
|
227
|
+
raise ModuleNotFoundError(
|
|
228
|
+
f"{name} requiere la capability opcional '{extra_name}'. "
|
|
229
|
+
f"Instala con `persistence-kit[{extra_name}]`."
|
|
230
|
+
) from exc
|
|
231
|
+
value = getattr(module, attr_name)
|
|
232
|
+
globals()[name] = value
|
|
233
|
+
return value
|
|
@@ -7,6 +7,7 @@ from .exceptions import (
|
|
|
7
7
|
NotFoundException,
|
|
8
8
|
ValidationException,
|
|
9
9
|
)
|
|
10
|
+
from .rate_limit import InMemoryRateLimiter, build_auth_rate_limit_dependency
|
|
10
11
|
from .route_loader import build_api_router
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
@@ -20,4 +21,6 @@ __all__ = [
|
|
|
20
21
|
"handle_service_errors",
|
|
21
22
|
"handle_repository_errors",
|
|
22
23
|
"build_api_router",
|
|
24
|
+
"InMemoryRateLimiter",
|
|
25
|
+
"build_auth_rate_limit_dependency",
|
|
23
26
|
]
|