velocity-python 0.0.100__tar.gz → 0.0.102__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.
Potentially problematic release.
This version of velocity-python might be problematic. Click here for more details.
- {velocity_python-0.0.100/src/velocity_python.egg-info → velocity_python-0.0.102}/PKG-INFO +1 -1
- {velocity_python-0.0.100 → velocity_python-0.0.102}/pyproject.toml +1 -1
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/__init__.py +4 -1
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/exceptions.py +16 -0
- velocity_python-0.0.102/src/velocity/db/exceptions.py +112 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/sql.py +1 -1
- {velocity_python-0.0.100 → velocity_python-0.0.102/src/velocity_python.egg-info}/PKG-INFO +1 -1
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- velocity_python-0.0.102/tests/test_process_error_robustness.py +236 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/LICENSE +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/README.md +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/setup.cfg +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/app/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/app/invoices.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/app/orders.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/app/payments.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/app/purchase_orders.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/result.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/table.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/mysql.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/mysql_reserved.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/sqlite.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/sqlite_reserved.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/sqlserver.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/sqlserver_reserved.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_db.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_email_processing.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_fix.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_format.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_iconv.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_merge.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_oconv.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_original_error.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_postgres.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_response.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_sql_builder.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_tablehelper.py +0 -0
- {velocity_python-0.0.100 → velocity_python-0.0.102}/tests/test_timer.py +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
from velocity.db
|
|
1
|
+
from velocity.db import exceptions
|
|
2
2
|
from velocity.db.servers import postgres
|
|
3
3
|
from velocity.db.servers import mysql
|
|
4
4
|
from velocity.db.servers import sqlite
|
|
5
5
|
from velocity.db.servers import sqlserver
|
|
6
|
+
|
|
7
|
+
# Export exceptions at the package level for backward compatibility
|
|
8
|
+
from velocity.db.exceptions import *
|
|
@@ -52,3 +52,19 @@ class DbDataIntegrityError(DbException):
|
|
|
52
52
|
|
|
53
53
|
class DuplicateRowsFoundError(Exception):
|
|
54
54
|
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class DbQueryError(DbException):
|
|
58
|
+
"""Database query error"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class DbTransactionError(DbException):
|
|
63
|
+
"""Database transaction error"""
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Add aliases for backward compatibility with engine.py
|
|
68
|
+
class DatabaseError(DbException):
|
|
69
|
+
"""Generic database error - alias for DbException"""
|
|
70
|
+
pass
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database exceptions for the velocity library.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DbException(Exception):
|
|
7
|
+
"""Base class for all database exceptions."""
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DbApplicationError(DbException):
|
|
12
|
+
"""Application-level database error."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DbForeignKeyMissingError(DbException):
|
|
17
|
+
"""Foreign key constraint violation."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DbDatabaseMissingError(DbException):
|
|
22
|
+
"""Database does not exist."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DbTableMissingError(DbException):
|
|
27
|
+
"""Table does not exist."""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DbColumnMissingError(DbException):
|
|
32
|
+
"""Column does not exist."""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DbTruncationError(DbException):
|
|
37
|
+
"""Data truncation error."""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DbConnectionError(DbException):
|
|
42
|
+
"""Database connection error."""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class DbDuplicateKeyError(DbException):
|
|
47
|
+
"""Duplicate key constraint violation."""
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class DbObjectExistsError(DbException):
|
|
52
|
+
"""Database object already exists."""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class DbLockTimeoutError(DbException):
|
|
57
|
+
"""Lock timeout error."""
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class DbRetryTransaction(DbException):
|
|
62
|
+
"""Transaction should be retried."""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class DbDataIntegrityError(DbException):
|
|
67
|
+
"""Data integrity constraint violation."""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class DbQueryError(DbException):
|
|
72
|
+
"""Database query error."""
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class DbTransactionError(DbException):
|
|
77
|
+
"""Database transaction error."""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class DuplicateRowsFoundError(Exception):
|
|
82
|
+
"""Multiple rows found when expecting single result."""
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# Add aliases for backward compatibility with engine.py
|
|
87
|
+
class DatabaseError(DbException):
|
|
88
|
+
"""Generic database error - alias for DbException."""
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
__all__ = [
|
|
92
|
+
# Base exceptions
|
|
93
|
+
'DbException',
|
|
94
|
+
'DatabaseError',
|
|
95
|
+
|
|
96
|
+
# Specific exceptions
|
|
97
|
+
'DbApplicationError',
|
|
98
|
+
'DbForeignKeyMissingError',
|
|
99
|
+
'DbDatabaseMissingError',
|
|
100
|
+
'DbTableMissingError',
|
|
101
|
+
'DbColumnMissingError',
|
|
102
|
+
'DbTruncationError',
|
|
103
|
+
'DbConnectionError',
|
|
104
|
+
'DbDuplicateKeyError',
|
|
105
|
+
'DbObjectExistsError',
|
|
106
|
+
'DbLockTimeoutError',
|
|
107
|
+
'DbRetryTransaction',
|
|
108
|
+
'DbDataIntegrityError',
|
|
109
|
+
'DbQueryError',
|
|
110
|
+
'DbTransactionError',
|
|
111
|
+
'DuplicateRowsFoundError',
|
|
112
|
+
]
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
@@ -15,6 +15,7 @@ src/velocity/aws/handlers/lambda_handler.py
|
|
|
15
15
|
src/velocity/aws/handlers/response.py
|
|
16
16
|
src/velocity/aws/handlers/sqs_handler.py
|
|
17
17
|
src/velocity/db/__init__.py
|
|
18
|
+
src/velocity/db/exceptions.py
|
|
18
19
|
src/velocity/db/core/__init__.py
|
|
19
20
|
src/velocity/db/core/column.py
|
|
20
21
|
src/velocity/db/core/database.py
|
|
@@ -64,6 +65,7 @@ tests/test_merge.py
|
|
|
64
65
|
tests/test_oconv.py
|
|
65
66
|
tests/test_original_error.py
|
|
66
67
|
tests/test_postgres.py
|
|
68
|
+
tests/test_process_error_robustness.py
|
|
67
69
|
tests/test_response.py
|
|
68
70
|
tests/test_spreadsheet_functions.py
|
|
69
71
|
tests/test_sql_builder.py
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Test the robustness of the improved process_error method
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
import unittest
|
|
9
|
+
from unittest.mock import Mock, patch
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
# Add the source directory to the path
|
|
13
|
+
sys.path.insert(0, '/home/ubuntu/tenspace/velocity-python/src')
|
|
14
|
+
|
|
15
|
+
from velocity.db.core.engine import Engine
|
|
16
|
+
from velocity.db import exceptions
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MockException(Exception):
|
|
20
|
+
"""Mock exception for testing"""
|
|
21
|
+
def __init__(self, message, pgcode=None, pgerror=None):
|
|
22
|
+
super().__init__(message)
|
|
23
|
+
self.pgcode = pgcode
|
|
24
|
+
self.pgerror = pgerror
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MockSQL:
|
|
28
|
+
"""Mock SQL class for testing"""
|
|
29
|
+
server = "PostgreSQL"
|
|
30
|
+
|
|
31
|
+
ApplicationErrorCodes = ["22P02", "42883", "42501", "42601", "25P01", "25P02"]
|
|
32
|
+
DatabaseMissingErrorCodes = ["3D000"]
|
|
33
|
+
TableMissingErrorCodes = ["42P01"]
|
|
34
|
+
ColumnMissingErrorCodes = ["42703"]
|
|
35
|
+
ForeignKeyMissingErrorCodes = ["42704"]
|
|
36
|
+
ConnectionErrorCodes = ["08001", "08S01", "57P03", "08006", "53300", "08003", "08004", "08P01"]
|
|
37
|
+
DuplicateKeyErrorCodes = ["23505"]
|
|
38
|
+
RetryTransactionCodes = ["40001", "40P01", "40002"]
|
|
39
|
+
TruncationErrorCodes = ["22001"]
|
|
40
|
+
LockTimeoutErrorCodes = ["55P03"]
|
|
41
|
+
DatabaseObjectExistsErrorCodes = ["42710", "42P07", "42P04"]
|
|
42
|
+
DataIntegrityErrorCodes = ["23503", "23502", "23514", "23P01", "22003"]
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def get_error(cls, e):
|
|
46
|
+
return getattr(e, 'pgcode', None), getattr(e, 'pgerror', None)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TestProcessErrorRobustness(unittest.TestCase):
|
|
50
|
+
|
|
51
|
+
def setUp(self):
|
|
52
|
+
"""Set up test fixtures"""
|
|
53
|
+
self.engine = Engine(
|
|
54
|
+
driver=Mock(),
|
|
55
|
+
config={'test': 'config'},
|
|
56
|
+
sql=MockSQL()
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Capture logs for testing
|
|
60
|
+
self.log_handler = logging.StreamHandler()
|
|
61
|
+
self.log_handler.setLevel(logging.DEBUG)
|
|
62
|
+
logger = logging.getLogger("velocity.db.engine")
|
|
63
|
+
logger.addHandler(self.log_handler)
|
|
64
|
+
logger.setLevel(logging.DEBUG)
|
|
65
|
+
|
|
66
|
+
def test_error_code_classification(self):
|
|
67
|
+
"""Test that error codes are properly classified"""
|
|
68
|
+
test_cases = [
|
|
69
|
+
# (pgcode, expected_exception_class, description)
|
|
70
|
+
("23505", exceptions.DbDuplicateKeyError, "unique violation"),
|
|
71
|
+
("40001", exceptions.DbRetryTransaction, "serialization failure"),
|
|
72
|
+
("40P01", exceptions.DbRetryTransaction, "deadlock detected"),
|
|
73
|
+
("42501", exceptions.DbApplicationError, "insufficient privilege"),
|
|
74
|
+
("42601", exceptions.DbApplicationError, "syntax error"),
|
|
75
|
+
("25P01", exceptions.DbApplicationError, "no active sql transaction"),
|
|
76
|
+
("3D000", exceptions.DbDatabaseMissingError, "invalid catalog name"),
|
|
77
|
+
("08003", exceptions.DbConnectionError, "connection does not exist"),
|
|
78
|
+
("23502", exceptions.DbDataIntegrityError, "not null violation"),
|
|
79
|
+
("42P01", exceptions.DbTableMissingError, "undefined table"),
|
|
80
|
+
("42703", exceptions.DbColumnMissingError, "undefined column"),
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
for pgcode, expected_exception, description in test_cases:
|
|
84
|
+
with self.subTest(pgcode=pgcode, description=description):
|
|
85
|
+
mock_exc = MockException(f"Test error: {description}", pgcode=pgcode)
|
|
86
|
+
|
|
87
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
88
|
+
with self.assertRaises(expected_exception):
|
|
89
|
+
self.engine.process_error("test sql", {"param": "value"})
|
|
90
|
+
|
|
91
|
+
def test_regex_fallback_patterns(self):
|
|
92
|
+
"""Test regex pattern fallback when error codes aren't available"""
|
|
93
|
+
test_cases = [
|
|
94
|
+
# (message, expected_exception_class, description)
|
|
95
|
+
("key (sys_id)=(123) already exists.", exceptions.DbDuplicateKeyError, "sys_id duplicate"),
|
|
96
|
+
("duplicate key value violates unique constraint", exceptions.DbDuplicateKeyError, "unique constraint"),
|
|
97
|
+
("database 'testdb' does not exist", exceptions.DbDatabaseMissingError, "database missing"),
|
|
98
|
+
("no such database: mydb", exceptions.DbDatabaseMissingError, "database not found"),
|
|
99
|
+
("table 'users' already exists", exceptions.DbObjectExistsError, "object exists"),
|
|
100
|
+
("server closed the connection unexpectedly", exceptions.DbConnectionError, "connection closed"),
|
|
101
|
+
("connection timed out", exceptions.DbConnectionError, "connection timeout"),
|
|
102
|
+
("no such table: users", exceptions.DbTableMissingError, "table missing"),
|
|
103
|
+
("permission denied for table users", exceptions.DbApplicationError, "permission denied"),
|
|
104
|
+
("syntax error at or near 'SELCT'", exceptions.DbApplicationError, "syntax error"),
|
|
105
|
+
("deadlock detected", exceptions.DbLockTimeoutError, "deadlock"),
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
for message, expected_exception, description in test_cases:
|
|
109
|
+
with self.subTest(message=message, description=description):
|
|
110
|
+
mock_exc = MockException(message) # No pgcode - will trigger regex fallback
|
|
111
|
+
|
|
112
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
113
|
+
with self.assertRaises(expected_exception):
|
|
114
|
+
self.engine.process_error("test sql", {"param": "value"})
|
|
115
|
+
|
|
116
|
+
def test_already_custom_exception(self):
|
|
117
|
+
"""Test that custom exceptions are re-raised as-is"""
|
|
118
|
+
custom_exc = exceptions.DbConnectionError("Already a custom exception")
|
|
119
|
+
|
|
120
|
+
with patch('sys.exc_info', return_value=(type(custom_exc), custom_exc, None)):
|
|
121
|
+
with self.assertRaises(exceptions.DbConnectionError):
|
|
122
|
+
self.engine.process_error()
|
|
123
|
+
|
|
124
|
+
def test_no_active_exception(self):
|
|
125
|
+
"""Test handling when no exception is active"""
|
|
126
|
+
with patch('sys.exc_info', return_value=(None, None, None)):
|
|
127
|
+
with self.assertRaises(RuntimeError) as cm:
|
|
128
|
+
self.engine.process_error()
|
|
129
|
+
self.assertIn("no active exception", str(cm.exception))
|
|
130
|
+
|
|
131
|
+
def test_get_error_failure(self):
|
|
132
|
+
"""Test handling when get_error fails"""
|
|
133
|
+
mock_exc = MockException("Test error")
|
|
134
|
+
|
|
135
|
+
# Mock get_error to raise an exception
|
|
136
|
+
with patch.object(self.engine.sql, 'get_error', side_effect=Exception("get_error failed")):
|
|
137
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
138
|
+
# Should still handle the error using fallback mechanisms
|
|
139
|
+
with self.assertRaises(Exception): # Original exception should be re-raised
|
|
140
|
+
self.engine.process_error()
|
|
141
|
+
|
|
142
|
+
def test_exception_str_failure(self):
|
|
143
|
+
"""Test handling when converting exception to string fails"""
|
|
144
|
+
class UnstringableException(Exception):
|
|
145
|
+
def __str__(self):
|
|
146
|
+
raise Exception("Cannot convert to string")
|
|
147
|
+
|
|
148
|
+
mock_exc = UnstringableException("Test error")
|
|
149
|
+
|
|
150
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
151
|
+
with self.assertRaises(UnstringableException):
|
|
152
|
+
self.engine.process_error()
|
|
153
|
+
|
|
154
|
+
def test_exception_chaining(self):
|
|
155
|
+
"""Test that exception chaining is preserved"""
|
|
156
|
+
mock_exc = MockException("Original error", pgcode="23505")
|
|
157
|
+
|
|
158
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
159
|
+
try:
|
|
160
|
+
self.engine.process_error()
|
|
161
|
+
except exceptions.DbDuplicateKeyError as e:
|
|
162
|
+
# Check that the original exception is chained
|
|
163
|
+
self.assertIsInstance(e.__cause__, MockException)
|
|
164
|
+
self.assertEqual(str(e.__cause__), "Original error")
|
|
165
|
+
|
|
166
|
+
def test_enhanced_logging(self):
|
|
167
|
+
"""Test that enhanced logging provides good context"""
|
|
168
|
+
mock_exc = MockException("Test error for logging", pgcode="23505", pgerror="duplicate key")
|
|
169
|
+
|
|
170
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
171
|
+
with patch('velocity.db.core.engine.logger') as mock_logger:
|
|
172
|
+
with self.assertRaises(exceptions.DbDuplicateKeyError):
|
|
173
|
+
self.engine.process_error("SELECT * FROM test", {"id": 123})
|
|
174
|
+
|
|
175
|
+
# Verify warning log was called with proper context
|
|
176
|
+
mock_logger.warning.assert_called_once()
|
|
177
|
+
call_args = mock_logger.warning.call_args
|
|
178
|
+
|
|
179
|
+
# Check the message contains key information
|
|
180
|
+
message = call_args[0][0]
|
|
181
|
+
self.assertIn("code=23505", message)
|
|
182
|
+
self.assertIn("message=duplicate key", message)
|
|
183
|
+
self.assertIn("type=MockException", message)
|
|
184
|
+
|
|
185
|
+
# Check extra context is provided
|
|
186
|
+
extra = call_args[1]['extra']
|
|
187
|
+
self.assertEqual(extra['error_code'], "23505")
|
|
188
|
+
self.assertEqual(extra['sql_stmt'], "SELECT * FROM test")
|
|
189
|
+
self.assertEqual(extra['sql_params'], {"id": 123})
|
|
190
|
+
|
|
191
|
+
def test_unknown_error_logging(self):
|
|
192
|
+
"""Test logging for unhandled/unknown errors"""
|
|
193
|
+
class UnknownException(Exception):
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
mock_exc = UnknownException("Unknown error type")
|
|
197
|
+
|
|
198
|
+
with patch('sys.exc_info', return_value=(type(mock_exc), mock_exc, None)):
|
|
199
|
+
with patch('velocity.db.core.engine.logger') as mock_logger:
|
|
200
|
+
with self.assertRaises(UnknownException):
|
|
201
|
+
self.engine.process_error("SELECT unknown", {"param": "test"})
|
|
202
|
+
|
|
203
|
+
# Verify error log was called for unhandled case
|
|
204
|
+
mock_logger.error.assert_called_once()
|
|
205
|
+
call_args = mock_logger.error.call_args
|
|
206
|
+
|
|
207
|
+
# Check that comprehensive context is logged
|
|
208
|
+
extra = call_args[1]['extra']
|
|
209
|
+
self.assertIn('available_error_codes', extra)
|
|
210
|
+
self.assertIn('original_exception_type', extra)
|
|
211
|
+
self.assertEqual(extra['original_exception_type'], 'UnknownException')
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def main():
|
|
215
|
+
print("Testing robustness of improved process_error method...")
|
|
216
|
+
|
|
217
|
+
# Configure logging to see the output
|
|
218
|
+
logging.basicConfig(
|
|
219
|
+
level=logging.DEBUG,
|
|
220
|
+
format='%(levelname)s - %(name)s - %(message)s'
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Run the tests
|
|
224
|
+
unittest.main(argv=[''], exit=False, verbosity=2)
|
|
225
|
+
|
|
226
|
+
print("\n=== Summary ===")
|
|
227
|
+
print("✅ Enhanced error code classification")
|
|
228
|
+
print("✅ Robust regex pattern fallback")
|
|
229
|
+
print("✅ Exception chaining preservation")
|
|
230
|
+
print("✅ Enhanced logging with context")
|
|
231
|
+
print("✅ Graceful handling of edge cases")
|
|
232
|
+
print("✅ Better debugging information")
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
if __name__ == "__main__":
|
|
236
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/aws/handlers/sqs_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/mysql_reserved.py
RENAMED
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/reserved.py
RENAMED
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/postgres/types.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/sqlite_reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity/db/servers/sqlserver_reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{velocity_python-0.0.100 → velocity_python-0.0.102}/src/velocity_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|