velocity-python 0.0.105__tar.gz → 0.0.108__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.105/src/velocity_python.egg-info → velocity_python-0.0.108}/PKG-INFO +1 -1
- {velocity_python-0.0.105 → velocity_python-0.0.108}/pyproject.toml +1 -1
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/__init__.py +1 -1
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/result.py +8 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/table.py +4 -4
- {velocity_python-0.0.105 → velocity_python-0.0.108/src/velocity_python.egg-info}/PKG-INFO +1 -1
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity_python.egg-info/SOURCES.txt +2 -0
- velocity_python-0.0.108/tests/test_cursor_rowcount_fix.py +150 -0
- velocity_python-0.0.108/tests/test_result_sql_aware.py +115 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/LICENSE +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/README.md +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/setup.cfg +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/app/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/app/invoices.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/app/orders.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/app/payments.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/app/purchase_orders.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/amplify.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/handlers/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/handlers/context.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/handlers/lambda_handler.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/handlers/response.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/handlers/sqs_handler.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/column.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/database.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/decorators.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/engine.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/exceptions.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/row.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/sequence.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/core/transaction.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/exceptions.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/mysql.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/mysql_reserved.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/operators.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/reserved.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/sql.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/types.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/sqlite.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/sqlite_reserved.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/sqlserver.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/sqlserver_reserved.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/tablehelper.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/utils.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/conv/__init__.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/conv/iconv.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/conv/oconv.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/db.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/export.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/format.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/mail.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/merge.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/timer.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/misc/tools.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity_python.egg-info/dependency_links.txt +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity_python.egg-info/requires.txt +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity_python.egg-info/top_level.txt +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_db.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_db_utils.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_email_processing.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_fix.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_format.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_iconv.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_merge.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_oconv.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_original_error.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_payment_profile_sorting.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_postgres.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_process_error_robustness.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_response.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_result_caching.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_row_get_missing_column.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_spreadsheet_functions.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_sql_builder.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_tablehelper.py +0 -0
- {velocity_python-0.0.105 → velocity_python-0.0.108}/tests/test_timer.py +0 -0
|
@@ -56,10 +56,18 @@ class Result:
|
|
|
56
56
|
def _fetch_first_row(self):
|
|
57
57
|
"""
|
|
58
58
|
Pre-fetch the first row from the cursor to enable immediate boolean evaluation.
|
|
59
|
+
Only attempts to fetch for SELECT-like operations that return rows.
|
|
59
60
|
"""
|
|
60
61
|
if self._first_row_fetched or not self._cursor:
|
|
61
62
|
return
|
|
62
63
|
|
|
64
|
+
# Don't try to fetch from INSERT/UPDATE/DELETE operations
|
|
65
|
+
# These operations don't return rows, only rowcount
|
|
66
|
+
if self.__sql and self.__sql.strip().upper().startswith(('INSERT', 'UPDATE', 'DELETE', 'TRUNCATE')):
|
|
67
|
+
self._exhausted = True
|
|
68
|
+
self._first_row_fetched = True
|
|
69
|
+
return
|
|
70
|
+
|
|
63
71
|
try:
|
|
64
72
|
raw_row = self._cursor.fetchone()
|
|
65
73
|
if raw_row:
|
|
@@ -431,7 +431,7 @@ class Table:
|
|
|
431
431
|
if kwds.get("sql_only", False):
|
|
432
432
|
return sql, vals
|
|
433
433
|
result = self.tx.execute(sql, vals, cursor=self.cursor())
|
|
434
|
-
return result.cursor.rowcount
|
|
434
|
+
return result.cursor.rowcount if result.cursor else 0
|
|
435
435
|
|
|
436
436
|
@reset_id_on_dup_key
|
|
437
437
|
@create_missing
|
|
@@ -443,7 +443,7 @@ class Table:
|
|
|
443
443
|
if kwds.get("sql_only", False):
|
|
444
444
|
return sql, vals
|
|
445
445
|
result = self.tx.execute(sql, vals, cursor=self.cursor())
|
|
446
|
-
return result.cursor.rowcount
|
|
446
|
+
return result.cursor.rowcount if result.cursor else 0
|
|
447
447
|
|
|
448
448
|
@reset_id_on_dup_key
|
|
449
449
|
@create_missing
|
|
@@ -462,7 +462,7 @@ class Table:
|
|
|
462
462
|
if kwds.get("sql_only", False):
|
|
463
463
|
return sql, vals
|
|
464
464
|
result = self.tx.execute(sql, vals, cursor=self.cursor())
|
|
465
|
-
return result.cursor.rowcount
|
|
465
|
+
return result.cursor.rowcount if result.cursor else 0
|
|
466
466
|
|
|
467
467
|
upsert = merge
|
|
468
468
|
indate = merge
|
|
@@ -662,7 +662,7 @@ class Table:
|
|
|
662
662
|
if kwds.get("sql_only", False):
|
|
663
663
|
return sql, vals
|
|
664
664
|
result = self.tx.execute(sql, vals)
|
|
665
|
-
return result.cursor.rowcount
|
|
665
|
+
return result.cursor.rowcount if result.cursor else 0
|
|
666
666
|
|
|
667
667
|
def truncate(self, **kwds):
|
|
668
668
|
"""
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity_python.egg-info/SOURCES.txt
RENAMED
|
@@ -57,6 +57,7 @@ src/velocity_python.egg-info/SOURCES.txt
|
|
|
57
57
|
src/velocity_python.egg-info/dependency_links.txt
|
|
58
58
|
src/velocity_python.egg-info/requires.txt
|
|
59
59
|
src/velocity_python.egg-info/top_level.txt
|
|
60
|
+
tests/test_cursor_rowcount_fix.py
|
|
60
61
|
tests/test_db.py
|
|
61
62
|
tests/test_db_utils.py
|
|
62
63
|
tests/test_email_processing.py
|
|
@@ -71,6 +72,7 @@ tests/test_postgres.py
|
|
|
71
72
|
tests/test_process_error_robustness.py
|
|
72
73
|
tests/test_response.py
|
|
73
74
|
tests/test_result_caching.py
|
|
75
|
+
tests/test_result_sql_aware.py
|
|
74
76
|
tests/test_row_get_missing_column.py
|
|
75
77
|
tests/test_spreadsheet_functions.py
|
|
76
78
|
tests/test_sql_builder.py
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import Mock, MagicMock
|
|
3
|
+
from velocity.db.core.table import Table
|
|
4
|
+
from velocity.db.core.result import Result
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestCursorRowCountFix(unittest.TestCase):
|
|
8
|
+
"""
|
|
9
|
+
Test cases to verify that table methods handle None cursors gracefully
|
|
10
|
+
when accessing result.cursor.rowcount.
|
|
11
|
+
|
|
12
|
+
This addresses the AttributeError: 'NoneType' object has no attribute 'rowcount'
|
|
13
|
+
issue that can occur when the cursor is None due to connection errors or
|
|
14
|
+
other exceptional conditions.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def setUp(self):
|
|
18
|
+
"""Set up mock objects for testing."""
|
|
19
|
+
self.mock_tx = Mock()
|
|
20
|
+
self.mock_sql = Mock()
|
|
21
|
+
self.table = Table(self.mock_tx, "test_table")
|
|
22
|
+
self.table.sql = self.mock_sql
|
|
23
|
+
|
|
24
|
+
def test_insert_with_none_cursor(self):
|
|
25
|
+
"""Test that insert() returns 0 when result.cursor is None."""
|
|
26
|
+
# Mock the SQL generation
|
|
27
|
+
self.mock_sql.insert.return_value = ("INSERT SQL", ["values"])
|
|
28
|
+
|
|
29
|
+
# Create a mock result with cursor = None
|
|
30
|
+
mock_result = Mock(spec=Result)
|
|
31
|
+
mock_result.cursor = None
|
|
32
|
+
|
|
33
|
+
# Mock the execute method to return our mock result
|
|
34
|
+
self.mock_tx.execute.return_value = mock_result
|
|
35
|
+
|
|
36
|
+
# Mock the cursor method
|
|
37
|
+
mock_cursor = Mock()
|
|
38
|
+
self.table.cursor = Mock(return_value=mock_cursor)
|
|
39
|
+
|
|
40
|
+
# Call insert and verify it returns 0 instead of raising AttributeError
|
|
41
|
+
result = self.table.insert({"test_field": "test_value"})
|
|
42
|
+
self.assertEqual(result, 0)
|
|
43
|
+
|
|
44
|
+
def test_update_with_none_cursor(self):
|
|
45
|
+
"""Test that update() returns 0 when result.cursor is None."""
|
|
46
|
+
# Mock the SQL generation
|
|
47
|
+
self.mock_sql.update.return_value = ("UPDATE SQL", ["values"])
|
|
48
|
+
|
|
49
|
+
# Create a mock result with cursor = None
|
|
50
|
+
mock_result = Mock(spec=Result)
|
|
51
|
+
mock_result.cursor = None
|
|
52
|
+
|
|
53
|
+
# Mock the execute method to return our mock result
|
|
54
|
+
self.mock_tx.execute.return_value = mock_result
|
|
55
|
+
|
|
56
|
+
# Mock the cursor method
|
|
57
|
+
mock_cursor = Mock()
|
|
58
|
+
self.table.cursor = Mock(return_value=mock_cursor)
|
|
59
|
+
|
|
60
|
+
# Call update and verify it returns 0 instead of raising AttributeError
|
|
61
|
+
result = self.table.update({"test_field": "new_value"}, where={"id": 1})
|
|
62
|
+
self.assertEqual(result, 0)
|
|
63
|
+
|
|
64
|
+
def test_merge_with_none_cursor(self):
|
|
65
|
+
"""Test that merge() returns 0 when result.cursor is None."""
|
|
66
|
+
# Mock the SQL generation
|
|
67
|
+
self.mock_sql.merge.return_value = ("MERGE SQL", ["values"])
|
|
68
|
+
|
|
69
|
+
# Create a mock result with cursor = None
|
|
70
|
+
mock_result = Mock(spec=Result)
|
|
71
|
+
mock_result.cursor = None
|
|
72
|
+
|
|
73
|
+
# Mock the execute method to return our mock result
|
|
74
|
+
self.mock_tx.execute.return_value = mock_result
|
|
75
|
+
|
|
76
|
+
# Mock the cursor method
|
|
77
|
+
mock_cursor = Mock()
|
|
78
|
+
self.table.cursor = Mock(return_value=mock_cursor)
|
|
79
|
+
|
|
80
|
+
# Call merge and verify it returns 0 instead of raising AttributeError
|
|
81
|
+
result = self.table.merge({"test_field": "test_value"})
|
|
82
|
+
self.assertEqual(result, 0)
|
|
83
|
+
|
|
84
|
+
def test_delete_with_none_cursor(self):
|
|
85
|
+
"""Test that delete() returns 0 when result.cursor is None."""
|
|
86
|
+
# Mock the SQL generation
|
|
87
|
+
self.mock_sql.delete.return_value = ("DELETE SQL", ["values"])
|
|
88
|
+
|
|
89
|
+
# Create a mock result with cursor = None
|
|
90
|
+
mock_result = Mock(spec=Result)
|
|
91
|
+
mock_result.cursor = None
|
|
92
|
+
|
|
93
|
+
# Mock the execute method to return our mock result
|
|
94
|
+
self.mock_tx.execute.return_value = mock_result
|
|
95
|
+
|
|
96
|
+
# Call delete and verify it returns 0 instead of raising AttributeError
|
|
97
|
+
result = self.table.delete(where={"id": 1})
|
|
98
|
+
self.assertEqual(result, 0)
|
|
99
|
+
|
|
100
|
+
def test_insert_with_valid_cursor(self):
|
|
101
|
+
"""Test that insert() returns rowcount when result.cursor is valid."""
|
|
102
|
+
# Mock the SQL generation
|
|
103
|
+
self.mock_sql.insert.return_value = ("INSERT SQL", ["values"])
|
|
104
|
+
|
|
105
|
+
# Create a mock cursor with rowcount
|
|
106
|
+
mock_cursor = Mock()
|
|
107
|
+
mock_cursor.rowcount = 1
|
|
108
|
+
|
|
109
|
+
# Create a mock result with valid cursor
|
|
110
|
+
mock_result = Mock(spec=Result)
|
|
111
|
+
mock_result.cursor = mock_cursor
|
|
112
|
+
|
|
113
|
+
# Mock the execute method to return our mock result
|
|
114
|
+
self.mock_tx.execute.return_value = mock_result
|
|
115
|
+
|
|
116
|
+
# Mock the cursor method
|
|
117
|
+
table_cursor = Mock()
|
|
118
|
+
self.table.cursor = Mock(return_value=table_cursor)
|
|
119
|
+
|
|
120
|
+
# Call insert and verify it returns the actual rowcount
|
|
121
|
+
result = self.table.insert({"test_field": "test_value"})
|
|
122
|
+
self.assertEqual(result, 1)
|
|
123
|
+
|
|
124
|
+
def test_update_with_valid_cursor(self):
|
|
125
|
+
"""Test that update() returns rowcount when result.cursor is valid."""
|
|
126
|
+
# Mock the SQL generation
|
|
127
|
+
self.mock_sql.update.return_value = ("UPDATE SQL", ["values"])
|
|
128
|
+
|
|
129
|
+
# Create a mock cursor with rowcount
|
|
130
|
+
mock_cursor = Mock()
|
|
131
|
+
mock_cursor.rowcount = 2
|
|
132
|
+
|
|
133
|
+
# Create a mock result with valid cursor
|
|
134
|
+
mock_result = Mock(spec=Result)
|
|
135
|
+
mock_result.cursor = mock_cursor
|
|
136
|
+
|
|
137
|
+
# Mock the execute method to return our mock result
|
|
138
|
+
self.mock_tx.execute.return_value = mock_result
|
|
139
|
+
|
|
140
|
+
# Mock the cursor method
|
|
141
|
+
table_cursor = Mock()
|
|
142
|
+
self.table.cursor = Mock(return_value=table_cursor)
|
|
143
|
+
|
|
144
|
+
# Call update and verify it returns the actual rowcount
|
|
145
|
+
result = self.table.update({"test_field": "new_value"}, where={"id": 1})
|
|
146
|
+
self.assertEqual(result, 2)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
unittest.main()
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import Mock, MagicMock
|
|
3
|
+
from velocity.db.core.result import Result
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestResultSQLAwareFetch(unittest.TestCase):
|
|
7
|
+
"""
|
|
8
|
+
Test cases to verify that Result doesn't attempt to fetch from
|
|
9
|
+
INSERT/UPDATE/DELETE operations, preventing cursor errors.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def test_insert_sql_no_fetch_attempt(self):
|
|
13
|
+
"""Test that INSERT SQL doesn't attempt to fetch rows."""
|
|
14
|
+
mock_cursor = Mock()
|
|
15
|
+
|
|
16
|
+
# Create Result with INSERT SQL
|
|
17
|
+
result = Result(cursor=mock_cursor, sql="INSERT INTO test (name) VALUES ('test')")
|
|
18
|
+
|
|
19
|
+
# Verify fetchone was never called on INSERT
|
|
20
|
+
mock_cursor.fetchone.assert_not_called()
|
|
21
|
+
|
|
22
|
+
# Verify result is marked as exhausted (no rows expected)
|
|
23
|
+
self.assertTrue(result._exhausted)
|
|
24
|
+
self.assertTrue(result._first_row_fetched)
|
|
25
|
+
|
|
26
|
+
# Verify cursor is still valid (not set to None)
|
|
27
|
+
self.assertIsNotNone(result.cursor)
|
|
28
|
+
|
|
29
|
+
def test_update_sql_no_fetch_attempt(self):
|
|
30
|
+
"""Test that UPDATE SQL doesn't attempt to fetch rows."""
|
|
31
|
+
mock_cursor = Mock()
|
|
32
|
+
|
|
33
|
+
# Create Result with UPDATE SQL
|
|
34
|
+
result = Result(cursor=mock_cursor, sql="UPDATE test SET name='new' WHERE id=1")
|
|
35
|
+
|
|
36
|
+
# Verify fetchone was never called on UPDATE
|
|
37
|
+
mock_cursor.fetchone.assert_not_called()
|
|
38
|
+
|
|
39
|
+
# Verify result is marked as exhausted (no rows expected)
|
|
40
|
+
self.assertTrue(result._exhausted)
|
|
41
|
+
self.assertIsNotNone(result.cursor)
|
|
42
|
+
|
|
43
|
+
def test_delete_sql_no_fetch_attempt(self):
|
|
44
|
+
"""Test that DELETE SQL doesn't attempt to fetch rows."""
|
|
45
|
+
mock_cursor = Mock()
|
|
46
|
+
|
|
47
|
+
# Create Result with DELETE SQL
|
|
48
|
+
result = Result(cursor=mock_cursor, sql="DELETE FROM test WHERE id=1")
|
|
49
|
+
|
|
50
|
+
# Verify fetchone was never called on DELETE
|
|
51
|
+
mock_cursor.fetchone.assert_not_called()
|
|
52
|
+
|
|
53
|
+
# Verify result is marked as exhausted (no rows expected)
|
|
54
|
+
self.assertTrue(result._exhausted)
|
|
55
|
+
self.assertIsNotNone(result.cursor)
|
|
56
|
+
|
|
57
|
+
def test_select_sql_does_fetch(self):
|
|
58
|
+
"""Test that SELECT SQL still attempts to fetch rows."""
|
|
59
|
+
mock_cursor = Mock()
|
|
60
|
+
mock_cursor.fetchone.return_value = None # No rows returned
|
|
61
|
+
|
|
62
|
+
# Create Result with SELECT SQL
|
|
63
|
+
result = Result(cursor=mock_cursor, sql="SELECT * FROM test")
|
|
64
|
+
|
|
65
|
+
# Verify fetchone WAS called on SELECT
|
|
66
|
+
mock_cursor.fetchone.assert_called_once()
|
|
67
|
+
|
|
68
|
+
# Verify result is marked as exhausted (no rows returned)
|
|
69
|
+
self.assertTrue(result._exhausted)
|
|
70
|
+
self.assertIsNotNone(result.cursor)
|
|
71
|
+
|
|
72
|
+
def test_select_sql_with_rows(self):
|
|
73
|
+
"""Test that SELECT SQL with rows works correctly."""
|
|
74
|
+
mock_cursor = Mock()
|
|
75
|
+
mock_cursor.fetchone.return_value = ('test_value',)
|
|
76
|
+
mock_cursor.description = [('column1',)]
|
|
77
|
+
|
|
78
|
+
# Create Result with SELECT SQL
|
|
79
|
+
result = Result(cursor=mock_cursor, sql="SELECT column1 FROM test")
|
|
80
|
+
|
|
81
|
+
# Verify fetchone WAS called on SELECT
|
|
82
|
+
mock_cursor.fetchone.assert_called_once()
|
|
83
|
+
|
|
84
|
+
# Verify result has cached first row and is not exhausted
|
|
85
|
+
self.assertIsNotNone(result._cached_first_row)
|
|
86
|
+
self.assertFalse(result._exhausted)
|
|
87
|
+
self.assertIsNotNone(result.cursor)
|
|
88
|
+
|
|
89
|
+
def test_case_insensitive_sql_detection(self):
|
|
90
|
+
"""Test that SQL detection works with various cases."""
|
|
91
|
+
test_cases = [
|
|
92
|
+
"insert into test values (1)", # lowercase
|
|
93
|
+
"INSERT INTO test VALUES (1)", # uppercase
|
|
94
|
+
" INSERT INTO test VALUES (1)", # leading whitespace
|
|
95
|
+
"Insert Into test Values (1)", # mixed case
|
|
96
|
+
"UPDATE test SET name='x'", # update
|
|
97
|
+
"delete from test", # delete
|
|
98
|
+
"TRUNCATE TABLE test" # truncate
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
for sql in test_cases:
|
|
102
|
+
with self.subTest(sql=sql):
|
|
103
|
+
mock_cursor = Mock()
|
|
104
|
+
result = Result(cursor=mock_cursor, sql=sql)
|
|
105
|
+
|
|
106
|
+
# Verify fetchone was never called
|
|
107
|
+
mock_cursor.fetchone.assert_not_called()
|
|
108
|
+
|
|
109
|
+
# Verify result is marked as exhausted
|
|
110
|
+
self.assertTrue(result._exhausted)
|
|
111
|
+
self.assertIsNotNone(result.cursor)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
unittest.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
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/aws/handlers/lambda_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/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
|
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/mysql_reserved.py
RENAMED
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/__init__.py
RENAMED
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/operators.py
RENAMED
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/postgres/types.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity/db/servers/sqlite_reserved.py
RENAMED
|
File without changes
|
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/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
|
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/src/velocity_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{velocity_python-0.0.105 → velocity_python-0.0.108}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|