aws-python-helper 1.10.0__tar.gz → 1.12.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.
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/PKG-INFO +1 -1
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/api_client.py +60 -20
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/repository/audit.py +20 -11
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/repository/base.py +24 -2
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/PKG-INFO +1 -1
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/pyproject.toml +1 -1
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/tests/test_audit_stamp.py +28 -1
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/README.md +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/auth_middleware.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/auth_validators.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/base.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/dispatcher.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/exceptions.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/fetcher.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/handler.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/context/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/context/session.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/context/state_validator.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/database_proxy.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/external_database_proxy.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/external_mongo_manager.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/mongo_manager.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/fargate/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/fargate/executor.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/fargate/fetcher.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/fargate/handler.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/fargate/task_base.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/exceptions.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/lambda_invoker.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/base.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/fetcher.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/handler.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_index_sync/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_index_sync/base.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_query/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_query/base.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/monitoring/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/monitoring/run.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/permissions/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/permissions/catalog.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/repository/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sns/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sns/publisher.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sqs/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sqs/consumer_base.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sqs/fetcher.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sqs/handler.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/utils/__init__.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/utils/json_encoder.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/utils/response.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/utils/serializer.py +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/SOURCES.txt +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/dependency_links.txt +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/requires.txt +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/top_level.txt +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/setup.cfg +0 -0
- {aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/tests/test_sns_publisher.py +0 -0
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/api_client.py
RENAMED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import logging
|
|
3
2
|
import os
|
|
4
3
|
from typing import Any, Dict, Optional
|
|
@@ -13,26 +12,58 @@ _AUTH_HEADER = "Authorization"
|
|
|
13
12
|
_BEARER_PREFIX = "Bearer"
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
CORE = "core"
|
|
16
|
+
|
|
17
|
+
# Lo que este contenedor ya averiguó. Vive lo que vive la lambda, que es lo que
|
|
18
|
+
# se quiere: un servicio redesplegado con otra URL se conoce en el próximo
|
|
19
|
+
# arranque en frío, no dentro de horas.
|
|
20
|
+
_RESOLVED: Dict[str, str] = {}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _core_url() -> str:
|
|
24
|
+
"""Dónde está core. Es lo único que un servicio necesita saber de memoria.
|
|
25
|
+
|
|
26
|
+
Todo lo demás se lo pregunta a core, que lleva el registro de quién existe y
|
|
27
|
+
dónde responde. Una sola variable por servicio en vez de un mapa que había
|
|
28
|
+
que escribir en el secret de cada uno y mantener sincronizado a mano.
|
|
29
|
+
"""
|
|
30
|
+
url = (os.getenv("CORE_API_URL") or "").rstrip("/")
|
|
31
|
+
if not url:
|
|
19
32
|
raise ServiceNotConfiguredError(
|
|
20
|
-
"
|
|
33
|
+
"CORE_API_URL is not set: this service cannot reach core, and core is "
|
|
34
|
+
"where it learns about everything else."
|
|
21
35
|
)
|
|
22
|
-
|
|
23
|
-
urls = json.loads(raw)
|
|
24
|
-
except json.JSONDecodeError as exc:
|
|
25
|
-
raise ServiceNotConfiguredError(
|
|
26
|
-
"MICROSERVICE_URLS is not valid JSON"
|
|
27
|
-
) from exc
|
|
36
|
+
return url
|
|
28
37
|
|
|
29
|
-
|
|
38
|
+
|
|
39
|
+
async def resolve_service_url(service_name: str) -> str:
|
|
40
|
+
"""La dirección de un servicio, según el registro de core."""
|
|
41
|
+
if service_name == CORE:
|
|
42
|
+
return _core_url()
|
|
43
|
+
|
|
44
|
+
if service_name in _RESOLVED:
|
|
45
|
+
return _RESOLVED[service_name]
|
|
46
|
+
|
|
47
|
+
token = _resolve_token()
|
|
48
|
+
headers = {_AUTH_HEADER: f"{_BEARER_PREFIX} {token}"} if token else {}
|
|
49
|
+
|
|
50
|
+
async with httpx.AsyncClient(timeout=10) as client:
|
|
51
|
+
response = await client.get(f"{_core_url()}/services", headers=headers)
|
|
52
|
+
response.raise_for_status()
|
|
53
|
+
services = (response.json() or {}).get("services") or []
|
|
54
|
+
|
|
55
|
+
for service in services:
|
|
56
|
+
if service.get("api_url"):
|
|
57
|
+
_RESOLVED[service["code"]] = service["api_url"].rstrip("/")
|
|
58
|
+
|
|
59
|
+
url = _RESOLVED.get(service_name)
|
|
30
60
|
if not url:
|
|
31
|
-
|
|
61
|
+
known = ", ".join(sorted(_RESOLVED)) or "none"
|
|
32
62
|
raise ServiceNotConfiguredError(
|
|
33
|
-
f"
|
|
63
|
+
f"Core does not know a service called '{service_name}'. Registered: {known}. "
|
|
64
|
+
"A service appears here when it deploys."
|
|
34
65
|
)
|
|
35
|
-
return url
|
|
66
|
+
return url
|
|
36
67
|
|
|
37
68
|
|
|
38
69
|
def _resolve_token() -> Optional[str]:
|
|
@@ -61,8 +92,8 @@ class ApiClient:
|
|
|
61
92
|
client = ApiClient("dockets", headers={"constitution-state": "CT"})
|
|
62
93
|
|
|
63
94
|
Environment variables:
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
CORE_API_URL Where core answers. The only address a service
|
|
96
|
+
holds; everything else it asks core for.
|
|
66
97
|
INTER_SERVICE_TOKEN Bearer token for service-to-service calls
|
|
67
98
|
AUTH_BYPASS_TOKEN Fallback if INTER_SERVICE_TOKEN is not set
|
|
68
99
|
"""
|
|
@@ -73,7 +104,8 @@ class ApiClient:
|
|
|
73
104
|
headers: Optional[Dict[str, str]] = None,
|
|
74
105
|
timeout: int = 30,
|
|
75
106
|
):
|
|
76
|
-
self.
|
|
107
|
+
self._service_name = service_name
|
|
108
|
+
self._base_url: Optional[str] = None
|
|
77
109
|
self._timeout = timeout
|
|
78
110
|
self._headers = self._build_default_headers(headers or {})
|
|
79
111
|
self.logger = logging.getLogger(self.__class__.__name__)
|
|
@@ -86,7 +118,15 @@ class ApiClient:
|
|
|
86
118
|
headers.update(extra)
|
|
87
119
|
return headers
|
|
88
120
|
|
|
89
|
-
def _url(self, path: str) -> str:
|
|
121
|
+
async def _url(self, path: str) -> str:
|
|
122
|
+
"""La URL completa, resolviendo el servicio la primera vez que hace falta.
|
|
123
|
+
|
|
124
|
+
Se resuelve al usarse y no al construirse porque preguntarle a core es
|
|
125
|
+
una llamada de red, y un constructor que hace una llamada de red no se
|
|
126
|
+
puede usar en ningún lado sin pensarlo.
|
|
127
|
+
"""
|
|
128
|
+
if self._base_url is None:
|
|
129
|
+
self._base_url = await resolve_service_url(self._service_name)
|
|
90
130
|
return f"{self._base_url}/{path.lstrip('/')}"
|
|
91
131
|
|
|
92
132
|
async def get(self, path: str, params: Optional[Dict] = None) -> Any:
|
|
@@ -120,7 +160,7 @@ class ApiClient:
|
|
|
120
160
|
params: Optional[Dict] = None,
|
|
121
161
|
body: Optional[Dict] = None,
|
|
122
162
|
) -> Any:
|
|
123
|
-
url = self._url(path)
|
|
163
|
+
url = await self._url(path)
|
|
124
164
|
try:
|
|
125
165
|
async with httpx.AsyncClient(timeout=self._timeout) as client:
|
|
126
166
|
response = await client.request(
|
|
@@ -82,10 +82,13 @@ class InvalidStatusError(ValueError):
|
|
|
82
82
|
"""A status the repository does not declare."""
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def _check_status(
|
|
85
|
+
def _check_status(
|
|
86
|
+
value: Any, statuses: Optional[List[str]], field: str = STATUS
|
|
87
|
+
) -> None:
|
|
86
88
|
if statuses and value is not None and value not in statuses:
|
|
87
89
|
raise InvalidStatusError(
|
|
88
|
-
f"'{value}' is not a valid
|
|
90
|
+
f"'{value}' is not a valid value for '{field}'. "
|
|
91
|
+
f"Declared: {', '.join(statuses)}"
|
|
89
92
|
)
|
|
90
93
|
|
|
91
94
|
|
|
@@ -93,6 +96,7 @@ def stamp_new(
|
|
|
93
96
|
document: Dict[str, Any],
|
|
94
97
|
statuses: Optional[List[str]] = None,
|
|
95
98
|
default_status: Optional[str] = None,
|
|
99
|
+
status_field: str = STATUS,
|
|
96
100
|
) -> Dict[str, Any]:
|
|
97
101
|
"""The framework fields on a document being created.
|
|
98
102
|
|
|
@@ -110,8 +114,8 @@ def stamp_new(
|
|
|
110
114
|
document.setdefault(UPDATED_BY, who)
|
|
111
115
|
|
|
112
116
|
if statuses:
|
|
113
|
-
document.setdefault(
|
|
114
|
-
_check_status(document.get(
|
|
117
|
+
document.setdefault(status_field, default_status or statuses[0])
|
|
118
|
+
_check_status(document.get(status_field), statuses, status_field)
|
|
115
119
|
return document
|
|
116
120
|
|
|
117
121
|
|
|
@@ -146,6 +150,7 @@ def stamp_update(
|
|
|
146
150
|
upsert: bool = False,
|
|
147
151
|
statuses: Optional[List[str]] = None,
|
|
148
152
|
default_status: Optional[str] = None,
|
|
153
|
+
status_field: str = STATUS,
|
|
149
154
|
) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
|
|
150
155
|
"""The two 'updated' fields on a modification, and the 'created' ones on an upsert.
|
|
151
156
|
|
|
@@ -165,14 +170,14 @@ def stamp_update(
|
|
|
165
170
|
|
|
166
171
|
# Un reemplazo entero —sin operadores— es un documento, no una modificación.
|
|
167
172
|
if update and not any(key.startswith('$') for key in update):
|
|
168
|
-
return stamp_new(dict(update), statuses, default_status)
|
|
173
|
+
return stamp_new(dict(update), statuses, default_status, status_field)
|
|
169
174
|
|
|
170
175
|
update = dict(update)
|
|
171
176
|
if statuses:
|
|
172
177
|
for operator in ('$set', '$setOnInsert'):
|
|
173
178
|
section = update.get(operator)
|
|
174
|
-
if isinstance(section, dict) and
|
|
175
|
-
_check_status(section[
|
|
179
|
+
if isinstance(section, dict) and status_field in section:
|
|
180
|
+
_check_status(section[status_field], statuses, status_field)
|
|
176
181
|
|
|
177
182
|
_merge_into_set(update, touched, '$set')
|
|
178
183
|
if upsert:
|
|
@@ -180,7 +185,7 @@ def stamp_update(
|
|
|
180
185
|
# inicial sólo en ese caso.
|
|
181
186
|
born = {CREATED_AT: now, CREATED_BY: who}
|
|
182
187
|
if statuses:
|
|
183
|
-
born[
|
|
188
|
+
born[status_field] = default_status or statuses[0]
|
|
184
189
|
born = {
|
|
185
190
|
key: value
|
|
186
191
|
for key, value in born.items()
|
|
@@ -201,23 +206,27 @@ class AuditedCollection:
|
|
|
201
206
|
than asking for the stamp explicitly.
|
|
202
207
|
"""
|
|
203
208
|
|
|
204
|
-
__slots__ = ('_collection', '_statuses', '_default_status')
|
|
209
|
+
__slots__ = ('_collection', '_statuses', '_default_status', '_status_field')
|
|
205
210
|
|
|
206
211
|
def __init__(
|
|
207
212
|
self,
|
|
208
213
|
collection: Any,
|
|
209
214
|
statuses: Optional[List[str]] = None,
|
|
210
215
|
default_status: Optional[str] = None,
|
|
216
|
+
status_field: str = STATUS,
|
|
211
217
|
):
|
|
212
218
|
object.__setattr__(self, '_collection', collection)
|
|
213
219
|
object.__setattr__(self, '_statuses', statuses)
|
|
214
220
|
object.__setattr__(self, '_default_status', default_status)
|
|
221
|
+
object.__setattr__(self, '_status_field', status_field)
|
|
215
222
|
|
|
216
223
|
def _new(self, document: Dict[str, Any]) -> Dict[str, Any]:
|
|
217
|
-
return stamp_new(document, self._statuses, self._default_status)
|
|
224
|
+
return stamp_new(document, self._statuses, self._default_status, self._status_field)
|
|
218
225
|
|
|
219
226
|
def _update(self, update: Any, upsert: bool) -> Any:
|
|
220
|
-
return stamp_update(
|
|
227
|
+
return stamp_update(
|
|
228
|
+
update, upsert, self._statuses, self._default_status, self._status_field
|
|
229
|
+
)
|
|
221
230
|
|
|
222
231
|
def __getattr__(self, name: str) -> Any:
|
|
223
232
|
return getattr(self._collection, name)
|
|
@@ -13,7 +13,7 @@ from typing import Any, Dict, List, Optional, Tuple
|
|
|
13
13
|
from ..database.mongo_manager import MongoManager
|
|
14
14
|
from ..database.external_mongo_manager import ExternalMongoManager
|
|
15
15
|
from ..context.session import get_session
|
|
16
|
-
from .audit import DEFAULT_STATUSES, AuditedCollection
|
|
16
|
+
from .audit import DEFAULT_STATUSES, STATUS, AuditedCollection
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class Repository(ABC):
|
|
@@ -169,6 +169,26 @@ class Repository(ABC):
|
|
|
169
169
|
"""
|
|
170
170
|
return list(DEFAULT_STATUSES)
|
|
171
171
|
|
|
172
|
+
@property
|
|
173
|
+
def status_field(self) -> str:
|
|
174
|
+
"""Cómo se llama el campo que lleva el ciclo de vida del registro.
|
|
175
|
+
|
|
176
|
+
`status` por defecto. Se cambia cuando una colección ya usa ese nombre
|
|
177
|
+
para otra cosa y migrarla no vale la pena: los 1,2 millones de empresas
|
|
178
|
+
traen el estado del registro del estado en `status`, y 5,7 millones de
|
|
179
|
+
parcels podrían traer otro. Renombrar en la base es lo más limpio cuando
|
|
180
|
+
se puede; cuando no, se le dice al framework dónde escribir el suyo.
|
|
181
|
+
|
|
182
|
+
class ParcelRepository(Repository):
|
|
183
|
+
@property
|
|
184
|
+
def status_field(self):
|
|
185
|
+
return "lifecycle_status"
|
|
186
|
+
|
|
187
|
+
Las dos cosas son independientes: `statuses` dice qué valores valen, esto
|
|
188
|
+
dice dónde se guardan.
|
|
189
|
+
"""
|
|
190
|
+
return STATUS
|
|
191
|
+
|
|
172
192
|
@property
|
|
173
193
|
def default_status(self) -> Optional[str]:
|
|
174
194
|
"""What a record gets when nobody says otherwise. First of `statuses`."""
|
|
@@ -256,7 +276,9 @@ class Repository(ABC):
|
|
|
256
276
|
collection = db[self.collection_name]
|
|
257
277
|
# La envoltura completa las escrituras; todo lo demás pasa de largo.
|
|
258
278
|
self._collection_cache[key] = (
|
|
259
|
-
AuditedCollection(
|
|
279
|
+
AuditedCollection(
|
|
280
|
+
collection, self.statuses, self.default_status, self.status_field
|
|
281
|
+
)
|
|
260
282
|
if self.audit
|
|
261
283
|
else collection
|
|
262
284
|
)
|
|
@@ -15,7 +15,7 @@ import sys
|
|
|
15
15
|
|
|
16
16
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
17
17
|
|
|
18
|
-
from aws_python_helper.repository.audit import stamp_update # noqa: E402
|
|
18
|
+
from aws_python_helper.repository.audit import stamp_new, stamp_update # noqa: E402
|
|
19
19
|
|
|
20
20
|
STATUSES = ["active", "inactive"]
|
|
21
21
|
|
|
@@ -82,6 +82,33 @@ result = stamp_update([{"$set": {"name": "ct"}}], upsert=True, statuses=STATUSES
|
|
|
82
82
|
check("still a list", isinstance(result, list))
|
|
83
83
|
check("stamp appended last", result[-1]["$set"].get("updated_at") is not None)
|
|
84
84
|
|
|
85
|
+
print("\nthe lifecycle field can be called something else")
|
|
86
|
+
result = stamp_new(
|
|
87
|
+
{"name": "x", "status": "FORFEITED"},
|
|
88
|
+
["active", "inactive"],
|
|
89
|
+
"active",
|
|
90
|
+
status_field="lifecycle_status",
|
|
91
|
+
)
|
|
92
|
+
check("the collection's own status is untouched", result["status"] == "FORFEITED")
|
|
93
|
+
check("the framework writes its own field", result["lifecycle_status"] == "active")
|
|
94
|
+
|
|
95
|
+
result = stamp_update(
|
|
96
|
+
{"$set": {"name": "x"}},
|
|
97
|
+
upsert=True,
|
|
98
|
+
statuses=["active"],
|
|
99
|
+
default_status="active",
|
|
100
|
+
status_field="lifecycle_status",
|
|
101
|
+
)
|
|
102
|
+
check("and on an upsert it stamps that one", result["$setOnInsert"]["lifecycle_status"] == "active")
|
|
103
|
+
check("with no path conflict", not conflicts(result))
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
stamp_new({"lifecycle_status": "made up"}, ["active"], status_field="lifecycle_status")
|
|
107
|
+
check("a value outside the vocabulary is refused", False)
|
|
108
|
+
except ValueError as error:
|
|
109
|
+
check("a value outside the vocabulary is refused", "lifecycle_status" in str(error),
|
|
110
|
+
"and the message names the field")
|
|
111
|
+
|
|
85
112
|
if failures:
|
|
86
113
|
print(f"\n{len(failures)} failed: {failures}")
|
|
87
114
|
raise SystemExit(1)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/auth_middleware.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/api/auth_validators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/context/state_validator.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/__init__.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/database_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/database/mongo_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/fargate/task_base.py
RENAMED
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/exceptions.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/invoker/lambda_invoker.py
RENAMED
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/base.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/fetcher.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/lambda_standalone/handler.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_index_sync/__init__.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_index_sync/base.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/model_query/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/monitoring/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/permissions/__init__.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/permissions/catalog.py
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/repository/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/sqs/consumer_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper/utils/json_encoder.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/requires.txt
RENAMED
|
File without changes
|
{aws_python_helper-1.10.0 → aws_python_helper-1.12.0}/aws_python_helper.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|