jaaql-middleware-python 5.3.4__tar.gz → 5.3.5__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 (78) hide show
  1. {jaaql_middleware_python-5.3.4/jaaql_middleware_python.egg-info → jaaql_middleware_python-5.3.5}/PKG-INFO +1 -1
  2. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/constants.py +1 -1
  3. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/db/db_interface.py +17 -6
  4. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/db/db_pg_interface.py +6 -0
  5. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/db/db_utils.py +20 -4
  6. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/exceptions/http_status_exception.py +9 -0
  7. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5/jaaql_middleware_python.egg-info}/PKG-INFO +1 -1
  8. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/LICENSE.txt +0 -0
  9. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/README.md +0 -0
  10. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/__init__.py +0 -0
  11. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/config/__init__.py +0 -0
  12. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/config/config-docker.ini +0 -0
  13. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/config/config-test.ini +0 -0
  14. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/config/config.ini +0 -0
  15. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/config_constants.py +0 -0
  16. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/db/__init__.py +0 -0
  17. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/db/db_utils_no_circ.py +0 -0
  18. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/documentation/__init__.py +0 -0
  19. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/documentation/documentation_internal.py +0 -0
  20. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/documentation/documentation_public.py +0 -0
  21. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/documentation/documentation_shared.py +0 -0
  22. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/email/__init__.py +0 -0
  23. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/email/email_manager.py +0 -0
  24. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/email/email_manager_service.py +0 -0
  25. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/email/patch_ems.py +0 -0
  26. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/exceptions/__init__.py +0 -0
  27. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/exceptions/custom_http_status.py +0 -0
  28. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/exceptions/jaaql_interpretable_handled_errors.py +0 -0
  29. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/exceptions/not_yet_implement_exception.py +0 -0
  30. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/generated_constants.py +0 -0
  31. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/interpreter/__init__.py +0 -0
  32. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/interpreter/interpret_jaaql.py +0 -0
  33. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/jaaql.py +0 -0
  34. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/migrations/__init__.py +0 -0
  35. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/migrations/migrations.py +0 -0
  36. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/__init__.py +0 -0
  37. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/base_controller.py +0 -0
  38. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/base_model.py +0 -0
  39. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/controller.py +0 -0
  40. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/controller_interface.py +0 -0
  41. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/exception_queries.py +0 -0
  42. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/generated_queries.py +0 -0
  43. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/handmade_queries.py +0 -0
  44. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/model.py +0 -0
  45. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/model_interface.py +0 -0
  46. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/mvc/response.py +0 -0
  47. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/openapi/__init__.py +0 -0
  48. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/openapi/swagger_documentation.py +0 -0
  49. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/patch.py +0 -0
  50. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/01.install_domains.generated.sql +0 -0
  51. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/02.install_super_user.exceptions.sql +0 -0
  52. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/03.install_super_user.handwritten.sql +0 -0
  53. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/04.install_jaaql_data_structures.generated.sql +0 -0
  54. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/05.install_static_data.generated.sql +0 -0
  55. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/06.install_jaaql.exceptions.sql +0 -0
  56. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/ZZZZ.generated_functions_views_and_permissions.sql +0 -0
  57. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/ZZZZ.reset_references.sql +0 -0
  58. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/scripts/swagger_template.html +0 -0
  59. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/services/__init__.py +0 -0
  60. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/services/cached_canned_query_service.py +0 -0
  61. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/services/migrations_manager_service.py +0 -0
  62. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/services/patch_mms.py +0 -0
  63. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/services/patch_shared_var_service.py +0 -0
  64. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/services/shared_var_service.py +0 -0
  65. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/__init__.py +0 -0
  66. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/bootstrap_secrets.py +0 -0
  67. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/cron.py +0 -0
  68. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/crypt_utils.py +0 -0
  69. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/options.py +0 -0
  70. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/utils.py +0 -0
  71. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/utils_no_project_imports.py +0 -0
  72. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql/utilities/vault.py +0 -0
  73. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql_middleware_python.egg-info/SOURCES.txt +0 -0
  74. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql_middleware_python.egg-info/dependency_links.txt +0 -0
  75. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql_middleware_python.egg-info/requires.txt +0 -0
  76. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/jaaql_middleware_python.egg-info/top_level.txt +0 -0
  77. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/setup.cfg +0 -0
  78. {jaaql_middleware_python-5.3.4 → jaaql_middleware_python-5.3.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jaaql-middleware-python
3
- Version: 5.3.4
3
+ Version: 5.3.5
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
@@ -218,5 +218,5 @@ ROLE__dba = "dba"
218
218
 
219
219
  PROTOCOL__postgres = "postgresql://"
220
220
 
221
- VERSION = "5.3.4"
221
+ VERSION = "5.3.5"
222
222
 
@@ -68,6 +68,11 @@ class DBInterface(ABC):
68
68
  def get_conn(self):
69
69
  pass
70
70
 
71
+ def is_connection_error(self, ex) -> bool:
72
+ # Overridden by the concrete interface. True when a failure means the connection/backend went
73
+ # away (so nothing persisted and the operation is safe to retry on a fresh connection).
74
+ return False
75
+
71
76
  def log_warning(self, exc):
72
77
  if self.logging:
73
78
  logging.warning(exc, exc_info=False)
@@ -108,11 +113,20 @@ class DBInterface(ABC):
108
113
  self.log_warning(ex) # Serious error, connection failure to db or similar
109
114
  raise ex
110
115
 
116
+ def __raise_commit_failure(self, commit_err):
117
+ # A failed commit persisted nothing; surface it (instead of the old silent swallow) so the
118
+ # caller cannot treat lost writes as success and hit a misleading error further on. A
119
+ # connection-loss failure is raised as a retriable marker so a self-contained caller can
120
+ # re-run on a fresh connection; any other commit failure is a genuine error.
121
+ if self.is_connection_error(commit_err):
122
+ raise ConnectionLostError(str(commit_err))
123
+ raise HttpStatusException("Commit failed, transaction not persisted: " + str(commit_err),
124
+ HTTPStatus.INTERNAL_SERVER_ERROR)
125
+
111
126
  def handle_error(self, conn, err, echo=ECHO__none):
112
127
  commit_err = self.__attempt_commit_rollback(conn, err)
113
128
  if err is None and commit_err is not None:
114
- raise HttpStatusException("Commit failed, transaction not persisted: " + str(commit_err),
115
- HTTPStatus.INTERNAL_SERVER_ERROR)
129
+ self.__raise_commit_failure(commit_err)
116
130
  self.__err_to_exception(err, echo)
117
131
 
118
132
  def put_conn_handle_error(self, conn, err, echo=ECHO__none, skip_rollback_commit: bool = False):
@@ -125,11 +139,8 @@ class DBInterface(ABC):
125
139
  except Exception as ex:
126
140
  self.log_warning(ex)
127
141
 
128
- # A failed commit persisted nothing; surface it (instead of the old silent swallow) so the
129
- # caller does not treat lost writes as success and hit a misleading error further on.
130
142
  if err is None and commit_err is not None:
131
- raise HttpStatusException("Commit failed, transaction not persisted: " + str(commit_err),
132
- HTTPStatus.INTERNAL_SERVER_ERROR)
143
+ self.__raise_commit_failure(commit_err)
133
144
 
134
145
  self.__err_to_exception(err, echo)
135
146
 
@@ -430,6 +430,12 @@ class DBPGInterface(DBInterface):
430
430
  def rollback(self, conn):
431
431
  conn.rollback()
432
432
 
433
+ def is_connection_error(self, ex) -> bool:
434
+ # psycopg raises OperationalError when the backend/connection went away (e.g. terminated by
435
+ # \wipe dbms). The same class the execute retry loop keys off; a commit that fails this way
436
+ # persisted nothing, so the operation is safe to retry on a fresh connection.
437
+ return isinstance(ex, OperationalError)
438
+
433
439
  def handle_db_error(self, err, echo):
434
440
  if isinstance(err, ProgrammingError) and hasattr(err, 'pgresult'):
435
441
  err = err.pgresult.error_message.decode("UTF-8")
@@ -1,4 +1,4 @@
1
- from jaaql.exceptions.http_status_exception import HttpStatusException, HttpSingletonStatusException
1
+ from jaaql.exceptions.http_status_exception import HttpStatusException, HttpSingletonStatusException, ConnectionLostError
2
2
  from jaaql.interpreter.interpret_jaaql import InterpretJAAQL
3
3
  from jaaql.constants import ENCODING__utf, VAULT_KEY__super_db_credentials
4
4
  from typing import Union
@@ -16,6 +16,10 @@ ERR__expected_single_row = "Expected single row response but received '%d' rows"
16
16
  ERR__unsupported_interface = "Unsupported interface '%s'. We only support %s"
17
17
  ERR__schema_invalid = "Schema invalid!"
18
18
 
19
+ # A lost connection persisted nothing, so a self-contained statement is re-run on a fresh connection.
20
+ # Bounded so a genuinely-down database still surfaces an error rather than looping.
21
+ CONN_LOST__max_attempts = 3
22
+
19
23
  KEY_CONFIG__db = "DATABASE"
20
24
  KEY_CONFIG__interface = "interface"
21
25
  INTERFACE__postgres_key = "postgres"
@@ -104,9 +108,21 @@ def execute_supplied_statement(db_interface, query: str, parameters: dict = None
104
108
  "decrypt": decrypt_columns
105
109
  }
106
110
 
107
- data = InterpretJAAQL(db_interface).transform(statement, skip_commit=skip_commit, encryption_key=encryption_key, autocommit=autocommit,
108
- do_prepare_only=do_prepare_only, attempt_fetch_domain_types=attempt_fetch_domain_types,
109
- psql=psql, pre_psql=pre_psql)
111
+ # Retry only on a lost connection: nothing committed, so re-running on a fresh connection is safe.
112
+ # This closes the gap the deferred-auth optimisation opened - \wipe dbms terminates every backend,
113
+ # and a pooled connection handed out afterwards has no checkout probe and can die at commit. Params
114
+ # are already encrypted above, so the retry re-runs the transform only (never re-encrypts).
115
+ attempts = 0
116
+ while True:
117
+ attempts += 1
118
+ try:
119
+ data = InterpretJAAQL(db_interface).transform(statement, skip_commit=skip_commit, encryption_key=encryption_key, autocommit=autocommit,
120
+ do_prepare_only=do_prepare_only, attempt_fetch_domain_types=attempt_fetch_domain_types,
121
+ psql=psql, pre_psql=pre_psql)
122
+ break
123
+ except ConnectionLostError:
124
+ if attempts >= CONN_LOST__max_attempts:
125
+ raise
110
126
 
111
127
  if as_objects:
112
128
  data = objectify(data)
@@ -34,6 +34,15 @@ class HttpSingletonStatusException(HttpStatusException):
34
34
  self.actual_count = actual_count
35
35
 
36
36
 
37
+ class ConnectionLostError(HttpStatusException):
38
+ # Raised when a database operation failed because its connection was lost (e.g. the backend was
39
+ # terminated by \wipe dbms's pg_terminate_backend) BEFORE anything committed. Nothing persisted,
40
+ # so a self-contained operation may safely be retried on a fresh connection. Subclasses
41
+ # HttpStatusException so that if retries are exhausted it still surfaces as a clean 500.
42
+ def __init__(self, message: str):
43
+ super().__init__("Commit failed, transaction not persisted: " + message, HTTPStatus.INTERNAL_SERVER_ERROR)
44
+
45
+
37
46
  class JaaqlInterpretableHandledError(Exception):
38
47
  def __init__(self, error_code: int, http_response_code: int,
39
48
  table_name: str | None, index: int | None, message: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jaaql-middleware-python
3
- Version: 5.3.4
3
+ Version: 5.3.5
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