velocity-python 0.0.108__py3-none-any.whl → 0.0.110__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.
Potentially problematic release.
This version of velocity-python might be problematic. Click here for more details.
- velocity/__init__.py +1 -1
- velocity/db/core/engine.py +76 -129
- {velocity_python-0.0.108.dist-info → velocity_python-0.0.110.dist-info}/METADATA +1 -1
- {velocity_python-0.0.108.dist-info → velocity_python-0.0.110.dist-info}/RECORD +7 -7
- {velocity_python-0.0.108.dist-info → velocity_python-0.0.110.dist-info}/WHEEL +0 -0
- {velocity_python-0.0.108.dist-info → velocity_python-0.0.110.dist-info}/licenses/LICENSE +0 -0
- {velocity_python-0.0.108.dist-info → velocity_python-0.0.110.dist-info}/top_level.txt +0 -0
velocity/__init__.py
CHANGED
velocity/db/core/engine.py
CHANGED
|
@@ -327,146 +327,93 @@ class Engine:
|
|
|
327
327
|
|
|
328
328
|
def process_error(self, exception, sql=None, parameters=None):
|
|
329
329
|
"""
|
|
330
|
-
|
|
331
|
-
Enhanced for robustness with exception chaining and comprehensive error handling.
|
|
332
|
-
|
|
333
|
-
Args:
|
|
334
|
-
exception: The original exception from the database driver
|
|
335
|
-
sql: The SQL statement that caused the error (optional)
|
|
336
|
-
parameters: The parameters passed to the SQL statement (optional)
|
|
337
|
-
|
|
338
|
-
Raises:
|
|
339
|
-
The appropriate velocity exception with proper chaining
|
|
330
|
+
Central method to parse driver exceptions and re-raise them as our custom exceptions.
|
|
340
331
|
"""
|
|
341
332
|
logger = logging.getLogger(__name__)
|
|
342
333
|
|
|
343
|
-
#
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
logger.error(
|
|
347
|
-
f"🔴 Database Error Detected\n"
|
|
348
|
-
f" Exception Type: {type(exception).__name__}\n"
|
|
349
|
-
f" SQL Statement: {sql_preview}\n"
|
|
350
|
-
f" Processing error for classification..."
|
|
351
|
-
)
|
|
334
|
+
# If it's already a velocity exception, just re-raise it
|
|
335
|
+
if isinstance(exception, exceptions.DbException):
|
|
336
|
+
raise exception
|
|
352
337
|
|
|
353
|
-
#
|
|
338
|
+
# Get error code and message from the SQL driver
|
|
354
339
|
try:
|
|
355
|
-
error_code
|
|
356
|
-
except Exception
|
|
357
|
-
|
|
358
|
-
error_code = None
|
|
359
|
-
|
|
360
|
-
try:
|
|
361
|
-
error_message = str(exception)
|
|
362
|
-
except Exception as e:
|
|
363
|
-
logger.warning(f"⚠️ Unable to convert exception to string: {e}")
|
|
364
|
-
error_message = f"<Error converting exception: {type(exception).__name__}>"
|
|
365
|
-
|
|
366
|
-
# Primary error classification by error code
|
|
367
|
-
if error_code and hasattr(self, 'error_codes'):
|
|
368
|
-
for error_class, codes in self.error_codes.items():
|
|
369
|
-
if error_code in codes:
|
|
370
|
-
logger.info(f"✅ Successfully classified error: {error_code} → {error_class}")
|
|
371
|
-
try:
|
|
372
|
-
raise self._create_exception_with_chaining(
|
|
373
|
-
error_class, error_message, exception, sql, parameters
|
|
374
|
-
)
|
|
375
|
-
except Exception as creation_error:
|
|
376
|
-
logger.error(f"❌ Failed to create {error_class} exception: {creation_error}")
|
|
377
|
-
# Fall through to regex classification
|
|
378
|
-
break
|
|
379
|
-
|
|
380
|
-
# Secondary error classification by message patterns (regex fallback)
|
|
381
|
-
error_message_lower = error_message.lower()
|
|
382
|
-
|
|
383
|
-
# Enhanced connection error patterns
|
|
384
|
-
connection_patterns = [
|
|
385
|
-
r'connection.*refused|could not connect',
|
|
386
|
-
r'network.*unreachable|network.*down',
|
|
387
|
-
r'broken pipe|connection.*broken',
|
|
388
|
-
r'timeout.*connection|connection.*timeout',
|
|
389
|
-
r'server.*closed.*connection|connection.*lost',
|
|
390
|
-
r'no route to host|host.*unreachable',
|
|
391
|
-
r'connection.*reset|reset.*connection'
|
|
392
|
-
]
|
|
393
|
-
|
|
394
|
-
# Enhanced duplicate key patterns
|
|
395
|
-
duplicate_patterns = [
|
|
396
|
-
r'duplicate.*key.*value|unique.*constraint.*violated',
|
|
397
|
-
r'duplicate.*entry|key.*already.*exists',
|
|
398
|
-
r'violates.*unique.*constraint',
|
|
399
|
-
r'unique.*violation|constraint.*unique'
|
|
400
|
-
]
|
|
401
|
-
|
|
402
|
-
# Enhanced permission/authorization patterns
|
|
403
|
-
permission_patterns = [
|
|
404
|
-
r'permission.*denied|access.*denied|authorization.*failed',
|
|
405
|
-
r'insufficient.*privileges|privilege.*denied',
|
|
406
|
-
r'not.*authorized|unauthorized.*access',
|
|
407
|
-
r'authentication.*failed|login.*failed'
|
|
408
|
-
]
|
|
409
|
-
|
|
410
|
-
# Enhanced database/table not found patterns
|
|
411
|
-
not_found_patterns = [
|
|
412
|
-
r'database.*does.*not.*exist|unknown.*database',
|
|
413
|
-
r'table.*does.*not.*exist|relation.*does.*not.*exist',
|
|
414
|
-
r'no.*such.*database|database.*not.*found',
|
|
415
|
-
r'schema.*does.*not.*exist|unknown.*table'
|
|
416
|
-
]
|
|
417
|
-
|
|
418
|
-
# Enhanced syntax error patterns
|
|
419
|
-
syntax_patterns = [
|
|
420
|
-
r'syntax.*error|invalid.*syntax',
|
|
421
|
-
r'malformed.*query|bad.*sql.*grammar',
|
|
422
|
-
r'unexpected.*token|parse.*error'
|
|
423
|
-
]
|
|
424
|
-
|
|
425
|
-
# Enhanced deadlock/timeout patterns
|
|
426
|
-
deadlock_patterns = [
|
|
427
|
-
r'deadlock.*detected|lock.*timeout',
|
|
428
|
-
r'timeout.*waiting.*for.*lock|query.*timeout',
|
|
429
|
-
r'lock.*wait.*timeout|deadlock.*found'
|
|
430
|
-
]
|
|
431
|
-
|
|
432
|
-
# Comprehensive pattern matching with error class mapping
|
|
433
|
-
pattern_mappings = [
|
|
434
|
-
(connection_patterns, 'ConnectionError'),
|
|
435
|
-
(duplicate_patterns, 'DuplicateError'),
|
|
436
|
-
(permission_patterns, 'PermissionError'),
|
|
437
|
-
(not_found_patterns, 'NotFoundError'),
|
|
438
|
-
(syntax_patterns, 'SyntaxError'),
|
|
439
|
-
(deadlock_patterns, 'DeadlockError')
|
|
440
|
-
]
|
|
340
|
+
error_code, error_message = self.sql.get_error(exception)
|
|
341
|
+
except Exception:
|
|
342
|
+
error_code, error_message = None, str(exception)
|
|
441
343
|
|
|
442
|
-
|
|
443
|
-
for patterns, error_class in pattern_mappings:
|
|
444
|
-
for pattern in patterns:
|
|
445
|
-
try:
|
|
446
|
-
if re.search(pattern, error_message_lower):
|
|
447
|
-
logger.info(f"✅ Classified error by pattern match: '{pattern}' → {error_class}")
|
|
448
|
-
raise self._create_exception_with_chaining(
|
|
449
|
-
error_class, error_message, exception, sql, parameters
|
|
450
|
-
)
|
|
451
|
-
except re.error as regex_error:
|
|
452
|
-
logger.warning(f"⚠️ Regex pattern error for '{pattern}': {regex_error}")
|
|
453
|
-
continue
|
|
454
|
-
except Exception as pattern_error:
|
|
455
|
-
logger.error(f"❌ Error applying pattern '{pattern}': {pattern_error}")
|
|
456
|
-
continue
|
|
344
|
+
msg = str(exception).strip().lower()
|
|
457
345
|
|
|
458
|
-
# Fallback: return generic database error with full context
|
|
459
|
-
available_codes = list(getattr(self, 'error_codes', {}).keys()) if hasattr(self, 'error_codes') else []
|
|
460
346
|
logger.warning(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
f" → Available Classifications: {available_codes or 'None configured'}"
|
|
347
|
+
"Database error caught. Attempting to transform: code=%s message=%s",
|
|
348
|
+
error_code,
|
|
349
|
+
error_message,
|
|
465
350
|
)
|
|
466
351
|
|
|
467
|
-
|
|
468
|
-
|
|
352
|
+
# Direct error code mapping
|
|
353
|
+
if error_code in self.sql.ApplicationErrorCodes:
|
|
354
|
+
raise exceptions.DbApplicationError(str(exception)) from exception
|
|
355
|
+
if error_code in self.sql.ColumnMissingErrorCodes:
|
|
356
|
+
raise exceptions.DbColumnMissingError(str(exception)) from exception
|
|
357
|
+
if error_code in self.sql.TableMissingErrorCodes:
|
|
358
|
+
raise exceptions.DbTableMissingError(str(exception)) from exception
|
|
359
|
+
if error_code in self.sql.DatabaseMissingErrorCodes:
|
|
360
|
+
raise exceptions.DbDatabaseMissingError(str(exception)) from exception
|
|
361
|
+
if error_code in self.sql.ForeignKeyMissingErrorCodes:
|
|
362
|
+
raise exceptions.DbForeignKeyMissingError(str(exception)) from exception
|
|
363
|
+
if error_code in self.sql.TruncationErrorCodes:
|
|
364
|
+
raise exceptions.DbTruncationError(str(exception)) from exception
|
|
365
|
+
if error_code in self.sql.DataIntegrityErrorCodes:
|
|
366
|
+
raise exceptions.DbDataIntegrityError(str(exception)) from exception
|
|
367
|
+
if error_code in self.sql.ConnectionErrorCodes:
|
|
368
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
369
|
+
if error_code in self.sql.DuplicateKeyErrorCodes:
|
|
370
|
+
raise exceptions.DbDuplicateKeyError(str(exception)) from exception
|
|
371
|
+
if error_code in self.sql.DatabaseObjectExistsErrorCodes:
|
|
372
|
+
raise exceptions.DbObjectExistsError(str(exception)) from exception
|
|
373
|
+
if error_code in self.sql.LockTimeoutErrorCodes:
|
|
374
|
+
raise exceptions.DbLockTimeoutError(str(exception)) from exception
|
|
375
|
+
if error_code in self.sql.RetryTransactionCodes:
|
|
376
|
+
raise exceptions.DbRetryTransaction(str(exception)) from exception
|
|
377
|
+
|
|
378
|
+
# Regex-based fallback patterns
|
|
379
|
+
if re.search(r"key \(sys_id\)=\(\d+\) already exists.", msg, re.M):
|
|
380
|
+
raise exceptions.DbDuplicateKeyError(str(exception)) from exception
|
|
381
|
+
if re.findall(r"database.*does not exist", msg, re.M):
|
|
382
|
+
raise exceptions.DbDatabaseMissingError(str(exception)) from exception
|
|
383
|
+
if re.findall(r"no such database", msg, re.M):
|
|
384
|
+
raise exceptions.DbDatabaseMissingError(str(exception)) from exception
|
|
385
|
+
if re.findall(r"already exists", msg, re.M):
|
|
386
|
+
raise exceptions.DbObjectExistsError(str(exception)) from exception
|
|
387
|
+
if re.findall(r"server closed the connection unexpectedly", msg, re.M):
|
|
388
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
389
|
+
if re.findall(r"no connection to the server", msg, re.M):
|
|
390
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
391
|
+
if re.findall(r"connection timed out", msg, re.M):
|
|
392
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
393
|
+
if re.findall(r"could not connect to server", msg, re.M):
|
|
394
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
395
|
+
if re.findall(r"cannot connect to server", msg, re.M):
|
|
396
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
397
|
+
if re.findall(r"connection already closed", msg, re.M):
|
|
398
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
399
|
+
if re.findall(r"cursor already closed", msg, re.M):
|
|
400
|
+
raise exceptions.DbConnectionError(str(exception)) from exception
|
|
401
|
+
if "no such table:" in msg:
|
|
402
|
+
raise exceptions.DbTableMissingError(str(exception)) from exception
|
|
403
|
+
|
|
404
|
+
logger.error(
|
|
405
|
+
"Unhandled/Unknown Error in engine.process_error",
|
|
406
|
+
exc_info=True,
|
|
407
|
+
extra={
|
|
408
|
+
"error_code": error_code,
|
|
409
|
+
"error_msg": error_message,
|
|
410
|
+
"sql_stmt": sql,
|
|
411
|
+
"sql_params": parameters,
|
|
412
|
+
},
|
|
469
413
|
)
|
|
414
|
+
|
|
415
|
+
# If we can't classify it, re-raise the original exception
|
|
416
|
+
raise exception
|
|
470
417
|
|
|
471
418
|
def _format_human_readable_error(self, error_class, message, original_exception, sql=None, parameters=None, format_type='console'):
|
|
472
419
|
"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
velocity/__init__.py,sha256
|
|
1
|
+
velocity/__init__.py,sha256=5Na4DTc1X43viY7Pm3xBOpXkedLfKb2sDq7Y3pK6Z8M,107
|
|
2
2
|
velocity/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
velocity/app/invoices.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
velocity/app/orders.py,sha256=W-HAXEwY8-IFXbKh82HnMeRVZM7P-TWGEQOWtkLIzI4,6298
|
|
@@ -18,7 +18,7 @@ velocity/db/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
|
18
18
|
velocity/db/core/column.py,sha256=tAr8tL3a2nyaYpNHhGl508FrY_pGZTzyYgjAV5CEBv4,4092
|
|
19
19
|
velocity/db/core/database.py,sha256=3zNGItklu9tZCKsbx2T2vCcU1so8AL9PPL0DLjvaz6s,3554
|
|
20
20
|
velocity/db/core/decorators.py,sha256=76Jkr9XptXt8cvcgp1zbHfuL8uHzWy8lwfR29u-DVu4,4574
|
|
21
|
-
velocity/db/core/engine.py,sha256=
|
|
21
|
+
velocity/db/core/engine.py,sha256=ykF-UjYlDqDgD_KDLp7kiot-TEOrh5BifnPLyQEewgo,47549
|
|
22
22
|
velocity/db/core/exceptions.py,sha256=tuDniRqTX8Opc2d033LPJOI3Ux4NSwUcHqW729n-HXA,1027
|
|
23
23
|
velocity/db/core/result.py,sha256=dgiOXH-iJXuDH4PbSTWVkn-heAkJQcXCC-gs0ZuqF94,12814
|
|
24
24
|
velocity/db/core/row.py,sha256=zZ3zZbWjZkZfYAYuZJLHFJ8jdXc7dYv8Iyv9Ut8W8tE,7261
|
|
@@ -49,8 +49,8 @@ velocity/misc/tools.py,sha256=_bGneHHA_BV-kUonzw5H3hdJ5AOJRCKfzhgpkFbGqIo,1502
|
|
|
49
49
|
velocity/misc/conv/__init__.py,sha256=MLYF58QHjzfDSxb1rdnmLnuEQCa3gnhzzZ30CwZVvQo,40
|
|
50
50
|
velocity/misc/conv/iconv.py,sha256=d4_BucW8HTIkGNurJ7GWrtuptqUf-9t79ObzjJ5N76U,10603
|
|
51
51
|
velocity/misc/conv/oconv.py,sha256=h5Lo05DqOQnxoD3y6Px_MQP_V-pBbWf8Hkgkb9Xp1jk,6032
|
|
52
|
-
velocity_python-0.0.
|
|
53
|
-
velocity_python-0.0.
|
|
54
|
-
velocity_python-0.0.
|
|
55
|
-
velocity_python-0.0.
|
|
56
|
-
velocity_python-0.0.
|
|
52
|
+
velocity_python-0.0.110.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
|
|
53
|
+
velocity_python-0.0.110.dist-info/METADATA,sha256=KSop21_ZqWqh1EZNPMcOge75C9POxKMVG5ZQhg6NrrM,34262
|
|
54
|
+
velocity_python-0.0.110.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
55
|
+
velocity_python-0.0.110.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
|
|
56
|
+
velocity_python-0.0.110.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|