db-sync-tool-kmi 2.11.6__py3-none-any.whl → 3.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.
Files changed (41) hide show
  1. db_sync_tool/__main__.py +7 -252
  2. db_sync_tool/cli.py +733 -0
  3. db_sync_tool/database/process.py +94 -111
  4. db_sync_tool/database/utility.py +339 -121
  5. db_sync_tool/info.py +1 -1
  6. db_sync_tool/recipes/drupal.py +87 -12
  7. db_sync_tool/recipes/laravel.py +7 -6
  8. db_sync_tool/recipes/parsing.py +102 -0
  9. db_sync_tool/recipes/symfony.py +17 -28
  10. db_sync_tool/recipes/typo3.py +33 -54
  11. db_sync_tool/recipes/wordpress.py +13 -12
  12. db_sync_tool/remote/client.py +206 -71
  13. db_sync_tool/remote/file_transfer.py +303 -0
  14. db_sync_tool/remote/rsync.py +18 -15
  15. db_sync_tool/remote/system.py +2 -3
  16. db_sync_tool/remote/transfer.py +51 -47
  17. db_sync_tool/remote/utility.py +29 -30
  18. db_sync_tool/sync.py +52 -28
  19. db_sync_tool/utility/config.py +367 -0
  20. db_sync_tool/utility/config_resolver.py +573 -0
  21. db_sync_tool/utility/console.py +779 -0
  22. db_sync_tool/utility/exceptions.py +32 -0
  23. db_sync_tool/utility/helper.py +155 -148
  24. db_sync_tool/utility/info.py +53 -20
  25. db_sync_tool/utility/log.py +55 -31
  26. db_sync_tool/utility/logging_config.py +410 -0
  27. db_sync_tool/utility/mode.py +85 -150
  28. db_sync_tool/utility/output.py +122 -51
  29. db_sync_tool/utility/parser.py +33 -53
  30. db_sync_tool/utility/pure.py +93 -0
  31. db_sync_tool/utility/security.py +79 -0
  32. db_sync_tool/utility/system.py +277 -194
  33. db_sync_tool/utility/validation.py +2 -9
  34. db_sync_tool_kmi-3.0.2.dist-info/METADATA +99 -0
  35. db_sync_tool_kmi-3.0.2.dist-info/RECORD +44 -0
  36. {db_sync_tool_kmi-2.11.6.dist-info → db_sync_tool_kmi-3.0.2.dist-info}/WHEEL +1 -1
  37. db_sync_tool_kmi-2.11.6.dist-info/METADATA +0 -276
  38. db_sync_tool_kmi-2.11.6.dist-info/RECORD +0 -34
  39. {db_sync_tool_kmi-2.11.6.dist-info → db_sync_tool_kmi-3.0.2.dist-info}/entry_points.txt +0 -0
  40. {db_sync_tool_kmi-2.11.6.dist-info → db_sync_tool_kmi-3.0.2.dist-info/licenses}/LICENSE +0 -0
  41. {db_sync_tool_kmi-2.11.6.dist-info → db_sync_tool_kmi-3.0.2.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: future_fstrings -*-
3
2
 
4
3
  """
5
4
  Mode script
6
5
  """
7
6
 
8
7
  import subprocess
9
- import sys
10
8
 
11
9
  from db_sync_tool.utility import system, output, helper
10
+ from db_sync_tool.utility.exceptions import DbSyncError
11
+ from db_sync_tool.utility.security import sanitize_command_for_logging # noqa: F401 (re-export)
12
12
  from db_sync_tool.remote import system as remote_system
13
13
 
14
14
 
@@ -38,140 +38,72 @@ class SyncMode:
38
38
  SYNC_LOCAL = 'SYNC_LOCAL'
39
39
 
40
40
  @staticmethod
41
- def is_dump_local():
42
- """
43
-
44
- :return: boolean
45
- """
46
- return SyncMode.is_full_local() and SyncMode.is_same_host() and not SyncMode.is_sync_local()
47
-
48
- @staticmethod
49
- def is_dump_remote():
50
- """
51
-
52
- :return: boolean
53
- """
54
- return SyncMode.is_full_remote() and SyncMode.is_same_host() and \
55
- not SyncMode.is_sync_remote()
56
-
57
- @staticmethod
58
- def is_receiver():
59
- """
60
-
61
- :return: boolean
62
- """
63
- return 'host' in system.config[Client.ORIGIN] and not SyncMode.is_proxy() and \
64
- not SyncMode.is_sync_remote()
65
-
66
- @staticmethod
67
- def is_sender():
68
- """
69
-
70
- :return: boolean
71
- """
72
- return 'host' in system.config[Client.TARGET] and not SyncMode.is_proxy() and \
73
- not SyncMode.is_sync_remote()
41
+ def is_dump_local() -> bool:
42
+ cfg = system.get_typed_config()
43
+ both_local = not cfg.origin.is_remote and not cfg.target.is_remote
44
+ return both_local and SyncMode.is_same_host() and not SyncMode.is_sync_local()
74
45
 
75
46
  @staticmethod
76
- def is_proxy():
77
- """
78
-
79
- :return: boolean
80
- """
81
- return SyncMode.is_full_remote()
47
+ def is_dump_remote() -> bool:
48
+ cfg = system.get_typed_config()
49
+ both_remote = cfg.origin.is_remote and cfg.target.is_remote
50
+ return both_remote and SyncMode.is_same_host() and not SyncMode.is_sync_remote()
82
51
 
83
52
  @staticmethod
84
- def is_import_local():
85
- """
86
-
87
- :return: boolean
88
- """
89
- return system.config['import'] != '' and 'host' not in system.config[Client.TARGET]
53
+ def is_receiver() -> bool:
54
+ cfg = system.get_typed_config()
55
+ return cfg.origin.is_remote and not SyncMode.is_proxy() and not SyncMode.is_sync_remote()
90
56
 
91
57
  @staticmethod
92
- def is_import_remote():
93
- """
94
-
95
- :return: boolean
96
- """
97
- return system.config['import'] != '' and 'host' in system.config[Client.TARGET]
58
+ def is_sender() -> bool:
59
+ cfg = system.get_typed_config()
60
+ return cfg.target.is_remote and not SyncMode.is_proxy() and not SyncMode.is_sync_remote()
98
61
 
99
62
  @staticmethod
100
- def is_sync_local():
101
- """
102
-
103
- :return: boolean
104
- """
105
- return SyncMode.is_full_local() and SyncMode.is_same_host() and SyncMode.is_same_sync()
63
+ def is_proxy() -> bool:
64
+ cfg = system.get_typed_config()
65
+ return cfg.origin.is_remote and cfg.target.is_remote
106
66
 
107
67
  @staticmethod
108
- def is_sync_remote():
109
- """
110
-
111
- :return: boolean
112
- """
113
- return SyncMode.is_full_remote() and SyncMode.is_same_host() and SyncMode.is_same_sync()
68
+ def is_import_local() -> bool:
69
+ cfg = system.get_typed_config()
70
+ return cfg.import_file != '' and not cfg.target.is_remote
114
71
 
115
72
  @staticmethod
116
- def is_same_sync():
117
- """
118
-
119
- :return: boolean
120
- """
121
- return ((SyncMode.is_available_configuration('path') and
122
- not SyncMode.is_same_configuration('path')) or
123
- (SyncMode.is_available_configuration('db') and
124
- not SyncMode.is_same_configuration('db')))
73
+ def is_import_remote() -> bool:
74
+ cfg = system.get_typed_config()
75
+ return cfg.import_file != '' and cfg.target.is_remote
125
76
 
126
77
  @staticmethod
127
- def is_full_remote():
128
- """
129
-
130
- :return: boolean
131
- """
132
- return SyncMode.is_available_configuration('host')
78
+ def is_sync_local() -> bool:
79
+ cfg = system.get_typed_config()
80
+ return (not cfg.origin.is_remote and not cfg.target.is_remote and
81
+ SyncMode.is_same_host() and SyncMode.is_same_sync())
133
82
 
134
83
  @staticmethod
135
- def is_full_local():
136
- """
137
-
138
- :return: boolean
139
- """
140
- return SyncMode.is_unavailable_configuration('host')
84
+ def is_sync_remote() -> bool:
85
+ cfg = system.get_typed_config()
86
+ return (cfg.origin.is_remote and cfg.target.is_remote and
87
+ SyncMode.is_same_host() and SyncMode.is_same_sync())
141
88
 
142
89
  @staticmethod
143
- def is_same_host():
144
- """
145
-
146
- :return: boolean
147
- """
148
- return SyncMode.is_same_configuration('host') and SyncMode.is_same_configuration('port')
149
-
150
- @staticmethod
151
- def is_available_configuration(key):
152
- """
153
-
154
- :return: boolean
155
- """
156
- return key in system.config[Client.ORIGIN] and key in system.config[Client.TARGET]
157
-
158
- @staticmethod
159
- def is_unavailable_configuration(key):
160
- """
161
-
162
- :return: boolean
163
- """
164
- return key not in system.config[Client.ORIGIN] and key not in system.config[Client.TARGET]
90
+ def is_same_sync() -> bool:
91
+ cfg = system.get_typed_config()
92
+ # Different paths on same host
93
+ if cfg.origin.path and cfg.target.path and cfg.origin.path != cfg.target.path:
94
+ return True
95
+ # Different databases on same host
96
+ if cfg.origin.db.name and cfg.target.db.name:
97
+ if (cfg.origin.db.name, cfg.origin.db.host) != (cfg.target.db.name, cfg.target.db.host):
98
+ return True
99
+ return False
165
100
 
166
101
  @staticmethod
167
- def is_same_configuration(key):
168
- """
169
-
170
- :return: boolean
171
- """
172
- return (SyncMode.is_available_configuration(key) and
173
- system.config[Client.ORIGIN][key] == system.config[Client.TARGET][key]) or \
174
- SyncMode.is_unavailable_configuration(key)
102
+ def is_same_host() -> bool:
103
+ cfg = system.get_typed_config()
104
+ return (cfg.origin.host == cfg.target.host and
105
+ cfg.origin.port == cfg.target.port and
106
+ cfg.origin.user == cfg.target.user)
175
107
 
176
108
 
177
109
  # Default sync mode
@@ -181,7 +113,7 @@ sync_mode = SyncMode.RECEIVER
181
113
  #
182
114
  # FUNCTIONS
183
115
  #
184
- def get_sync_mode():
116
+ def get_sync_mode() -> str:
185
117
  """
186
118
  Returning the sync mode
187
119
  :return: String sync_mode
@@ -189,10 +121,9 @@ def get_sync_mode():
189
121
  return sync_mode
190
122
 
191
123
 
192
- def check_sync_mode():
124
+ def check_sync_mode() -> None:
193
125
  """
194
126
  Checking the sync_mode based on the given configuration
195
- :return: String subject
196
127
  """
197
128
  global sync_mode
198
129
  _description = ''
@@ -214,14 +145,15 @@ def check_sync_mode():
214
145
  sync_mode = _mode
215
146
  _description = _desc
216
147
 
148
+ cfg = system.get_typed_config()
217
149
  if is_import():
218
150
  output.message(
219
151
  output.Subject.INFO,
220
- f'Import file {output.CliFormat.BLACK}{system.config["import"]}{output.CliFormat.ENDC}',
152
+ f'Import file {output.CliFormat.BLACK}{cfg.import_file}{output.CliFormat.ENDC}',
221
153
  True
222
154
  )
223
155
 
224
- system.config['is_same_client'] = SyncMode.is_same_host()
156
+ system.set_is_same_client(SyncMode.is_same_host())
225
157
 
226
158
  output.message(
227
159
  output.Subject.INFO,
@@ -232,23 +164,19 @@ def check_sync_mode():
232
164
  check_for_protection()
233
165
 
234
166
 
235
- def is_remote(client):
167
+ def is_remote(client: str) -> bool:
236
168
  """
237
169
  Check if given client is remote client
238
- :param client: String
170
+ :param client: Client identifier
239
171
  :return: Boolean
240
172
  """
241
- if client == Client.ORIGIN:
242
- return is_origin_remote()
243
- elif client == Client.TARGET:
244
- return is_target_remote()
245
- elif client == Client.LOCAL:
246
- return False
247
- else:
248
- return False
173
+ return {
174
+ Client.ORIGIN: is_origin_remote,
175
+ Client.TARGET: is_target_remote,
176
+ }.get(client, lambda: False)()
249
177
 
250
178
 
251
- def is_target_remote():
179
+ def is_target_remote() -> bool:
252
180
  """
253
181
  Check if target is remote client
254
182
  :return: Boolean
@@ -257,7 +185,7 @@ def is_target_remote():
257
185
  SyncMode.IMPORT_REMOTE, SyncMode.SYNC_REMOTE)
