blackant-sdk 1.0.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.
- blackant/__init__.py +31 -0
- blackant/auth/__init__.py +10 -0
- blackant/auth/blackant_auth.py +518 -0
- blackant/auth/keycloak_manager.py +363 -0
- blackant/auth/request_id.py +52 -0
- blackant/auth/role_assignment.py +443 -0
- blackant/auth/tokens.py +57 -0
- blackant/client.py +400 -0
- blackant/config/__init__.py +0 -0
- blackant/config/docker_config.py +457 -0
- blackant/config/keycloak_admin_config.py +107 -0
- blackant/docker/__init__.py +12 -0
- blackant/docker/builder.py +616 -0
- blackant/docker/client.py +983 -0
- blackant/docker/dao.py +462 -0
- blackant/docker/registry.py +172 -0
- blackant/exceptions.py +111 -0
- blackant/http/__init__.py +8 -0
- blackant/http/client.py +125 -0
- blackant/patterns/__init__.py +1 -0
- blackant/patterns/singleton.py +20 -0
- blackant/services/__init__.py +10 -0
- blackant/services/dao.py +414 -0
- blackant/services/registry.py +635 -0
- blackant/utils/__init__.py +8 -0
- blackant/utils/initialization.py +32 -0
- blackant/utils/logging.py +337 -0
- blackant/utils/request_id.py +13 -0
- blackant/utils/store.py +50 -0
- blackant_sdk-1.0.2.dist-info/METADATA +117 -0
- blackant_sdk-1.0.2.dist-info/RECORD +70 -0
- blackant_sdk-1.0.2.dist-info/WHEEL +5 -0
- blackant_sdk-1.0.2.dist-info/top_level.txt +5 -0
- calculation/__init__.py +0 -0
- calculation/base.py +26 -0
- calculation/errors.py +2 -0
- calculation/impl/__init__.py +0 -0
- calculation/impl/my_calculation.py +144 -0
- calculation/impl/simple_calc.py +53 -0
- calculation/impl/test.py +1 -0
- calculation/impl/test_calc.py +36 -0
- calculation/loader.py +227 -0
- notifinations/__init__.py +8 -0
- notifinations/mail_sender.py +212 -0
- storage/__init__.py +0 -0
- storage/errors.py +10 -0
- storage/factory.py +26 -0
- storage/interface.py +19 -0
- storage/minio.py +106 -0
- task/__init__.py +0 -0
- task/dao.py +38 -0
- task/errors.py +10 -0
- task/log_adapter.py +11 -0
- task/parsers/__init__.py +0 -0
- task/parsers/base.py +13 -0
- task/parsers/callback.py +40 -0
- task/parsers/cmd_args.py +52 -0
- task/parsers/freetext.py +19 -0
- task/parsers/objects.py +50 -0
- task/parsers/request.py +56 -0
- task/resource.py +84 -0
- task/states/__init__.py +0 -0
- task/states/base.py +14 -0
- task/states/error.py +47 -0
- task/states/idle.py +12 -0
- task/states/ready.py +51 -0
- task/states/running.py +21 -0
- task/states/set_up.py +40 -0
- task/states/tear_down.py +29 -0
- task/task.py +358 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# src/blackant/utils/logging.py
|
|
2
|
+
"""BlackAnt SDK Logging module.
|
|
3
|
+
|
|
4
|
+
This module provides unified logging functionality for the entire BlackAnt SDK.
|
|
5
|
+
Supports colorized console output, file logging, and request tracking.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import sys
|
|
10
|
+
import threading
|
|
11
|
+
import re
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional, Dict, Union
|
|
15
|
+
from colorama import Fore, Style, init
|
|
16
|
+
|
|
17
|
+
init(autoreset=True)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CustomFormatter(logging.Formatter):
|
|
21
|
+
"""Custom formatter with colorized log levels and abbreviated level names."""
|
|
22
|
+
|
|
23
|
+
LEVEL_ABBREVIATIONS = {
|
|
24
|
+
logging.DEBUG: "DBG",
|
|
25
|
+
logging.INFO: "INF",
|
|
26
|
+
logging.WARNING: "WAR",
|
|
27
|
+
logging.ERROR: "ERR",
|
|
28
|
+
logging.CRITICAL: "CRT",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
LEVEL_COLORS = {
|
|
32
|
+
logging.DEBUG: Fore.WHITE,
|
|
33
|
+
logging.INFO: Fore.CYAN,
|
|
34
|
+
logging.WARNING: Fore.YELLOW,
|
|
35
|
+
logging.ERROR: Fore.RED,
|
|
36
|
+
logging.CRITICAL: Fore.LIGHTRED_EX,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def __init__(self, use_colors: bool = True, include_request_id: bool = True):
|
|
40
|
+
self.use_colors = use_colors
|
|
41
|
+
self.include_request_id = include_request_id
|
|
42
|
+
|
|
43
|
+
if include_request_id:
|
|
44
|
+
template = (
|
|
45
|
+
"[{asctime}].[{name}].[{levelname}].[{request_id}] -> "
|
|
46
|
+
"{message} \t || {module}:{funcName}"
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
template = "[{asctime}].[{name}].[{levelname}] -> {message} \t || {module}:{funcName}"
|
|
50
|
+
|
|
51
|
+
super().__init__(template, style="{", datefmt="%Y-%m-%d %H:%M:%S")
|
|
52
|
+
|
|
53
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
54
|
+
if self.include_request_id:
|
|
55
|
+
request_id = getattr(record, "request_id", "NO-REQ-ID")
|
|
56
|
+
record.request_id = request_id
|
|
57
|
+
|
|
58
|
+
level_abbr = self.LEVEL_ABBREVIATIONS.get(record.levelno, record.levelname[:3])
|
|
59
|
+
|
|
60
|
+
if self.use_colors:
|
|
61
|
+
color = self.LEVEL_COLORS.get(record.levelno, "")
|
|
62
|
+
levelname_colored = f"{color}{level_abbr}{Style.RESET_ALL}"
|
|
63
|
+
msg_colored = f"{color}{record.getMessage()}{Style.RESET_ALL}"
|
|
64
|
+
else:
|
|
65
|
+
levelname_colored = level_abbr
|
|
66
|
+
msg_colored = record.getMessage()
|
|
67
|
+
|
|
68
|
+
record_copy = logging.makeLogRecord(record.__dict__)
|
|
69
|
+
record_copy.levelname = levelname_colored
|
|
70
|
+
record_copy.msg = msg_colored
|
|
71
|
+
|
|
72
|
+
return super().format(record_copy)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SensitiveDataFilter(logging.Filter): # pylint: disable=too-few-public-methods
|
|
76
|
+
"""Filter to scrub sensitive data from log messages."""
|
|
77
|
+
|
|
78
|
+
DEFAULT_PATTERNS = [
|
|
79
|
+
r"Bearer\s+[A-Za-z0-9\-_]+",
|
|
80
|
+
r'token["\s:=]+[A-Za-z0-9\-_\.]+',
|
|
81
|
+
r'password["\s:=]+\S+',
|
|
82
|
+
r'api_key["\s:=]+[A-Za-z0-9\-_]+',
|
|
83
|
+
r"Authorization:\s*[^\s]+",
|
|
84
|
+
r"X-API-Key:\s*[^\s]+",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
def __init__(self, patterns: Optional[list] = None):
|
|
88
|
+
super().__init__()
|
|
89
|
+
self.patterns = patterns or self.DEFAULT_PATTERNS
|
|
90
|
+
self._compiled_patterns = [re.compile(pattern, re.IGNORECASE) for pattern in self.patterns]
|
|
91
|
+
|
|
92
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
93
|
+
message = record.getMessage()
|
|
94
|
+
for pattern in self._compiled_patterns:
|
|
95
|
+
message = pattern.sub("[REDACTED]", message)
|
|
96
|
+
|
|
97
|
+
record.msg = message
|
|
98
|
+
record.args = ()
|
|
99
|
+
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class RequestIdFilter(logging.Filter):
|
|
104
|
+
"""Filter that adds request ID context to log records."""
|
|
105
|
+
|
|
106
|
+
def __init__(self):
|
|
107
|
+
super().__init__()
|
|
108
|
+
self._local = threading.local()
|
|
109
|
+
|
|
110
|
+
def set_request_id(self, request_id: str):
|
|
111
|
+
self._local.request_id = request_id
|
|
112
|
+
|
|
113
|
+
def clear_request_id(self):
|
|
114
|
+
if hasattr(self._local, "request_id"):
|
|
115
|
+
delattr(self._local, "request_id")
|
|
116
|
+
|
|
117
|
+
def get_request_id(self) -> Optional[str]:
|
|
118
|
+
return getattr(self._local, "request_id", None)
|
|
119
|
+
|
|
120
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
121
|
+
request_id = self.get_request_id()
|
|
122
|
+
record.request_id = request_id or "NO-REQ-ID"
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class LoggerManager: # pylint: disable=too-many-instance-attributes
|
|
127
|
+
"""Central logger manager for the BlackAnt SDK."""
|
|
128
|
+
|
|
129
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
130
|
+
self,
|
|
131
|
+
app_name: str = "BlackAnt",
|
|
132
|
+
default_log_file: Optional[str] = None,
|
|
133
|
+
log_level: Union[str, int] = logging.INFO,
|
|
134
|
+
enable_colors: bool = True,
|
|
135
|
+
enable_request_tracking: bool = True,
|
|
136
|
+
enable_sensitive_filter: bool = True,
|
|
137
|
+
):
|
|
138
|
+
self.app_name = app_name
|
|
139
|
+
self.enable_colors = enable_colors
|
|
140
|
+
self.enable_request_tracking = enable_request_tracking
|
|
141
|
+
self.enable_sensitive_filter = enable_sensitive_filter
|
|
142
|
+
|
|
143
|
+
if default_log_file is None:
|
|
144
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
145
|
+
default_log_file = f"{app_name.lower()}_{timestamp}.log"
|
|
146
|
+
|
|
147
|
+
self.log_file = Path(default_log_file)
|
|
148
|
+
|
|
149
|
+
self.request_id_filter = RequestIdFilter() if enable_request_tracking else None
|
|
150
|
+
self.sensitive_filter = SensitiveDataFilter() if enable_sensitive_filter else None
|
|
151
|
+
|
|
152
|
+
self._setup_root_logger(log_level)
|
|
153
|
+
|
|
154
|
+
self._module_loggers: Dict[str, logging.Logger] = {}
|
|
155
|
+
|
|
156
|
+
def _setup_root_logger(self, log_level: Union[str, int]):
|
|
157
|
+
root_logger = logging.getLogger(self.app_name)
|
|
158
|
+
root_logger.setLevel(log_level)
|
|
159
|
+
root_logger.propagate = False
|
|
160
|
+
|
|
161
|
+
for handler in root_logger.handlers[:]:
|
|
162
|
+
root_logger.removeHandler(handler)
|
|
163
|
+
|
|
164
|
+
console_handler = self._create_console_handler()
|
|
165
|
+
root_logger.addHandler(console_handler)
|
|
166
|
+
|
|
167
|
+
file_handler = self._create_file_handler(self.log_file)
|
|
168
|
+
root_logger.addHandler(file_handler)
|
|
169
|
+
|
|
170
|
+
self.root_logger = root_logger
|
|
171
|
+
|
|
172
|
+
def _create_console_handler(self) -> logging.StreamHandler:
|
|
173
|
+
handler = logging.StreamHandler(sys.stdout)
|
|
174
|
+
handler.setLevel(logging.INFO)
|
|
175
|
+
|
|
176
|
+
formatter = CustomFormatter(
|
|
177
|
+
use_colors=self.enable_colors, include_request_id=self.enable_request_tracking
|
|
178
|
+
)
|
|
179
|
+
handler.setFormatter(formatter)
|
|
180
|
+
|
|
181
|
+
if self.request_id_filter:
|
|
182
|
+
handler.addFilter(self.request_id_filter)
|
|
183
|
+
|
|
184
|
+
if self.sensitive_filter:
|
|
185
|
+
handler.addFilter(self.sensitive_filter)
|
|
186
|
+
|
|
187
|
+
return handler
|
|
188
|
+
|
|
189
|
+
def _create_file_handler(self, log_file: Path) -> logging.FileHandler:
|
|
190
|
+
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
191
|
+
|
|
192
|
+
handler = logging.FileHandler(log_file, mode="w", encoding="utf-8")
|
|
193
|
+
handler.setLevel(logging.DEBUG)
|
|
194
|
+
|
|
195
|
+
formatter = CustomFormatter(
|
|
196
|
+
use_colors=False, include_request_id=self.enable_request_tracking
|
|
197
|
+
)
|
|
198
|
+
handler.setFormatter(formatter)
|
|
199
|
+
|
|
200
|
+
if self.request_id_filter:
|
|
201
|
+
handler.addFilter(self.request_id_filter)
|
|
202
|
+
|
|
203
|
+
if self.sensitive_filter:
|
|
204
|
+
handler.addFilter(self.sensitive_filter)
|
|
205
|
+
|
|
206
|
+
return handler
|
|
207
|
+
|
|
208
|
+
def get_logger(self, name: str) -> logging.Logger:
|
|
209
|
+
full_name = f"{self.app_name}.{name}" if name else self.app_name
|
|
210
|
+
|
|
211
|
+
if full_name not in self._module_loggers:
|
|
212
|
+
logger = logging.getLogger(full_name)
|
|
213
|
+
logger.setLevel(self.root_logger.level)
|
|
214
|
+
|
|
215
|
+
if not logger.handlers:
|
|
216
|
+
logger.parent = self.root_logger
|
|
217
|
+
|
|
218
|
+
self._module_loggers[full_name] = logger
|
|
219
|
+
|
|
220
|
+
return self._module_loggers[full_name]
|
|
221
|
+
|
|
222
|
+
def set_request_id(self, request_id: str):
|
|
223
|
+
if self.request_id_filter:
|
|
224
|
+
self.request_id_filter.set_request_id(request_id)
|
|
225
|
+
|
|
226
|
+
def clear_request_id(self):
|
|
227
|
+
if self.request_id_filter:
|
|
228
|
+
self.request_id_filter.clear_request_id()
|
|
229
|
+
|
|
230
|
+
def update_log_file(self, new_log_file: Union[str, Path]):
|
|
231
|
+
new_path = Path(new_log_file)
|
|
232
|
+
|
|
233
|
+
for handler in self.root_logger.handlers[:]:
|
|
234
|
+
if isinstance(handler, logging.FileHandler):
|
|
235
|
+
self.root_logger.removeHandler(handler)
|
|
236
|
+
handler.close()
|
|
237
|
+
|
|
238
|
+
new_file_handler = self._create_file_handler(new_path)
|
|
239
|
+
self.root_logger.addHandler(new_file_handler)
|
|
240
|
+
|
|
241
|
+
self.log_file = new_path
|
|
242
|
+
self.root_logger.info("Log file updated to: %s", new_path)
|
|
243
|
+
|
|
244
|
+
def set_level(self, level: Union[str, int]):
|
|
245
|
+
self.root_logger.setLevel(level)
|
|
246
|
+
for logger in self._module_loggers.values():
|
|
247
|
+
logger.setLevel(level)
|
|
248
|
+
|
|
249
|
+
def enable_debug_mode(self):
|
|
250
|
+
self.set_level(logging.DEBUG)
|
|
251
|
+
|
|
252
|
+
for handler in self.root_logger.handlers:
|
|
253
|
+
if isinstance(handler, logging.StreamHandler) and handler.stream == sys.stdout:
|
|
254
|
+
handler.setLevel(logging.DEBUG)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
_logger_manager: Optional[LoggerManager] = None
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def init_logging( # pylint: disable=too-many-arguments
|
|
261
|
+
app_name: str = "BlackAnt",
|
|
262
|
+
log_file: Optional[str] = None,
|
|
263
|
+
log_level: Union[str, int] = logging.INFO,
|
|
264
|
+
enable_colors: bool = True,
|
|
265
|
+
enable_request_tracking: bool = True,
|
|
266
|
+
enable_sensitive_filter: bool = True,
|
|
267
|
+
) -> LoggerManager:
|
|
268
|
+
global _logger_manager # pylint: disable=global-statement,invalid-name
|
|
269
|
+
|
|
270
|
+
_logger_manager = LoggerManager(
|
|
271
|
+
app_name=app_name,
|
|
272
|
+
default_log_file=log_file,
|
|
273
|
+
log_level=log_level,
|
|
274
|
+
enable_colors=enable_colors,
|
|
275
|
+
enable_request_tracking=enable_request_tracking,
|
|
276
|
+
enable_sensitive_filter=enable_sensitive_filter,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
return _logger_manager
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def get_logger(name: str = "") -> logging.Logger:
|
|
283
|
+
global _logger_manager # pylint: disable=global-statement,invalid-name
|
|
284
|
+
|
|
285
|
+
if _logger_manager is None:
|
|
286
|
+
_logger_manager = init_logging()
|
|
287
|
+
|
|
288
|
+
return _logger_manager.get_logger(name)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def set_request_id(request_id: str):
|
|
292
|
+
if _logger_manager:
|
|
293
|
+
_logger_manager.set_request_id(request_id)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def clear_request_id():
|
|
297
|
+
if _logger_manager:
|
|
298
|
+
_logger_manager.clear_request_id()
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def update_log_file(new_log_file: Union[str, Path]):
|
|
302
|
+
if _logger_manager:
|
|
303
|
+
_logger_manager.update_log_file(new_log_file)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def set_log_level(level: Union[str, int]):
|
|
307
|
+
if _logger_manager:
|
|
308
|
+
_logger_manager.set_level(level)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def enable_debug_mode():
|
|
312
|
+
if _logger_manager:
|
|
313
|
+
_logger_manager.enable_debug_mode()
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def gb_to_mb(gigabytes: float) -> int:
|
|
317
|
+
return int(gigabytes * 1024)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
if __name__ == "__main__":
|
|
321
|
+
init_logging(app_name="BlackAnt-Demo", log_level="DEBUG")
|
|
322
|
+
|
|
323
|
+
main_logger = get_logger("main")
|
|
324
|
+
http_logger = get_logger("http")
|
|
325
|
+
|
|
326
|
+
main_logger.debug("Debug message")
|
|
327
|
+
main_logger.info("Info message")
|
|
328
|
+
main_logger.warning("Warning message")
|
|
329
|
+
main_logger.error("Error message")
|
|
330
|
+
|
|
331
|
+
set_request_id("req_demo_12345")
|
|
332
|
+
http_logger.info("Message with request ID")
|
|
333
|
+
|
|
334
|
+
clear_request_id()
|
|
335
|
+
main_logger.info("Message without request ID")
|
|
336
|
+
|
|
337
|
+
http_logger.info("Token test: Bearer secret_token_123")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class RequestIdGenerator: # pylint: disable=too-few-public-methods
|
|
6
|
+
def __init__(self, header_name="X-Request-ID"):
|
|
7
|
+
self.header_name = header_name
|
|
8
|
+
self._counter = 0
|
|
9
|
+
|
|
10
|
+
def generate_id(self):
|
|
11
|
+
self._counter += 1
|
|
12
|
+
timestamp = int(time.time() * 1000)
|
|
13
|
+
return f"req_{timestamp}_{self._counter}_{uuid.uuid4().hex[:8]}"
|
blackant/utils/store.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Runtime data storage module for BlackAnt SDK.
|
|
2
|
+
|
|
3
|
+
Provides thread-safe storage using threading.local() for storing
|
|
4
|
+
data across different modules and components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
import threading
|
|
9
|
+
|
|
10
|
+
from ..patterns.singleton import Singleton
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Store(metaclass=Singleton): # pylint: disable=too-few-public-methods
|
|
14
|
+
"""Base class for runtime data storage.
|
|
15
|
+
|
|
16
|
+
Thread-safe storage implementation using threading.local().
|
|
17
|
+
All specific stores (auth tokens, request IDs) inherit from this class.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__tls = threading.local()
|
|
21
|
+
|
|
22
|
+
def _get(self, name: str):
|
|
23
|
+
"""Get data from thread-local storage.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
name (str): Attribute name to retrieve.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Any or None: Attribute value or None if not set.
|
|
30
|
+
"""
|
|
31
|
+
if not hasattr(self.__tls, name):
|
|
32
|
+
return None
|
|
33
|
+
return self.__tls.__getattribute__(name)
|
|
34
|
+
|
|
35
|
+
def _set(self, name: str, value: Any):
|
|
36
|
+
"""Set data in thread-local storage.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
name (str): Attribute name to set.
|
|
40
|
+
value (Any): Value to store.
|
|
41
|
+
"""
|
|
42
|
+
self.__tls.__setattr__(name, value)
|
|
43
|
+
|
|
44
|
+
def _del(self, name: str):
|
|
45
|
+
"""Delete data from thread-local storage.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
name (str): Attribute name to delete.
|
|
49
|
+
"""
|
|
50
|
+
self.__tls.__delattr__(name)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blackant-sdk
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Python SDK for Docker operations with automatic authentication through BlackAnt platform
|
|
5
|
+
Author-email: Balázs Milán <milan.balazs@uni-obuda.hu>
|
|
6
|
+
Maintainer-email: BlackAnt Development Team <dev@blackant.app>
|
|
7
|
+
License: Proprietary - Óbudai Egyetem
|
|
8
|
+
Project-URL: Homepage, https://env.blackant.app/systemdevelopers/blackant_sdk
|
|
9
|
+
Project-URL: Documentation, https://docs.blackant.app
|
|
10
|
+
Project-URL: Repository, https://env.blackant.app/systemdevelopers/blackant_sdk
|
|
11
|
+
Project-URL: Bug Tracker, https://env.blackant.app/systemdevelopers/blackant_sdk/-/issues
|
|
12
|
+
Keywords: docker,sdk,authentication,blackant,container,orchestration,swarm
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: flask>=2.3.2
|
|
24
|
+
Requires-Dist: flask-restful>=0.3.10
|
|
25
|
+
Requires-Dist: waitress>=2.1.2
|
|
26
|
+
Requires-Dist: minio>=6.0.0
|
|
27
|
+
Requires-Dist: requests>=2.31.0
|
|
28
|
+
Requires-Dist: docker>=4.4.3
|
|
29
|
+
Requires-Dist: urllib3<2.0
|
|
30
|
+
Requires-Dist: gunicorn>=21.2.0
|
|
31
|
+
Requires-Dist: colorama>=0.4.6
|
|
32
|
+
Requires-Dist: python-keycloak>=3.0.0
|
|
33
|
+
Requires-Dist: PyJWT>=2.8.0
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
|
|
38
|
+
Requires-Dist: sphinx>=5.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "dev"
|
|
40
|
+
Provides-Extra: test
|
|
41
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
42
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "test"
|
|
43
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
|
|
44
|
+
Provides-Extra: docs
|
|
45
|
+
Requires-Dist: sphinx>=5.0.0; extra == "docs"
|
|
46
|
+
Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "docs"
|
|
47
|
+
|
|
48
|
+
# Python REST API docker template
|
|
49
|
+
|
|
50
|
+
A simple template to implement REST APIs using Python Flask & docker.
|
|
51
|
+
|
|
52
|
+
## Build arguments
|
|
53
|
+
|
|
54
|
+
### INSTALL_DEBUG_TOOLS
|
|
55
|
+
|
|
56
|
+
If it's set to True, ptvsd is installed during build to be able to do live debugging.
|
|
57
|
+
|
|
58
|
+
## Environment variables
|
|
59
|
+
|
|
60
|
+
### CALCULATION_NAME
|
|
61
|
+
|
|
62
|
+
Name of the calculation. Mandatory parameter.
|
|
63
|
+
|
|
64
|
+
### SERVER_PORT
|
|
65
|
+
|
|
66
|
+
Port which on the server runs. Default: 5000
|
|
67
|
+
|
|
68
|
+
### DEBUG_MODE
|
|
69
|
+
|
|
70
|
+
A switch to select between debug and release mode. If it is set to True, a Flask server will be started in debug mode and a ptvsd server. Otherwise, it is served using gevent production server. Default: False
|
|
71
|
+
|
|
72
|
+
### OBJECT_STORAGE_URL
|
|
73
|
+
|
|
74
|
+
Url for the object storage. Mandatory if the code uses object storage.
|
|
75
|
+
|
|
76
|
+
### OBJECT_STORAGE_ACCESS_KEY
|
|
77
|
+
|
|
78
|
+
Public key for the object storage.
|
|
79
|
+
|
|
80
|
+
### OBJECT_STORAGE_SECRET_KEY
|
|
81
|
+
|
|
82
|
+
Private key for the object storage.
|
|
83
|
+
|
|
84
|
+
### SCHEDULER_URL
|
|
85
|
+
|
|
86
|
+
Callback url of the scheduler.
|
|
87
|
+
|
|
88
|
+
## Commands
|
|
89
|
+
|
|
90
|
+
### Build
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
docker-compose build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Run
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
docker-compose up
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Create task
|
|
103
|
+
|
|
104
|
+
You can use the tools/send_request.py script to send a simple request to the calculation container.
|
|
105
|
+
|
|
106
|
+
### Debug
|
|
107
|
+
|
|
108
|
+
If you use Visual Studio Code, there is a debug configuration called Python: Remote Attach which will start a debug session and connect to your running container.
|
|
109
|
+
|
|
110
|
+
## Documentation
|
|
111
|
+
|
|
112
|
+
Full HTML and PDF documentation can be generated from any revision using the generate_documentation job in the CI.
|
|
113
|
+
After the job have run successfully, the artifacts are stored for one day.
|
|
114
|
+
If it's necessary it can be rerun any time.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
......
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
blackant/__init__.py,sha256=THZWaFP_eIFEDVsIQC5HSCY9k2nGeR1TQ3rNhdlScEM,746
|
|
2
|
+
blackant/client.py,sha256=dsF-vPDzhv8Bx_OoakP4NC5dnbYRfkB4MHXcIAsIr9I,15180
|
|
3
|
+
blackant/exceptions.py,sha256=6y9FwBlO_ntYmVyJfrhKVUUnAHaA0wkyJx2WtddU1Ts,2845
|
|
4
|
+
blackant/auth/__init__.py,sha256=Ax1FqQsZNucr4CEUCqeZkrnbWN8Fx72IHFg3PZzbd2A,289
|
|
5
|
+
blackant/auth/blackant_auth.py,sha256=eLZ2T17kxRyl54LII1roGsyxkM-hMAWyqgi_HowwSLQ,19113
|
|
6
|
+
blackant/auth/keycloak_manager.py,sha256=6ubCAC8lR-6d5UyEXdX4X7aKTo3NF3N1kZ5KnPUcOOA,11708
|
|
7
|
+
blackant/auth/request_id.py,sha256=vWh-GX6f7aQAgvj2XINqn_8gJVgQ0a3bk_B3JqrtGaQ,1396
|
|
8
|
+
blackant/auth/role_assignment.py,sha256=Y14FIxSys9ICrYkVEERW3t2IyUyZwGODalXLV6kmD0c,14865
|
|
9
|
+
blackant/auth/tokens.py,sha256=A8fdd4a6KS24PmuiHvNgJCH5UJRGNfgm8wO6Q0hY4vE,1498
|
|
10
|
+
blackant/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
blackant/config/docker_config.py,sha256=80VM0kvUV-AWbzB2qDCFOHog9MDklsXdfsB3wEFRtX0,15049
|
|
12
|
+
blackant/config/keycloak_admin_config.py,sha256=a4de2bCd_PjuCXajQIzZko7YaPJVmifQlvNVK8M3iTU,3370
|
|
13
|
+
blackant/docker/__init__.py,sha256=RtBjt7fX4cUjszHtlH6izgFOXPDqhCUYU7NOUALQCF0,362
|
|
14
|
+
blackant/docker/builder.py,sha256=pGOyHTVvZLn9hTFu-VX2V4YGo2e2aur2l95i3ZdHp6s,24728
|
|
15
|
+
blackant/docker/client.py,sha256=i0JG7FCBeR9-gstom1rMTwc4ZCKVmMj0QIxyEXi_7fg,37405
|
|
16
|
+
blackant/docker/dao.py,sha256=bNtGhArc3kzD19QpeYoXNYvRwr7Bk3NsQ0DirohlYdA,17258
|
|
17
|
+
blackant/docker/registry.py,sha256=lGTECoCAklMe5-oD9bJDM1q9wq35YYDt6TM7hQdyM1I,5813
|
|
18
|
+
blackant/http/__init__.py,sha256=s54aPP80f6AWCEq2XS97CM2Z8-mAKamKaAlZgWy6-vE,207
|
|
19
|
+
blackant/http/client.py,sha256=DacZlA3MMNS6Ys0tWSNXT57avwN5Dr5PpX6Iekji5es,4597
|
|
20
|
+
blackant/patterns/__init__.py,sha256=iOEhKRqynyPbMNqDn1nHVWF6BoEq1htKtjjlJbmHp8U,48
|
|
21
|
+
blackant/patterns/singleton.py,sha256=LpNrQ5ct_tl9HIhDE4x7UDamezaMBDeiyDHXe9LwosU,610
|
|
22
|
+
blackant/services/__init__.py,sha256=UAPWaWiaPJ5XlvWtsqLO16eQkrkVAj4xzeeoyE9o3Vk,278
|
|
23
|
+
blackant/services/dao.py,sha256=4qm0MFIO2c0lkOUqOC8Fyp0tcF4MbBkF7RNcBdpuIWU,15187
|
|
24
|
+
blackant/services/registry.py,sha256=RPSTRPtKxa53NXxBVzW0TAdK3z8ai_ObnS47YjKCuE8,23473
|
|
25
|
+
blackant/utils/__init__.py,sha256=tzO_ZleysoT7Yf7kpI_io4udNAeH7c9cxwJqydEF5jA,130
|
|
26
|
+
blackant/utils/initialization.py,sha256=pe0fVfeV0mQkYdYJPoashTBTSNs4wQHtNEtABR2Jw7I,846
|
|
27
|
+
blackant/utils/logging.py,sha256=c1bNgWido4j1mD6p8l8pVhYCZgWfarP-R439pBOrIP8,10700
|
|
28
|
+
blackant/utils/request_id.py,sha256=RzuiIhlyVWLbAnSWmFh9pfwzPzLPxkLs3i8dyCxY92I,383
|
|
29
|
+
blackant/utils/store.py,sha256=Vewqt42Ne5e_m9DTxEnxA3afyhsyrNbuPrq4Y0v5P90,1348
|
|
30
|
+
calculation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
calculation/base.py,sha256=648e38zekvKsv4a7DL2skcjWX8ed7FDwSy6I3ubG7j4,529
|
|
32
|
+
calculation/errors.py,sha256=h5jZmvA76RApr4vIUqkyTYmjk3NzxknUjlWqNZDelcU,46
|
|
33
|
+
calculation/loader.py,sha256=Jrt3dadpgU2b-UhNhZrdAuFGN2gzyrlcgnHNjbGtXk8,8005
|
|
34
|
+
calculation/impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
calculation/impl/my_calculation.py,sha256=dsi5pDfgiCGOCZ7Rivjs7n5fiBCuB9Q8GOT4VR5v-0U,5054
|
|
36
|
+
calculation/impl/simple_calc.py,sha256=xhTlEt8oIz-oHDxtT_Iz3zSPjTl23a_XleC8kJUYdeU,1245
|
|
37
|
+
calculation/impl/test.py,sha256=_P06owSXxM9cK3FeeyYPXi17Km3-n394C_LYfMhUlbA,13
|
|
38
|
+
calculation/impl/test_calc.py,sha256=iSr4OUsupJpnug8SVl32-qWiLjP3iGrJc8I4W7JfAJk,954
|
|
39
|
+
notifinations/__init__.py,sha256=eOVctP2iedEe94bzz01B_0hqhNr8pFq9j7Qq9a2xK5o,175
|
|
40
|
+
notifinations/mail_sender.py,sha256=bx3jRShq4EjPesfIzP6vfmdB8XL8fi0ilMnURhWy_YY,7958
|
|
41
|
+
storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
+
storage/errors.py,sha256=ja71c2WQbtsamIRbFO4ea66Lr7SpIh8kWhf0h7gValI,187
|
|
43
|
+
storage/factory.py,sha256=ki2lYvA5JrxWQVZ3WX3Tykldo1q6F-20eAKudMo5Iig,905
|
|
44
|
+
storage/interface.py,sha256=87pQJ3uW8EJ4uLMi07iQxPaVM0HhUTXrshcUlRFSSM4,420
|
|
45
|
+
storage/minio.py,sha256=VxP6JNa_ktuY-0LB8-jvDGb9dm193pBgD3JFmKJOVhY,3985
|
|
46
|
+
task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
task/dao.py,sha256=Qs7-ACKWtWaWTwV1nuoRMOHXQObj_Z9vWNI-SPTvNaI,1012
|
|
48
|
+
task/errors.py,sha256=O6Uwj2benf3bs6AKtdkrPCtP_jPXWTS5nepUWEy3NZM,163
|
|
49
|
+
task/log_adapter.py,sha256=HmXpus2fYuRcPlUgSMFByqj7HZoFwQ2ABv28sEZ3uPk,323
|
|
50
|
+
task/resource.py,sha256=n0rOvOu4tYD9v9zEFxl-pZmp9NjqT-8Cqzb3ErEq68g,3307
|
|
51
|
+
task/task.py,sha256=_b0P-lM9LtLZxvmRIHWgrecziG_TuaUTVZifFs7hv2s,13314
|
|
52
|
+
task/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
|
+
task/parsers/base.py,sha256=VUpZrPJPTnwAvPzxqvI0MgkzEW-550996izlFGJm2uI,249
|
|
54
|
+
task/parsers/callback.py,sha256=dgQFc3n3tlGcd7qhK_BYe-RRXxh3OLHznHiaqzGCwgw,1038
|
|
55
|
+
task/parsers/cmd_args.py,sha256=lUjZD6T27elvx1qQdia0WiXlXjLIgGeztB10MK6PqH8,1684
|
|
56
|
+
task/parsers/freetext.py,sha256=KA5g1tyb648RXHpl8XY6h-UVAvWNrEnZiuJt7bw8QFM,545
|
|
57
|
+
task/parsers/objects.py,sha256=fQcRVEQjQ1UxlWrt6kEfqzH3JaQqFX_ON4ign_omuZ0,1555
|
|
58
|
+
task/parsers/request.py,sha256=dfV1ow8e1tb1Cdmb0FBIagGCynFHfNWftBX40I10QAE,1859
|
|
59
|
+
task/states/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
+
task/states/base.py,sha256=xsh2CoLoOcAcjpQrZri8F9sYbBv8StdCMl-9hJqRQsE,263
|
|
61
|
+
task/states/error.py,sha256=19Vpvvmx-qHG2zgtGfHK7ULHx6ZCisMdcPNVPSNDZDA,1766
|
|
62
|
+
task/states/idle.py,sha256=3JYb8-_eJ5NlirMWOaEh_OUP7HtjqqyBIQye-nzoRYQ,326
|
|
63
|
+
task/states/ready.py,sha256=kMpC6qY_IGkLc1JpaH_jf_NcZgC4vyLzoEZhYMDOwZA,1967
|
|
64
|
+
task/states/running.py,sha256=HVkkZlC7xOV5M3NnJAf4SWyVE5JqT2LhZokIbRyskbQ,773
|
|
65
|
+
task/states/set_up.py,sha256=NsoEGKVL_E3hQFIm3p3Bv6uC7J0DOPzTc8UZrMEVR1g,1634
|
|
66
|
+
task/states/tear_down.py,sha256=xq6xSC2Q_Yuky047kRP4fSwM992PILIOYBZbOl1RIDA,1050
|
|
67
|
+
blackant_sdk-1.0.2.dist-info/METADATA,sha256=uzdQjvqBJNSYM414ju-eN0aHA7JbSiMWCdi4hfRZUkg,3615
|
|
68
|
+
blackant_sdk-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
69
|
+
blackant_sdk-1.0.2.dist-info/top_level.txt,sha256=MZZ_UBTnah0fs9yzTmlavd4Z0HuJDD3alhfGlB79ZIE,48
|
|
70
|
+
blackant_sdk-1.0.2.dist-info/RECORD,,
|
calculation/__init__.py
ADDED
|
File without changes
|
calculation/base.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CalculationBase:
|
|
5
|
+
def __init__(self, logger):
|
|
6
|
+
self._logger = logger
|
|
7
|
+
|
|
8
|
+
@abc.abstractproperty
|
|
9
|
+
def result(self):
|
|
10
|
+
raise NotImplementedError
|
|
11
|
+
|
|
12
|
+
@abc.abstractmethod
|
|
13
|
+
def set_up(self):
|
|
14
|
+
raise NotImplementedError
|
|
15
|
+
|
|
16
|
+
@abc.abstractmethod
|
|
17
|
+
def run(self):
|
|
18
|
+
raise NotImplementedError
|
|
19
|
+
|
|
20
|
+
@abc.abstractmethod
|
|
21
|
+
def tear_down(self):
|
|
22
|
+
raise NotImplementedError
|
|
23
|
+
|
|
24
|
+
@abc.abstractmethod
|
|
25
|
+
def stop(self):
|
|
26
|
+
raise NotImplementedError
|
calculation/errors.py
ADDED
|
File without changes
|