Commit [d55bfb] MySQLdb History

Tons of changes from major refactoring/cleanup. This is all really broken

right now. In particular, all results are returned as strings.

adustman adustman 2008-03-14

removed test_capabilities.py
removed _mysql_exceptions.py
removed test_MySQLdb_capabilities.py
removed dbapi20.py
changed MySQLdb/cursors.py
changed MySQLdb/__init__.py
changed MySQLdb/connections.py
changed metadata.cfg
changed MANIFEST.in
changed _mysql.h
changed _mysql_results.c
changed _mysql.c
changed setup.py
copied test_MySQLdb_dbapi20.py -> MySQLdb/exceptions.py
test_capabilities.py
File was removed.
_mysql_exceptions.py
File was removed.
test_MySQLdb_capabilities.py
File was removed.
dbapi20.py
File was removed.
MySQLdb/cursors.py Diff Switch to side-by-side view
Loading...
MySQLdb/__init__.py Diff Switch to side-by-side view
Loading...
MySQLdb/connections.py Diff Switch to side-by-side view
Loading...
metadata.cfg Diff Switch to side-by-side view
Loading...
MANIFEST.in Diff Switch to side-by-side view
Loading...
_mysql.h Diff Switch to side-by-side view
Loading...
_mysql_results.c Diff Switch to side-by-side view
Loading...
_mysql.c Diff Switch to side-by-side view
Loading...
setup.py Diff Switch to side-by-side view
Loading...
test_MySQLdb_dbapi20.py to MySQLdb/exceptions.py
--- a/test_MySQLdb_dbapi20.py
+++ b/MySQLdb/exceptions.py
@@ -1,205 +1,117 @@
-#!/usr/bin/env python
-import dbapi20
-import unittest
-import MySQLdb
+"""
+MySQLdb.exceptions
+==================
 
-class test_MySQLdb(dbapi20.DatabaseAPI20Test):
-    driver = MySQLdb
-    connect_args = ()
-    connect_kw_args = dict(db='test',
-                           read_default_file='~/.my.cnf',
-                           charset='utf8',
-                           sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")
+These classes are dictated by the DB API v2.0:
 
-    def test_setoutputsize(self): pass
-    def test_setoutputsize_basic(self): pass
-    def test_nextset(self): pass
+    http://www.python.org/topics/database/DatabaseAPI-2.0.html
+"""
 
-    """The tests on fetchone and fetchall and rowcount bogusly
-    test for an exception if the statement cannot return a
-    result set. MySQL always returns a result set; it's just that
-    some things return empty result sets."""
+# from __future__ import absolute_import
+# Unfortunately, you cannot put the above in a conditional statement.
+# It would make things much cleaner for Python-2.5, but breaks older.
+
+try:
+    from exceptions import Exception, StandardError, Warning
+except ImportError:
+    import sys
+    e = sys.modules['exceptions']
+    StandardError = e.StandardError
+    Warning = e.Warning
     
-    def test_fetchall(self):
-        con = self._connect()
-        try:
-            cur = con.cursor()
-            # cursor.fetchall should raise an Error if called
-            # without executing a query that may return rows (such
-            # as a select)
-            self.assertRaises(self.driver.Error, cur.fetchall)
+from MySQLdb.constants import ER
 
-            self.executeDDL1(cur)
-            for sql in self._populate():
-                cur.execute(sql)
+class MySQLError(StandardError):
+    
+    """Exception related to operation with MySQL."""
 
-            # cursor.fetchall should raise an Error if called
-            # after executing a a statement that cannot return rows
-##             self.assertRaises(self.driver.Error,cur.fetchall)
 
-            cur.execute('select name from %sbooze' % self.table_prefix)
-            rows = cur.fetchall()
-            self.failUnless(cur.rowcount in (-1,len(self.samples)))
-            self.assertEqual(len(rows),len(self.samples),
-                'cursor.fetchall did not retrieve all rows'
-                )
-            rows = [r[0] for r in rows]
-            rows.sort()
-            for i in range(0,len(self.samples)):
-                self.assertEqual(rows[i],self.samples[i],
-                'cursor.fetchall retrieved incorrect rows'
-                )
-            rows = cur.fetchall()
-            self.assertEqual(
-                len(rows),0,
-                'cursor.fetchall should return an empty list if called '
-                'after the whole result set has been fetched'
-                )
-            self.failUnless(cur.rowcount in (-1,len(self.samples)))
+class Warning(Warning, MySQLError):
 
