jaaql-middleware-python 4.24.4__tar.gz → 4.24.6__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 (76) hide show
  1. {jaaql-middleware-python-4.24.4/jaaql_middleware_python.egg-info → jaaql-middleware-python-4.24.6}/PKG-INFO +1 -1
  2. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/constants.py +1 -1
  3. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/db/db_interface.py +241 -241
  4. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/db/db_pg_interface.py +247 -247
  5. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/db/db_utils.py +5 -2
  6. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/documentation/documentation_internal.py +16 -0
  7. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/interpreter/interpret_jaaql.py +66 -7
  8. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/controller.py +4 -0
  9. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/model.py +93 -1
  10. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6/jaaql_middleware_python.egg-info}/PKG-INFO +1 -1
  11. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/LICENSE.txt +0 -0
  12. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/README.md +0 -0
  13. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/__init__.py +0 -0
  14. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/config/__init__.py +0 -0
  15. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/config/config-docker.ini +0 -0
  16. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/config/config-test.ini +0 -0
  17. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/config/config.ini +0 -0
  18. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/config_constants.py +0 -0
  19. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/db/__init__.py +0 -0
  20. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/db/db_utils_no_circ.py +0 -0
  21. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/documentation/__init__.py +0 -0
  22. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/documentation/documentation_public.py +0 -0
  23. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/documentation/documentation_shared.py +0 -0
  24. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/email/__init__.py +0 -0
  25. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/email/email_manager.py +0 -0
  26. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/email/email_manager_service.py +0 -0
  27. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/email/patch_ems.py +0 -0
  28. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/exceptions/__init__.py +0 -0
  29. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/exceptions/custom_http_status.py +0 -0
  30. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/exceptions/http_status_exception.py +0 -0
  31. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/exceptions/jaaql_interpretable_handled_errors.py +0 -0
  32. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/exceptions/not_yet_implement_exception.py +0 -0
  33. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/generated_constants.py +0 -0
  34. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/interpreter/__init__.py +0 -0
  35. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/jaaql.py +0 -0
  36. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/migrations/__init__.py +0 -0
  37. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/migrations/migrations.py +0 -0
  38. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/__init__.py +0 -0
  39. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/base_controller.py +0 -0
  40. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/base_model.py +0 -0
  41. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/controller_interface.py +0 -0
  42. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/exception_queries.py +0 -0
  43. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/generated_queries.py +0 -0
  44. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/handmade_queries.py +0 -0
  45. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/model_interface.py +0 -0
  46. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/mvc/response.py +0 -0
  47. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/openapi/__init__.py +0 -0
  48. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/openapi/swagger_documentation.py +0 -0
  49. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/patch.py +0 -0
  50. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/01.install_domains.generated.sql +0 -0
  51. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/02.install_super_user.exceptions.sql +0 -0
  52. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/03.install_super_user.handwritten.sql +0 -0
  53. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/04.install_jaaql_data_structures.generated.sql +0 -0
  54. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/05.install_jaaql.exceptions.sql +0 -0
  55. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/06.install_jaaql.handwritten.sql +0 -0
  56. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/ZZZZ.generated_functions_views_and_permissions.sql +0 -0
  57. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/ZZZZ.reset_references.sql +0 -0
  58. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/scripts/swagger_template.html +0 -0
  59. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/services/__init__.py +0 -0
  60. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/services/cached_canned_query_service.py +0 -0
  61. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/services/migrations_manager_service.py +0 -0
  62. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/services/patch_mms.py +0 -0
  63. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/services/patch_shared_var_service.py +0 -0
  64. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/services/shared_var_service.py +0 -0
  65. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/utilities/__init__.py +0 -0
  66. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/utilities/crypt_utils.py +0 -0
  67. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/utilities/options.py +0 -0
  68. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/utilities/utils.py +0 -0
  69. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/utilities/utils_no_project_imports.py +0 -0
  70. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql/utilities/vault.py +0 -0
  71. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql_middleware_python.egg-info/SOURCES.txt +0 -0
  72. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql_middleware_python.egg-info/dependency_links.txt +0 -0
  73. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql_middleware_python.egg-info/requires.txt +0 -0
  74. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/jaaql_middleware_python.egg-info/top_level.txt +0 -0
  75. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/setup.cfg +0 -0
  76. {jaaql-middleware-python-4.24.4 → jaaql-middleware-python-4.24.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaaql-middleware-python
3
- Version: 4.24.4
3
+ Version: 4.24.6
4
4
  Summary: The jaaql package, allowing for rapid development and deployment of RESTful HTTP applications
5
5
  Home-page: https://github.com/JAAQL/JAAQL-middleware-python
6
6
  Author: Software Quality Measurement and Improvement bv
@@ -180,5 +180,5 @@ ROLE__postgres = "postgres"
180
180
 
181
181
  PROTOCOL__postgres = "postgresql://"
182
182
 
183
- VERSION = "4.24.4"
183
+ VERSION = "4.24.6"
184
184
 
@@ -1,241 +1,241 @@
1
- import traceback
2
- from abc import ABC, abstractmethod
3
- from datetime import datetime
4
- import logging
5
- from jaaql.exceptions.http_status_exception import *
6
- from typing import Optional
7
- from jaaql.utilities.utils_no_project_imports import objectify
8
- import queue
9
-
10
- ERR__unknown_echo = "Unknown echo type '%s'. Please use either %s"
11
-
12
- KEY_CONFIG__system = "SYSTEM"
13
- KEY_CONFIG__logging = "logging"
14
-
15
-
16
- RET__echo = "echo"
17
- RET__columns = "columns"
18
- RET__type_codes = "type_codes"
19
- RET__rows = "rows"
20
-
21
- DIVIDER__protocol = "://"
22
- DIVIDER__db = "/"
23
- DIVIDER__port = ":"
24
- DIVIDER__password = ":"
25
- DIVIDER__address = "@"
26
-
27
- ECHO__none = False
28
- ECHO__debug = "debug"
29
- ECHO__execute = True
30
- ECHO__allowed = [ECHO__none, ECHO__debug, ECHO__execute]
31
-
32
- CHAR__newline = "\r\n"
33
-
34
- FILE__read = "r"
35
- FILE__query_separator = ";"
36
-
37
- ERR__missing_database = "The database name was missing from the connection"
38
-
39
-
40
- class DBInterface(ABC):
41
-
42
- @abstractmethod
43
- def __init__(self, config, address: str, username: str):
44
- self.config = config
45
- self.output_exceptions = self.config["DEBUG"]["output_query_exceptions"].lower() == "true"
46
- self.logging = config.get(KEY_CONFIG__system, {KEY_CONFIG__logging: True}).get(KEY_CONFIG__logging, True)
47
- self.username = username
48
- self.address = address
49
-
50
- @staticmethod
51
- def fracture_uri(uri: str, allow_missing_database: bool = False) -> (str, int, str, str, str):
52
- if DIVIDER__protocol in uri:
53
- uri = uri.split(DIVIDER__protocol)[1]
54
-
55
- db_split = uri.split(DIVIDER__address)[-1].split(DIVIDER__db)
56
- address = db_split[0]
57
- db_name = db_split[1] if len(db_split) > 1 else None
58
-
59
- if not allow_missing_database and db_name is None:
60
- raise HttpStatusException(ERR__missing_database)
61
-
62
- username, password = DIVIDER__address.join(uri.split(DIVIDER__address)[:-1]).split(DIVIDER__password)
63
- address, port = address.split(DIVIDER__port)
64
-
65
- return address, port, db_name, username, password
66
-
67
- @abstractmethod
68
- def get_conn(self):
69
- pass
70
-
71
- def log_warning(self, exc):
72
- if self.logging:
73
- logging.warning(exc, exc_info=False)
74
-
75
- def log_critical(self, exc):
76
- if self.logging:
77
- logging.warning(exc, exc_info=False)
78
-
79
- def __attempt_commit_rollback(self, conn, err):
80
- try:
81
- if err is None:
82
- self.commit(conn)
83
- else:
84
- self.rollback(conn)
85
- except Exception as ex:
86
- if err is None:
87
- self.log_warning(ex) # error committing. User stuffed up the SQL
88
- else:
89
- self.log_critical(ex) # error rolling back. It is serious
90
-
91
- def __err_to_exception(self, err, echo):
92
- if err is not None:
93
- if isinstance(err, HttpStatusException) or isinstance(err, JaaqlInterpretableHandledError):
94
- self.log_warning(err)
95
- raise err
96
- else:
97
- ex = self.handle_db_error(err, echo)
98
- if ex.response_code in [HTTPStatus.BAD_REQUEST, HTTPStatus.NOT_FOUND, HTTPStatus.UNAUTHORIZED]:
99
- self.log_warning(ex) # Minor error. User made a bad request (bad query, unauthorised etc.)
100
- else:
101
- self.log_warning(ex) # Serious error, connection failure to db or similar
102
- raise ex
103
-
104
- def handle_error(self, conn, err, echo=ECHO__none):
105
- self.__attempt_commit_rollback(conn, err)
106
- self.__err_to_exception(err, echo)
107
-
108
- def put_conn_handle_error(self, conn, err, echo=ECHO__none, skip_rollback_commit: bool = False):
109
- if not skip_rollback_commit:
110
- self.__attempt_commit_rollback(conn, err)
111
-
112
- try:
113
- self.put_conn(conn)
114
- except Exception as ex:
115
- self.log_warning(ex)
116
-
117
- self.__err_to_exception(err, echo)
118
-
119
- @abstractmethod
120
- def put_conn(self, conn):
121
- pass
122
-
123
- @abstractmethod
124
- def rollback(self, conn):
125
- pass
126
-
127
- def execute_query_fetching_results(self, conn, query, parameters=None, echo=ECHO__none, as_objects=False, wait_hook: queue.Queue = None,
128
- requires_dba_check: bool = False):
129
- if echo not in ECHO__allowed:
130
- allowed_echoes = ", ".join([str(allowed_echo) for allowed_echo in ECHO__allowed])
131
- raise HttpStatusException(ERR__unknown_echo % (str(echo), allowed_echoes), HTTPStatus.BAD_REQUEST)
132
-
133
- if parameters is None:
134
- parameters = {}
135
-
136
- if echo == ECHO__debug:
137
- ret = {}
138
- else:
139
- new_parameters = {}
140
- for key, value in parameters.items():
141
- if value is not None:
142
- if isinstance(value, datetime):
143
- new_parameters[key] = str(value)
144
- else:
145
- new_parameters[key] = value
146
-
147
- if requires_dba_check:
148
- self.check_dba(conn, wait_hook=wait_hook)
149
- if wait_hook:
150
- wait_hook = None
151
-
152
- columns, type_codes, rows = self.execute_query(conn, query, new_parameters, wait_hook)
153
-
154
- ret = {
155
- RET__columns: columns,
156
- RET__rows: rows,
157
- RET__type_codes: type_codes
158
- }
159
-
160
- if echo != ECHO__none:
161
- ret[RET__echo] = query
162
-
163
- if as_objects:
164
- return objectify(ret)
165
- else:
166
- return ret
167
-
168
- def read_utf8(self, filename):
169
- with open(filename, 'rb') as file:
170
- # Read the first few bytes to check for BOM
171
- first_bytes = file.read(3)
172
-
173
- # Check for UTF-8-SIG (BOM)
174
- if first_bytes.startswith(b'\xef\xbb\xbf'):
175
- # Reopen with 'utf-8-sig' to properly handle BOM
176
- file = open(filename, FILE__read, encoding='utf-8-sig')
177
- else:
178
- # Reopen with 'utf-8' assuming no BOM
179
- file = open(filename, FILE__read, encoding='utf-8')
180
-
181
- return file
182
-
183
- def execute_script_file(self, conn, file_loc: str = None, as_content: str = None, as_individual=False, commit=True):
184
- ret = None
185
- err = None
186
-
187
- if as_individual:
188
- ret = []
189
-
190
- try:
191
- if as_content:
192
- queries = as_content
193
- else:
194
- with self.read_utf8(file_loc) as file:
195
- queries = file.read()
196
-
197
- if as_individual:
198
- queries = queries.split(FILE__query_separator)
199
- else:
200
- queries = [queries]
201
-
202
- for query in queries:
203
- if len(query.strip()) != 0:
204
- query = query.strip()
205
- resp = self.execute_query_fetching_results(conn, query, {}, ECHO__execute)
206
-
207
- if as_individual:
208
- ret.append(resp)
209
- else:
210
- ret = resp
211
-
212
- except Exception as ex:
213
- if self.output_exceptions:
214
- traceback.print_exc()
215
- err = ex
216
-
217
- if commit:
218
- self.handle_error(conn, err)
219
- return ret
220
- else:
221
- return ret, err
222
-
223
- @abstractmethod
224
- def check_dba(self, conn, wait_hook: queue.Queue = None):
225
- pass
226
-
227
- @abstractmethod
228
- def execute_query(self, conn, query, parameters: Optional[dict] = None, wait_hook: queue.Queue = None):
229
- pass
230
-
231
- @abstractmethod
232
- def commit(self, conn):
233
- pass
234
-
235
- @abstractmethod
236
- def handle_db_error(self, err, echo) -> HttpStatusException:
237
- pass
238
-
239
- @abstractmethod
240
- def close(self):
241
- pass
1
+ import traceback
2
+ from abc import ABC, abstractmethod
3
+ from datetime import datetime
4
+ import logging
5
+ from jaaql.exceptions.http_status_exception import *
6
+ from typing import Optional
7
+ from jaaql.utilities.utils_no_project_imports import objectify
8
+ import queue
9
+
10
+ ERR__unknown_echo = "Unknown echo type '%s'. Please use either %s"
11
+
12
+ KEY_CONFIG__system = "SYSTEM"
13
+ KEY_CONFIG__logging = "logging"
14
+
15
+
16
+ RET__echo = "echo"
17
+ RET__columns = "columns"
18
+ RET__type_codes = "type_codes"
19
+ RET__rows = "rows"
20
+
21
+ DIVIDER__protocol = "://"
22
+ DIVIDER__db = "/"
23
+ DIVIDER__port = ":"
24
+ DIVIDER__password = ":"
25
+ DIVIDER__address = "@"
26
+
27
+ ECHO__none = False
28
+ ECHO__debug = "debug"
29
+ ECHO__execute = True
30
+ ECHO__allowed = [ECHO__none, ECHO__debug, ECHO__execute]
31
+
32
+ CHAR__newline = "\r\n"
33
+
34
+ FILE__read = "r"
35
+ FILE__query_separator = ";"
36
+
37
+ ERR__missing_database = "The database name was missing from the connection"
38
+
39
+
40
+ class DBInterface(ABC):
41
+
42
+ @abstractmethod
43
+ def __init__(self, config, address: str, username: str):
44
+ self.config = config
45
+ self.output_exceptions = self.config["DEBUG"]["output_query_exceptions"].lower() == "true"
46
+ self.logging = config.get(KEY_CONFIG__system, {KEY_CONFIG__logging: True}).get(KEY_CONFIG__logging, True)
47
+ self.username = username
48
+ self.address = address
49
+
50
+ @staticmethod
51
+ def fracture_uri(uri: str, allow_missing_database: bool = False) -> (str, int, str, str, str):
52
+ if DIVIDER__protocol in uri:
53
+ uri = uri.split(DIVIDER__protocol)[1]
54
+
55
+ db_split = uri.split(DIVIDER__address)[-1].split(DIVIDER__db)
56
+ address = db_split[0]
57
+ db_name = db_split[1] if len(db_split) > 1 else None
58
+
59
+ if not allow_missing_database and db_name is None:
60
+ raise HttpStatusException(ERR__missing_database)
61
+
62
+ username, password = DIVIDER__address.join(uri.split(DIVIDER__address)[:-1]).split(DIVIDER__password)
63
+ address, port = address.split(DIVIDER__port)
64
+
65
+ return address, port, db_name, username, password
66
+
67
+ @abstractmethod
68
+ def get_conn(self):
69
+ pass
70
+
71
+ def log_warning(self, exc):
72
+ if self.logging:
73
+ logging.warning(exc, exc_info=False)
74
+
75
+ def log_critical(self, exc):
76
+ if self.logging:
77
+ logging.warning(exc, exc_info=False)
78
+
79
+ def __attempt_commit_rollback(self, conn, err):
80
+ try:
81
+ if err is None:
82
+ self.commit(conn)
83
+ else:
84
+ self.rollback(conn)
85
+ except Exception as ex:
86
+ if err is None:
87
+ self.log_warning(ex) # error committing. User stuffed up the SQL
88
+ else:
89
+ self.log_critical(ex) # error rolling back. It is serious
90
+
91
+ def __err_to_exception(self, err, echo):
92
+ if err is not None:
93
+ if isinstance(err, HttpStatusException) or isinstance(err, JaaqlInterpretableHandledError):
94
+ self.log_warning(err)
95
+ raise err
96
+ else:
97
+ ex = self.handle_db_error(err, echo)
98
+ if ex.response_code in [HTTPStatus.BAD_REQUEST, HTTPStatus.NOT_FOUND, HTTPStatus.UNAUTHORIZED]:
99
+ self.log_warning(ex) # Minor error. User made a bad request (bad query, unauthorised etc.)
100
+ else:
101
+ self.log_warning(ex) # Serious error, connection failure to db or similar
102
+ raise ex
103
+
104
+ def handle_error(self, conn, err, echo=ECHO__none):
105
+ self.__attempt_commit_rollback(conn, err)
106
+ self.__err_to_exception(err, echo)
107
+
108
+ def put_conn_handle_error(self, conn, err, echo=ECHO__none, skip_rollback_commit: bool = False):
109
+ if not skip_rollback_commit:
110
+ self.__attempt_commit_rollback(conn, err)
111
+
112
+ try:
113
+ self.put_conn(conn)
114
+ except Exception as ex:
115
+ self.log_warning(ex)
116
+
117
+ self.__err_to_exception(err, echo)
118
+
119
+ @abstractmethod
120
+ def put_conn(self, conn):
121
+ pass
122
+
123
+ @abstractmethod
124
+ def rollback(self, conn):
125
+ pass
126
+
127
+ def execute_query_fetching_results(self, conn, query, parameters=None, echo=ECHO__none, as_objects=False, wait_hook: queue.Queue = None,
128
+ requires_dba_check: bool = False):
129
+ if echo not in ECHO__allowed:
130
+ allowed_echoes = ", ".join([str(allowed_echo) for allowed_echo in ECHO__allowed])
131
+ raise HttpStatusException(ERR__unknown_echo % (str(echo), allowed_echoes), HTTPStatus.BAD_REQUEST)
132
+
133
+ if parameters is None:
134
+ parameters = {}
135
+
136
+ if echo == ECHO__debug:
137
+ ret = {}
138
+ else:
139
+ new_parameters = {}
140
+ for key, value in parameters.items():
141
+ if value is not None:
142
+ if isinstance(value, datetime):
143
+ new_parameters[key] = str(value)
144
+ else:
145
+ new_parameters[key] = value
146
+
147
+ if requires_dba_check:
148
+ self.check_dba(conn, wait_hook=wait_hook)
149
+ if wait_hook:
150
+ wait_hook = None
151
+
152
+ columns, type_codes, rows = self.execute_query(conn, query, new_parameters, wait_hook)
153
+
154
+ ret = {
155
+ RET__columns: columns,
156
+ RET__rows: rows,
157
+ RET__type_codes: type_codes
158
+ }
159
+
160
+ if echo != ECHO__none:
161
+ ret[RET__echo] = query
162
+
163
+ if as_objects:
164
+ return objectify(ret)
165
+ else:
166
+ return ret
167
+
168
+ def read_utf8(self, filename):
169
+ with open(filename, 'rb') as file:
170
+ # Read the first few bytes to check for BOM
171
+ first_bytes = file.read(3)
172
+
173
+ # Check for UTF-8-SIG (BOM)
174
+ if first_bytes.startswith(b'\xef\xbb\xbf'):
175
+ # Reopen with 'utf-8-sig' to properly handle BOM
176
+ file = open(filename, FILE__read, encoding='utf-8-sig')
177
+ else:
178
+ # Reopen with 'utf-8' assuming no BOM
179
+ file = open(filename, FILE__read, encoding='utf-8')
180
+
181
+ return file
182
+
183
+ def execute_script_file(self, conn, file_loc: str = None, as_content: str = None, as_individual=False, commit=True):
184
+ ret = None
185
+ err = None
186
+
187
+ if as_individual:
188
+ ret = []
189
+
190
+ try:
191
+ if as_content:
192
+ queries = as_content
193
+ else:
194
+ with self.read_utf8(file_loc) as file:
195
+ queries = file.read()
196
+
197
+ if as_individual:
198
+ queries = queries.split(FILE__query_separator)
199
+ else:
200
+ queries = [queries]
201
+
202
+ for query in queries:
203
+ if len(query.strip()) != 0:
204
+ query = query.strip()
205
+ resp = self.execute_query_fetching_results(conn, query, {}, ECHO__execute)
206
+
207
+ if as_individual:
208
+ ret.append(resp)
209
+ else:
210
+ ret = resp
211
+
212
+ except Exception as ex:
213
+ if self.output_exceptions:
214
+ traceback.print_exc()
215
+ err = ex
216
+
217
+ if commit:
218
+ self.handle_error(conn, err)
219
+ return ret
220
+ else:
221
+ return ret, err
222
+
223
+ @abstractmethod
224
+ def check_dba(self, conn, wait_hook: queue.Queue = None):
225
+ pass
226
+
227
+ @abstractmethod
228
+ def execute_query(self, conn, query, parameters: Optional[dict] = None, wait_hook: queue.Queue = None):
229
+ pass
230
+
231
+ @abstractmethod
232
+ def commit(self, conn):
233
+ pass
234
+
235
+ @abstractmethod
236
+ def handle_db_error(self, err, echo) -> HttpStatusException:
237
+ pass
238
+
239
+ @abstractmethod
240
+ def close(self):
241
+ pass