258
186
 
259
187
 
260
- def is_origin_remote():
188
+ def is_origin_remote() -> bool:
261
189
  """
262
190
  Check if origin is remote client
263
191
  :return: Boolean
@@ -266,7 +194,7 @@ def is_origin_remote():
266
194
  SyncMode.IMPORT_REMOTE, SyncMode.SYNC_REMOTE)
267
195
 
268
196
 
269
- def is_import():
197
+ def is_import() -> bool:
270
198
  """
271
199
  Check if sync mode is import
272
200
  :return: Boolean
@@ -274,15 +202,16 @@ def is_import():
274
202
  return sync_mode in (SyncMode.IMPORT_LOCAL, SyncMode.IMPORT_REMOTE)
275
203
 
276
204
 
277
- def is_dump():
205
+ def is_dump() -> bool:
278
206
  """
279
- Check if sync mode is import
207
+ Check if sync mode is dump
280
208
  :return: Boolean
281
209
  """
282
210
  return sync_mode in (SyncMode.DUMP_LOCAL, SyncMode.DUMP_REMOTE)
283
211
 
284
212
 
285
- def run_command(command, client, force_output=False, allow_fail=False, skip_dry_run=False):
213
+ def run_command(command: str, client: str, force_output: bool = False,
214
+ allow_fail: bool = False, skip_dry_run: bool = False) -> str | None:
286
215
  """
287
216
  Run command depending on the given client
288
217
  :param command: String
@@ -290,17 +219,20 @@ def run_command(command, client, force_output=False, allow_fail=False, skip_dry_
290
219
  :param force_output: Boolean
291
220
  :param allow_fail: Boolean
292
221
  :param skip_dry_run: Boolean
293
- :return:
222
+ :return: Command output or None
294
223
  """