-            self.executeDDL2(cur)
-            cur.execute('select name from %sbarflys' % self.table_prefix)
-            rows = cur.fetchall()
-            self.failUnless(cur.rowcount in (-1,0))
-            self.assertEqual(len(rows),0,
-                'cursor.fetchall should return an empty list if '
-                'a select query returns no rows'
-                )
-            
-        finally:
-            con.close()
-                
-    def test_fetchone(self):
-        con = self._connect()
-        try:
-            cur = con.cursor()
+    """Exception raised for important warnings like data truncations
+    while inserting, etc."""
 
-            # cursor.fetchone should raise an Error if called before
-            # executing a select-type query
-            self.assertRaises(self.driver.Error,cur.fetchone)
+class Error(MySQLError):
 
-            # cursor.fetchone should raise an Error if called after
-            # executing a query that cannnot return rows
-            self.executeDDL1(cur)
-##             self.assertRaises(self.driver.Error,cur.fetchone)
+    """Exception that is the base class of all other error exceptions
+    (not Warning)."""
 
-            cur.execute('select name from %sbooze' % self.table_prefix)
-            self.assertEqual(cur.fetchone(),None,
-                'cursor.fetchone should return None if a query retrieves '
-                'no rows'
-                )
-            self.failUnless(cur.rowcount in (-1,0))
 
-            # cursor.fetchone should raise an Error if called after
-            # executing a query that cannnot return rows
-            cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
-                self.table_prefix
-                ))
-##             self.assertRaises(self.driver.Error,cur.fetchone)
+class InterfaceError(Error):
 
-            cur.execute('select name from %sbooze' % self.table_prefix)
-            r = cur.fetchone()
-            self.assertEqual(len(r),1,
-                'cursor.fetchone should have retrieved a single row'
-                )
-            self.assertEqual(r[0],'Victoria Bitter',
-                'cursor.fetchone retrieved incorrect data'
-                )
-##             self.assertEqual(cur.fetchone(),None,
-##                 'cursor.fetchone should return None if no more rows available'
-##                 )
-            self.failUnless(cur.rowcount in (-1,1))
-        finally:
-            con.close()
+    """Exception raised for errors that are related to the database
+    interface rather than the database itself."""
 
-    # Same complaint as for fetchall and fetchone
-    def test_rowcount(self):
-        con = self._connect()
-        try:
-            cur = con.cursor()
-            self.executeDDL1(cur)
-##             self.assertEqual(cur.rowcount,-1,
-##                 'cursor.rowcount should be -1 after executing no-result '
-##                 'statements'
-##                 )
-            cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
-                self.table_prefix
-                ))
-##             self.failUnless(cur.rowcount in (-1,1),
-##                 'cursor.rowcount should == number or rows inserted, or '
-##                 'set to -1 after executing an insert statement'
-##                 )
-            cur.execute("select name from %sbooze" % self.table_prefix)
-            self.failUnless(cur.rowcount in (-1,1),
-                'cursor.rowcount should == number of rows returned, or '
-                'set to -1 after executing a select statement'
-                )
-            self.executeDDL2(cur)
-##             self.assertEqual(cur.rowcount,-1,
-##                 'cursor.rowcount not being reset to -1 after executing '
-##                 'no-result statements'
-##                 )
-        finally:
-            con.close()
 
-    def test_callproc(self):
-        pass # performed in test_MySQL_capabilities
+class DatabaseError(Error):
 
-    def help_nextset_setUp(self,cur):
-        ''' Should create a procedure called deleteme
-            that returns two result sets, first the 
-	    number of rows in booze then "name from booze"
-        '''
-        sql="""
-           create procedure deleteme()
-           begin
-               select count(*) from %(tp)sbooze;
-               select name from %(tp)sbooze;
-           end
-        """ % dict(tp=self.table_prefix)
-        cur.execute(sql)
+    """Exception raised for errors that are related to the
+    database."""
 
-    def help_nextset_tearDown(self,cur):
-        'If cleaning up is needed after nextSetTest'
-        cur.execute("drop procedure deleteme")
 
