persistence-kit 3.8.0__tar.gz → 3.9.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 (99) hide show
  1. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/PKG-INFO +4 -4
  2. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/dynamodb_repo/dynamodb_repo.py +31 -12
  3. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/pyproject.toml +5 -5
  4. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/LICENSE +0 -0
  5. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/README.md +0 -0
  6. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/__init__.py +0 -0
  7. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/api/__init__.py +0 -0
  8. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/api/common.py +0 -0
  9. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/api/error_handlers.py +0 -0
  10. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/api/exceptions.py +0 -0
  11. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/api/rate_limit.py +0 -0
  12. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/api/route_loader.py +0 -0
  13. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/authenticated_user.py +0 -0
  14. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/bootstrap/__init__.py +0 -0
  15. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/bootstrap/configuration.py +0 -0
  16. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/bootstrap/seeders.py +0 -0
  17. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/bootstrap/startup.py +0 -0
  18. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/cache/__init__.py +0 -0
  19. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/cache/contracts.py +0 -0
  20. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/cache/factory.py +0 -0
  21. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/cache/memory.py +0 -0
  22. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/cache/mongo.py +0 -0
  23. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/cache/namespaced.py +0 -0
  24. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/contracts/__init__.py +0 -0
  25. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/contracts/repository.py +0 -0
  26. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/contracts/view_repository.py +0 -0
  27. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/py.typed +0 -0
  28. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/__init__.py +0 -0
  29. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/dynamodb_repo/dynamodb_mapper.py +0 -0
  30. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/filter_ops.py +0 -0
  31. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/memory_repo/__init__.py +0 -0
  32. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/memory_repo/memory_repo.py +0 -0
  33. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/mongo_repo/__init__.py +0 -0
  34. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/mongo_repo/mongo_mapper.py +0 -0
  35. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/mongo_repo/mongo_repo.py +0 -0
  36. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/sqlalchemy_repo/__init__.py +0 -0
  37. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/sqlalchemy_repo/schema_evolve.py +0 -0
  38. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_dataclass_mapper.py +0 -0
  39. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_engine.py +0 -0
  40. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_repo.py +0 -0
  41. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository/sqlalchemy_repo/table_factory.py +0 -0
  42. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/__init__.py +0 -0
  43. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/factory/__init__.py +0 -0
  44. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/factory/repository_factory.py +0 -0
  45. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/registry/__init__.py +0 -0
  46. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/registry/entity_registry.py +0 -0
  47. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/view/__init__.py +0 -0
  48. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/repository_factory/view/populating_repository.py +0 -0
  49. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/resilience/__init__.py +0 -0
  50. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/resilience/circuit.py +0 -0
  51. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/__init__.py +0 -0
  52. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/aggregate.py +0 -0
  53. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/__init__.py +0 -0
  54. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/api_key.py +0 -0
  55. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/base.py +0 -0
  56. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/basic.py +0 -0
  57. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/bearer.py +0 -0
  58. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/login.py +0 -0
  59. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/auth/oauth2.py +0 -0
  60. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/caching.py +0 -0
  61. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/client.py +0 -0
  62. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/config.py +0 -0
  63. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/contracts.py +0 -0
  64. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/errors.py +0 -0
  65. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/factory.py +0 -0
  66. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/mapping.py +0 -0
  67. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/memory.py +0 -0
  68. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/payload.py +0 -0
  69. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/populate.py +0 -0
  70. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/provider.py +0 -0
  71. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/registry.py +0 -0
  72. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/resolver.py +0 -0
  73. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/restclient/retry.py +0 -0
  74. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/__init__.py +0 -0
  75. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/factory.py +0 -0
  76. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/ports.py +0 -0
  77. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/providers/__init__.py +0 -0
  78. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/providers/cognito_identity_provider.py +0 -0
  79. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/providers/memory_security_provider.py +0 -0
  80. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/registration.py +0 -0
  81. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/token_verifiers/__init__.py +0 -0
  82. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/token_verifiers/cognito_jwt_verifier.py +0 -0
  83. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/security/token_verifiers/memory_jwt_verifier.py +0 -0
  84. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/settings/__init__.py +0 -0
  85. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/settings/app_settings.py +0 -0
  86. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/settings/cache_settings.py +0 -0
  87. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/settings/constants.py +0 -0
  88. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/settings/parsers.py +0 -0
  89. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/settings/repo_settings.py +0 -0
  90. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/__init__.py +0 -0
  91. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/contracts.py +0 -0
  92. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/errors.py +0 -0
  93. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/factory.py +0 -0
  94. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/local.py +0 -0
  95. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/media.py +0 -0
  96. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/routes.py +0 -0
  97. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/storage/s3.py +0 -0
  98. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/persistence_kit/utils/__init__.py +0 -0
  99. {persistence_kit-3.8.0 → persistence_kit-3.9.1}/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.8.0
