Encryptors 2.50__tar.gz → 2.52__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 (101) hide show
  1. {encryptors-2.50 → encryptors-2.52}/PKG-INFO +1 -1
  2. {encryptors-2.50 → encryptors-2.52}/setup.py +1 -1
  3. {encryptors-2.50 → encryptors-2.52}/src/Encryptors.egg-info/PKG-INFO +1 -1
  4. {encryptors-2.50 → encryptors-2.52}/src/Encryptors.egg-info/SOURCES.txt +24 -29
  5. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Cache/Redis.py +8 -6
  6. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Cli/__init__.py +7 -5
  7. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Database/BaseRepository.py +1 -1
  8. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Database/Connection.py +11 -0
  9. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Decorators/Grpc.py +3 -1
  10. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Decorators/SecureResolver.py +5 -2
  11. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/Aes.py +6 -4
  12. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/Jwt.py +7 -5
  13. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/Rsa.py +6 -4
  14. encryptors-2.52/src/Osdental/Enums/FileType.py +9 -0
  15. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Enums/GrahpqlOperation.py +2 -2
  16. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Exception/ControlledException.py +2 -2
  17. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/Extensions/AuditExtension.py +3 -1
  18. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/AuditDispatcher.py +4 -1
  19. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/JwtTokenHelper.py +28 -40
  20. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/ResponseDecryptor.py +4 -1
  21. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Http/APIClient.py +8 -4
  22. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Http/_Helpers.py +5 -2
  23. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/ApiResponse.py +2 -2
  24. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/Response.py +2 -2
  25. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/TokenClaims.py +0 -1
  26. encryptors-2.50/src/Osdental/Helpers/KeyVaultService.py → encryptors-2.52/src/Osdental/Secrets/AzureKeyVaultProvider.py +1 -8
  27. encryptors-2.52/src/Osdental/Secrets/__init__.py +7 -0
  28. {encryptors-2.50/src/Osdental/Helpers → encryptors-2.52/src/Osdental/Services}/JwtAuthTokenService.py +2 -3
  29. {encryptors-2.50/src/Osdental/Helpers → encryptors-2.52/src/Osdental/Services}/WebsocketClient.py +4 -3
  30. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/FileMetaData.py +1 -1
  31. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/PasswordGenerator.py +1 -1
  32. encryptors-2.50/src/Osdental/Decorators/PublicResolver.py +0 -3
  33. encryptors-2.50/src/Osdental/Decorators/SqlDataNormalizer.py +0 -60
  34. encryptors-2.50/src/Osdental/Shared/Enums/Constant.py +0 -10
  35. encryptors-2.50/src/Osdental/Shared/Enums/FileType.py +0 -9
  36. encryptors-2.50/src/Osdental/Shared/Enums/Message.py +0 -40
  37. encryptors-2.50/src/Osdental/Shared/Logger.py +0 -17
  38. encryptors-2.50/src/Osdental/__init__.py +0 -0
  39. {encryptors-2.50 → encryptors-2.52}/README.md +0 -0
  40. {encryptors-2.50 → encryptors-2.52}/setup.cfg +0 -0
  41. {encryptors-2.50 → encryptors-2.52}/src/Encryptors.egg-info/dependency_links.txt +0 -0
  42. {encryptors-2.50 → encryptors-2.52}/src/Encryptors.egg-info/entry_points.txt +0 -0
  43. {encryptors-2.50 → encryptors-2.52}/src/Encryptors.egg-info/requires.txt +0 -0
  44. {encryptors-2.50 → encryptors-2.52}/src/Encryptors.egg-info/top_level.txt +0 -0
  45. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Cache/__init__.py +0 -0
  46. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Database/__init__.py +0 -0
  47. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Decorators/Retry.py +0 -0
  48. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Decorators/__init__.py +0 -0
  49. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/Argon2.py +0 -0
  50. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/Bcrypt.py +0 -0
  51. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/Sha512.py +0 -0
  52. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Encryptor/__init__.py +0 -0
  53. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Enums/Profile.py +0 -0
  54. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Enums/StatusCode.py +0 -0
  55. {encryptors-2.50/src/Osdental/Exception → encryptors-2.52/src/Osdental/Enums}/__init__.py +0 -0
  56. {encryptors-2.50/src/Osdental/Graphql/Extensions → encryptors-2.52/src/Osdental/Exception}/__init__.py +0 -0
  57. {encryptors-2.50/src/Osdental/Graphql/_Helpers → encryptors-2.52/src/Osdental/Graphql/Extensions}/__init__.py +0 -0
  58. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/Models/__init__.py +0 -0
  59. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/_Exceptions/__init__.py +0 -0
  60. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/_Helpers/_AuditHelper.py +0 -0
  61. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/_Helpers/_ExtractAuthToken.py +0 -0
  62. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/_Helpers/_TenantPolicy.py +0 -0
  63. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Graphql/_Helpers/_TokenService.py +0 -0
  64. {encryptors-2.50/src/Osdental/Graphql → encryptors-2.52/src/Osdental/Graphql/_Helpers}/__init__.py +0 -0
  65. {encryptors-2.50/src/Osdental/Helpers → encryptors-2.52/src/Osdental/Graphql}/__init__.py +0 -0
  66. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/AzureClassifier.py +0 -0
  67. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/GrpcConnection.py +0 -0
  68. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/Resilience.py +0 -0
  69. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Helpers/_AuthTokenProcessor.py +0 -0
  70. {encryptors-2.50/src/Osdental/Http → encryptors-2.52/src/Osdental/Helpers}/__init__.py +0 -0
  71. {encryptors-2.50/src/Osdental/Models → encryptors-2.52/src/Osdental/Http}/__init__.py +0 -0
  72. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Messaging/AzureServiceBus.py +0 -0
  73. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Messaging/Kafka.py +0 -0
  74. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Messaging/RabbitMQ.py +0 -0
  75. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Messaging/__init__.py +0 -0
  76. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/AuditConfig.py +0 -0
  77. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/Notification.py +0 -0
  78. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/Token.py +0 -0
  79. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Models/_Audit.py +0 -0
  80. {encryptors-2.50/src/Osdental/Rest/Context → encryptors-2.52/src/Osdental/Models}/__init__.py +0 -0
  81. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Rest/Context/RequestContext.py +0 -0
  82. {encryptors-2.50/src/Osdental/Rest/Middlewares → encryptors-2.52/src/Osdental/Rest/Context}/__init__.py +0 -0
  83. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Rest/Middlewares/RequestContextMiddleware.py +0 -0
  84. {encryptors-2.50/src/Osdental/Rest → encryptors-2.52/src/Osdental/Rest/Middlewares}/__init__.py +0 -0
  85. {encryptors-2.50/src/Osdental/Shared/Enums → encryptors-2.52/src/Osdental/Rest}/__init__.py +0 -0
  86. /encryptors-2.50/src/Osdental/Helpers/_Ports.py → /encryptors-2.52/src/Osdental/Services/__init__.py +0 -0
  87. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Storage/AzureBlobStorage.py +0 -0
  88. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Storage/S3Storage.py +0 -0
  89. {encryptors-2.50 → encryptors-2.52}/src/Osdental/Storage/__init__.py +0 -0
  90. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/CaseConverter.py +0 -0
  91. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/CodeGenerator.py +0 -0
  92. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/DataNormalizer.py +0 -0
  93. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/DataUtils.py +0 -0
  94. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/DateUtils.py +0 -0
  95. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/HashValidator.py +0 -0
  96. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/Mapper.py +0 -0
  97. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/QueryGenerator.py +0 -0
  98. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/RsaUtils.py +0 -0
  99. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/TextProcessor.py +0 -0
  100. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/Utils/__init__.py +0 -0
  101. {encryptors-2.50/src/Osdental/Shared → encryptors-2.52/src/Osdental}/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Encryptors
