sqlite3: add Connection exception attributes and fix autocommit ValueError (#8533)

Add DB-API 2.0 optional extension: expose exception classes as attributes
on Connection objects (Warning, Error, InterfaceError, DatabaseError,
DataError, OperationalError, IntegrityError, InternalError,
ProgrammingError, NotSupportedError).

Also fix autocommit validation to raise ValueError (not TypeError) when
an unsupported type is passed.

Assisted-by: GitHub Copilot:claude-sonnet-4-6
This commit is contained in:
Jiseok CHOI authored and GitHub committed 2026-08-15 21:05:12 +09:00
1 parent 7cda53b946
commit a142de9abc
3 files changed
+42 -4

No files matched your search

-2
View File
@@ -364,7 +364,6 @@ class ConnectionTests(unittest.TestCase):
with self.cx:
pass
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_exceptions(self):
# Optional DB-API extension.
self.assertEqual(self.cx.Warning, sqlite.Warning)
@@ -401,7 +400,6 @@ class ConnectionTests(unittest.TestCase):
with self.assertRaises(AttributeError):
self.cx.in_transaction = True
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_connection_exceptions(self):
exceptions = [
"DataError",
-1
View File
@@ -387,7 +387,6 @@ class AutocommitAttribute(unittest.TestCase):
cx.autocommit = mode
self.assertEqual(cx.autocommit, mode)
@unittest.expectedFailure # TODO: RUSTPYTHON; autocommit validation error messages differ
def test_autocommit_setget_invalid(self):
msg = "autocommit must be True, False, or.*LEGACY"
for mode in "a", 12, (), None:
+42 -1
View File
@@ -322,7 +322,7 @@ mod _sqlite3 {
)))
}
} else {
Err(vm.new_type_error(format!(
Err(vm.new_value_error(format!(
"autocommit must be True, False, or sqlite3.LEGACY_TRANSACTION_CONTROL, not {}",
obj.class().name()
)))
@@ -1645,6 +1645,47 @@ mod _sqlite3 {
fn total_changes(&self, vm: &VirtualMachine) -> PyResult<c_int> {
self._db_lock(vm).map(|x| x.total_changes())
}
#[pygetset(name = "Warning")]
fn exc_warning(&self) -> PyTypeRef {
warning_type().to_owned()
}
#[pygetset(name = "Error")]
fn exc_error(&self) -> PyTypeRef {
error_type().to_owned()
}
#[pygetset(name = "InterfaceError")]
fn exc_interface_error(&self) -> PyTypeRef {
interface_error_type().to_owned()
}
#[pygetset(name = "DatabaseError")]
fn exc_database_error(&self) -> PyTypeRef {
database_error_type().to_owned()
}
#[pygetset(name = "DataError")]
fn exc_data_error(&self) -> PyTypeRef {
data_error_type().to_owned()
}
#[pygetset(name = "OperationalError")]
fn exc_operational_error(&self) -> PyTypeRef {
operational_error_type().to_owned()
}
#[pygetset(name = "IntegrityError")]
fn exc_integrity_error(&self) -> PyTypeRef {
integrity_error_type().to_owned()
}
#[pygetset(name = "InternalError")]
fn exc_internal_error(&self) -> PyTypeRef {
internal_error_type().to_owned()
}
#[pygetset(name = "ProgrammingError")]
fn exc_programming_error(&self) -> PyTypeRef {
programming_error_type().to_owned()
}
#[pygetset(name = "NotSupportedError")]
fn exc_not_supported_error(&self) -> PyTypeRef {
not_supported_error_type().to_owned()
}
}
#[pyattr]