3
+ Version: 3.9.1
4
4
  Summary: Reusable persistence and repository toolkit
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -27,14 +27,14 @@ Provides-Extra: security-cognito
27
27
  Provides-Extra: storage-routes
28
28
  Provides-Extra: storage-s3
29
29
  Provides-Extra: testing
30
- Requires-Dist: asyncpg (>=0.30.0,<0.31.0)
30
+ Requires-Dist: asyncpg (>=0.30.0,<1.0.0)
31
31
  Requires-Dist: boto3 (>=1.35.0,<2.0.0) ; extra == "storage-s3" or extra == "security-cognito" or extra == "dynamodb" or extra == "all"
32
32
  Requires-Dist: fastapi (>=0.115.0,<1.0.0) ; extra == "api" or extra == "storage-routes" or extra == "security" or extra == "security-cognito" or extra == "testing" or extra == "all"
33
- Requires-Dist: httpx (>=0.28.0,<0.29.0) ; extra == "restclient" or extra == "testing" or extra == "all"
33
+ Requires-Dist: httpx (>=0.28.0,<1.0.0) ; extra == "restclient" or extra == "testing" or extra == "all"
34
34
  Requires-Dist: motor (>=3.7.1,<4.0.0)
35
35
  Requires-Dist: pydantic-settings (>=2.3.0,<3.0.0)
36
36
  Requires-Dist: pyjwt[crypto] (>=2.10.1,<3.0.0) ; extra == "security" or extra == "security-cognito" or extra == "testing" or extra == "all"
37
- 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"
37
+ Requires-Dist: python-multipart (>=0.0.31,<1.0.0) ; extra == "api" or extra == "storage-routes" or extra == "security" or extra == "security-cognito" or extra == "testing" or extra == "all"
38
38
  Requires-Dist: sqlalchemy[asyncio] (>=2.0.43,<3.0.0)
39
39
  Requires-Dist: typing-extensions (>=4.12.0,<5.0.0)
40
40
  Project-URL: Documentation, https://github.com/andresfserrano/persistence-kit#readme
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  from typing import Optional, Sequence, TypeVar, Generic, Hashable, Mapping, Any
4
5
  try:
5
6
  from typing import override
@@ -129,14 +130,18 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
129
130
  @override
130
131
  async def add(self, entity: T) -> None:
131
132
  item = self._mapper.to_item(entity)
132
- self._table.put_item(
133
+ await asyncio.to_thread(
134
+ self._table.put_item,
133
135
  Item=item,
134
136
  ConditionExpression=Attr("id").not_exists(),
135
137
  )
136
138
 
137
139
  @override
138
140
  async def get(self, entity_id: TId) -> Optional[T]:
139
- response = self._table.get_item(Key={"id": _serialize_value(entity_id)})
141
+ response = await asyncio.to_thread(
142
+ self._table.get_item,
143
+ Key={"id": _serialize_value(entity_id)},
144
+ )
140
145
  item = response.get("Item")
141
146
  return self._mapper.from_item(item) if item else None
142
147
 
@@ -149,7 +154,7 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
149
154
  sort_by: str | None = None,
150
155
  sort_desc: bool = False,
151
156
  ) -> Sequence[T]:
152
- items = self._scan_all()
157
+ items = await asyncio.to_thread(self._scan_all)
153
158
  entities = [self._mapper.from_item(i) for i in items]
154
159
  if sort_by is not None:
155
160
  if not self._mapper.has_attr(sort_by):
@@ -160,18 +165,22 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
160
165
  @override
161
166
  async def update(self, entity: T) -> None:
162
167
  item = self._mapper.to_item(entity)
163
- self._table.put_item(Item=item)
168
+ await asyncio.to_thread(self._table.put_item, Item=item)
164
169
 
165
170
  @override
166
171
  async def delete(self, entity_id: TId) -> None:
167
- self._table.delete_item(Key={"id": _serialize_value(entity_id)})
172
+ await asyncio.to_thread(
173
+ self._table.delete_item,
174
+ Key={"id": _serialize_value(entity_id)},
175
+ )
168
176
 
169
177
  @override
170
178
  async def get_by_index(self, index: str, value: Hashable) -> Optional[T]:
171
179
  field = self._mapper.unique_fields().get(index)
172
180
  if not field:
173
181
  return None