3
- Version: 2.50
3
+ Version: 2.52
4
4
  Summary: End-to-end algorithm library
5
5
  Author: OSDental LLC
6
6
  Author-email: support@osdental.ai
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
  # ANDERSON REVISAR EL CACHE LOCAL DEL KEYVAULT PARA VALIDAR SI FUNCIONA
3
3
  setup(
4
4
  name="Encryptors",
5
- version="2.50",
5
+ version="2.52",
6
6
  author="OSDental LLC",
7
7
  author_email="support@osdental.ai",
8
8
  description="End-to-end algorithm library",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Encryptors
3
- Version: 2.50
3
+ Version: 2.52
4
4
  Summary: End-to-end algorithm library
5
5
  Author: OSDental LLC
6
6
  Author-email: support@osdental.ai
@@ -14,10 +14,8 @@ src/Osdental/Database/BaseRepository.py
14
14
  src/Osdental/Database/Connection.py
15
15
  src/Osdental/Database/__init__.py
16
16
  src/Osdental/Decorators/Grpc.py
17
- src/Osdental/Decorators/PublicResolver.py
18
17
  src/Osdental/Decorators/Retry.py
19
18
  src/Osdental/Decorators/SecureResolver.py
20
- src/Osdental/Decorators/SqlDataNormalizer.py
21
19
  src/Osdental/Decorators/__init__.py
22
20
  src/Osdental/Encryptor/Aes.py
23
21
  src/Osdental/Encryptor/Argon2.py
@@ -26,6 +24,11 @@ src/Osdental/Encryptor/Jwt.py
26
24
  src/Osdental/Encryptor/Rsa.py
27
25
  src/Osdental/Encryptor/Sha512.py
28
26
  src/Osdental/Encryptor/__init__.py
27
+ src/Osdental/Enums/FileType.py
28
+ src/Osdental/Enums/GrahpqlOperation.py
29
+ src/Osdental/Enums/Profile.py
30
+ src/Osdental/Enums/StatusCode.py
31
+ src/Osdental/Enums/__init__.py
29
32
  src/Osdental/Exception/ControlledException.py
30
33
  src/Osdental/Exception/__init__.py
31
34
  src/Osdental/Graphql/__init__.py
@@ -41,14 +44,10 @@ src/Osdental/Graphql/_Helpers/__init__.py
41
44
  src/Osdental/Helpers/AuditDispatcher.py
42
45
  src/Osdental/Helpers/AzureClassifier.py
43
46
  src/Osdental/Helpers/GrpcConnection.py
44
- src/Osdental/Helpers/JwtAuthTokenService.py
45
47
  src/Osdental/Helpers/JwtTokenHelper.py
46
- src/Osdental/Helpers/KeyVaultService.py
47
48
  src/Osdental/Helpers/Resilience.py
48
49
  src/Osdental/Helpers/ResponseDecryptor.py
49
- src/Osdental/Helpers/WebsocketClient.py
50
50
  src/Osdental/Helpers/_AuthTokenProcessor.py
51
- src/Osdental/Helpers/_Ports.py
52
51
  src/Osdental/Helpers/__init__.py
53
52
  src/Osdental/Http/APIClient.py
54
53
  src/Osdental/Http/_Helpers.py
@@ -70,28 +69,24 @@ src/Osdental/Rest/Context/RequestContext.py
70
69
  src/Osdental/Rest/Context/__init__.py
71
70
  src/Osdental/Rest/Middlewares/RequestContextMiddleware.py
72
71
  src/Osdental/Rest/Middlewares/__init__.py
73
- src/Osdental/Shared/Logger.py
74
- src/Osdental/Shared/__init__.py
75
- src/Osdental/Shared/Enums/Constant.py
76
- src/Osdental/Shared/Enums/FileType.py
77
- src/Osdental/Shared/Enums/GrahpqlOperation.py
78
- src/Osdental/Shared/Enums/Message.py
79
- src/Osdental/Shared/Enums/Profile.py
80
- src/Osdental/Shared/Enums/StatusCode.py
81
- src/Osdental/Shared/Enums/__init__.py
82
- src/Osdental/Shared/Utils/CaseConverter.py
83
- src/Osdental/Shared/Utils/CodeGenerator.py
84
- src/Osdental/Shared/Utils/DataNormalizer.py
85
- src/Osdental/Shared/Utils/DataUtils.py
86
- src/Osdental/Shared/Utils/DateUtils.py
87
- src/Osdental/Shared/Utils/FileMetaData.py
88
- src/Osdental/Shared/Utils/HashValidator.py
89
- src/Osdental/Shared/Utils/Mapper.py
90
- src/Osdental/Shared/Utils/PasswordGenerator.py
91
- src/Osdental/Shared/Utils/QueryGenerator.py
92
- src/Osdental/Shared/Utils/RsaUtils.py
93
- src/Osdental/Shared/Utils/TextProcessor.py
94
- src/Osdental/Shared/Utils/__init__.py
72
+ src/Osdental/Secrets/AzureKeyVaultProvider.py
73
+ src/Osdental/Secrets/__init__.py
74
+ src/Osdental/Services/JwtAuthTokenService.py
75
+ src/Osdental/Services/WebsocketClient.py
76
+ src/Osdental/Services/__init__.py
95
77
  src/Osdental/Storage/AzureBlobStorage.py
96
78
  src/Osdental/Storage/S3Storage.py
97
- src/Osdental/Storage/__init__.py
79
+ src/Osdental/Storage/__init__.py
80
+ src/Osdental/Utils/CaseConverter.py
81
+ src/Osdental/Utils/CodeGenerator.py
82
+ src/Osdental/Utils/DataNormalizer.py
83
+ src/Osdental/Utils/DataUtils.py
84
+ src/Osdental/Utils/DateUtils.py
85
+ src/Osdental/Utils/FileMetaData.py
86
+ src/Osdental/Utils/HashValidator.py
87
+ src/Osdental/Utils/Mapper.py
88
+ src/Osdental/Utils/PasswordGenerator.py
89
+ src/Osdental/Utils/QueryGenerator.py
90
+ src/Osdental/Utils/RsaUtils.py
91
+ src/Osdental/Utils/TextProcessor.py
92
+ src/Osdental/Utils/__init__.py
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import asyncio
2
3
  import json
3
4
  from typing import Dict, List, Optional, Any
@@ -9,10 +10,11 @@ from Osdental.Cache import ICacheService
9
10
  from Osdental.Exception.ControlledException import RedisException
10
11
  from Osdental.Helpers.Resilience import AzureResiliencePolicy, AzureTransientError
11
12
  from Osdental.Helpers.AzureClassifier import classify_redis
12
- from Osdental.Shared.Logger import logger
13
- from Osdental.Shared.Enums.Message import Message
13
+ from Osdental.Constants.Message import Message
14
14
 
15
15
 
16
+ logger = logging.getLogger(__name__)
17
+
16
18
  class RedisCacheAsync(ICacheService):
17
19
 
18
20
  _instances: Dict[str, "RedisCacheAsync"] = {}
@@ -74,12 +76,12 @@ class RedisCacheAsync(ICacheService):
74
76
  await self._reconnect()
75
77
 
76
78
  except Exception as reconnect_exc:
77
- logger.error(
79
+ logger.exception(
78
80
  "redis.reconnect.failed error=%s",
79
81
  reconnect_exc
80
82
  )
81
83
 
82
- logger.error(
84
+ logger.exception(
83
85
  "redis.exhausted error=%s",
84
86
  exc
85
87
  )
@@ -131,7 +133,7 @@ class RedisCacheAsync(ICacheService):
131
133
  except Exception as e:
132
134
  self.client = None
133
135
 
134
- logger.error(
136
+ logger.exception(
135
137
  f"Redis connection error: {str(e)}"
136
138
  )
137
139
 
@@ -320,6 +322,6 @@ class RedisCacheAsync(ICacheService):
320
322
 
321
323
  except Exception as e:
322
324
 
323
- logger.error(
325
+ logger.exception(
324
326
  f"Redis close error: {str(e)}"
325
327
  )
@@ -1,10 +1,12 @@
1
+ import logging
1
2
  import os
2
3
  import sys
3
4
  import subprocess
4
5
  import platform
5
6
  import click
6
- from Osdental.Shared.Logger import logger
7
- from Osdental.Shared.Enums.Message import Message
7
+ from Osdental.Constants.Message import Message
8
+
9
+ logger = logging.getLogger(__name__)
8
10
 
9
11
 
10
12
  @click.group()
@@ -29,7 +31,7 @@ def start(port: int):
29
31
  try:
30
32
  subprocess.run(['uvicorn', 'app:app', '--port', str(port), '--reload'], check=True)
31
33
  except subprocess.CalledProcessError as e:
32
- logger.error(f'{Message.SERVER_NETWORK_ACCESS_ERROR_MSG}: {e}')
34
+ logger.exception(f'{Message.SERVER_NETWORK_ACCESS_ERROR_MSG}: {e}')
33
35
 
34
36
  @cli.command()
35
37
  @click.argument('port')
@@ -38,7 +40,7 @@ def serve(port: int):
38
40
  try:
39
41
  subprocess.run(['uvicorn', 'app:app', '--host', '0.0.0.0', '--port', str(port), '--reload'], check=True)
40
42
  except subprocess.CalledProcessError as e:
41
- logger.error(f'{Message.SERVER_NETWORK_ACCESS_ERROR_MSG}: {e}')
43
+ logger.exception(f'{Message.SERVER_NETWORK_ACCESS_ERROR_MSG}: {e}')
42
44
 
43
45
  @cli.command("clean-redis")
44
46
  @click.argument('redis_env')
@@ -54,7 +56,7 @@ async def clean_redis(redis_env: str):
54
56
  await redis.flush()
55
57
  logger.info(Message.REDIS_CLEANUP_SUCCESS_MSG)
56
58
  except Exception as e:
57
- logger.error(f'{Message.REDIS_CLEANUP_ERROR_MSG}: {e}')
59
+ logger.exception(f'{Message.REDIS_CLEANUP_ERROR_MSG}: {e}')
58
60
 
59
61
  @cli.command(name='proto-files')
60
62
  @click.argument('name')
@@ -6,7 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
6
6
  from Osdental.Exception.ControlledException import DatabaseException
7
7
  from Osdental.Helpers.Resilience import AzureResiliencePolicy, AzureTransientError
8
8
  from Osdental.Shared.Utils.DataNormalizer import normalize
9
- from Osdental.Shared.Enums.Message import Message
9
+ from Osdental.Constants.Message import Message
10
10
 
11
11
  _TRANSIENT_SQL_ERRORS = {
12
12
  "08S01", "40197", "40501", "40613", "49918",
@@ -74,6 +74,17 @@ class Connection:
74
74
  self.initialized = True
75
75
  logger.info("db.connection_ready url=%s", self._safe_url(db_url))
76
76
 
77
+ @staticmethod
78
+ def _safe_url(db_url: str) -> str:
79
+ """Enmascara contraseñas del connection string para logging seguro."""
80
+ import re
81
+ return re.sub(
82
+ r"(password|pwd)=[^;]+",
83
+ r"\1=***",
84
+ db_url,
85
+ flags=re.IGNORECASE
86
+ )
87
+
77
88
  def _ensure_connection_resiliency(self, db_url: str) -> str:
78
89
  """
79
90
  Agrega parámetros resilientes por defecto para Azure SQL
@@ -1,6 +1,8 @@
1
+ import logging
1
2
  import json
2
3
  from functools import wraps
3
- from Osdental.Shared.Logger import logger
4
+
5
+ logger = logging.getLogger(__name__)
4
6
 
5
7
  def parse_rpc_request_payload(func):
6
8
 
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  from functools import wraps
2
3
  from typing import Callable
3
4
  from graphql import GraphQLResolveInfo
@@ -7,13 +8,15 @@ from Osdental.Exception.ControlledException import (
7
8
  OSDException, AccessDeniedException
8
9
  )
9
10
  from Osdental.Graphql.Models import BaseGraphQLContext
10
- from Osdental.Shared.Logger import logger
11
11
  from Osdental.Helpers._Ports import IAuthTokenService
12
12
  from Osdental.Helpers._AuthTokenProcessor import (
13
13
  extract_bearer_token, build_auth_token, decrypt_and_parse_payload
14
14
  )
15
15
  from Osdental.Models.TokenClaims import UserTokenClaims
16
- from Osdental.Shared.Enums.StatusCode import StatusCode
16
+ from Osdental.Enums.StatusCode import StatusCode
17
+
18
+
19
+ logger = logging.getLogger(__name__)
17
20
 
18
21
 
19
22
  def __test(dispatcher, request, request_payload, result, decrypted_key):
@@ -1,13 +1,15 @@
1
+ import logging
1
2
  import os
2
3
  import json
3
4
  import base64
4
5
  from typing import Dict, List
5
6
  from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
6
7
  from Osdental.Exception.ControlledException import AESEncryptException
7
- from Osdental.Shared.Logger import logger
8
- from Osdental.Shared.Enums.Message import Message
8
+ from Osdental.Constants.Message import Message
9
9
  from Osdental.Shared.Enums.Constant import Constant
10
10
 
11
+ logger = logging.getLogger(__name__)
12
+
11
13
  class AES:
12
14
 
13
15
  IV_LENGTH = 32
@@ -49,7 +51,7 @@ class AES:
49
51
  return base64.b64encode(encrypted_data).decode(Constant.DEFAULT_ENCODING)
50
52
 
51
53
  except Exception as e:
52
- logger.error(f'Unexpected AES encryption error: {str(e)}')
54
+ logger.exception(f'Unexpected AES encryption error: {str(e)}')
53
55
  raise AESEncryptException(error=str(e))
54
56
 
55
57
  @classmethod
@@ -80,6 +82,6 @@ class AES:
80
82
 
81
83
  except Exception as e:
82
84
  if not silent:
83
- logger.error(f'Unexpected AES decryption error: {str(e)}')
85
+ logger.exception(f'Unexpected AES decryption error: {str(e)}')
84
86
 
85
87
  raise AESEncryptException(error=str(e))
@@ -1,12 +1,14 @@
1
+ import logging
1
2
  import jwt
2
3
  from typing import Dict, Any
3
4
  from cryptography.hazmat.primitives import serialization
4
5
  from cryptography.hazmat.backends import default_backend
5
6
  from Osdental.Exception.ControlledException import JWTokenException
6
- from Osdental.Shared.Logger import logger
7
- from Osdental.Shared.Enums.Message import Message
7
+ from Osdental.Constants.Message import Message
8
8
 
9
9
 
10
+ logger = logging.getLogger(__name__)
11
+
10
12
  class JWT:
11
13
 
12
14
  @staticmethod
@@ -18,7 +20,7 @@ class JWT:
18
20
  return token
19
21
 
20
22
  except Exception as e:
21
- logger.error(f"Unexpected jwt generating error: {str(e)}")
23
+ logger.exception(f"Unexpected jwt generating error: {str(e)}")
22
24
  raise JWTokenException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
23
25
 
24
26
  @staticmethod
@@ -28,7 +30,7 @@ class JWT:
28
30
  return payload
29
31
 
30
32
  except Exception as e:
31
- logger.error(f"Unexpected jwt extract payload error: {str(e)}")
33
+ logger.exception(f"Unexpected jwt extract payload error: {str(e)}")
32
34
  raise JWTokenException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
33
35
 
34
36
  @staticmethod
@@ -39,5 +41,5 @@ class JWT:
39
41
  )
40
42
  return private_key
41
43
  except Exception as e:
42
- logger.error(f"Unexpected jwt private key generating error: {str(e)}")
44
+ logger.exception(f"Unexpected jwt private key generating error: {str(e)}")
43
45
  raise JWTokenException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import json
2
3
  from base64 import b64decode, b64encode
3
4
  from typing import Dict, Any
@@ -5,10 +6,11 @@ from cryptography.hazmat.primitives import serialization
5
6
  from cryptography.hazmat.primitives.asymmetric import padding
6
7
  from cryptography.hazmat.primitives import hashes
7
8
  from Osdental.Exception.ControlledException import RSAEncryptException
8
- from Osdental.Shared.Logger import logger
9
- from Osdental.Shared.Enums.Message import Message
9
+ from Osdental.Constants.Message import Message
10
10
  from Osdental.Shared.Enums.Constant import Constant
11
11
 
12
+
13
+ logger = logging.getLogger(__name__)
12
14
  class RSAEncryptor:
13
15
 
14
16
  @staticmethod
@@ -31,7 +33,7 @@ class RSAEncryptor:
31
33
  return b64encode(encrypted_bytes).decode(Constant.DEFAULT_ENCODING)
32
34
 
33
35
  except Exception as e:
34
- logger.error(f'Unexpected RSA encryption error: {str(e)}')
36
+ logger.exception(f'Unexpected RSA encryption error: {str(e)}')
35
37
  raise RSAEncryptException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
36
38
 
37
39
 
@@ -53,6 +55,6 @@ class RSAEncryptor:
53
55
 
54
56
  except Exception as e:
55
57
  if not silent:
56
- logger.error(f'Unexpected RSA decryption error: {str(e)}')
58
+ logger.exception(f'Unexpected RSA decryption error: {str(e)}')
57
59
 
58
60
  raise RSAEncryptException(message=Message.UNEXPECTED_ERROR_MSG, error=str(e))
@@ -0,0 +1,9 @@
1
+ from enum import StrEnum
2
+
3
+ class FileType(StrEnum):
4
+ IMAGE = "image"
5
+ VIDEO = "video"
6
+ AUDIO = "audio"
7
+ DOCUMENT = "document"
8
+ ARCHIVE = "archive"
9
+ OTHER = "other"
@@ -1,5 +1,5 @@
1
1
  from enum import StrEnum
2
2
 
3
3
  class GraphqlOperation(StrEnum):
4
- QUERY = 'query'
5
- MUTATION = 'mutation'
4
+ QUERY = "query"
5
+ MUTATION = "mutation"
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
- from Osdental.Shared.Enums.StatusCode import StatusCode
3
- from Osdental.Shared.Enums.Message import Message
2
+ from Osdental.Enums.StatusCode import StatusCode
3
+ from Osdental.Constants.Message import Message
4
4
 
5
5
  class OSDException(Exception):
6
6
  """ Base class for all custom exceptions. """
@@ -1,8 +1,8 @@
1
1
  import inspect
2
+ import logging
2
3
  import json
3
4
  from graphql.pyutils import is_awaitable
4
5
  from ariadne.types import Extension
5
- from Osdental.Shared.Logger import logger
6
6
  from Osdental.Encryptor.Aes import AES
7
7
  from Osdental.Graphql._Helpers._TenantPolicy import TenantPolicy
8
8
  from Osdental.Rest.Context.RequestContext import (
@@ -13,6 +13,8 @@ from Osdental.Models.Response import Response
13
13
  from Osdental.Graphql.Models import BaseGraphQLContext
14
14
  from Osdental.Shared.Enums.Constant import Constant
15
15
 
16
+ logger = logging.getLogger(__name__)
17
+
16
18
  class AuditExtension(Extension):
17
19
 
18
20
  def request_started(self, context):
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import asyncio
2
3
  from typing import Dict, Any, Optional
3
4
  from fastapi import Request
@@ -10,7 +11,9 @@ from Osdental.Models._Audit import Audit
10
11
  from Osdental.Models.Response import Response
11
12
  from Osdental.Models.ApiResponse import ApiResponse
12
13
  from Osdental.Shared.Enums.Constant import Constant
13
- from Osdental.Shared.Logger import logger
14
+
15
+
16
+ logger = logging.getLogger(__name__)
14
17
 
15
18
  class AuditDispatcher:
16
19
 
@@ -3,8 +3,10 @@ from datetime import datetime, timedelta, timezone
3
3
  from jwcrypto import jwk
4
4
  from jwcrypto import jwt
5
5
  from jwcrypto import jwe
6
+ from jwcrypto.jwt import JWTExpired
6
7
  from Osdental.Models.TokenClaims import TokenValidationOptions
7
-
8
+ from Osdental.Exception.ControlledException import UnauthorizedException
9
+ from Osdental.Enums.StatusCode import StatusCode
8
10
 
9
11
  class JwtTokenHelper:
10
12
 
@@ -78,37 +80,43 @@ class JwtTokenHelper:
78
80
  Desencripta y verifica firma.
79
81
 
80
82
  NO valida:
81
- - expiration
82
83
  - issuer
83
84
  - audience
84
85
 
85
86
  Retorna claims incluso si el token está expirado.
86
87
  """
87
88
 
88
- encrypted = jwe.JWE()
89
+ try:
90
+ encrypted = jwe.JWE()
89
91
 
90
- encrypted.deserialize(
91
- token
92
- )
92
+ encrypted.deserialize(
93
+ token
94
+ )
93
95
 
94
- encrypted.decrypt(
95
- self._private_key
96
- )
96
+ encrypted.decrypt(
97
+ self._private_key
98
+ )
97
99
 
98
- inner_token = (
99
- encrypted.payload.decode()
100
- )
100
+ inner_token = (
101
+ encrypted.payload.decode()
102
+ )
101
103
 
102
- verified = jwt.JWT()
104
+ verified = jwt.JWT()
103
105
 
104
- verified.deserialize(
105
- jwt=inner_token,
106
- key=self._public_key,
107
- )
106
+ verified.deserialize(
107
+ jwt=inner_token,
108
+ key=self._public_key,
109
+ )
108
110
 
109
- return json.loads(
110
- verified.claims
111
- )
111
+ return json.loads(
112
+ verified.claims
113
+ )
114
+
115
+ except JWTExpired:
116
+ raise UnauthorizedException(
117
+ message="Token expired",
118
+ status_code=StatusCode.UNAUTHORIZED
119
+ )
112
120
 
113
121
  def validate_claims(
114
122
  self,
@@ -143,26 +151,6 @@ class JwtTokenHelper:
143
151
  )
144
152
 
145
153
 
146
- if options.validate_expiration:
147
-
148
- exp = claims.get("exp")
149
-
150
- if exp is None:
151
- raise ValueError(
152
- "exp claim not found"
153
- )
154
-
155
- now = int(
156
- datetime.now(
157
- timezone.utc
158
- ).timestamp()
159
- )
160
-
161
- if now > exp:
162
- raise ValueError(
163
- "Token expired"
164
- )
165
-
166
154
  def validate_token(
167
155
  self,
168
156
  token: str,
@@ -1,7 +1,10 @@
1
+ import logging
1
2
  from typing import Dict, Any
2
3
  from Osdental.Encryptor.Aes import AES
3
4
  from Osdental.Encryptor.Rsa import RSAEncryptor
4
- from Osdental.Shared.Logger import logger
5
+
6
+ logger = logging.getLogger(__name__)
7
+
5
8
 
6
9
  VALID_TYPES = {"RSA", "AES"}
7
10
 
@@ -1,12 +1,16 @@
1
- import httpx
1
+ import logging
2
2
  from typing import Optional, Dict, Any
3
+ import httpx
4
+ from http import HTTPMethod
3
5
  from Osdental.Decorators.Retry import rest_retry
4
6
  from Osdental.Http._Helpers import (
5
7
  audit_success, audit_http_error, audit_exception_error,
6
8
  audit_unknown_error, audit_graphql_error
7
9
  )
8
10
  from Osdental.Exception.ControlledException import HttpClientException
9
- from Osdental.Shared.Logger import logger
11
+
12
+
13
+ logger = logging.getLogger(__name__)
10
14
 
11
15
  class APIClient:
12
16
 
@@ -28,7 +32,7 @@ class APIClient:
28
32
  await self._client.aclose()
29
33
 
30
34
  @rest_retry
31
- async def _request(self, method: str, url: str, **kwargs) -> httpx.Response:
35
+ async def _request(self, method: HTTPMethod, url: str, **kwargs) -> httpx.Response:
32
36
 
33
37
  try:
34
38
 
@@ -68,7 +72,7 @@ class APIClient:
68
72
 
69
73
  async def request(
70
74
  self,
71
- method: str,
75
+ method: HTTPMethod,
72
76
  url: str,
73
77
  **kwargs
74
78
  ) -> Any:
@@ -1,7 +1,10 @@
1
+ import logging
1
2
  from Osdental.Rest.Context.RequestContext import current_context
2
3
  from Osdental.Models.ApiResponse import ApiResponse
3
4
  from Osdental.Shared.Enums.Constant import Constant
4
- from Osdental.Shared.Logger import logger
5
+
6
+
7
+ logger = logging.getLogger(__name__)
5
8
 
6
9
  """
7
10
  Helpers to control external API audit logging.
@@ -22,7 +25,7 @@ def _safe_dispatch(**kwargs):
22
25
  if dispatcher:
23
26
  dispatcher.dispatch(**kwargs)
24
27
  except Exception as e:
25
- logger.error(f"Audit error: {str(e)}")
28
+ logger.exception(f"Audit error: {str(e)}")
26
29
 
27
30
  def _build_payload(method, url, kwargs):
28
31
  return {
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass, field, asdict
2
2
  from typing import Any, Optional
3
- from Osdental.Shared.Enums.StatusCode import StatusCode
4
- from Osdental.Shared.Enums.Message import Message
3
+ from Osdental.Enums.StatusCode import StatusCode
4
+ from Osdental.Constants.Message import Message
5
5
 
6
6
  @dataclass
7
7
  class ApiResponse:
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass, field, asdict
2
2
  from typing import Optional, Any, Literal
3
- from Osdental.Shared.Enums.StatusCode import StatusCode
4
- from Osdental.Shared.Enums.Message import Message
3
+ from Osdental.Enums.StatusCode import StatusCode
4
+ from Osdental.Constants.Message import Message
5
5
 
6
6
  @dataclass
7
7
  class Response:
@@ -7,7 +7,6 @@ class TokenValidationOptions:
7
7
  issuer: Optional[str] = None
8
8
  audience: Optional[str] = None
9
9
 
10
- validate_expiration: bool = True
11
10
  validate_issuer: bool = True
12
11
  validate_audience: bool = True
13
12
 
@@ -1,16 +1,9 @@
1
1
  import asyncio
2
2
  import time
3
3
  from typing import Dict
4
- from abc import ABC, abstractmethod
5
4
  from azure.identity.aio import DefaultAzureCredential
6
5
  from azure.keyvault.secrets.aio import SecretClient
7
-
8
-
9
- class ISecretProvider(ABC):
10
-
11
- @abstractmethod
12
- async def get(self, name: str) -> str:
13
- pass
6
+ from Osdental.Secrets import ISecretProvider
14
7
 
15
8
  class AzureKeyVaultSecretProvider(ISecretProvider):
16
9
 
@@ -0,0 +1,7 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class ISecretProvider(ABC):
4
+
5
+ @abstractmethod
6
+ async def get(self, name: str) -> str:
7
+ pass
@@ -5,14 +5,13 @@ from Osdental.Models.TokenClaims import (
5
5
  ActionTokenClaims, TokenValidationOptions
6
6
  )
7
7
 
8
- from Osdental.Helpers._Ports import IAuthTokenService
8
+ from Osdental.Services import IAuthTokenService
9
9
 
10
10
  from Osdental.Helpers.JwtTokenHelper import JwtTokenHelper
11
11
 
12
-
13
12
  from Osdental.Shared.Utils.RsaUtils import normalize_rsa_keys
14
13
 
15
- from Osdental.Helpers.KeyVaultService import ISecretProvider
14
+ from Osdental.Secrets import ISecretProvider
16
15
 
17
16
  class JwtAuthTokenService(IAuthTokenService):
18
17
 
@@ -1,9 +1,10 @@
1
+ import logging
1
2
  import json
2
3
  from Osdental.Http.APIClient import APIClient
3
- from Osdental.Shared.Logger import logger
4
- from Osdental.Helpers._Ports import INotificationPublisher
4
+ from Osdental.Services import INotificationPublisher
5
5
  from Osdental.Models.Notification import Notification
6
6
 
7
+ logger = logging.getLogger(__name__)
7
8
 
8
9
  class WebsocketClient(INotificationPublisher):
9
10
 
@@ -37,7 +38,7 @@ class WebsocketClient(INotificationPublisher):
37
38
 
38
39
  except Exception as e:
39
40
 
40
- logger.error(
41
+ logger.exception(
41
42
  f"Error sending websocket notification: {e}"
42
43
  )
43
44
 
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import mimetypes
3
3
  from Osdental.Exception.ControlledException import ValidationDataException
4
- from Osdental.Shared.Enums.Message import Message
4
+ from Osdental.Constants.Message import Message
5
5
  from Osdental.Shared.Enums.FileType import FileType
6
6
 
7
7
  class FileMetaData:
@@ -1,6 +1,6 @@
1
1
  import random
2
2
  import string
3
- from Osdental.Shared.Enums.Message import Message
3
+ from Osdental.Constants.Message import Message
4
4
 
5
5
  class PasswordGenerator:
6
6
 
@@ -1,3 +0,0 @@
1
- def public_resolver(resolver):
2
- setattr(resolver, "_is_public", True)
3
- return resolver
@@ -1,60 +0,0 @@
1
- import uuid
2
- from functools import wraps
3
- from sqlalchemy.engine.row import RowMapping, Row
4
- from sqlalchemy.engine import Result
5
- from typing import Any, Callable, Awaitable
6
-
7
-
8
- def dictify_sql_result(func: Callable[..., Awaitable[Any]]) -> Callable[..., Awaitable[Any]]:
9
- """
10
- Decorador que convierte automáticamente los resultados devueltos por funciones asíncronas
11
- que usan SQLAlchemy (ORM o Core), transformando RowMapping o Row en dicts puros.
12
-
13
- Maneja correctamente:
14
- - None
15
- - Escalares (int, str, etc.)
16
- - RowMapping / Row únicos o listas
17
- - Result devuelto sin procesar
18
- """
19
-
20
- def normalize_value(value: Any) -> Any:
21
- if isinstance(value, uuid.UUID):
22
- return str(value).lower()
23
- elif isinstance(value, dict):
24
- return {k: normalize_value(v) for k, v in value.items()}
25
- elif isinstance(value, (list, tuple)):
26
- return [normalize_value(v) for v in value]
27
- return value
28
-
29
- @wraps(func)
30
- async def wrapper(*args, **kwargs):
31
- result = await func(*args, **kwargs)
32
-
33
- if result is None:
34
- return None
35
-
36
- if isinstance(result, Result):
37
- try:
38
- rows = result.mappings().all()
39
- return [normalize_value(dict(r)) for r in rows]
40
- except Exception:
41
- rows = result.all()
42
- return [normalize_value(dict(r._mapping)) for r in rows]
43
-
44
- if isinstance(result, list) and result:
45
- first_item = result[0]
46
- if isinstance(first_item, RowMapping):
47
- return [normalize_value(dict(r)) for r in result]
48
- if isinstance(first_item, Row):
49
- return [normalize_value(dict(r._mapping)) for r in result]
50
-
51
- return [normalize_value(r) for r in result]
52
-
53
- if isinstance(result, RowMapping):
54
- return normalize_value(dict(result))
55
- if isinstance(result, Row):
56
- return normalize_value(dict(result._mapping))
57
-
58
- return normalize_value(result)
59
-
60
- return wrapper
@@ -1,10 +0,0 @@
1
- from enum import StrEnum
2
-
3
- class Constant(StrEnum):
4
- DEFAULT_ENCODING = 'utf-8'
5
- MESSAGE_LOG_INTERNAL = 'MESSAGE_LOG_INTERNAL'
6
- DEFAULT_EMPTY_VALUE = '*'
7
- RESPONSE_TYPE_ERROR = 'ERROR'
8
- RESPONSE_TYPE_REQUEST = 'REQUEST'
9
- RESPONSE_TYPE_RESPONSE = 'RESPONSE'
10
- MESSAGE_LOG_EXTERNAL = 'MESSAGE_LOG_EXTERNAL'
@@ -1,9 +0,0 @@
1
- from enum import StrEnum
2
-
3
- class FileType(StrEnum):
4
- IMAGE = 'image'
5
- VIDEO = 'video'
6
- AUDIO = 'audio'
7
- DOCUMENT = 'document'
8
- ARCHIVE = 'archive'
9
- OTHER = 'other'
@@ -1,40 +0,0 @@
1
- from enum import StrEnum
2
-
3
- class Message(StrEnum):
4
- ACCESS_DENIED_MSG = "You do not have the necessary privileges for this operation."
5
- UNEXPECTED_ERROR_MSG = "Something went wrong while processing your request. Please try again later."
6
- PORTAL_ACCESS_RESTRICTED_MSG = "You are not authorized to access this portal."
7
- PROCESS_SUCCESS_MSG = "Process executed successfully."
8
- NO_RESULTS_FOUND_MSG = "No records were found matching your request."
9
- INVALID_REQUEST_PARAMS_MSG = "Please review the required fields and try again."
10
- SERVER_NETWORK_ACCESS_ERROR_MSG = "Error making the server accessible on the network."
11
- HEXAGONAL_SERVICE_CREATED_MSG = "The hexagonal service structure was created."
12
- PYCACHE_CLEANUP_SUCCESS_MSG = "All __pycache__ have been removed."
13
- NO_PASSWORD_CHARACTERS_MSG = "There are no characters available to generate the password."
14
- INSUFFICIENT_LENGTH_MSG = "Insufficient length to meet minimum rules."
15
- LEGACY_NAME_REQUIRED_MSG = "Legacy name cannot be empty."
16
- REFRESH_TOKEN_EXP_REQUIRED_MSG = "Refresh token expiration time cannot be empty."
17
- ACCESS_TOKEN_EXP_REQUIRED_MSG = "Access token expiration time cannot be empty."
18
- PUBLIC_KEY2_REQUIRED_MSG = "Public key 2 cannot be empty."
19
- PRIVATE_KEY1_REQUIRED_MSG = "Private key 1 cannot be empty."
20
- PRIVATE_KEY2_REQUIRED_MSG = "Private key 2 cannot be empty."
21
- AES_KEY_USER_REQUIRED_MSG = "AES key user cannot be empty."
22
- AES_KEY_AUTH_REQUIRED_MSG = "AES key auth cannot be empty."
23
- MISSING_FIELD_ERROR_MSG = "A required field is missing. Please review the data."
24
- EXP_TIME_REQUIRED = "Expiration time (cdata integration) cannot be empty or null"
25
- KEY_PRIVATE_REQUIRED = "Key private cannot be empty or null"
26
- SUB_ACCOUNT_REQUIRED = "Sub account parameter is required"
27
- CATALOG_DATA_CREDENTIALS_MISSED = "Catalog data or/and data credentials not found"
28
- PROFILE_PERMISSION_DENIED_MSG = "Your profile does not have permission to perform this action."
29
- INVALID_FORMAT_MSG = "The provided data format is invalid."
30
- INVALID_AES_JSON_FORMAT_MSG = "Invalid JSON format in AES decrypted data."
31
- UNEXPECTED_DECRYPTED_DATA_FORMAT_MSG = "Unexpected format in decrypted data."
32
- REDIS_CLEANUP_SUCCESS_MSG = "Redis cleanup completed successfully."
33
- REDIS_CLEANUP_ERROR_MSG = "An error occurred while attempting to clean up Redis."
34
- DATABASE_EXECUTION_ERROR_MSG = "An unexpected error occurred while executing a database operation."
35
- DATABASE_INTEGRITY_ERROR_MSG = "A database integrity constraint was violated during execution."
36
- QUERY_NOT_PROVIDED_MSG = "Query not provided. Please include a valid query in your request."
37
- FILE_PATH_NOT_PROVIDED_MSG = "File path not provided."
38
- PROTO_FILES_GENERATED_MSG = "Proto files have been successfully generated."
39
- ERROR_INVALID_DATA_TYPE = "Invalid data type: expected dict, str, or list."
40
- EXTERNAL_API_ERROR_MESSAGE = "An error occurred while consuming an external API."
@@ -1,17 +0,0 @@
1
- import logging
2
- import colorlog
3
-
4
- handler = colorlog.StreamHandler()
5
- handler.setFormatter(colorlog.ColoredFormatter(
6
- '%(log_color)s%(levelname)s:%(name)s:%(message)s',
7
- log_colors={
8
- 'DEBUG': 'cyan',
9
- 'INFO': 'green',
10
- 'WARNING': 'yellow',
11
- 'ERROR': 'red',
12
- 'CRITICAL': 'bold_red',
13
- }
14
- ))
15
- logger = colorlog.getLogger('my_logger')
16
- logger.addHandler(handler)
17
- logger.setLevel(logging.DEBUG)
File without changes
File without changes
File without changes