eco-back 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl
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.
- eco_back/__init__.py +3 -2
- eco_back/registro/trazabilidad.py +2 -2
- eco_back/utils/__init__.py +13 -0
- eco_back/utils/exceptions.py +46 -0
- eco_back/utils/logger_generico.py +107 -0
- {eco_back-0.2.1.dist-info → eco_back-0.2.2.dist-info}/METADATA +61 -7
- {eco_back-0.2.1.dist-info → eco_back-0.2.2.dist-info}/RECORD +10 -7
- {eco_back-0.2.1.dist-info → eco_back-0.2.2.dist-info}/WHEEL +0 -0
- {eco_back-0.2.1.dist-info → eco_back-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {eco_back-0.2.1.dist-info → eco_back-0.2.2.dist-info}/top_level.txt +0 -0
eco_back/__init__.py
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
eco-back - Librería Python
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.2.
|
|
5
|
+
__version__ = "0.2.2"
|
|
6
6
|
|
|
7
7
|
# Módulos principales
|
|
8
8
|
from . import database
|
|
9
9
|
from . import api
|
|
10
10
|
from . import documento
|
|
11
11
|
from . import registro
|
|
12
|
+
from . import utils
|
|
12
13
|
|
|
13
|
-
__all__ = ["database", "api", "documento", "registro", "__version__"]
|
|
14
|
+
__all__ = ["database", "api", "documento", "registro", "utils", "__version__"]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from eco_back.utils.exceptions import ServiceValidationError, handle_service_validation_error
|
|
2
|
+
from eco_back.utils.logger_generico import _log_warn
|
|
1
3
|
from rest_framework.decorators import api_view, renderer_classes
|
|
2
4
|
from django.views.decorators.csrf import csrf_exempt
|
|
3
5
|
from rest_framework.renderers import JSONRenderer
|
|
@@ -6,8 +8,6 @@ from registro.models.models_global import Trazabilidad
|
|
|
6
8
|
from registro.serializer.serializer_get import TrazabilidadSerializer
|
|
7
9
|
from rest_framework.response import Response
|
|
8
10
|
|
|
9
|
-
from utils.guardado_datos.exceptions import ServiceValidationError, ServiceValidationError, handle_service_validation_error
|
|
10
|
-
from utils.logger_generico import _log_warn
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@csrf_exempt
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Módulo de utilidades para eco-back
|
|
3
|
+
Incluye manejo de excepciones y logging
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .exceptions import ServiceValidationError, handle_service_validation_error
|
|
7
|
+
from .logger_generico import _log_warn
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"ServiceValidationError",
|
|
11
|
+
"handle_service_validation_error",
|
|
12
|
+
"_log_warn"
|
|
13
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Raise custom exception for service validation errors
|
|
2
|
+
# - Envía un mensaje y un código HTTP asociado
|
|
3
|
+
import datetime
|
|
4
|
+
from functools import wraps
|
|
5
|
+
from django.http import JsonResponse
|
|
6
|
+
|
|
7
|
+
from eco_back.utils.logger_generico import _log_warn
|
|
8
|
+
|
|
9
|
+
class ServiceValidationError(Exception):
|
|
10
|
+
def __init__(self, message: str, code: int = 400, errors=None, extra=None, context=None, user_id=None, request_path=None):
|
|
11
|
+
super().__init__(message)
|
|
12
|
+
self.message = message
|
|
13
|
+
self.code = code
|
|
14
|
+
self.errors = errors
|
|
15
|
+
self.extra = extra
|
|
16
|
+
self.context = context
|
|
17
|
+
self.user_id = user_id
|
|
18
|
+
self.request_path = request_path
|
|
19
|
+
self.timestamp = datetime.datetime.now().isoformat()
|
|
20
|
+
|
|
21
|
+
def handle_service_validation_error(view_func):
|
|
22
|
+
@wraps(view_func)
|
|
23
|
+
def _wrapped_view(request, *args, **kwargs):
|
|
24
|
+
try:
|
|
25
|
+
return view_func(request, *args, **kwargs)
|
|
26
|
+
except ServiceValidationError as e:
|
|
27
|
+
_log_warn(f"Error: {e.message}", level="warning", extra={"errors": e.errors, "extra": e.extra, "context": e.context}, exc_info=True)
|
|
28
|
+
resp = {"status": "error", "message": e.message}
|
|
29
|
+
if e.errors:
|
|
30
|
+
resp["errors"] = e.errors
|
|
31
|
+
if e.extra:
|
|
32
|
+
resp["extra"] = e.extra
|
|
33
|
+
if e.context:
|
|
34
|
+
resp["context"] = e.context
|
|
35
|
+
if e.user_id:
|
|
36
|
+
resp["user_id"] = e.user_id
|
|
37
|
+
if e.request_path:
|
|
38
|
+
resp["request_path"] = e.request_path
|
|
39
|
+
|
|
40
|
+
resp["timestamp"] = e.timestamp
|
|
41
|
+
return JsonResponse(resp, status=e.code)
|
|
42
|
+
except Exception as e:
|
|
43
|
+
_log_warn(f"Error inesperado en decorator: {e}", level="error", exc_info=True, extra={"view": view_func.__name__})
|
|
44
|
+
print(f"handle_service_validation_error atrapó excepción: {e}")
|
|
45
|
+
return JsonResponse({"status": "error", "message": "Error interno"}, status=500)
|
|
46
|
+
return _wrapped_view
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import inspect
|
|
3
|
+
logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
# Mensajes
|
|
6
|
+
def _log_warn(msg, level='info', exc_info=False, extra=None):
|
|
7
|
+
"""
|
|
8
|
+
Registrar mensajes usando el logger configurado.
|
|
9
|
+
|
|
10
|
+
Parámetros:
|
|
11
|
+
msg: mensaje (se convierte a str).
|
|
12
|
+
level: nivel de log ('debug','info','warning','error','critical' o int). Default 'info'.
|
|
13
|
+
exc_info: bool o excepción para incluir traceback. Default False.
|
|
14
|
+
extra: dict opcional para pasar como extra al logger.
|
|
15
|
+
|
|
16
|
+
Llamadas anteriores _log_warn(msg) siguen funcionando y producirán un INFO por defecto.
|
|
17
|
+
"""
|
|
18
|
+
# compatibilidad: si se llama con un solo argumento, funciona como antes (INFO)
|
|
19
|
+
try:
|
|
20
|
+
# obtener frame llamante de forma ligera
|
|
21
|
+
frm = inspect.currentframe()
|
|
22
|
+
caller = frm.f_back if frm is not None else None
|
|
23
|
+
mod = inspect.getmodule(caller) if caller is not None else None
|
|
24
|
+
logger_name = mod.__name__ if mod and hasattr(mod, '__name__') else __name__
|
|
25
|
+
logger = logging.getLogger(logger_name)
|
|
26
|
+
|
|
27
|
+
extra = extra or {}
|
|
28
|
+
lvl = level.lower() if isinstance(level, str) else None
|
|
29
|
+
|
|
30
|
+
if isinstance(level, str):
|
|
31
|
+
lvl = level.lower()
|
|
32
|
+
if lvl == 'debug':
|
|
33
|
+
logger.debug("%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
34
|
+
elif lvl == 'info':
|
|
35
|
+
logger.info("%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
36
|
+
elif lvl in ('warn', 'warning'):
|
|
37
|
+
logger.warning("%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
38
|
+
elif lvl == 'error':
|
|
39
|
+
logger.error("%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
40
|
+
elif lvl == 'critical':
|
|
41
|
+
logger.critical("%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
42
|
+
else:
|
|
43
|
+
logger.info("%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
44
|
+
else:
|
|
45
|
+
# nivel numérico
|
|
46
|
+
logger.log(int(level), "%s", str(msg), exc_info=exc_info, **({'extra': extra} if extra else {}))
|
|
47
|
+
except Exception:
|
|
48
|
+
try:
|
|
49
|
+
logging.getLogger(__name__).error("Error al loggear mensaje: %s", str(msg), exc_info=True)
|
|
50
|
+
except Exception:
|
|
51
|
+
# fallback: siempre imprimir por stdout/stderr para depuración inmediata
|
|
52
|
+
try:
|
|
53
|
+
import sys, traceback
|
|
54
|
+
print("[LOGGER-ERROR] Error al loggear mensaje:", str(msg), file=sys.stderr)
|
|
55
|
+
traceback.print_exc()
|
|
56
|
+
except Exception:
|
|
57
|
+
pass
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
# Usos de _log_warn
|
|
61
|
+
'''
|
|
62
|
+
# Mensaje simple (por compatibilidad -> level='info')
|
|
63
|
+
_log_warn("Inicio del proceso")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Nivel explícito
|
|
67
|
+
_log_warn("Campo faltante en payload", level="warning")
|
|
68
|
+
_log_warn("Operación completada", level="debug")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Con exception traceback dentro de un except
|
|
72
|
+
try:
|
|
73
|
+
# hacer_algo()
|
|
74
|
+
print(1) # ejemplo que lanza excepción
|
|
75
|
+
except Exception as e:
|
|
76
|
+
_log_warn(f"Error al ejecutar hacer_algo: {e}", level="error", exc_info=True)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Loggear estructuras (dict/list) de forma legible
|
|
80
|
+
import json
|
|
81
|
+
data = {"usuario": "juan", "roles": ["admin", "analista"]}
|
|
82
|
+
_log_warn(json.dumps(data, ensure_ascii=False), level="info")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# o directamente (se convierte a str internamente)
|
|
86
|
+
_log_warn(data, level="debug")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# Loggear una instancia Django (recomendado convertir a dict)
|
|
90
|
+
from django.forms.models import model_to_dict
|
|
91
|
+
instancia_modelo = ... # instancia de un modelo Django
|
|
92
|
+
_log_warn(model_to_dict(instancia_modelo), level="debug")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Loggear una instancia Django (recomendado convertir a dict)
|
|
96
|
+
from django.forms.models import model_to_dict
|
|
97
|
+
_log_warn(model_to_dict(instancia_modelo), level="debug")
|
|
98
|
+
|
|
99
|
+
# Usar extra para pasar metadata (si el handler/formatter lo soporta)
|
|
100
|
+
user = ... # instancia de usuario
|
|
101
|
+
ot = ... # alguna otra variable relevante
|
|
102
|
+
_log_warn("Acceso a recurso", level="info", extra={"user_id": str(user.id), "ot": ot})
|
|
103
|
+
|
|
104
|
+
# Nivel numérico
|
|
105
|
+
_log_warn("Mensaje crítico numérico", level=50) # equivale a CRITICAL
|
|
106
|
+
|
|
107
|
+
'''
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eco-back
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Librería Python eco-back
|
|
5
5
|
Author-email: EI UNP <ecosistema@unp.gov.co>
|
|
6
6
|
License: MIT
|
|
@@ -38,18 +38,20 @@ Dynamic: license-file
|
|
|
38
38
|
|
|
39
39
|
# eco-back
|
|
40
40
|
|
|
41
|
-
Librería Python para backend con soporte para PostgreSQL/PostGIS
|
|
41
|
+
Librería Python para backend con soporte para PostgreSQL/PostGIS, clientes API, manejo de excepciones y logging
|
|
42
42
|
|
|
43
43
|
## Características
|
|
44
44
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
45
|
+
- **Base de datos**: Conexión y operaciones con PostgreSQL
|
|
46
|
+
- **PostGIS**: Operaciones geoespaciales (puntos, polígonos, búsquedas por proximidad)
|
|
47
|
+
- **Cliente API**: Cliente HTTP genérico y cliente específico UNP
|
|
48
|
+
- **Patrón Repository**: Implementación de patrones de diseño para acceso a datos
|
|
49
|
+
- **Utils**: Sistema de excepciones y logging para Django
|
|
50
|
+
- **Registro**: Funciones de trazabilidad para Django REST Framework
|
|
49
51
|
|
|
50
52
|
## Descripción
|
|
51
53
|
|
|
52
|
-
eco-back es una librería modular que facilita el desarrollo de aplicaciones backend, proporcionando abstracciones para bases de datos geoespaciales
|
|
54
|
+
eco-back es una librería modular que facilita el desarrollo de aplicaciones backend, proporcionando abstracciones para bases de datos geoespaciales, consumo de APIs REST, manejo de excepciones y logging estructurado.
|
|
53
55
|
|
|
54
56
|
## Instalación
|
|
55
57
|
|
|
@@ -194,6 +196,58 @@ flake8 src/ tests/
|
|
|
194
196
|
mypy src/
|
|
195
197
|
```
|
|
196
198
|
|
|
199
|
+
### Manejo de excepciones y logging (Django)
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from eco_back.utils import (
|
|
203
|
+
ServiceValidationError,
|
|
204
|
+
handle_service_validation_error,
|
|
205
|
+
_log_warn
|
|
206
|
+
)
|
|
207
|
+
from rest_framework.decorators import api_view
|
|
208
|
+
from rest_framework.response import Response
|
|
209
|
+
|
|
210
|
+
@api_view(['GET'])
|
|
211
|
+
@handle_service_validation_error
|
|
212
|
+
def mi_vista(request, user_id):
|
|
213
|
+
try:
|
|
214
|
+
_log_warn(f"Buscando usuario {user_id}", level="info")
|
|
215
|
+
|
|
216
|
+
usuario = Usuario.objects.get(id=user_id)
|
|
217
|
+
return Response({"usuario": usuario.username})
|
|
218
|
+
|
|
219
|
+
except Usuario.DoesNotExist:
|
|
220
|
+
_log_warn(f"Usuario {user_id} no encontrado", level="warning")
|
|
221
|
+
raise ServiceValidationError(
|
|
222
|
+
"Usuario no encontrado",
|
|
223
|
+
code=404,
|
|
224
|
+
context={"user_id": user_id}
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Trazabilidad de registros (Django)
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from eco_back.registro import TrazabilidadRegistroPermiso
|
|
232
|
+
from django.urls import path
|
|
233
|
+
|
|
234
|
+
urlpatterns = [
|
|
235
|
+
path('api/trazabilidad/<int:registro_id>/', TrazabilidadRegistroPermiso),
|
|
236
|
+
]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Módulos disponibles
|
|
240
|
+
|
|
241
|
+
- `eco_back.database` - Conexiones y operaciones con PostgreSQL/PostGIS
|
|
242
|
+
- `eco_back.api` - Clientes HTTP y consumo de APIs
|
|
243
|
+
- `eco_back.documento` - Manejo de documentos y anexos
|
|
244
|
+
- `eco_back.utils` - Excepciones y logging para Django
|
|
245
|
+
- `eco_back.registro` - Funciones de trazabilidad (Django REST Framework)
|
|
246
|
+
|
|
247
|
+
Para más información, consulta los README de cada módulo:
|
|
248
|
+
- [Utils (excepciones y logging)](src/eco_back/utils/README.md)
|
|
249
|
+
- [Registro (trazabilidad)](src/eco_back/registro/README.md)
|
|
250
|
+
|
|
197
251
|
## Licencia
|
|
198
252
|
|
|
199
253
|
MIT
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
eco_back/__init__.py,sha256
|
|
1
|
+
eco_back/__init__.py,sha256=CZC7VjSE1Z_VIpywk8VNxKdD2QYZxMF4FcX6Ok2qKn8,285
|
|
2
2
|
eco_back/api/__init__.py,sha256=9moiU5H8jGlva8k65bUK49LRIkE7bcLH1SK1dk23wcM,202
|
|
3
3
|
eco_back/api/client.py,sha256=b2J9ty7mRtPUsMD-YJui60B9GEa-85VAAb-sS5y1Rp8,8537
|
|
4
4
|
eco_back/api/config.py,sha256=dyERZY_4lXtRjhqLaHI0F4WlgPOQ_sw35eHNWGkQNLo,1590
|
|
@@ -12,9 +12,12 @@ eco_back/database/repository.py,sha256=NFh0pfvf7Pw878qOoVhR8ARMFC0CiJBQ_EwKshY8l
|
|
|
12
12
|
eco_back/documento/__init__.py,sha256=0rIgJ52in_BMg7VYr2pVlu9EnTPftgdqJ4hOZU5I4j0,146
|
|
13
13
|
eco_back/documento/anexos.py,sha256=KIzGNEVJ6tV3awhq4WGiqb8eSV2PluRRZ0PRbqeO5VE,17511
|
|
14
14
|
eco_back/registro/__init__.py,sha256=CRDv6OSKzt1r-RnKSfv86Ceb7yfL2Fn-OhHGCx467lE,148
|
|
15
|
-
eco_back/registro/trazabilidad.py,sha256=
|
|
16
|
-
eco_back
|
|
17
|
-
eco_back
|
|
18
|
-
eco_back
|
|
19
|
-
eco_back-0.2.
|
|
20
|
-
eco_back-0.2.
|
|
15
|
+
eco_back/registro/trazabilidad.py,sha256=usjHeF7cY2cJGlOcJaTFCfQLAvOjXNAQsTQkb2GQM7I,1237
|
|
16
|
+
eco_back/utils/__init__.py,sha256=DM0Y6fMeoRH6tG0skpkfEUVR71OAIFuVKQDC3_XBHvc,317
|
|
17
|
+
eco_back/utils/exceptions.py,sha256=woKrhxkncGIG_rCgRFT6B9ZAgV2TdaCH4Vcusyj3aX4,2010
|
|
18
|
+
eco_back/utils/logger_generico.py,sha256=1FIalQDkxzu0NBj-L7SzTuKEWcZuh25ZcIEux5WCB2c,4227
|
|
19
|
+
eco_back-0.2.2.dist-info/licenses/LICENSE,sha256=XKKSDU9WlUEAyPNlRhq6e2xhVNpJc097JwPZJ1rUnRE,1077
|
|
20
|
+
eco_back-0.2.2.dist-info/METADATA,sha256=1i4xVs7pPTO1sLaOmSxGAG92y8NqnAg-tYOtFHum674,6544
|
|
21
|
+
eco_back-0.2.2.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
22
|
+
eco_back-0.2.2.dist-info/top_level.txt,sha256=ViJZv023782XNNFMcAsRC9iN1CU3tb8lP9wDAHacMyc,9
|
|
23
|
+
eco_back-0.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|