174
- response = self._table.scan(
182
+ response = await asyncio.to_thread(
183
+ self._table.scan,
175
184
  FilterExpression=Attr(field).eq(_serialize_value(value)),
176
185
  Limit=1,
177
186
  )
@@ -180,7 +189,7 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
180
189
 
181
190
  @override
182
191
  async def count(self) -> int:
183
- return self._table.item_count
192
+ return await asyncio.to_thread(self._read_item_count)
184
193
 
185
194
  @override
186
195
  async def count_by_fields(
@@ -192,7 +201,7 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
192
201
  filter_expr = _build_filter(self._mapper, criteria)
193
202
  if filter_expr is False:
194
203
  return 0
195
- items = self._scan_with_filter(filter_expr)
204
+ items = await asyncio.to_thread(self._scan_with_filter, filter_expr)
196
205
  return len(items)
197
206
 
198
207
  @override
@@ -210,7 +219,8 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
210
219
  filter_expr = _build_filter(self._mapper, criteria)
211
220
  if filter_expr is False:
212
221
  return []
213
- items = self._scan_with_filter(filter_expr)
222
+ max_items = None if sort_by is not None or limit is None else offset + limit
223
+ items = await asyncio.to_thread(self._scan_with_filter, filter_expr, max_items)
214
224
  entities = [self._mapper.from_item(i) for i in items]
215
225
  if sort_by is not None:
216
226
  if not self._mapper.has_attr(sort_by):
@@ -232,9 +242,9 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
232
242
  filter_expr = _build_filter(self._mapper, criteria)
233
243
  if filter_expr is False:
234
244
  return []
235
- items = self._scan_with_filter(filter_expr)
245
+ items = await asyncio.to_thread(self._scan_with_filter, filter_expr)
236
246
  else:
237
- items = self._scan_all()
247
+ items = await asyncio.to_thread(self._scan_all)
238
248
  seen: set = set()
239
249
  result: list[Any] = []
240
250
  for item in items:
@@ -244,6 +254,9 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
244
254
  result.append(val)
245
255
  return result
246
256
 
257
+ def _read_item_count(self) -> int:
258
+ return self._table.item_count
259
+
247
260
  def _scan_all(self) -> list[dict]:
248
261
  items: list[dict] = []
249
262
  response = self._table.scan()
@@ -253,7 +266,11 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
253
266
  items.extend(response.get("Items", []))
254
267
  return items
255
268
 
256
- def _scan_with_filter(self, filter_expr: ConditionBase | None) -> list[dict]:
269
+ def _scan_with_filter(
270
+ self,
271
+ filter_expr: ConditionBase | None,
272
+ max_items: Optional[int] = None,
273
+ ) -> list[dict]:
257
274
  items: list[dict] = []
258
275
  kwargs: dict[str, Any] = {}
259
276
  if filter_expr is not None:
@@ -261,6 +278,8 @@ class DynamoRepository(Repository[T, TId], Generic[T, TId]):
261
278
  response = self._table.scan(**kwargs)
262
279
  items.extend(response.get("Items", []))
263
280
  while "LastEvaluatedKey" in response:
281
+ if max_items is not None and len(items) >= max_items:
282
+ break
264
283
  kwargs["ExclusiveStartKey"] = response["LastEvaluatedKey"]
265
284
  response = self._table.scan(**kwargs)
266
285
  items.extend(response.get("Items", []))
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "persistence-kit"
3
- version = "3.8.0"
3
+ version = "3.9.1"
4
4
  description = "Reusable persistence and repository toolkit"
5
5
  authors = ["Andres Felipe Serrano Barrios <andresfserrano1@gmail.com>"]
6
6
  readme = "README.md"
@@ -27,14 +27,14 @@ documentation = "https://github.com/andresfserrano/persistence-kit#readme"
27
27
  python = ">=3.11,<4.0"
28
28
  motor = "^3.7.1"
29
29
  sqlalchemy = {extras = ["asyncio"], version = "^2.0.43"}
30
- asyncpg = "^0.30.0"
30
+ asyncpg = ">=0.30.0,<1.0.0"
31
31
  typing-extensions = "^4.12.0"
32
32
  pydantic-settings = "^2.3.0"
33
33
  fastapi = {version = ">=0.115.0,<1.0.0", optional = true}
34
34
  boto3 = {version = "^1.35.0", optional = true}
35
35
  pyjwt = {version = "^2.10.1", extras = ["crypto"], optional = true}
36
- python-multipart = {version = "^0.0.20", optional = true}
37
- httpx = {version = "^0.28.0", optional = true}
36
+ python-multipart = {version = ">=0.0.31,<1.0.0", optional = true}
37
+ httpx = {version = ">=0.28.0,<1.0.0", optional = true}
38
38
 
39
39
  [tool.poetry.extras]
40
40
  api = ["fastapi", "python-multipart"]
@@ -49,7 +49,7 @@ all = ["fastapi", "boto3", "pyjwt", "python-multipart", "httpx"]
49
49
 
50
50
  [tool.poetry.group.dev.dependencies]
51
51
  pytest = "^8.3.0"
52
- pytest-asyncio = "^0.23.0"
52
+ pytest-asyncio = ">=0.23.0,<2.0.0"
53
53
 
54
54
  [tool.pytest.ini_options]
55
55
  testpaths = ["tests"]
File without changes