Edgewall Software

Ticket #8625: 8625-get-supported-schemes-r8575.patch

File 8625-get-supported-schemes-r8575.patch, 7.3 KB (added by rblank, 3 years ago)

Updated patch, adds support for errors in the other backends.

  • trac/db/api.py

    diff --git a/trac/db/api.py b/trac/db/api.py
    a b  
    3636 
    3737    def get_supported_schemes(): 
    3838        """Return the connection URL schemes supported by the connector, and 
    39         their relative priorities as an iterable of `(scheme, priority)` tuples. 
     39        their relative priorities as an iterable of `(scheme, priority)` 
     40        tuples. 
     41         
     42        If `priority` is a negative number, this is indicative of an 
     43        error  condition with the connector. An error message should be  
     44        attached to the `error` attribute of the connector. 
    4045        """ 
    4146 
    4247    def get_connection(path, log=None, **kwargs): 
     
    116121 
    117122    def _get_connector(self): ### FIXME: Make it public? 
    118123        scheme, args = _parse_db_str(self.connection_uri) 
    119         candidates = {} 
    120         for connector in self.connectors: 
    121             for scheme_, priority in connector.get_supported_schemes(): 
    122                 if scheme_ != scheme: 
    123                     continue 
    124                 highest = candidates.get(scheme_, (None, 0))[1] 
    125                 if priority > highest: 
    126                     candidates[scheme] = (connector, priority) 
    127  
    128         connector = candidates.get(scheme, [None])[0] 
    129         if not connector: 
     124        candidates = [ 
     125            (priority, connector) 
     126            for connector in self.connectors 
     127            for scheme_, priority in connector.get_supported_schemes() 
     128            if scheme_ == scheme 
     129        ] 
     130        if not candidates: 
    130131            raise TracError('Unsupported database type "%s"' % scheme) 
     132        priority, connector = max(candidates) 
     133        if priority < 0: 
     134            raise TracError(connector.error) 
    131135 
    132136        if scheme == 'sqlite': 
    133137            # Special case for SQLite to support a path relative to the 
  • trac/db/mysql_backend.py

    diff --git a/trac/db/mysql_backend.py b/trac/db/mysql_backend.py
    a b  
    2323from trac.util import get_pkginfo 
    2424from trac.util.compat import close_fds 
    2525from trac.util.text import to_unicode 
     26from trac.util.translation import _ 
    2627 
    2728_like_escape_re = re.compile(r'([/_%])') 
    2829 
     
    6465 
    6566    def __init__(self): 
    6667        self._version = None 
     68        self.error = None 
    6769 
    6870    def get_supported_schemes(self): 
    69         global has_mysqldb 
    70         if has_mysqldb: 
    71             return [('mysql', 1)] 
    72         else: 
    73             return [] 
     71        if not has_mysqldb: 
     72            self.error = _("Cannot load Python bindings for MySQL") 
     73        yield ('mysql', self.error and -1 or 1) 
    7474 
    7575    def get_connection(self, path, log=None, user=None, password=None, 
    7676                       host=None, port=None, params={}): 
  • trac/db/postgres_backend.py

    diff --git a/trac/db/postgres_backend.py b/trac/db/postgres_backend.py
    a b  
    2323from trac.util import get_pkginfo 
    2424from trac.util.compat import close_fds 
    2525from trac.util.text import to_unicode 
     26from trac.util.translation import _ 
    2627 
    27 psycopg = None 
    28 PgSQL = None 
     28has_psycopg = False 
     29has_pgsql = False 
    2930PGSchemaError = None 
     31try: 
     32    import psycopg2 as psycopg 
     33    import psycopg2.extensions 
     34    from psycopg2 import ProgrammingError as PGSchemaError 
     35    psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) 
     36    has_psycopg = True 
     37except ImportError: 
     38    try: 
     39        from pyPgSQL import PgSQL 
     40        from pyPgSQL.libpq import OperationalError as PGSchemaError 
     41        has_pgsql = True 
     42    except ImportError: 
     43        pass 
     44 
    3045 
    3146_like_escape_re = re.compile(r'([/_%])') 
    3247 
     
    4156 
    4257    def __init__(self): 
    4358        self._version = None 
     59        self.error = None 
    4460 
    4561    def get_supported_schemes(self): 
    46         return [('postgres', 1)] 
     62        if not (has_psycopg or has_pgsql): 
     63            self.error = _("Cannot load Python bindings for PostgreSQL") 
     64        yield ('postgres', self.error and -1 or 1) 
    4765 
    4866    def get_connection(self, path, log=None, user=None, password=None, 
    4967                       host=None, port=None, params={}): 
    50         global psycopg 
    51         global PgSQL 
    5268        cnx = PostgreSQLConnection(path, log, user, password, host, port, 
    5369                                   params) 
    5470        if not self._version: 
    55             if psycopg: 
     71            if has_psycopg: 
    5672                self._version = get_pkginfo(psycopg).get('version', 
    5773                                                         psycopg.__version__) 
    5874                name = 'psycopg2' 
    59             elif PgSQL: 
     75            elif has_pgsql: 
    6076                import pyPgSQL 
    6177                self._version = get_pkginfo(pyPgSQL).get('version', 
    6278                                                         pyPgSQL.__version__) 
     
    152168                 port=None, params={}): 
    153169        if path.startswith('/'): 
    154170            path = path[1:] 
    155         # We support both psycopg and PgSQL but prefer psycopg 
    156         global psycopg 
    157         global PgSQL 
    158         global PGSchemaError 
    159          
    160         if not psycopg and not PgSQL: 
    161             try: 
    162                 import psycopg2 as psycopg 
    163                 import psycopg2.extensions 
    164                 from psycopg2 import ProgrammingError as PGSchemaError 
    165                 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) 
    166             except ImportError: 
    167                 from pyPgSQL import PgSQL 
    168                 from pyPgSQL.libpq import OperationalError as PGSchemaError 
    169171        if 'host' in params: 
    170172            host = params['host'] 
    171         if psycopg: 
     173        if has_psycopg: 
    172174            dsn = [] 
    173175            if path: 
    174176                dsn.append('dbname=' + path) 
     
    182184                dsn.append('port=' + str(port)) 
    183185            cnx = psycopg.connect(' '.join(dsn)) 
    184186            cnx.set_client_encoding('UNICODE') 
    185         else: 
     187        elif has_pgsql: 
    186188            # Don't use chatty, inefficient server-side cursors. 
    187189            # http://pypgsql.sourceforge.net/pypgsql-faq.html#id2787367 
    188190            PgSQL.fetchReturnsList = 1 
  • trac/db/sqlite_backend.py

    diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
    a b  
    2222from trac.db.api import IDatabaseConnector 
    2323from trac.db.util import ConnectionWrapper 
    2424from trac.util import get_pkginfo, getuser 
     25from trac.util.translation import _ 
    2526 
    2627_like_escape_re = re.compile(r'([/_%])') 
    2728 
     
    112113 
    113114    def __init__(self): 
    114115        self._version = None 
     116        self.error = None 
    115117 
    116118    def get_supported_schemes(self): 
    117         return [('sqlite', 1)] 
     119        if not have_pysqlite: 
     120            self.error = _("Cannot load Python bindings for SQLite") 
     121        elif sqlite.sqlite_version_info >= (3, 3, 3): 
     122            if sqlite.version_info < (1, 0, 7): 
     123                self.error = _("Need at least PySqlite 1.0.7 or higher") 
     124            elif sqlite.version_info[0] == 2 and \ 
     125                    sqlite.version_info < (2, 0, 7): 
     126                self.error = _("Need at least PySqlite 2.0.7 or higher") 
     127        yield ('sqlite', self.error and -1 or 1) 
    118128 
    119129    def get_connection(self, path, log=None, params={}): 
    120130        if not self._version: 
    121             global sqlite_version_string, have_pysqlite 
    122131            self._version = get_pkginfo(sqlite).get( 
    123132                'version', '%d.%d.%s' % sqlite.version_info) 
    124133            self.env.systeminfo.extend([('SQLite', sqlite_version_string),