maleo-foundation 0.3.46__py3-none-any.whl → 0.3.47__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.
Files changed (135) hide show
  1. maleo_foundation/authentication.py +24 -13
  2. maleo_foundation/authorization.py +2 -1
  3. maleo_foundation/client/manager.py +22 -21
  4. maleo_foundation/client/services/__init__.py +16 -7
  5. maleo_foundation/client/services/encryption/__init__.py +13 -4
  6. maleo_foundation/client/services/encryption/aes.py +41 -36
  7. maleo_foundation/client/services/encryption/rsa.py +50 -50
  8. maleo_foundation/client/services/hash/__init__.py +19 -6
  9. maleo_foundation/client/services/hash/bcrypt.py +20 -18
  10. maleo_foundation/client/services/hash/hmac.py +20 -17
  11. maleo_foundation/client/services/hash/sha256.py +18 -15
  12. maleo_foundation/client/services/key.py +50 -42
  13. maleo_foundation/client/services/signature.py +46 -42
  14. maleo_foundation/client/services/token.py +49 -58
  15. maleo_foundation/constants.py +12 -19
  16. maleo_foundation/enums.py +14 -13
  17. maleo_foundation/expanded_types/__init__.py +2 -3
  18. maleo_foundation/expanded_types/client.py +30 -34
  19. maleo_foundation/expanded_types/encryption/__init__.py +2 -1
  20. maleo_foundation/expanded_types/encryption/aes.py +7 -5
  21. maleo_foundation/expanded_types/encryption/rsa.py +7 -5
  22. maleo_foundation/expanded_types/general.py +13 -11
  23. maleo_foundation/expanded_types/hash.py +7 -5
  24. maleo_foundation/expanded_types/key.py +8 -6
  25. maleo_foundation/expanded_types/service.py +30 -34
  26. maleo_foundation/expanded_types/signature.py +7 -5
  27. maleo_foundation/expanded_types/token.py +7 -5
  28. maleo_foundation/extended_types.py +4 -3
  29. maleo_foundation/managers/cache.py +2 -1
  30. maleo_foundation/managers/client/base.py +25 -12
  31. maleo_foundation/managers/client/google/base.py +11 -4
  32. maleo_foundation/managers/client/google/parameter.py +9 -11
  33. maleo_foundation/managers/client/google/secret.py +53 -35
  34. maleo_foundation/managers/client/google/storage.py +52 -22
  35. maleo_foundation/managers/client/google/subscription.py +37 -39
  36. maleo_foundation/managers/client/maleo.py +18 -23
  37. maleo_foundation/managers/configuration.py +5 -9
  38. maleo_foundation/managers/credential.py +14 -17
  39. maleo_foundation/managers/db.py +51 -40
  40. maleo_foundation/managers/middleware.py +9 -9
  41. maleo_foundation/managers/service.py +47 -54
  42. maleo_foundation/middlewares/authentication.py +29 -54
  43. maleo_foundation/middlewares/base.py +83 -72
  44. maleo_foundation/middlewares/cors.py +8 -7
  45. maleo_foundation/models/__init__.py +2 -1
  46. maleo_foundation/models/responses.py +57 -29
  47. maleo_foundation/models/schemas/__init__.py +2 -1
  48. maleo_foundation/models/schemas/encryption.py +5 -2
  49. maleo_foundation/models/schemas/general.py +38 -18
  50. maleo_foundation/models/schemas/hash.py +2 -1
  51. maleo_foundation/models/schemas/key.py +5 -2
  52. maleo_foundation/models/schemas/parameter.py +45 -15
  53. maleo_foundation/models/schemas/result.py +35 -20
  54. maleo_foundation/models/schemas/signature.py +5 -2
  55. maleo_foundation/models/schemas/token.py +5 -2
  56. maleo_foundation/models/table.py +33 -27
  57. maleo_foundation/models/transfers/__init__.py +2 -1
  58. maleo_foundation/models/transfers/general/__init__.py +2 -1
  59. maleo_foundation/models/transfers/general/configurations/__init__.py +10 -4
  60. maleo_foundation/models/transfers/general/configurations/cache/__init__.py +3 -2
  61. maleo_foundation/models/transfers/general/configurations/cache/redis.py +13 -5
  62. maleo_foundation/models/transfers/general/configurations/client/__init__.py +5 -1
  63. maleo_foundation/models/transfers/general/configurations/client/maleo.py +38 -12
  64. maleo_foundation/models/transfers/general/configurations/database.py +5 -2
  65. maleo_foundation/models/transfers/general/configurations/middleware.py +22 -15
  66. maleo_foundation/models/transfers/general/configurations/service.py +2 -1
  67. maleo_foundation/models/transfers/general/credentials.py +2 -1
  68. maleo_foundation/models/transfers/general/database.py +11 -4
  69. maleo_foundation/models/transfers/general/key.py +13 -4
  70. maleo_foundation/models/transfers/general/request.py +28 -9
  71. maleo_foundation/models/transfers/general/settings.py +12 -22
  72. maleo_foundation/models/transfers/general/signature.py +4 -2
  73. maleo_foundation/models/transfers/general/token.py +34 -27
  74. maleo_foundation/models/transfers/parameters/__init__.py +2 -1
  75. maleo_foundation/models/transfers/parameters/client.py +15 -19
  76. maleo_foundation/models/transfers/parameters/encryption/__init__.py +2 -1
  77. maleo_foundation/models/transfers/parameters/encryption/aes.py +7 -5
  78. maleo_foundation/models/transfers/parameters/encryption/rsa.py +7 -5
  79. maleo_foundation/models/transfers/parameters/general.py +15 -13
  80. maleo_foundation/models/transfers/parameters/hash/__init__.py +2 -1
  81. maleo_foundation/models/transfers/parameters/hash/bcrypt.py +5 -5
  82. maleo_foundation/models/transfers/parameters/hash/hmac.py +6 -6
  83. maleo_foundation/models/transfers/parameters/hash/sha256.py +5 -5
  84. maleo_foundation/models/transfers/parameters/key.py +9 -8
  85. maleo_foundation/models/transfers/parameters/service.py +42 -48
  86. maleo_foundation/models/transfers/parameters/signature.py +7 -4
  87. maleo_foundation/models/transfers/parameters/token.py +10 -10
  88. maleo_foundation/models/transfers/results/__init__.py +2 -1
  89. maleo_foundation/models/transfers/results/client/__init__.py +2 -1
  90. maleo_foundation/models/transfers/results/client/controllers/__init__.py +2 -1
  91. maleo_foundation/models/transfers/results/client/controllers/http.py +10 -7
  92. maleo_foundation/models/transfers/results/client/service.py +12 -6
  93. maleo_foundation/models/transfers/results/encryption/__init__.py +2 -1
  94. maleo_foundation/models/transfers/results/encryption/aes.py +13 -5
  95. maleo_foundation/models/transfers/results/encryption/rsa.py +12 -4
  96. maleo_foundation/models/transfers/results/hash.py +7 -3
  97. maleo_foundation/models/transfers/results/key.py +18 -6
  98. maleo_foundation/models/transfers/results/service/__init__.py +2 -3
  99. maleo_foundation/models/transfers/results/service/controllers/__init__.py +2 -1
  100. maleo_foundation/models/transfers/results/service/controllers/rest.py +14 -11
  101. maleo_foundation/models/transfers/results/service/general.py +16 -10
  102. maleo_foundation/models/transfers/results/signature.py +12 -4
  103. maleo_foundation/models/transfers/results/token.py +10 -4
  104. maleo_foundation/rest_controller_result.py +23 -21
  105. maleo_foundation/types.py +15 -14
  106. maleo_foundation/utils/__init__.py +2 -1
  107. maleo_foundation/utils/cache.py +10 -13
  108. maleo_foundation/utils/client.py +25 -12
  109. maleo_foundation/utils/controller.py +59 -37
  110. maleo_foundation/utils/dependencies/__init__.py +2 -1
  111. maleo_foundation/utils/dependencies/auth.py +5 -12
  112. maleo_foundation/utils/dependencies/context.py +3 -4
  113. maleo_foundation/utils/exceptions.py +50 -28
  114. maleo_foundation/utils/extractor.py +18 -6
  115. maleo_foundation/utils/formatter/__init__.py +2 -1
  116. maleo_foundation/utils/formatter/case.py +5 -4
  117. maleo_foundation/utils/loaders/__init__.py +2 -1
  118. maleo_foundation/utils/loaders/credential/__init__.py +2 -1
  119. maleo_foundation/utils/loaders/credential/google.py +29 -15
  120. maleo_foundation/utils/loaders/json.py +3 -2
  121. maleo_foundation/utils/loaders/key/__init__.py +2 -1
  122. maleo_foundation/utils/loaders/key/rsa.py +26 -13
  123. maleo_foundation/utils/loaders/yaml.py +2 -1
  124. maleo_foundation/utils/logging.py +70 -46
  125. maleo_foundation/utils/merger.py +7 -9
  126. maleo_foundation/utils/query.py +41 -34
  127. maleo_foundation/utils/repository.py +28 -13
  128. maleo_foundation/utils/searcher.py +4 -6
  129. {maleo_foundation-0.3.46.dist-info → maleo_foundation-0.3.47.dist-info}/METADATA +14 -1
  130. maleo_foundation-0.3.47.dist-info/RECORD +137 -0
  131. maleo_foundation/expanded_types/repository.py +0 -68
  132. maleo_foundation/models/transfers/results/service/repository.py +0 -39
  133. maleo_foundation-0.3.46.dist-info/RECORD +0 -139
  134. {maleo_foundation-0.3.46.dist-info → maleo_foundation-0.3.47.dist-info}/WHEEL +0 -0
  135. {maleo_foundation-0.3.46.dist-info → maleo_foundation-0.3.47.dist-info}/top_level.txt +0 -0
