Project

General

Profile

« Previous | Next » 

Revision 1869

sql.py: DbConn: Made it picklable by establishing a connection on demand

View differences:

sql.py
1 1
# Database access
2 2

  
3
import copy
3 4
import random
4 5
import re
5 6
import sys
......
54 55
    else: raise NotImplementedError("Can't escape name for "+module+' database')
55 56
    return quote + name.replace(quote, '') + quote
56 57

  
57
##### Connection object
58
##### Database connections
58 59

  
60
db_engines = {
61
    'MySQL': ('MySQLdb', {'password': 'passwd', 'database': 'db'}),
62
    'PostgreSQL': ('psycopg2', {}),
63
}
64

  
65
DatabaseErrors_set = set([DbException])
66
DatabaseErrors = tuple(DatabaseErrors_set)
67

  
68
def _add_module(module):
69
    DatabaseErrors_set.add(module.DatabaseError)
70
    global DatabaseErrors
71
    DatabaseErrors = tuple(DatabaseErrors_set)
72

  
73
def db_config_str(db_config):
74
    return db_config['engine']+' database '+db_config['database']
75

  
59 76
class DbConn:
60
    def __init__(self, db):
61
        self.db = db
77
    def __init__(self, db_config, serializable=True):
78
        self.db_config = db_config
79
        self.serializable = serializable
80
        
81
        self.__db = None
62 82
        self.pkeys = {}
63 83
        self.index_cols = {}
84
    
85
    def __getattr__(self, name):
86
        if name == '__dict__': raise Exception('getting __dict__')
87
        if name == 'db': return self._db()
88
        else: raise AttributeError()
89
    
90
    def __getstate__(self):
91
        state = copy.copy(self.__dict__) # shallow copy
92
        state['_DbConn__db'] = None # don't pickle the connection
93
        return state
94
    
95
    def _db(self):
96
        if self.__db == None:
97
            # Process db_config
98
            db_config = self.db_config.copy() # don't modify input!
99
            module_name, mappings = db_engines[db_config.pop('engine')]
100
            module = __import__(module_name)
101
            _add_module(module)
102
            for orig, new in mappings.iteritems():
103
                try: util.rename_key(db_config, orig, new)
104
                except KeyError: pass
105
            
106
            # Connect
107
            self.__db = module.connect(**db_config)
108
            
109
            # Configure connection
110
            if self.serializable: run_raw_query(self,
111
                'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')
112
        
113
        return self.__db
64 114

  
115
connect = DbConn
116

  
65 117
##### Querying
66 118

  
67 119
def run_raw_query(db, query, params=None):
......
299 351
    except StopIteration:
300 352
        if not create: raise
301 353
        return put(db, table, row, pkey, row_ct_ref) # insert new row
302

  
303
##### Database connections
304

  
305
db_engines = {
306
    'MySQL': ('MySQLdb', {'password': 'passwd', 'database': 'db'}),
307
    'PostgreSQL': ('psycopg2', {}),
308
}
309

  
310
DatabaseErrors_set = set([DbException])
311
DatabaseErrors = tuple(DatabaseErrors_set)
312

  
313
def _add_module(module):
314
    DatabaseErrors_set.add(module.DatabaseError)
315
    global DatabaseErrors
316
    DatabaseErrors = tuple(DatabaseErrors_set)
317

  
318
def connect(db_config, serializable=True):
319
    db_config = db_config.copy() # don't modify input!
320
    module_name, mappings = db_engines[db_config.pop('engine')]
321
    module = __import__(module_name)
322
    _add_module(module)
323
    for orig, new in mappings.iteritems():
324
        try: util.rename_key(db_config, orig, new)
325
        except KeyError: pass
326
    db = DbConn(module.connect(**db_config))
327
    if serializable:
328
        run_raw_query(db, 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')
329
    return db
330

  
331
def db_config_str(db_config):
332
    return db_config['engine']+' database '+db_config['database']

Also available in: Unified diff