velocity-python 0.0.84__tar.gz → 0.0.86__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 (70) hide show
  1. {velocity_python-0.0.84/src/velocity_python.egg-info → velocity_python-0.0.86}/PKG-INFO +1 -1
  2. {velocity_python-0.0.84 → velocity_python-0.0.86}/pyproject.toml +1 -1
  3. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/__init__.py +2 -1
  4. velocity_python-0.0.86/src/velocity/app/orders.py +182 -0
  5. velocity_python-0.0.86/src/velocity/app/purchase_orders.py +0 -0
  6. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/handlers/lambda_handler.py +0 -4
  7. velocity_python-0.0.86/src/velocity/db/core/__init__.py +0 -0
  8. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/decorators.py +0 -1
  9. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/engine.py +91 -47
  10. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/table.py +1 -0
  11. velocity_python-0.0.86/src/velocity/db/servers/__init__.py +0 -0
  12. velocity_python-0.0.86/src/velocity/misc/__init__.py +0 -0
  13. {velocity_python-0.0.84 → velocity_python-0.0.86/src/velocity_python.egg-info}/PKG-INFO +1 -1
  14. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity_python.egg-info/SOURCES.txt +5 -0
  15. {velocity_python-0.0.84 → velocity_python-0.0.86}/LICENSE +0 -0
  16. {velocity_python-0.0.84 → velocity_python-0.0.86}/README.md +0 -0
  17. {velocity_python-0.0.84 → velocity_python-0.0.86}/setup.cfg +0 -0
  18. {velocity_python-0.0.84/src/velocity/db/core → velocity_python-0.0.86/src/velocity/app}/__init__.py +0 -0
  19. /velocity_python-0.0.84/src/velocity/db/servers/__init__.py → /velocity_python-0.0.86/src/velocity/app/invoices.py +0 -0
  20. /velocity_python-0.0.84/src/velocity/misc/__init__.py → /velocity_python-0.0.86/src/velocity/app/payments.py +0 -0
  21. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/__init__.py +0 -0
  22. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/amplify.py +0 -0
  23. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/handlers/__init__.py +0 -0
  24. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/handlers/context.py +0 -0
  25. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/handlers/response.py +0 -0
  26. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/aws/handlers/sqs_handler.py +0 -0
  27. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/__init__.py +0 -0
  28. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/column.py +0 -0
  29. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/database.py +0 -0
  30. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/exceptions.py +0 -0
  31. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/result.py +0 -0
  32. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/row.py +0 -0
  33. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/sequence.py +0 -0
  34. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/core/transaction.py +0 -0
  35. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/mysql.py +0 -0
  36. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/mysql_reserved.py +0 -0
  37. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/postgres/__init__.py +0 -0
  38. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/postgres/operators.py +0 -0
  39. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/postgres/reserved.py +0 -0
  40. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/postgres/sql.py +0 -0
  41. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/postgres/types.py +0 -0
  42. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/sqlite.py +0 -0
  43. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/sqlite_reserved.py +0 -0
  44. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/sqlserver.py +0 -0
  45. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/sqlserver_reserved.py +0 -0
  46. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/db/servers/tablehelper.py +0 -0
  47. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/conv/__init__.py +0 -0
  48. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/conv/iconv.py +0 -0
  49. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/conv/oconv.py +0 -0
  50. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/db.py +0 -0
  51. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/export.py +0 -0
  52. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/format.py +0 -0
  53. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/mail.py +0 -0
  54. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/merge.py +0 -0
  55. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/timer.py +0 -0
  56. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity/misc/tools.py +0 -0
  57. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity_python.egg-info/dependency_links.txt +0 -0
  58. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity_python.egg-info/requires.txt +0 -0
  59. {velocity_python-0.0.84 → velocity_python-0.0.86}/src/velocity_python.egg-info/top_level.txt +0 -0
  60. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_db.py +0 -0
  61. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_email_processing.py +0 -0
  62. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_format.py +0 -0
  63. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_iconv.py +0 -0
  64. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_merge.py +0 -0
  65. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_oconv.py +0 -0
  66. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_postgres.py +0 -0
  67. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_response.py +0 -0
  68. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_spreadsheet_functions.py +0 -0
  69. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_sql_builder.py +0 -0
  70. {velocity_python-0.0.84 → velocity_python-0.0.86}/tests/test_timer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.84
3
+ Version: 0.0.86
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Paul Perez <pperez@codeclubs.org>
6
6
  Project-URL: Homepage, https://codeclubs.org/projects/velocity
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "velocity-python"
3
- version = "0.0.84"
3
+ version = "0.0.86"
4
4
  authors = [
5
5
  { name="Paul Perez", email="pperez@codeclubs.org" },
6
6
  ]