295
- if system.config['verbose']:
224
+ cfg = system.get_typed_config()
225
+ if cfg.verbose:
226
+ # Sanitize command to prevent credentials from appearing in logs
227
+ _safe_command = sanitize_command_for_logging(command)
296
228
  output.message(
297
229
  output.host_to_subject(client),
298
- output.CliFormat.BLACK + command + output.CliFormat.ENDC,
230
+ output.CliFormat.BLACK + _safe_command + output.CliFormat.ENDC,
299
231
  debug=True
300
232
  )
301
233
 
302
- if system.config['dry_run'] and skip_dry_run:
303
- return
234
+ if cfg.dry_run and skip_dry_run:
235
+ return None
304
236
 
305
237
  if is_remote(client):
306
238
  if force_output:
@@ -314,22 +246,25 @@ def run_command(command, client, force_output=False, allow_fail=False, skip_dry_
314
246
 
315
247
  if res.wait() != 0 and err.decode() != '' and not allow_fail:
316
248
  helper.run_script(script='error')
317
- sys.exit(output.message(output.Subject.ERROR, err.decode(), False))
249
+ raise DbSyncError(err.decode())
318
250
 
319
251
  if force_output:
320
252
  return out.decode().strip()
321
253
 
254
+ return None
255
+
322
256
 
323
- def check_for_protection():
257
+ def check_for_protection() -> None:
324
258
  """
325
- Check if the target system is protected
326
- :return: Boolean
259
+ Check if the target system is protected and exit if so.
327
260
  """
261
+ cfg = system.get_typed_config()
328
262
  if sync_mode in (SyncMode.RECEIVER, SyncMode.SENDER, SyncMode.PROXY, SyncMode.SYNC_LOCAL,
329
263
  SyncMode.SYNC_REMOTE, SyncMode.IMPORT_LOCAL, SyncMode.IMPORT_REMOTE) and \
330
- 'protect' in system.config[Client.TARGET]:
264
+ cfg.target.protect:
331
265
  _host = helper.get_ssh_host_name(Client.TARGET)
332
- sys.exit(output.message(output.Subject.ERROR,
333
- f'The host {_host} is protected against the import of a database dump. Please '
334
- 'check synchronisation target or adjust the host configuration.', False))
266
+ raise DbSyncError(
267
+ f'The host {_host} is protected against the import of a database dump. '
268
+ 'Please check synchronisation target or adjust the host configuration.'
269
+ )
335
270
 
@@ -1,15 +1,25 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: future_fstrings -*-
3
2
 
4
3
  """
5
4
  Output script
5
+
6
+ This module provides the legacy output interface using Rich and structured logging.
7
+ For new code, prefer using the logging_config module directly:
8
+
9
+ from db_sync_tool.utility.logging_config import get_sync_logger
10
+
11
+ logger = get_sync_logger("origin", remote=True)
12
+ logger.info("Creating database dump")
6
13
  """
7
- import time
8
- from yaspin import yaspin
9
- from db_sync_tool.utility import log, mode, system
14
+ from __future__ import annotations
15
+
16
+ from db_sync_tool.utility import mode, system
17
+ from db_sync_tool.utility.console import get_output_manager
18
+ from db_sync_tool.utility.logging_config import get_sync_logger
10
19
 
11
20
 
12
21
  class CliFormat:
22
+ """ANSI color codes for CLI formatting (legacy compatibility)."""
13
23
  BEIGE = '\033[96m'
14
24
  PURPLE = '\033[95m'
15
25
  BLUE = '\033[94m'
@@ -23,6 +33,7 @@ class CliFormat:
23
33
 
24
34
 
25
35
  class Subject:
36
+ """Subject prefixes for messages (legacy compatibility)."""
26
37
  INFO = CliFormat.GREEN + '[INFO]' + CliFormat.ENDC
27
38
  LOCAL = CliFormat.BEIGE + '[LOCAL]' + CliFormat.ENDC
28
39
  TARGET = CliFormat.BLUE + '[TARGET]' + CliFormat.ENDC
@@ -32,57 +43,113 @@ class Subject:
32
43
  DEBUG = CliFormat.BLACK + '[DEBUG]' + CliFormat.ENDC
33
44
 
34
45
 
35
- def message(header, message, do_print=True, do_log=False, debug=False, verbose_only=False):
46
+ # Mapping from Subject constants to subject strings for structured logging
47
+ _SUBJECT_MAP = {
48
+ Subject.INFO: "INFO",
49
+ Subject.LOCAL: "LOCAL",
50
+ Subject.TARGET: "TARGET",
51
+ Subject.ORIGIN: "ORIGIN",
52
+ Subject.ERROR: "INFO", # Error level handled separately
53
+ Subject.WARNING: "INFO", # Warning level handled separately
54
+ Subject.DEBUG: "INFO", # Debug level handled separately
55
+ }
56
+
57
+
58
+ def message(
59
+ header: str,
60
+ message: str,
61
+ do_print: bool = True,
62
+ do_log: bool = False,
63
+ debug: bool = False,
64
+ verbose_only: bool = False,
65
+ ) -> str | None:
36
66
  """
37
- Formatting a message for print or log
38
- :param header: String
39
- :param message: String
40
- :param do_print: Boolean
41
- :param do_log: Boolean
42
- :param debug: Boolean
43
- :param verbose_only: Boolean
44
- :return: String message
67
+ Formatting a message for print or log.
68
+
69
+ This function maintains backward compatibility while using structured logging
70
+ and delegating console output to the Rich-based OutputManager.
71
+
72
+ Args:
73
+ header: Subject prefix (e.g., Subject.ORIGIN)
74
+ message: Message text
75
+ do_print: Whether to print to console
76
+ do_log: Whether to log the message
77
+ debug: Whether this is a debug message
78
+ verbose_only: Only show in verbose mode
79
+
80
+ Returns:
81
+ String message if do_print is False, None otherwise
45
82
  """
46
- # Logging if explicitly forced or verbose option is active
47
- if do_log or system.config['verbose']:
48
- _message = remove_multiple_elements_from_string([CliFormat.BEIGE,
49
- CliFormat.PURPLE,
50
- CliFormat.BLUE,
51
- CliFormat.YELLOW,
52
- CliFormat.GREEN,
53
- CliFormat.RED,
54
- CliFormat.BLACK,
55
- CliFormat.ENDC,
56
- CliFormat.BOLD,
57
- CliFormat.UNDERLINE], message)
58
- # @ToDo: Can this be done better? Dynamic functions?
83
+ cfg = system.get_typed_config()
84
+ output_manager = get_output_manager()
85
+
86
+ # Clean ANSI codes from message for logging and structured output
87
+ clean_message = remove_multiple_elements_from_string([
88
+ CliFormat.BEIGE, CliFormat.PURPLE, CliFormat.BLUE,
89
+ CliFormat.YELLOW, CliFormat.GREEN, CliFormat.RED,
90
+ CliFormat.BLACK, CliFormat.ENDC, CliFormat.BOLD,
91
+ CliFormat.UNDERLINE
92
+ ], message)
93
+
94
+ # Get subject and remote status for structured logging
95
+ subject_str = _SUBJECT_MAP.get(header, "INFO")
96
+ is_remote = _is_remote_for_header(header)
97
+
98
+ # Structured logging if explicitly forced or verbose option is active
99
+ if do_log or cfg.verbose:
100
+ logger = get_sync_logger(subject=subject_str, remote=is_remote)
101
+
59
102
  if debug:
60
- log.get_logger().debug(_message)
103
+ logger.debug(clean_message)
61
104
  elif header == Subject.WARNING:
62
- log.get_logger().warning(_message)
105
+ logger.warning(clean_message)
63
106
  elif header == Subject.ERROR:
64
- log.get_logger().error(_message)
107
+ logger.error(clean_message)
65
108
  else:
66
- log.get_logger().info(_message)
109
+ logger.info(clean_message)
67
110
 
68
- # Formatting message if mute option is inactive
69
- if (system.config['mute'] and header == Subject.ERROR) or (not system.config['mute']):
111
+ # Console output if mute option is inactive
112
+ if (cfg.mute and header == Subject.ERROR) or (not cfg.mute):
70
113
  if do_print:
71
- if not verbose_only or (verbose_only and system.config['verbose']):
72
- _message = header + extend_output_by_sync_mode(header, debug) + ' ' + message
73
- with yaspin(text=_message, color="yellow", side="right") as spinner:
74
- spinner.ok("\b\b")
114
+ if not verbose_only or (verbose_only and cfg.verbose):
115
+ # Use new OutputManager for console display
116
+ if header == Subject.ERROR:
117
+ output_manager.error(clean_message)
118
+ elif header == Subject.WARNING:
119
+ output_manager.warning(clean_message)
120
+ elif debug:
121
+ output_manager.debug(clean_message)
122
+ else:
123
+ # Legacy API: messages are logged after completion
124
+ # Set up step context for success() to use, then show completed
125
+ output_manager._setup_step(clean_message, subject=subject_str, remote=is_remote)
126
+ output_manager.success()
127
+ return None
75
128
  else:
76
129
  return header + extend_output_by_sync_mode(header, debug) + ' ' + message
130
+ return None
131
+
132
+
133
+ def _is_remote_for_header(header) -> bool:
134
+ """Determine if the operation is remote based on header."""
135
+ if header in (Subject.INFO, Subject.LOCAL, Subject.WARNING, Subject.ERROR):
136
+ return False
137
+
138
+ host = subject_to_host(header)
139
+ if host is None:
140
+ return False
141
+
142
+ return mode.is_remote(host)
77
143
 
78
144
 
79
145
  def extend_output_by_sync_mode(header, debug=False):
80
146
  """
81
- Extending the output by a client information (LOCAL|REMOTE)
82
- :param header: String
83
- :return: String message
147
+ Extending the output by a client information (LOCAL|REMOTE).
148
+
149
+ :param header: Subject prefix
150
+ :param debug: Whether to include debug tag
151
+ :return: String extension
84
152
  """
85
- _sync_mode = mode.get_sync_mode()
86
153
  _debug = ''
87
154
 
88
155
  if debug:
@@ -103,9 +170,10 @@ def extend_output_by_sync_mode(header, debug=False):
103
170
 
104
171
  def host_to_subject(host):
105
172
  """
106
- Converting the client to the according subject
107
- :param host: String
108
- :return: String subject
173
+ Converting the client to the according subject.
174
+
175
+ :param host: Client constant
176
+ :return: Subject prefix
109
177
  """
110
178
  if host == mode.Client.ORIGIN:
111
179
  return Subject.ORIGIN
@@ -113,13 +181,15 @@ def host_to_subject(host):
113
181
  return Subject.TARGET
114
182
  elif host == mode.Client.LOCAL:
115
183
  return Subject.LOCAL
184
+ return None
116
185
 
117
186
 
118
187
  def subject_to_host(subject):
119
188
  """
120
- Converting the subject to the according host
121
- :param subject: String
122
- :return: String host
189
+ Converting the subject to the according host.
190
+
191
+ :param subject: Subject prefix
192
+ :return: Client constant
123
193
  """
124
194
  if subject == Subject.ORIGIN:
125
195
  return mode.Client.ORIGIN
@@ -127,17 +197,18 @@ def subject_to_host(subject):
127
197
  return mode.Client.TARGET
128
198
  elif subject == Subject.LOCAL:
129
199
  return mode.Client.LOCAL
200
+ return None
130
201
 
131
202
 
132
203
  def remove_multiple_elements_from_string(elements, string):
133
204
  """
134
- Removing multiple elements from a string
135
- :param elements: List
136
- :param string: String
137
- :return: String string
205
+ Removing multiple elements from a string.
206
+
207
+ :param elements: List of strings to remove
208
+ :param string: Input string
209
+ :return: Cleaned string
138
210
  """
139
211
  for element in elements:
140
212
  if element in string:
141
213
  string = string.replace(element, '')
142
214
  return string
143
-