persistence-kit 3.15.0__tar.gz → 3.16.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.
Files changed (119) hide show
  1. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/PKG-INFO +10 -1
  2. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/README.md +9 -0
  3. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/factory.py +3 -3
  4. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/s3.py +32 -16
  5. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/pyproject.toml +1 -1
  6. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/LICENSE +0 -0
  7. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/__init__.py +0 -0
  8. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/__init__.py +0 -0
  9. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/common.py +0 -0
  10. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/encrypted_middleware.py +0 -0
  11. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/encrypted_routes.py +0 -0
  12. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/error_handlers.py +0 -0
  13. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/exceptions.py +0 -0
  14. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/rate_limit.py +0 -0
  15. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/api/route_loader.py +0 -0
  16. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/authenticated_user.py +0 -0
  17. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/bootstrap/__init__.py +0 -0
  18. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/bootstrap/configuration.py +0 -0
  19. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/bootstrap/seeders.py +0 -0
  20. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/bootstrap/startup.py +0 -0
  21. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/__init__.py +0 -0
  22. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/contracts.py +0 -0
  23. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/dynamodb.py +0 -0
  24. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/factory.py +0 -0
  25. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/memory.py +0 -0
  26. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/mongo.py +0 -0
  27. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/cache/namespaced.py +0 -0
  28. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/contracts/__init__.py +0 -0
  29. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/contracts/repository.py +0 -0
  30. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/contracts/view_repository.py +0 -0
  31. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/__init__.py +0 -0
  32. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/contracts.py +0 -0
  33. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/errors.py +0 -0
  34. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/factory.py +0 -0
  35. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/mailer.py +0 -0
  36. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/memory.py +0 -0
  37. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/message.py +0 -0
  38. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/mime.py +0 -0
  39. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/preview.py +0 -0
  40. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/smtp.py +0 -0
  41. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/mail/templates.py +0 -0
  42. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/py.typed +0 -0
  43. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/__init__.py +0 -0
  44. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/dynamodb_repo/dynamodb_mapper.py +0 -0
  45. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/dynamodb_repo/dynamodb_repo.py +0 -0
  46. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/filter_ops.py +0 -0
  47. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/memory_repo/__init__.py +0 -0
  48. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/memory_repo/memory_repo.py +0 -0
  49. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/mongo_repo/__init__.py +0 -0
  50. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/mongo_repo/mongo_mapper.py +0 -0
  51. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/mongo_repo/mongo_repo.py +0 -0
  52. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/sqlalchemy_repo/__init__.py +0 -0
  53. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/sqlalchemy_repo/schema_evolve.py +0 -0
  54. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_dataclass_mapper.py +0 -0
  55. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_engine.py +0 -0
  56. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_repo.py +0 -0
  57. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository/sqlalchemy_repo/table_factory.py +0 -0
  58. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/__init__.py +0 -0
  59. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/factory/__init__.py +0 -0
  60. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/factory/repository_factory.py +0 -0
  61. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/registry/__init__.py +0 -0
  62. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/registry/entity_registry.py +0 -0
  63. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/view/__init__.py +0 -0
  64. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/repository_factory/view/populating_repository.py +0 -0
  65. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/resilience/__init__.py +0 -0
  66. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/resilience/circuit.py +0 -0
  67. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/__init__.py +0 -0
  68. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/aggregate.py +0 -0
  69. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/__init__.py +0 -0
  70. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/api_key.py +0 -0
  71. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/base.py +0 -0
  72. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/basic.py +0 -0
  73. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/bearer.py +0 -0
  74. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/login.py +0 -0
  75. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/auth/oauth2.py +0 -0
  76. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/caching.py +0 -0
  77. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/client.py +0 -0
  78. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/config.py +0 -0
  79. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/contracts.py +0 -0
  80. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/errors.py +0 -0
  81. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/factory.py +0 -0
  82. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/mapping.py +0 -0
  83. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/memory.py +0 -0
  84. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/payload.py +0 -0
  85. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/populate.py +0 -0
  86. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/provider.py +0 -0
  87. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/registry.py +0 -0
  88. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/resolver.py +0 -0
  89. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/retry.py +0 -0
  90. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/restclient/tracing.py +0 -0
  91. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/__init__.py +0 -0
  92. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/encrypted/__init__.py +0 -0
  93. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/encrypted/envelope.py +0 -0
  94. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/encrypted/errors.py +0 -0
  95. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/factory.py +0 -0
  96. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/ports.py +0 -0
  97. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/providers/__init__.py +0 -0
  98. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/providers/cognito_identity_provider.py +0 -0
  99. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/providers/encryption_provider.py +0 -0
  100. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/providers/memory_security_provider.py +0 -0
  101. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/registration.py +0 -0
  102. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/token_verifiers/__init__.py +0 -0
  103. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/token_verifiers/cognito_jwt_verifier.py +0 -0
  104. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/security/token_verifiers/memory_jwt_verifier.py +0 -0
  105. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/__init__.py +0 -0
  106. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/app_settings.py +0 -0
  107. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/cache_settings.py +0 -0
  108. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/constants.py +0 -0
  109. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/mail_settings.py +0 -0
  110. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/parsers.py +0 -0
  111. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/settings/repo_settings.py +0 -0
  112. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/__init__.py +0 -0
  113. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/contracts.py +0 -0
  114. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/errors.py +0 -0
  115. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/local.py +0 -0
  116. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/media.py +0 -0
  117. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/storage/routes.py +0 -0
  118. {persistence_kit-3.15.0 → persistence_kit-3.16.0}/persistence_kit/utils/__init__.py +0 -0
  119. {persistence_kit-3.15.0 → persistence_kit-3.16.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.15.0
3
+ Version: 3.16.0
4
4
  Summary: Reusable persistence and repository toolkit
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -209,6 +209,15 @@ url = await storage.generate_presigned_url(key)
209
209
  `LocalObjectStorage` writes to a directory and signs its own download URLs.
210
210
  `S3ObjectStorage` uploads to S3 and returns AWS presigned URLs. Pick one with
211
211
  `get_export_storage(settings)`, which reads your settings and caches the adapter.
212
+ Give `S3ObjectStorage` a `prefix` and every key it writes, presigns, deletes or
213
+ lists stays under that folder of the bucket, while the keys you pass and get back
214
+ stay relative to it.
215
+
216
+ For files your users upload, `build_media_storage(settings, namespace=...,
217
+ url_prefix=...)` checks type and size and keeps each namespace in its own
218
+ folder: `<LOCAL_MEDIA_STORAGE_DIR>/<namespace>` with `MEDIA_STORAGE_PROVIDER=local`,
219
+ and `<namespace>/` inside `AWS_S3_MEDIA_BUCKET` with `s3`. Keys are the same on
220
+ both, so moving to S3 does not change what your app stores.
212
221
 
213
222
  FastAPI apps can mount `build_local_export_storage_router(...)` to serve local
214
223
  files, passing their settings provider, an optional current-user dependency, and
@@ -158,6 +158,15 @@ url = await storage.generate_presigned_url(key)
158
158
  `LocalObjectStorage` writes to a directory and signs its own download URLs.
159
159
  `S3ObjectStorage` uploads to S3 and returns AWS presigned URLs. Pick one with
160
160
  `get_export_storage(settings)`, which reads your settings and caches the adapter.
161
+ Give `S3ObjectStorage` a `prefix` and every key it writes, presigns, deletes or
162
+ lists stays under that folder of the bucket, while the keys you pass and get back
163
+ stay relative to it.
164
+
165
+ For files your users upload, `build_media_storage(settings, namespace=...,
166
+ url_prefix=...)` checks type and size and keeps each namespace in its own
167
+ folder: `<LOCAL_MEDIA_STORAGE_DIR>/<namespace>` with `MEDIA_STORAGE_PROVIDER=local`,
168
+ and `<namespace>/` inside `AWS_S3_MEDIA_BUCKET` with `s3`. Keys are the same on
169
+ both, so moving to S3 does not change what your app stores.
161
170
 
162
171
  FastAPI apps can mount `build_local_export_storage_router(...)` to serve local
163
172
  files, passing their settings provider, an optional current-user dependency, and
@@ -87,10 +87,10 @@ def _local_media_object_storage_cached(base_dir: str) -> ObjectStorage:
87
87
 
88
88
 
89
89
  @lru_cache
90
- def _s3_media_object_storage_cached(bucket: str, region: str) -> ObjectStorage:
90
+ def _s3_media_object_storage_cached(bucket: str, region: str, prefix: str) -> ObjectStorage:
91
91
  from persistence_kit.storage.s3 import S3ObjectStorage
92
92
 
93
- return S3ObjectStorage(bucket=bucket, region=region)
93
+ return S3ObjectStorage(bucket=bucket, region=region, prefix=prefix)
94
94
 
95
95
 
96
96
  def _build_media_object_storage(
@@ -110,7 +110,7 @@ def _build_media_object_storage(
110
110
  "Falta configuracion AWS_S3_MEDIA_BUCKET para el storage de media."
111
111
  )
112
112
  return _s3_media_object_storage_cached(
113
- settings.aws_s3_media_bucket, settings.aws_region
113
+ settings.aws_s3_media_bucket, settings.aws_region, namespace
114
114
  )
115
115
  provider = getattr(
116
116
  settings.media_storage_provider, "value", settings.media_storage_provider
@@ -22,35 +22,42 @@ logger = logging.getLogger(__name__)
22
22
 
23
23
 
24
24
  class S3ObjectStorage:
25
- def __init__(self, *, bucket: str, region: str) -> None:
25
+ def __init__(self, *, bucket: str, region: str, prefix: str = "") -> None:
26
26
  if boto3 is None:
27
27
  raise StorageConfigError("Falta dependencia boto3 para integrar con S3.")
28
28
  self._bucket = bucket
29
29
  self._region = region
30
+ normalized_prefix = prefix.strip("/")
31
+ self._prefix = f"{normalized_prefix}/" if normalized_prefix else ""
30
32
  self._client = boto3.client("s3", region_name=region)
31
33
 
34
+ def _object_key(self, key: str) -> str:
35
+ return f"{self._prefix}{key}"
36
+
32
37
  async def upload(
33
38
  self,
34
39
  key: str,
35
40
  data: bytes,
36
41
  content_type: str = "application/octet-stream",
37
42
  ) -> str:
43
+ object_key = self._object_key(key)
44
+
38
45
  def _upload() -> None:
39
46
  self._client.put_object(
40
47
  Bucket=self._bucket,
41
- Key=key,
48
+ Key=object_key,
42
49
  Body=data,
43
50
  ContentType=content_type,
44
51
  )
45
52
 
46
- logger.info("S3 upload iniciado bucket=%s key=%s", self._bucket, key)
53
+ logger.info("S3 upload iniciado bucket=%s key=%s", self._bucket, object_key)
47
54
  try:
48
55
  await asyncio.to_thread(_upload)
49
56
  except ClientError as exc:
50
- logger.exception("S3 upload fallido bucket=%s key=%s", self._bucket, key)
57
+ logger.exception("S3 upload fallido bucket=%s key=%s", self._bucket, object_key)
51
58
  raise StorageUploadError(f"No fue posible subir el archivo a S3: {exc}") from exc
52
59
 
53
- logger.info("S3 upload exitoso bucket=%s key=%s", self._bucket, key)
60
+ logger.info("S3 upload exitoso bucket=%s key=%s", self._bucket, object_key)
54
61
  return key
55
62
 
56
63
  async def upload_file(
@@ -59,66 +66,75 @@ class S3ObjectStorage:
59
66
  file_path: Path,
60
67
  content_type: str = "application/octet-stream",
61
68
  ) -> str:
69
+ object_key = self._object_key(key)
70
+
62
71
  def _upload_file() -> None:
63
72
  with file_path.open("rb") as file_obj:
64
73
  self._client.upload_fileobj(
65
74
  Fileobj=file_obj,
66
75
  Bucket=self._bucket,
67
- Key=key,
76
+ Key=object_key,
68
77
  ExtraArgs={"ContentType": content_type},
69
78
  )
70
79
 
71
- logger.info("S3 file upload iniciado bucket=%s key=%s path=%s", self._bucket, key, file_path)
80
+ logger.info(
81
+ "S3 file upload iniciado bucket=%s key=%s path=%s", self._bucket, object_key, file_path
82
+ )
72
83
  try:
73
84
  await asyncio.to_thread(_upload_file)
74
85
  except ClientError as exc:
75
- logger.exception("S3 file upload fallido bucket=%s key=%s", self._bucket, key)
86
+ logger.exception("S3 file upload fallido bucket=%s key=%s", self._bucket, object_key)
76
87
  raise StorageUploadError(f"No fue posible subir el archivo a S3: {exc}") from exc
77
88
 
78
- logger.info("S3 file upload exitoso bucket=%s key=%s", self._bucket, key)
89
+ logger.info("S3 file upload exitoso bucket=%s key=%s", self._bucket, object_key)
79
90
  return key
80
91
 
81
92
  async def generate_presigned_url(self, key: str, expires_in: int = 3600) -> str:
93
+ object_key = self._object_key(key)
94
+
82
95
  def _presign() -> str:
83
96
  return self._client.generate_presigned_url(
84
97
  "get_object",
85
- Params={"Bucket": self._bucket, "Key": key},
98
+ Params={"Bucket": self._bucket, "Key": object_key},
86
99
  ExpiresIn=expires_in,
87
100
  )
88
101
 
89
102
  try:
90
103
  return await asyncio.to_thread(_presign)
91
104
  except ClientError as exc:
92
- logger.exception("S3 presign fallido bucket=%s key=%s", self._bucket, key)
105
+ logger.exception("S3 presign fallido bucket=%s key=%s", self._bucket, object_key)
93
106
  raise StoragePresignError(f"No fue posible generar la URL prefirmada: {exc}") from exc
94
107
 
95
108
  async def delete(self, key: str) -> None:
109
+ object_key = self._object_key(key)
110
+
96
111
  def _delete() -> None:
97
- self._client.delete_object(Bucket=self._bucket, Key=key)
112
+ self._client.delete_object(Bucket=self._bucket, Key=object_key)
98
113
 
99
114
  try:
100
115
  await asyncio.to_thread(_delete)
101
116
  except ClientError as exc:
102
- logger.exception("S3 delete fallido bucket=%s key=%s", self._bucket, key)
117
+ logger.exception("S3 delete fallido bucket=%s key=%s", self._bucket, object_key)
103
118
  raise StorageError(f"No fue posible borrar el objeto en S3: {exc}") from exc
104
119
 
105
120
  async def list_keys(self, prefix: str = "") -> list[str]:
106
121
  normalized_prefix = prefix.lstrip("/")
107
122
  if normalized_prefix and not normalized_prefix.endswith("/"):
108
123
  normalized_prefix = normalized_prefix + "/"
124
+ search_prefix = self._object_key(normalized_prefix)
109
125
 
110
126
  def _list() -> list[str]:
111
127
  keys: list[str] = []
112
128
  paginator = self._client.get_paginator("list_objects_v2")
113
- for page in paginator.paginate(Bucket=self._bucket, Prefix=normalized_prefix):
129
+ for page in paginator.paginate(Bucket=self._bucket, Prefix=search_prefix):
114
130
  for obj in page.get("Contents", []) or []:
115
- keys.append(obj["Key"])
131
+ keys.append(obj["Key"].removeprefix(self._prefix))
116
132
  return keys
117
133
 
118
134
  try:
119
135
  return await asyncio.to_thread(_list)
120
136
  except ClientError as exc:
121
- logger.exception("S3 list fallido bucket=%s prefix=%s", self._bucket, normalized_prefix)
137
+ logger.exception("S3 list fallido bucket=%s prefix=%s", self._bucket, search_prefix)
122
138
  raise StorageError(f"No fue posible listar objetos en S3: {exc}") from exc
123
139
 
124
140
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "persistence-kit"
3
- version = "3.15.0"
3
+ version = "3.16.0"
4
4
  description = "Reusable persistence and repository toolkit"
5
5
  authors = ["Andres Felipe Serrano Barrios <andresfserrano1@gmail.com>"]
6
6
  readme = "README.md"