@@ -1,5 +1,6 @@
1
- __version__ = version = "0.0.84"
1
+ __version__ = version = "0.0.86"
2
2
 
3
3
  from . import aws
4
4
  from . import db
5
5
  from . import misc
6
+ from . import app
@@ -0,0 +1,182 @@
1
+ import datetime
2
+ import support.app
3
+ import pprint
4
+
5
+ engine = support.app.postgres()
6
+ REQUIRED = object()
7
+
8
+
9
+ @engine.transaction
10
+ class Order:
11
+ SCHEMA = {
12
+ "headers": {
13
+ "customer_email": REQUIRED,
14
+ "order_date": REQUIRED,
15
+ "order_type": REQUIRED,
16
+ },
17
+ "lineitems": {
18
+ "sku": REQUIRED,
19
+ "qty": REQUIRED,
20
+ "price": REQUIRED,
21
+ },
22
+ "lineitems_supp": {
23
+ "note": str,
24
+ },
25
+ }
26
+
27
+ DEFAULTS = {
28
+ "headers": {
29
+ "order_date": lambda: datetime.date.today(),
30
+ "effective_date": lambda: datetime.date.today(),
31
+ }
32
+ }
33
+
34
+ def __init__(self, order_id=None):
35
+ self.order_id = order_id
36
+ self.headers = {}
37
+ self.lineitems = {}
38
+ self.lineitems_supp = {}
39
+
40
+ def __repr__(self):
41
+ return f"Order(order_id={self.order_id}, headers={pprint.pformat(self.headers)}, lineitems={pprint.pformat(self.lineitems)}, lineitems_supp={pprint.pformat(self.lineitems_supp)})"
42
+
43
+ def exists(self, tx):
44
+ if not self.order_id:
45
+ raise ValueError("order_id must be set to check existence")
46
+ return tx.table("orders").find(self.order_id)
47
+
48
+ def __bool__(self):
49
+ return bool(self.order_id) and self.exists(engine.transaction())
50
+
51
+ def load(self, tx):
52
+ if not self.order_id:
53
+ raise ValueError("order_id must be set to load an order")
54
+
55
+ order = tx.table("orders").one(self.order_id)
56
+ if not order:
57
+ raise ValueError(f"Order {self.order_id} not found")
58
+
59
+ self.headers = dict(order)
60
+
61
+ items = (
62
+ tx.table("order_lineitems")
63
+ .select(where={"order_id": self.order_id}, orderby="line_number")
64
+ .all()
65
+ )
66
+ for idx, row in enumerate(items):
67
+ self.lineitems[idx] = dict(row)
68
+
69
+ supps = (
70
+ tx.table("order_lineitems_supp")
71
+ .select(where={"order_id": self.order_id}, orderby="line_number")
72
+ .all()
73
+ )
74
+ for idx, row in enumerate(supps):
75
+ self.lineitems_supp[idx] = dict(row)
76
+
77
+ def update_header(self, key, value):
78
+ self.headers[key] = value
79
+
80
+ def add_lineitem(self, data: dict, supp_data: dict = None):
81
+ index = len(self.lineitems)
82
+ self.lineitems[index] = data
83
+ self.lineitems_supp[index] = supp_data or {}
84
+
85
+ def update_lineitem(self, index: int, data: dict = None, supp_data: dict = None):
86
+ if index not in self.lineitems:
87
+ raise IndexError(f"No line item at index {index}")
88
+ if data:
89
+ self.lineitems[index].update(data)
90
+ if supp_data is not None:
91
+ self.lineitems_supp[index].update(supp_data)
92
+
93
+ def delete_lineitem(self, index: int):
94
+ if index not in self.lineitems:
95
+ raise IndexError(f"No line item at index {index}")
96
+ del self.lineitems[index]
97
+ if index in self.lineitems_supp:
98
+ del self.lineitems_supp[index]
99
+ self._reindex_lineitems()
100
+
101
+ def _reindex_lineitems(self):
102
+ """Re-index lineitems and supplemental data after deletion."""
103
+ new_items = {}
104
+ new_supps = {}
105
+ for i, key in enumerate(sorted(self.lineitems)):
106
+ new_items[i] = self.lineitems[key]
107
+ new_supps[i] = self.lineitems_supp.get(key, {})
108
+ self.lineitems = new_items
109
+ self.lineitems_supp = new_supps
110
+
111
+ def _apply_defaults(self):
112
+ for section, defaults in self.DEFAULTS.items():
113
+ target = getattr(self, section)
114
+ for key, default in defaults.items():
115
+ if key not in target:
116
+ target[key] = default() if callable(default) else default
117
+ elif key == "updated_at":
118
+ # Always update updated_at if present
119
+ target[key] = default() if callable(default) else default
120
+
121
+ def _validate(self):
122
+ self._apply_defaults()
123
+
124
+ for key, requirement in self.SCHEMA["headers"].items():
125
+ if requirement is REQUIRED and key not in self.headers:
126
+ raise ValueError(f"Missing required header field: {key}")
127
+ if (
128
+ key in self.headers
129
+ and requirement is not REQUIRED
130
+ and not isinstance(self.headers[key], requirement)
131
+ ):
132
+ raise TypeError(
133
+ f"Header field '{key}' must be of type {requirement.__name__}"
134
+ )
135
+
136
+ for idx, item in self.lineitems.items():
137
+ for key, requirement in self.SCHEMA["lineitems"].items():
138
+ if requirement is REQUIRED and key not in item:
139
+ raise ValueError(f"Line item {idx} missing required field: {key}")
140
+
141
+ for idx, supp in self.lineitems_supp.items():
142
+ for key, expected in self.SCHEMA["lineitems_supp"].items():
143
+ if key in supp and not isinstance(supp[key], expected):
144
+ raise TypeError(
145
+ f"Supplemental field '{key}' in item {idx} must be of type {expected.__name__}"
146
+ )
147
+
148
+ def persist(self, tx):
149
+ self._validate()
150
+
151
+ if self.order_id:
152
+ tx.table("orders").update(self.headers, self.order_id)
153
+ else:
154
+ record = tx.table("orders").new(self.headers)
155
+ self.order_id = record["sys_id"]
156
+
157
+ tx.table("order_lineitems").delete(where={"order_id": self.order_id})
158
+ tx.table("order_lineitems_supp").delete(where={"order_id": self.order_id})
159
+
160
+ for index in sorted(self.lineitems):
161
+ tx.table("order_lineitems").insert(
162
+ {
163
+ "order_id": self.order_id,
164
+ "line_number": index,
165
+ **self.lineitems[index],
166
+ }
167
+ )
168
+ tx.table("order_lineitems_supp").insert(
169
+ {
170
+ "order_id": self.order_id,
171
+ "line_number": index,
172
+ **self.lineitems_supp.get(index, {}),
173
+ }
174
+ )
175
+
176
+ def to_dict(self):
177
+ return {
178
+ "order_id": self.order_id,
179
+ "headers": self.headers,
180
+ "lineitems": self.lineitems,
181
+ "lineitems_supp": self.lineitems_supp,
182
+ }
@@ -158,10 +158,6 @@ class LambdaHandler:
158
158
  tx.table(helpers.get_tracking_table(user or self.session)).insert(data)
