1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
try:
from threading import local
except ImportError:
from sqlalchemy.util import ThreadLocal as local
from sqlalchemy import sql
from sqlalchemy.engine import create_engine
from sqlalchemy.types import TypeEngine
import thread, weakref
class ProxyEngine(object):
"""
SQLEngine proxy. Supports lazy and late initialization by
delegating to a real engine (set with connect()), and using proxy
classes for TableImpl, ColumnImpl and TypeEngine.
"""
def __init__(self):
# create the local storage for uri->engine map and current engine
self.storage = local()
self.storage.connection = {}
self.storage.engine = None
self.tables = {}
def connect(self, uri, opts=None, **kwargs):
"""Establish connection to a real engine.
"""
key = "%s(%s,%s)" % (uri, repr(opts), repr(kwargs))
try:
map = self.storage.connection
except AttributeError:
self.storage.connection = {}
self.storage.engine = None
map = self.storage.connection
try:
self.engine = map[key]
except KeyError:
map[key] = create_engine(uri, opts, **kwargs)
self.storage.engine = map[key]
def get_engine(self):
if self.storage.engine is None:
raise AttributeError('No connection established')
return self.storage.engine
def set_engine(self, engine):
self.storage.engine = engine
engine = property(get_engine, set_engine)
def hash_key(self):
return "%s(%s)" % (self.__class__.__name__, id(self))
def oid_column_name(self):
# NOTE: setting up mappers fails unless the proxy engine returns
# something for oid column name, and the call happens too early
# to proxy, so effecticely no oids are allowed when using
# proxy engine
if self.storage.engine is None:
return None
return self.get_engine().oid_column_name()
def columnimpl(self, column):
"""Proxy point: return a ProxyColumnImpl
"""
return ProxyColumnImpl(self, column)
def tableimpl(self, table):
"""Proxy point: return a ProxyTableImpl
"""
return ProxyTableImpl(self, table)
def type_descriptor(self, typeobj):
"""Proxy point: return a ProxyTypeEngine
"""
return ProxyTypeEngine(self, typeobj)
def __getattr__(self, attr):
# call get_engine() to give subclasses a chance to change
# connection establishment behavior
if self.get_engine() is not None:
return getattr(self.engine, attr)
raise AttributeError('No connection established in ProxyEngine: '
' no access to %s' % attr)
class ProxyColumnImpl(sql.ColumnImpl):
"""Proxy column; defers engine access to ProxyEngine
"""
def __init__(self, engine, column):
sql.ColumnImpl.__init__(self, column)
self._engine = engine
self.impls = weakref.WeakKeyDictionary()
def _get_impl(self):
e = self.engine
try:
return self.impls[e]
except KeyError:
impl = e.columnimpl(self.column)
self.impls[e] = impl
def __getattr__(self, key):
return getattr(self._get_impl(), key)
engine = property(lambda self: self._engine.engine)
class ProxyTableImpl(sql.TableImpl):
"""Proxy table; defers engine access to ProxyEngine
"""
def __init__(self, engine, table):
sql.TableImpl.__init__(self, table)
self._engine = engine
self.impls = weakref.WeakKeyDictionary()
def _get_impl(self):
e = self.engine
try:
return self.impls[e]
except KeyError:
impl = e.tableimpl(self.table)
self.impls[e] = impl
return impl
def __getattr__(self, key):
return getattr(self._get_impl(), key)
engine = property(lambda self: self._engine.engine)
class ProxyType(object):
"""ProxyType base class; used by ProxyTypeEngine to construct proxying
types
"""
def __init__(self, engine, typeobj):
self._engine = engine
self.typeobj = typeobj
def __getattribute__(self, attr):
if attr.startswith('__') and attr.endswith('__'):
return object.__getattribute__(self, attr)
engine = object.__getattribute__(self, '_engine').engine
typeobj = object.__getattribute__(self, 'typeobj')
return getattr(engine.type_descriptor(typeobj), attr)
def __repr__(self):
return '<Proxy %s>' % (object.__getattribute__(self, 'typeobj'))
class ProxyTypeEngine(object):
"""Proxy type engine; creates dynamic proxy type subclass that is instance
of actual type, but proxies engine-dependant operations through the proxy
engine.
"""
def __new__(cls, engine, typeobj):
"""Create a new subclass of ProxyType and typeobj
so that internal isinstance() calls will get the expected result.
"""
if isinstance(typeobj, type):
typeclass = typeobj
else:
typeclass = typeobj.__class__
typed = type('ProxyTypeHelper', (ProxyType, typeclass), {})
return typed(engine, typeobj)
|