Author: phd
Date: 2006-10-04 11:07:59 -0600 (Wed, 04 Oct 2006)
New Revision: 1984
Added:
home/phd/SQLObject/paramstyles/sqlobject/dberrors.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_exceptions.py
Modified:
home/phd/SQLObject/paramstyles/sqlobject/__init__.py
home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py
home/phd/SQLObject/paramstyles/sqlobject/sresults.py
home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_indexes.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py
home/phd/SQLObject/paramstyles/sqlobject/util/csvexport.py
Log:
Merged patches from the revisions 1975:1983 from the trunk
Modified: home/phd/SQLObject/paramstyles/sqlobject/__init__.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/__init__.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/__init__.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -5,6 +5,7 @@
from joins import *
from index import *
from dbconnection import connectionForURI
+import dberrors
## Each of these imports allows the driver to install itself
## Then we set up some backward compatibility
Copied: home/phd/SQLObject/paramstyles/sqlobject/dberrors.py (from rev 1983, SQLObject/trunk/sqlobject/dberrors.py)
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/dberrors.py (rev 0)
+++ home/phd/SQLObject/paramstyles/sqlobject/dberrors.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -0,0 +1,21 @@
+"""dberrors: database exception classes for SQLObject.
+
+ These classes are dictated by the DB API v2.0:
+
+ http://www.python.org/topics/database/DatabaseAPI-2.0.html
+"""
+
+class Error(StandardError): pass
+class Warning(StandardError): pass
+
+class InterfaceError(Error): pass
+class DatabaseError(Error): pass
+
+class InternalError(DatabaseError): pass
+class OperationalError(DatabaseError): pass
+class ProgrammingError(DatabaseError): pass
+class IntegrityError(DatabaseError): pass
+class DataError(DatabaseError): pass
+class NotSupportedError(DatabaseError): pass
+
+class DuplicateEntryError(IntegrityError): pass
Modified: home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/mysql/mysqlconnection.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -1,7 +1,16 @@
from sqlobject.dbconnection import DBAPI
+from sqlobject.dberrors import *
from sqlobject import col
MySQLdb = None
+class ErrorMessage(str):
+ def __new__(cls, e):
+ obj = str.__new__(cls, e[1])
+ obj.code = int(e[0])
+ obj.module = e.__module__
+ obj.exception = e.__class__.__name__
+ return obj
+
class MySQLConnection(DBAPI):
supportTransactions = False
@@ -54,9 +63,9 @@
conn = self.module.connect(host=self.host, port=self.port,
db=self.db, user=self.user, passwd=self.password, **self.kw)
except self.module.OperationalError, e:
- raise self.module.OperationalError(
+ raise OperationalError(
"%s; used connection string: host=%s, port=%s, db=%s, user=%s, pwd=%s" % (
- e, self.host, self.port, self.db, self.user, self.password)
+ e, self.host, self.port, self.db, self.user, self.password)
)
if hasattr(conn, 'autocommit'):
@@ -79,11 +88,33 @@
else:
return DBAPI._executeRetry(self, conn, cursor, query)
except MySQLdb.OperationalError, e:
- if e.args[0] == 2013: # SERVER_LOST error
+ if e.args[0] in (2006, 20013): # SERVER_GONE or SERVER_LOST error
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
- raise
+ raise OperationalError(ErrorMessage(e))
+ except MySQLdb.IntegrityError, e:
+ msg = ErrorMessage(e)
+ if e.args[0] == 1062:
+ raise DuplicateEntryError(msg)
+ else:
+ raise IntegrityError(msg)
+ except MySQLdb.InternalError, e:
+ raise InternalError(ErrorMessage(e))
+ except MySQLdb.ProgrammingError, e:
+ raise ProgrammingError(ErrorMessage(e))
+ except MySQLdb.DataError, e:
+ raise DataError(ErrorMessage(e))
+ except MySQLdb.NotSupportedError, e:
+ raise NotSupportedError(ErrorMessage(e))
+ except MySQLdb.DatabaseError, e:
+ raise DatabaseError(ErrorMessage(e))
+ except MySQLdb.InterfaceError, e:
+ raise InterfaceError(ErrorMessage(e))
+ except MySQLdb.Warning, e:
+ raise Warning(ErrorMessage(e))
+ except MySQLdb.Error, e:
+ raise Error(ErrorMessage(e))
def _queryInsertID(self, conn, soInstance, id, names, values):
table = soInstance.sqlmeta.table
@@ -136,8 +167,8 @@
# which is not always True (for an embedded application, e.g.)
self.query('DESCRIBE %s' % (tableName))
return True
- except MySQLdb.ProgrammingError, e:
- if e.args[0] == 1146: # ER_NO_SUCH_TABLE
+ except ProgrammingError, e:
+ if e.code == 1146: # ER_NO_SUCH_TABLE
return False
raise
Modified: home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/sqlite/sqliteconnection.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -1,11 +1,20 @@
from sqlobject.dbconnection import DBAPI
from sqlobject.col import popKey
+from sqlobject.dberrors import *
import thread
sqlite = None
using_sqlite2 = False
sqlite2_Binary = None
+class ErrorMessage(str):
+ def __new__(cls, e):
+ obj = str.__new__(cls, e[0])
+ obj.code = None
+ obj.module = e.__module__
+ obj.exception = e.__class__.__name__
+ return obj
+
class SQLiteConnection(DBAPI):
supportTransactions = True
@@ -158,6 +167,34 @@
return self._memoryConn
return sqlite.connect(self.filename, **self._connOptions)
+ def _executeRetry(self, conn, cursor, query):
+ try:
+ DBAPI._executeRetry(self, conn, c, query)
+ except self.module.OperationalError, e:
+ raise OperationalError(ErrorMessage(e))
+ except self.module.IntegrityError, e:
+ msg = ErrorMessage(e)
+ if msg.startswith('column') and msg.endswith('not unique'):
+ raise DuplicateEntryError(msg)
+ else:
+ raise IntegrityError(msg)
+ except self.module.InternalError, e:
+ raise InternalError(ErrorMessage(e))
+ except self.module.ProgrammingError, e:
+ raise ProgrammingError(ErrorMessage(e))
+ except self.module.DataError, e:
+ raise DataError(ErrorMessage(e))
+ except self.module.NotSupportedError, e:
+ raise NotSupportedError(ErrorMessage(e))
+ except self.module.DatabaseError, e:
+ raise DatabaseError(ErrorMessage(e))
+ except self.module.InterfaceError, e:
+ raise InterfaceError(ErrorMessage(e))
+ except self.module.Warning, e:
+ raise Warning(ErrorMessage(e))
+ except self.module.Error, e:
+ raise Error(ErrorMessage(e))
+
def _queryInsertID(self, conn, soInstance, id, names, values):
table = soInstance.sqlmeta.table
idName = soInstance.sqlmeta.idName
@@ -168,7 +205,7 @@
q = self._insertSQL(table, names, values)
if self.debug:
self.printDebug(conn, q, 'QueryIns')
- DBAPI._executeRetry(self, conn, c, q)
+ self._executeRetry(conn, c, q)
# lastrowid is a DB-API extension from "PEP 0249":
if id is None:
id = int(c.lastrowid)
Modified: home/phd/SQLObject/paramstyles/sqlobject/sresults.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sresults.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/sresults.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -35,6 +35,10 @@
def __repr__(self):
return "<%s at %x>" % (self.__class__.__name__, id(self))
+ def __nonzero__(self):
+ raise NotImplementedError(
+ "To test if a SelectResult will produce any items, use list(result) or result.count()")
+
def _getConnection(self):
return self.ops.get('connection') or self.sourceClass._connection
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/dbtest.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -33,6 +33,7 @@
"""
supportsMatrix = {
'+restrictedEnum': 'postgres',
+ '+exceptions': 'mysql sqlite',
'-transactions': 'mysql',
'-dropTableCascade': 'sybase mssql',
'-fromDatabase': 'sqlite sybase firebird',
Copied: home/phd/SQLObject/paramstyles/sqlobject/tests/test_exceptions.py (from rev 1983, SQLObject/trunk/sqlobject/tests/test_exceptions.py)
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_exceptions.py (rev 0)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_exceptions.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -0,0 +1,17 @@
+from sqlobject import *
+from sqlobject.dberrors import DuplicateEntryError
+from sqlobject.tests.dbtest import *
+
+########################################
+## Table aliases and self-joins
+########################################
+
+class TestException(SQLObject):
+ name = StringCol(unique=True)
+
+def test_exceptions():
+ if not supports("exceptions"):
+ return
+ setupClass(TestException)
+ TestException(name="test")
+ raises(DuplicateEntryError, TestException, name="test")
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_indexes.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_indexes.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_indexes.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -1,4 +1,5 @@
from sqlobject import *
+from sqlobject.dberrors import *
from sqlobject.tests.dbtest import *
########################################
@@ -29,7 +30,10 @@
mod = SOIndex1._connection.module
try:
SOIndex1(name='blah', number=0)
- except (mod.ProgrammingError, mod.IntegrityError, mod.OperationalError, mod.DatabaseError):
+ except (
+ mod.ProgrammingError, mod.IntegrityError, mod.OperationalError, mod.DatabaseError,
+ ProgrammingError, IntegrityError, OperationalError, DatabaseError
+ ):
# expected
pass
else:
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -168,3 +168,8 @@
assert IterTest.select(RLIKE(IterTest.q.name, "^sqlb.*$")).count() == 1
assert IterTest.select(RLIKE(IterTest.q.name, "^sqlb.*$")).count() == 1
assert IterTest.select(RLIKE(IterTest.q.name, "^sqlx.*$")).count() == 0
+
+def test_bool_SelectResults():
+ setupClass(IterTest)
+
+ raises(NotImplementedError, bool, IterTest.select())
Modified: home/phd/SQLObject/paramstyles/sqlobject/util/csvexport.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/util/csvexport.py 2006-10-04 16:59:56 UTC (rev 1983)
+++ home/phd/SQLObject/paramstyles/sqlobject/util/csvexport.py 2006-10-04 17:07:59 UTC (rev 1984)
@@ -58,14 +58,14 @@
writer = csv.writer(return_fileobj)
elif not hasattr(writer, 'writerow'):
writer = csv.writer(writer)
-
+
if isinstance(soClass, sqlobject.SQLObject.SelectResultsClass):
- assert not select, (
+ assert select is None, (
"You cannot pass in a select argument (%r) and a SelectResult argument (%r) for soClass"
% (select, soClass))
select = soClass
soClass = select.sourceClass
- elif not select:
+ elif select is None:
select = soClass.select()
if getattr(soClass, 'csvOrderBy', None):
select = select.orderBy(soClass.csvOrderBy)
|