159
159
 
160
160
  def OnActionDefault(self, tx, context):
161
- print("[ERROR] AWS_EVENT", str(self.aws_event))
162
- print("[ERROR] AWS_EVENT", dir(self.aws_event))
163
- print("[ERROR] AWS_EVENT", self.aws_event)
164
-
165
161
  context.response().set_body(
166
162
  {"event": self.aws_event, "postdata": context.postdata()}
167
163
  )
@@ -88,7 +88,6 @@ def return_default(
88
88
  if result is None:
89
89
  result = default
90
90
  except func.exceptions:
91
- traceback.print_exc()
92
91
  self.tx.rollback_savepoint(sp, cursor=self.cursor())
93
92
  return default
94
93
  self.tx.release_savepoint(sp, cursor=self.cursor())
@@ -6,6 +6,11 @@ from functools import wraps
6
6
  from velocity.db import exceptions
7
7
  from velocity.db.core.transaction import Transaction
8
8
 
9
+ import logging
10
+
11
+ logger = logging.getLogger("velocity.db.engine")
12
+ logger.setLevel(logging.INFO) # Or DEBUG for more verbosity
13
+
9
14
 
10
15
  class Engine:
11
16
  """
@@ -14,10 +19,11 @@ class Engine:
14
19
 
15
20
  MAX_RETRIES = 100
16
21
 
17
- def __init__(self, driver, config, sql):
22
+ def __init__(self, driver, config, sql, connect_timeout=5):
18
23
  self.__config = config
19
24
  self.__sql = sql
20
25
  self.__driver = driver
26
+ self.__connect_timeout = connect_timeout
21
27
 
22
28
  def __str__(self):
23
29
  return f"[{self.sql.server}] engine({self.config})"
@@ -39,16 +45,52 @@ class Engine:
39
45
  def __connect(self):
40
46
  """
41
47
  Internal connection logic, raising suitable exceptions on error.
48
+ Enforces a connect timeout and handles different config types.
42
49
  """
50
+ server = self.sql.server.lower()
51
+ timeout_key = "timeout" if "sqlite" in server else "connect_timeout"
52
+ timeout_val = self.__connect_timeout
53
+
43
54
  try:
44
55
  if isinstance(self.config, dict):
45
- return self.driver.connect(**self.config)
46
- if isinstance(self.config, (tuple, list)):
47
- return self.driver.connect(*self.config)
48
- if isinstance(self.config, str):
49
- return self.driver.connect(self.config)
50
- raise Exception("Unhandled configuration parameter.")
51
- except:
56
+ config = self.config.copy()
57
+ if timeout_key not in config:
58
+ config[timeout_key] = timeout_val
59
+ logger.info(
60
+ "Connecting to %s with dict config: %s", self.sql.server, config
61
+ )
62
+ return self.driver.connect(**config)
63
+
64
+ elif isinstance(self.config, str):
65
+ conn_str = self.config
66
+ if timeout_key not in conn_str:
67
+ conn_str += f" {timeout_key}={timeout_val}"
68
+ logger.info(
69
+ "Connecting to %s with str config: %s", self.sql.server, conn_str
70
+ )
71
+ return self.driver.connect(conn_str)
72
+
73
+ elif isinstance(self.config, (tuple, list)):
74
+ config_args = list(self.config)
75
+ if config_args and isinstance(config_args[-1], dict):
76
+ if timeout_key not in config_args[-1]:
77
+ config_args[-1][timeout_key] = timeout_val
78
+ else:
79
+ config_args.append({timeout_key: timeout_val})
80
+
81
+ logger.info(
82
+ "Connecting to %s with tuple/list config (with timeout): %s",
83
+ self.sql.server,
84
+ config_args,
85
+ )
86
+ return self.driver.connect(*config_args)
87
+
88
+ else:
89
+ raise TypeError(
90
+ f"Unhandled configuration parameter type: {type(self.config)}"
91
+ )
92
+
93
+ except Exception:
52
94
  self.process_error()
53
95
 
54
96
  def transaction(self, func_or_cls=None):
@@ -307,67 +349,69 @@ class Engine:
307
349
 
308
350
  error_code, error_mesg = self.sql.get_error(e)
309
351
 
352
+ logger.warning(
353
+ "Database error caught. Attempting to transform: code=%s message=%s",
354
+ error_code,
355
+ error_mesg,
356
+ )
357
+
310
358
  if error_code in self.sql.ApplicationErrorCodes:
311
- raise exceptions.DbApplicationError(e)
359
+ raise exceptions.DbApplicationError from None
312
360
  if error_code in self.sql.ColumnMissingErrorCodes:
313
- raise exceptions.DbColumnMissingError(e)
361
+ raise exceptions.DbColumnMissingError from None
314
362
  if error_code in self.sql.TableMissingErrorCodes:
315
- raise exceptions.DbTableMissingError(e)
363
+ raise exceptions.DbTableMissingError from None
316
364
  if error_code in self.sql.DatabaseMissingErrorCodes:
317
- raise exceptions.DbDatabaseMissingError(e)
365
+ raise exceptions.DbDatabaseMissingError from None
318
366
  if error_code in self.sql.ForeignKeyMissingErrorCodes:
319
- raise exceptions.DbForeignKeyMissingError(e)
367
+ raise exceptions.DbForeignKeyMissingError from None
320
368
  if error_code in self.sql.TruncationErrorCodes:
321
- raise exceptions.DbTruncationError(e)
369
+ raise exceptions.DbTruncationError from None
322
370
  if error_code in self.sql.DataIntegrityErrorCodes:
323
- raise exceptions.DbDataIntegrityError(e)
371
+ raise exceptions.DbDataIntegrityError from None
324
372
  if error_code in self.sql.ConnectionErrorCodes:
325
- raise exceptions.DbConnectionError(e)
373
+ raise exceptions.DbConnectionError from None
326
374
  if error_code in self.sql.DuplicateKeyErrorCodes:
327
- raise exceptions.DbDuplicateKeyError(e)
375
+ raise exceptions.DbDuplicateKeyError from None
328
376
  if re.search(r"key \(sys_id\)=\(\d+\) already exists.", msg, re.M):
329
- raise exceptions.DbDuplicateKeyError(e)
377
+ raise exceptions.DbDuplicateKeyError from None
330
378
  if error_code in self.sql.DatabaseObjectExistsErrorCodes:
331
- raise exceptions.DbObjectExistsError(e)
379
+ raise exceptions.DbObjectExistsError from None
332
380
  if error_code in self.sql.LockTimeoutErrorCodes:
333
- raise exceptions.DbLockTimeoutError(e)
381
+ raise exceptions.DbLockTimeoutError from None
334
382
  if error_code in self.sql.RetryTransactionCodes:
335
- raise exceptions.DbRetryTransaction(e)
383
+ raise exceptions.DbRetryTransaction from None
336
384
  if re.findall(r"database.*does not exist", msg, re.M):
337
- raise exceptions.DbDatabaseMissingError(e)
385
+ raise exceptions.DbDatabaseMissingError from None
338
386
  if re.findall(r"no such database", msg, re.M):
339
- raise exceptions.DbDatabaseMissingError(e)
387
+ raise exceptions.DbDatabaseMissingError from None
340
388
  if re.findall(r"already exists", msg, re.M):
341
- raise exceptions.DbObjectExistsError(e)
389
+ raise exceptions.DbObjectExistsError from None
342
390
  if re.findall(r"server closed the connection unexpectedly", msg, re.M):
343
- raise exceptions.DbConnectionError(e)
391
+ raise exceptions.DbConnectionError from None
344
392
  if re.findall(r"no connection to the server", msg, re.M):
345
- raise exceptions.DbConnectionError(e)
393
+ raise exceptions.DbConnectionError from None
346
394
  if re.findall(r"connection timed out", msg, re.M):
347
- raise exceptions.DbConnectionError(e)
395
+ raise exceptions.DbConnectionError from None
348
396
  if re.findall(r"could not connect to server", msg, re.M):
349
- raise exceptions.DbConnectionError(e)
397
+ raise exceptions.DbConnectionError from None
350
398
  if re.findall(r"cannot connect to server", msg, re.M):
351
- raise exceptions.DbConnectionError(e)
399
+ raise exceptions.DbConnectionError from None
352
400
  if re.findall(r"connection already closed", msg, re.M):
353
- raise exceptions.DbConnectionError(e)
401
+ raise exceptions.DbConnectionError from None
354
402
  if re.findall(r"cursor already closed", msg, re.M):
355
- raise exceptions.DbConnectionError(e)
403
+ raise exceptions.DbConnectionError from None
356
404
  if "no such table:" in msg:
357
- raise exceptions.DbTableMissingError(e)
358
-
359
- msg = f"""
360
- Unhandled/Unknown Error in engine.process_error
361
- EXC_TYPE = {type(e)}
362
- EXC_MSG = {str(e).strip()}
363
-
364
- ERROR_CODE = {error_code}
365
- ERROR_MSG = {error_mesg}
366
-
367
- SQL_STMT = {sql_stmt}
368
- SQL_PARAMS = {sql_params}
369
-
370
- {traceback.format_exc()}
371
- """
372
- print(msg)
405
+ raise exceptions.DbTableMissingError from None
406
+
407
+ logger.error(
408
+ "Unhandled/Unknown Error in engine.process_error",
409
+ exc_info=True,
410
+ extra={
411
+ "error_code": error_code,
412
+ "error_msg": error_mesg,
413
+ "sql_stmt": sql_stmt,
414
+ "sql_params": sql_params,
415
+ },
416
+ )
373
417
  raise
@@ -661,6 +661,7 @@ class Table:
661
661
  return sql, vals
662
662
  return self.tx.execute(sql, vals, cursor=self.cursor()).one()
663
663
 
664
+ @return_default(0)
664
665
  def delete(self, where, **kwds):
665
666
  """
666
667
  Deletes rows matching `where`. Raises Exception if `where` is falsy.
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.84
3
+ Version: 0.0.86
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Paul Perez <pperez@codeclubs.org>
6
6
  Project-URL: Homepage, https://codeclubs.org/projects/velocity
@@ -2,6 +2,11 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  src/velocity/__init__.py
5
+ src/velocity/app/__init__.py
6
+ src/velocity/app/invoices.py
7
+ src/velocity/app/orders.py
8
+ src/velocity/app/payments.py
9
+ src/velocity/app/purchase_orders.py
5
10
  src/velocity/aws/__init__.py
6
11
  src/velocity/aws/amplify.py
7
12
  src/velocity/aws/handlers/__init__.py