@@ -5,11 +5,10 @@ from google.oauth2.service_account import Credentials
5
5
  from pathlib import Path
6
6
  from typing import Optional, Union
7
7
 
8
+
8
9
  class GoogleCredentialsLoader:
9
10
  @staticmethod
10
- def load(
11
- credentials_path: Optional[Union[Path, str]] = None
12
- ) -> Credentials:
11
+ def load(credentials_path: Optional[Union[Path, str]] = None) -> Credentials:
13
12
  """
14
13
  Load Google service account credentials with guaranteed project_id.
15
14
  Priority:
@@ -49,26 +48,37 @@ class GoogleCredentialsLoader:
49
48
  """Load credentials from a service account file."""
50
49
  try:
51
50
  # First, read and validate the service account file
52
- with open(credentials_path, 'r') as f:
51
+ with open(credentials_path, "r") as f:
53
52
  service_account_info = json.load(f)
54
53
 
55
54
  # Ensure project_id is present in the file
56
- if 'project_id' not in service_account_info or not service_account_info['project_id']:
57
- raise ValueError(f"Service account file {credentials_path} does not contain project_id")
55
+ if (
56
+ "project_id" not in service_account_info
57
+ or not service_account_info["project_id"]
58
+ ):
59
+ raise ValueError(
60
+ f"Service account file {credentials_path} does not contain project_id"
61
+ )
58
62
 
59
63
  # Load credentials from the file
60
64
  credentials = Credentials.from_service_account_file(str(credentials_path))
61
65
 
62
66
  # Double-check that project_id is available in the credentials object
63
67
  if not credentials.project_id:
64
- raise ValueError(f"Loaded credentials from {credentials_path} do not have project_id")
68
+ raise ValueError(
69
+ f"Loaded credentials from {credentials_path} do not have project_id"
70
+ )
65
71
 
66
72
  return credentials
67
73
 
68
74
  except json.JSONDecodeError as e:
69
- raise ValueError(f"Invalid JSON in credentials file {credentials_path}: {str(e)}")
75
+ raise ValueError(
76
+ f"Invalid JSON in credentials file {credentials_path}: {str(e)}"
77
+ )
70
78
  except Exception as e:
71
- raise ValueError(f"Failed to load credentials from file {credentials_path}: {str(e)}")
79
+ raise ValueError(
80
+ f"Failed to load credentials from file {credentials_path}: {str(e)}"
81
+ )
72
82
 
73
83
  @staticmethod
74
84
  def _load_from_default() -> Credentials:
@@ -110,10 +120,10 @@ class GoogleCredentialsLoader:
110
120
  def _get_project_id_from_env() -> str:
111
121
  """Get project_id from environment variables."""
112
122
  project_id = (
113
- os.getenv("GOOGLE_CLOUD_PROJECT") or
114
- os.getenv("GCLOUD_PROJECT") or
115
- os.getenv("GCP_PROJECT") or
116
- os.getenv("PROJECT_ID")
123
+ os.getenv("GOOGLE_CLOUD_PROJECT")
124
+ or os.getenv("GCLOUD_PROJECT")
125
+ or os.getenv("GCP_PROJECT")
126
+ or os.getenv("PROJECT_ID")
117
127
  )
118
128
 
119
129
  if not project_id:
@@ -129,10 +139,14 @@ class GoogleCredentialsLoader:
129
139
  def validate_credentials(credentials: Credentials) -> None:
130
140
  """Validate that credentials are service account credentials with project_id."""
131
141
  if not isinstance(credentials, Credentials):
132
- raise ValueError("Credentials must be google.oauth2.service_account.Credentials")
142
+ raise ValueError(
143
+ "Credentials must be google.oauth2.service_account.Credentials"
144
+ )
133
145
 
134
146
  if not credentials.project_id:
135
147
  raise ValueError("Service account credentials must have project_id")
136
148
 
137
149
  if not credentials.service_account_email:
138
- raise ValueError("Service account credentials must have service_account_email")
150
+ raise ValueError(
151
+ "Service account credentials must have service_account_email"
152
+ )
@@ -2,6 +2,7 @@ import json
2
2
  from typing import Dict, List, Union, Any
3
3
  from pathlib import Path
4
4
 
5
+
5
6
  class JSONLoader:
6
7
  @staticmethod
7
8
  def load_from_path(path: Union[Path, str]) -> Union[Dict[str, Any], List[Any]]:
@@ -10,9 +11,9 @@ class JSONLoader:
10
11
  if not file_path.is_file():
11
12
  raise FileNotFoundError(f"File not found: {file_path}")
12
13
 
13
- with open(file_path, 'r') as f:
14
+ with open(file_path, "r") as f:
14
15
  return json.load(f)
15
16
 
16
17
  @staticmethod
17
18
  def load_from_string(string: str) -> Dict:
18
- return json.loads(string)
19
+ return json.loads(string)
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
  from .rsa import RSAKeyLoader
3
3
 
4
+
4
5
  class KeyLoaders:
5
- RSA = RSAKeyLoader
6
+ RSA = RSAKeyLoader
@@ -5,21 +5,27 @@ from typing import Optional, Union
5
5
  from maleo_foundation.enums import BaseEnums
6
6
  from maleo_foundation.types import BaseTypes
7
7
 
8
+
8
9
  class RSAKeyLoader:
9
10
  @staticmethod
10
11
  def load_with_cryptography(
11
- type:BaseEnums.KeyType,
12
- data:Optional[Union[bytes, str]] = None,
13
- path:Optional[Union[str, Path]] = None,
14
- password:Optional[Union[bytes, str]] = None,
15
- format:BaseEnums.KeyFormatType = BaseEnums.KeyFormatType.STRING,
12
+ type: BaseEnums.KeyType,
13
+ data: Optional[Union[bytes, str]] = None,
14
+ path: Optional[Union[str, Path]] = None,
15
+ password: Optional[Union[bytes, str]] = None,
16
+ format: BaseEnums.KeyFormatType = BaseEnums.KeyFormatType.STRING,
16
17
  ) -> Union[bytes, str]:
17
18
  if not isinstance(type, BaseEnums.KeyType):
18
19
  raise TypeError("Invalid key type")
19
20
 
21
+ if data is None and path is None:
22
+ raise ValueError("Either data or path must be provided")
23
+
20
24
  if data is not None and path is not None:
21
25
  raise ValueError("Only either data or path will be accepted as parameters")
22
26
 
27
+ key_data: Optional[bytes] = None
28
+
23
29
  if data is not None:
24
30
  if isinstance(data, bytes):
25
31
  key_data = data
@@ -36,6 +42,9 @@ class RSAKeyLoader:
36
42
 
37
43
  key_data = file_path.read_bytes()
38
44
 
45
+ if key_data is None:
46
+ raise ValueError("Key data is required")
47
+
39
48
  if password is not None and not isinstance(password, (str, bytes)):
40
49
  raise TypeError("Invalid passsword type")
41
50
 
@@ -50,7 +59,7 @@ class RSAKeyLoader:
50
59
  private_key_bytes = private_key.private_bytes(
51
60
  encoding=serialization.Encoding.PEM,
52
61
  format=serialization.PrivateFormat.PKCS8,
53
- encryption_algorithm=serialization.NoEncryption()
62
+ encryption_algorithm=serialization.NoEncryption(),
54
63
  )
55
64
  if format == BaseEnums.KeyFormatType.BYTES:
56
65
  return private_key_bytes
@@ -61,7 +70,7 @@ class RSAKeyLoader:
61
70
  public_key = serialization.load_pem_public_key(key_data)
62
71
  public_key_bytes = public_key.public_bytes(
63
72
  encoding=serialization.Encoding.PEM,
64
- format=serialization.PublicFormat.SubjectPublicKeyInfo
73
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
65
74
  )
66
75
  if format == BaseEnums.KeyFormatType.BYTES:
67
76
  return public_key_bytes
@@ -70,9 +79,9 @@ class RSAKeyLoader:
70
79
 
71
80
  @staticmethod
72
81
  def load_with_pycryptodome(
73
- type:BaseEnums.KeyType,
74
- extern_key:Union[bytes, str],
75
- passphrase:BaseTypes.OptionalString = None,
82
+ type: BaseEnums.KeyType,
83
+ extern_key: Union[bytes, str],
84
+ passphrase: BaseTypes.OptionalString = None,
76
85
  ) -> RSA.RsaKey:
77
86
  if not isinstance(type, BaseEnums.KeyType):
78
87
  raise TypeError("Invalid key type")
@@ -83,11 +92,15 @@ class RSAKeyLoader:
83
92
  if type == BaseEnums.KeyType.PRIVATE:
84
93
  private_key = RSA.import_key(extern_key=extern_key, passphrase=passphrase)
85
94
  if not private_key.has_private():
86
- raise TypeError("Invalid chosen key type, the private key did not has private inside it")
95
+ raise TypeError(
96
+ "Invalid chosen key type, the private key did not has private inside it"
97
+ )
87
98
  return private_key
88
99
 
89
100
  if type == BaseEnums.KeyType.PUBLIC:
90
101
  public_key = RSA.import_key(extern_key=extern_key)
91
102
  if public_key.has_private():
92
- raise TypeError("Invalid chosen key type, the public key did has private inside it")
93
- return public_key
103
+ raise TypeError(
104
+ "Invalid chosen key type, the public key did has private inside it"
105
+ )
106
+ return public_key
@@ -2,6 +2,7 @@ import yaml
2
2
  from pathlib import Path
3
3
  from typing import Dict, Union
4
4
 
5
+
5
6
  class YAMLLoader:
6
7
  @staticmethod
7
8
  def load_from_path(path: Union[Path, str]) -> Dict:
@@ -15,4 +16,4 @@ class YAMLLoader:
15
16
 
16
17
  @staticmethod
17
18
  def load_from_string(string: str) -> Dict:
18
- return yaml.safe_load(string)
19
+ return yaml.safe_load(string)
@@ -11,21 +11,25 @@ from maleo_foundation.enums import BaseEnums
11
11
  from maleo_foundation.types import BaseTypes
12
12
  from maleo_foundation.utils.loaders.credential.google import GoogleCredentialsLoader
13
13
 
14
+
14
15
  class GoogleCloudLogging:
15
- def __init__(
16
- self,
17
- credentials_path: Optional[Union[Path, str]] = None
18
- ) -> None:
19
- self._credentials = GoogleCredentialsLoader.load(credentials_path=credentials_path)
16
+ def __init__(self, credentials_path: Optional[Union[Path, str]] = None) -> None:
17
+ self._credentials = GoogleCredentialsLoader.load(
18
+ credentials_path=credentials_path
19
+ )
20
20
  self._client = Client(credentials=self._credentials)
21
21
  self._client.setup_logging()
22
22
 
23
23
  @property
24
24
  def credentials(self) -> Credentials:
25
+ if self._credentials is None:
26
+ raise ValueError("Credentials have not been initialized.")
25
27
  return self._credentials
26
28
 
27
29
  @property
28
30
  def client(self) -> Client:
31
+ if self._client is None:
32
+ raise ValueError("Client has not been initialized.")
29
33
  return self._client
30
34
 
31
35
  def dispose(self) -> None:
@@ -34,18 +38,21 @@ class GoogleCloudLogging:
34
38
  if self._client is not None:
35
39
  self._client = None
36
40
 
37
- def create_handler(
38
- self,
39
- name: str
40
- ) -> CloudLoggingHandler:
41
+ def create_handler(self, name: str) -> CloudLoggingHandler:
41
42
  return CloudLoggingHandler(client=self._client, name=name)
42
43
 
44
+
43
45
  class SimpleConfig(BaseModel):
44
46
  model_config = ConfigDict(arbitrary_types_allowed=True)
45
47
 
46
48
  dir: str = Field(..., description="Log's directory")
47
- level: BaseEnums.LoggerLevel = Field(BaseEnums.LoggerLevel.INFO, description="Log's level")
48
- google_cloud_logging: Optional[GoogleCloudLogging] = Field(default_factory=GoogleCloudLogging, description="Google cloud logging")
49
+ level: BaseEnums.LoggerLevel = Field(
50
+ BaseEnums.LoggerLevel.INFO, description="Log's level"
51
+ )
52
+ google_cloud_logging: Optional[GoogleCloudLogging] = Field(
53
+ default_factory=GoogleCloudLogging, description="Google cloud logging"
54
+ )
55
+
49
56
 
50
57
  class BaseLogger(logging.Logger):
51
58
  def __init__(
@@ -55,50 +62,58 @@ class BaseLogger(logging.Logger):
55
62
  service_key: BaseTypes.OptionalString = None,
56
63
  client_key: BaseTypes.OptionalString = None,
57
64
  level: BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO,
58
- google_cloud_logging: Optional[GoogleCloudLogging] = None
65
+ google_cloud_logging: Optional[GoogleCloudLogging] = None,
59
66
  ):
60
- self._type = type #* Declare logger type
67
+ self._type = type # * Declare logger type
61
68
 
62
- #* Ensure service_key exists
69
+ # * Ensure service_key exists
63
70
  self._service_key = service_key or os.getenv("SERVICE_KEY")
64
71
  if self._service_key is None:
65
- raise ValueError("SERVICE_KEY environment variable must be set if 'service_key' is set to None")
72
+ raise ValueError(
73
+ "SERVICE_KEY environment variable must be set if 'service_key' is set to None"
74
+ )
66
75
 
67
- self._client_key = client_key #* Declare client key
76
+ self._client_key = client_key # * Declare client key
68
77
 
69
- #* Ensure client_key is valid if logger type is a client
78
+ # * Ensure client_key is valid if logger type is a client
70
79
  if self._type == BaseEnums.LoggerType.CLIENT and self._client_key is None:
71
- raise ValueError("'client_key' parameter must be provided if 'logger_type' is 'client'")
80
+ raise ValueError(
81
+ "'client_key' parameter must be provided if 'logger_type' is 'client'"
82
+ )
72
83
 
73
- #* Define logger name
84
+ # * Define logger name
74
85
  if self._type == BaseEnums.LoggerType.CLIENT:
75
86
  self._name = f"{self._service_key} - {self._type} - {self._client_key}"
76
87
  else:
77
88
  self._name = f"{self._service_key} - {self._type}"
78
89
 
79
- super().__init__(self._name, level) #* Init the superclass's logger
90
+ super().__init__(self._name, level) # * Init the superclass's logger
80
91
 
81
- #* Clear existing handlers to prevent duplicates
92
+ # * Clear existing handlers to prevent duplicates
82
93
  for handler in list(self.handlers):
83
94
  self.removeHandler(handler)
84
95
  handler.close()
85
96
 
86
- #* Formatter for logs
87
- formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
97
+ # * Formatter for logs
98
+ formatter = logging.Formatter(
99
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
100
+ )
88
101
 
89
- #* Console handler
102
+ # * Console handler
90
103
  console_handler = logging.StreamHandler()
91
104
  console_handler.setFormatter(formatter)
92
105
  self.addHandler(console_handler)
93
106
 
94
- #* Google Cloud Logging handler (If enabled)
107
+ # * Google Cloud Logging handler (If enabled)
95
108
  if google_cloud_logging is not None:
96
- cloud_logging_handler = google_cloud_logging.create_handler(name=self._name.replace(" ", ""))
109
+ cloud_logging_handler = google_cloud_logging.create_handler(
110
+ name=self._name.replace(" ", "")
111
+ )
97
112
  self.addHandler(cloud_logging_handler)
98
113
  else:
99
114
  self.info("Cloud logging is not configured.")
100
115
 
101
- #* Define log directory
116
+ # * Define log directory
102
117
  if self._type == BaseEnums.LoggerType.CLIENT:
103
118
  log_dir = f"{self._type}/{self._client_key}"
104
119
  else:
@@ -106,11 +121,11 @@ class BaseLogger(logging.Logger):
106
121
  self._log_dir = os.path.join(dir, log_dir)
107
122
  os.makedirs(self._log_dir, exist_ok=True)
108
123
 
109
- #* Generate timestamped filename
124
+ # * Generate timestamped filename
110
125
  timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
111
126
  log_filename = os.path.join(self._log_dir, f"{timestamp}.log")
112
127
 
113
- #* File handler
128
+ # * File handler
114
129
  file_handler = logging.FileHandler(log_filename, mode="a")
115
130
  file_handler.setFormatter(formatter)
116
131
  self.addHandler(file_handler)
@@ -121,6 +136,8 @@ class BaseLogger(logging.Logger):
121
136
 
122
137
  @property
123
138
  def service(self) -> str:
139
+ if self._service_key is None:
140
+ raise ValueError("Service key has not been initialized.")
124
141
  return self._service_key
125
142
 
126
143
  @property
@@ -142,13 +159,14 @@ class BaseLogger(logging.Logger):
142
159
  handler.close()
143
160
  self.handlers.clear()
144
161
 
162
+
145
163
  class ApplicationLogger(BaseLogger):
146
164
  def __init__(
147
165
  self,
148
166
  dir: str,
149
167
  service_key: BaseTypes.OptionalString = None,
150
168
  level: BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO,
151
- google_cloud_logging: Optional[GoogleCloudLogging] = None
169
+ google_cloud_logging: Optional[GoogleCloudLogging] = None,
152
170
  ):
153
171
  super().__init__(
154
172
  dir=dir,
@@ -156,16 +174,17 @@ class ApplicationLogger(BaseLogger):
156
174
  service_key=service_key,
157
175
  client_key=None,
158
176
  level=level,
159
- google_cloud_logging=google_cloud_logging
177
+ google_cloud_logging=google_cloud_logging,
160
178
  )
161
179
 
180
+
162
181
  class CacheLogger(BaseLogger):
163
182
  def __init__(
164
183
  self,
165
184
  dir: str,
166
185
  service_key: BaseTypes.OptionalString = None,
167
186
  level: BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO,
168
- google_cloud_logging: Optional[GoogleCloudLogging] = None
187
+ google_cloud_logging: Optional[GoogleCloudLogging] = None,
169
188
  ):
170
189
  super().__init__(
171
190
  dir=dir,
@@ -173,9 +192,10 @@ class CacheLogger(BaseLogger):
173
192
  service_key=service_key,
174
193
  client_key=None,
175
194
  level=level,
176
- google_cloud_logging=google_cloud_logging
195
+ google_cloud_logging=google_cloud_logging,
177
196
  )
178
197
 
198
+
179
199
  class ClientLogger(BaseLogger):
180
200
  def __init__(
181
201
  self,
@@ -183,7 +203,7 @@ class ClientLogger(BaseLogger):
183
203
  client_key: str,
184
204
  service_key: BaseTypes.OptionalString = None,
185
205
  level: BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO,
186
- google_cloud_logging: Optional[GoogleCloudLogging] = None
206
+ google_cloud_logging: Optional[GoogleCloudLogging] = None,
187
207
  ):
188
208
  super().__init__(
189
209
  dir=dir,
@@ -191,16 +211,17 @@ class ClientLogger(BaseLogger):
191
211
  service_key=service_key,
192
212
  client_key=client_key,
193
213
  level=level,
194
- google_cloud_logging=google_cloud_logging
214
+ google_cloud_logging=google_cloud_logging,
195
215
  )
196
216
 
217
+
197
218
  class DatabaseLogger(BaseLogger):
198
219
  def __init__(
199
220
  self,
200
221
  dir: str,
201
222
  service_key: BaseTypes.OptionalString = None,
202
- level = BaseEnums.LoggerLevel.INFO,
203
- google_cloud_logging = None
223
+ level=BaseEnums.LoggerLevel.INFO,
224
+ google_cloud_logging=None,
204
225
  ):
205
226
  super().__init__(
206
227
  dir=dir,
@@ -208,16 +229,17 @@ class DatabaseLogger(BaseLogger):
208
229
  service_key=service_key,
209
230
  client_key=None,
210
231
  level=level,
211
- google_cloud_logging=google_cloud_logging
232
+ google_cloud_logging=google_cloud_logging,
212
233
  )
213
234
 
235
+
214
236
  class MiddlewareLogger(BaseLogger):
215
237
  def __init__(
216
238
  self,
217
239
  dir: str,
218
240
  service_key: BaseTypes.OptionalString = None,
219
- level = BaseEnums.LoggerLevel.INFO,
220
- google_cloud_logging = None
241
+ level=BaseEnums.LoggerLevel.INFO,
242
+ google_cloud_logging=None,
221
243
  ):
222
244
  super().__init__(
223
245
  dir=dir,
@@ -225,16 +247,17 @@ class MiddlewareLogger(BaseLogger):
225
247
  service_key=service_key,
226
248
  client_key=None,
227
249
  level=level,
228
- google_cloud_logging=google_cloud_logging
250
+ google_cloud_logging=google_cloud_logging,
229
251
  )
230
252
 
253
+
231
254
  class RepositoryLogger(BaseLogger):
232
255
  def __init__(
233
256
  self,
234
257
  dir: str,
235
258
  service_key: BaseTypes.OptionalString = None,
236
259
  level: BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO,
237
- google_cloud_logging: Optional[GoogleCloudLogging] = None
260
+ google_cloud_logging: Optional[GoogleCloudLogging] = None,
238
261
  ):
239
262
  super().__init__(
240
263
  dir=dir,
@@ -242,16 +265,17 @@ class RepositoryLogger(BaseLogger):
242
265
  service_key=service_key,
243
266
  client_key=None,
244
267
  level=level,
245
- google_cloud_logging=google_cloud_logging
268
+ google_cloud_logging=google_cloud_logging,
246
269
  )
247
270
 
271
+
248
272
  class ServiceLogger(BaseLogger):
249
273
  def __init__(
250
274
  self,
251
275
  dir: str,
252
276
  service_key: BaseTypes.OptionalString = None,
253
277
  level: BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO,
254
- google_cloud_logging: Optional[GoogleCloudLogging] = None
278
+ google_cloud_logging: Optional[GoogleCloudLogging] = None,
255
279
  ):
256
280
  super().__init__(
257
281
  dir=dir,
@@ -259,5 +283,5 @@ class ServiceLogger(BaseLogger):
259
283
  service_key=service_key,
260
284
  client_key=None,
261
285
  level=level,
262
- google_cloud_logging=google_cloud_logging
263
- )
286
+ google_cloud_logging=google_cloud_logging,
287
+ )
@@ -1,12 +1,10 @@
1
1
  from collections.abc import Mapping
2
- from typing import Dict
2
+ from typing import Dict, Any
3
3
 
4
- def deep_merge(*obj: Dict) -> Dict:
5
- def merge_dicts(
6
- a: Dict,
7
- b: Dict
8
- ) -> Dict:
9
- result = dict(a)
4
+
5
+ def deep_merge(*obj: Dict[str, Any]) -> Dict[str, Any]:
6
+ def merge_dicts(a: Mapping[str, Any], b: Mapping[str, Any]) -> Dict[str, Any]:
7
+ result = dict(a) # create a mutable copy
10
8
  for key, value in b.items():
11
9
  if (
12
10
  key in result
@@ -18,7 +16,7 @@ def deep_merge(*obj: Dict) -> Dict:
18
16
  result[key] = value
19
17
  return result
20
18
 
21
- merged = {}
19
+ merged: Dict[str, Any] = {}
22
20
  for ob in obj:
23
21
  merged = merge_dicts(merged, ob)
24
- return merged
22
+ return merged