-    def test_nextset(self):
-        from warnings import warn
-        con = self._connect()
-        try:
-            cur = con.cursor()
-            if not hasattr(cur,'nextset'):
-                return
+class DataError(DatabaseError):
 
-            try:
-                self.executeDDL1(cur)
-                sql=self._populate()
-                for sql in self._populate():
-                    cur.execute(sql)
+    """Exception raised for errors that are due to problems with the
+    processed data like division by zero, numeric value out of range,
+    etc."""
 
-                self.help_nextset_setUp(cur)
 
-                cur.callproc('deleteme')
-                numberofrows=cur.fetchone()
-                assert numberofrows[0]== len(self.samples)
-                assert cur.nextset()
-                names=cur.fetchall()
-                assert len(names) == len(self.samples)
-                s=cur.nextset()
-                if s:
-                    empty = cur.fetchall()
-                    self.assertEquals(len(empty), 0,
-                                      "non-empty result set after other result sets")
-                    #warn("Incompatibility: MySQL returns an empty result set for the CALL itself",
-                    #     Warning)
-                #assert s == None,'No more return sets, should return None'
-            finally:
-                self.help_nextset_tearDown(cur)
+class OperationalError(DatabaseError):
 
-        finally:
-            con.close()
+    """Exception raised for errors that are related to the database's
+    operation and not necessarily under the control of the programmer,
+    e.g. an unexpected disconnect occurs, the data source name is not
+    found, a transaction could not be processed, a memory allocation
+    error occurred during processing, etc."""
 
-    
-if __name__ == '__main__':
-    unittest.main()
-    print '''"Huh-huh, he said 'unit'." -- Butthead'''
+
+class IntegrityError(DatabaseError):
+
+    """Exception raised when the relational integrity of the database
+    is affected, e.g. a foreign key check fails, duplicate key,
+    etc."""
+
+
+class InternalError(DatabaseError):
+
+    """Exception raised when the database encounters an internal
+    error, e.g. the cursor is not valid anymore, the transaction is
+    out of sync, etc."""
+
+
+class ProgrammingError(DatabaseError):
+
+    """Exception raised for programming errors, e.g. table not found
+    or already exists, syntax error in the SQL statement, wrong number
+    of parameters specified, etc."""
+
+
+class NotSupportedError(DatabaseError):
+
+    """Exception raised in case a method or database API was used
+    which is not supported by the database, e.g. requesting a
+    .rollback() on a connection that does not support transaction or
+    has transactions turned off."""
+
+
+error_map = {}
+
+def _map_error(exc, *errors):
+    for error in errors:
+        error_map[error] = exc
+
+_map_error(ProgrammingError, ER.DB_CREATE_EXISTS, ER.SYNTAX_ERROR,
+           ER.PARSE_ERROR, ER.NO_SUCH_TABLE, ER.WRONG_DB_NAME,
+           ER.WRONG_TABLE_NAME, ER.FIELD_SPECIFIED_TWICE,
+           ER.INVALID_GROUP_FUNC_USE, ER.UNSUPPORTED_EXTENSION,
+           ER.TABLE_MUST_HAVE_COLUMNS, ER.CANT_DO_THIS_DURING_AN_TRANSACTION)
+_map_error(DataError, ER.WARN_DATA_TRUNCATED, ER.WARN_NULL_TO_NOTNULL,
+           ER.WARN_DATA_OUT_OF_RANGE, ER.NO_DEFAULT, ER.PRIMARY_CANT_HAVE_NULL,
+           ER.DATA_TOO_LONG, ER.DATETIME_FUNCTION_OVERFLOW)
+_map_error(IntegrityError, ER.DUP_ENTRY, ER.NO_REFERENCED_ROW,
+           ER.NO_REFERENCED_ROW_2, ER.ROW_IS_REFERENCED, ER.ROW_IS_REFERENCED_2,
+           ER.CANNOT_ADD_FOREIGN)
+_map_error(NotSupportedError, ER.WARNING_NOT_COMPLETE_ROLLBACK,
+           ER.NOT_SUPPORTED_YET, ER.FEATURE_DISABLED, ER.UNKNOWN_STORAGE_ENGINE)
+
+del StandardError, _map_error, ER