1
2
3
4 """
5 SQLAlchemy adapter module.
6
7 @see: U{SQLAlchemy homepage (external)<http://www.sqlalchemy.org>}
8
9 @since: 0.4
10 """
11
12 import sqlalchemy
13 from sqlalchemy.orm import collections
14
15 try:
16 from sqlalchemy.orm import class_mapper, object_mapper
17 except ImportError:
18 from sqlalchemy.orm.util import class_mapper, object_mapper
19
20 import pyamf
21 from pyamf.adapters import util
22
23 UnmappedInstanceError = None
24
25 try:
26 class_mapper(dict)
27 except Exception, e:
28 UnmappedInstanceError = e.__class__
29
31 KEY_ATTR = 'sa_key'
32 LAZY_ATTR = 'sa_lazy'
33 EXCLUDED_ATTRS = [
34 '_sa_instance_state', '_sa_session_id', '_state',
35 '_entity_name', '_instance_key', '_sa_class_manager',
36 '_sa_adapter', '_sa_appender', '_sa_instrumented',
37 '_sa_iterator', '_sa_remover', '_sa_initiator',
38 ]
39
41 """
42 Returns C{sqlalchemy.orm.mapper.Mapper} object.
43 """
44 if hasattr(self, 'primary_mapper'):
45 return self.primary_mapper
46
47 try:
48 self.primary_mapper = object_mapper(obj)
49 except UnmappedInstanceError:
50 self.primary_mapper = None
51
52 return self.primary_mapper
53
54 - def getAttrs(self, obj, *args, **kwargs):
55 """
56 Returns a C{tuple} containing 2 lists. The 1st is a list of allowed
57 static attribute names, and the 2nd is a list of allowed dynamic
58 attribute names.
59 """
60 mapper = self._getMapper(obj)
61
62 if mapper is None:
63 return pyamf.ClassAlias.getAttrs(self, obj, *args, **kwargs)
64
65 if not hasattr(self, 'static_attrs'):
66 self.static_attrs = [self.KEY_ATTR, self.LAZY_ATTR]
67 self.properties = []
68
69 for prop in mapper.iterate_properties:
70 self.static_attrs.append(prop.key)
71
72 for key, prop in self.klass.__dict__.iteritems():
73 if isinstance(prop, property):
74 self.properties.append(key)
75 self.static_attrs.append(key)
76
77 dynamic_attrs = []
78
79 for key in obj.__dict__.keys():
80 if key in self.EXCLUDED_ATTRS:
81 continue
82
83 if key not in self.static_attrs:
84 dynamic_attrs.append(key)
85
86 return self.static_attrs, dynamic_attrs
87
89 """
90 Returns a C{tuple} containing a dict of static and dynamic attributes
91 for C{obj}.
92 """
93 mapper = self._getMapper(obj)
94
95 if mapper is None:
96 return pyamf.ClassAlias.getAttributes(self, obj, *args, **kwargs)
97
98 static_attrs = {}
99 dynamic_attrs = {}
100 lazy_attrs = []
101
102 static_attr_names, dynamic_attr_names = self.getAttrs(obj)
103
104
105
106 static_attrs[self.KEY_ATTR] = mapper.primary_key_from_instance(obj)
107
108 for attr in static_attr_names:
109 if attr in obj.__dict__ or attr in self.properties:
110 static_attrs[attr] = getattr(obj, attr)
111
112 continue
113
114 if attr in [self.KEY_ATTR, self.LAZY_ATTR]:
115 continue
116
117
118 lazy_attrs.append(attr)
119 static_attrs[attr] = pyamf.Undefined
120
121 for attr in dynamic_attr_names:
122 if attr in obj.__dict__:
123 dynamic_attrs[attr] = getattr(obj, attr)
124
125 static_attrs[self.LAZY_ATTR] = lazy_attrs
126
127 return static_attrs, dynamic_attrs
128
130 """
131 Add decoded attributes to instance.
132 """
133 mapper = self._getMapper(obj)
134
135 if mapper is None:
136 pyamf.ClassAlias.applyAttributes(self, obj, attrs, *args, **kwargs)
137
138 return
139
140
141
142
143
144
145
146
147
148
149 if self.LAZY_ATTR in attrs:
150 obj_state = None
151
152 if hasattr(sqlalchemy.orm.attributes, 'instance_state'):
153 obj_state = sqlalchemy.orm.attributes.instance_state(obj)
154
155 for lazy_attr in attrs[self.LAZY_ATTR]:
156 if lazy_attr in obj.__dict__:
157
158
159 del obj.__dict__[lazy_attr]
160
161
162
163
164
165
166
167 if obj_state is not None:
168 if lazy_attr in obj_state.committed_state:
169 del obj_state.committed_state[lazy_attr]
170 if lazy_attr in obj_state.dict:
171 del obj_state.dict[lazy_attr]
172
173 if lazy_attr in attrs:
174 del attrs[lazy_attr]
175
176 del attrs[self.LAZY_ATTR]
177
178 if self.KEY_ATTR in attrs:
179 del attrs[self.KEY_ATTR]
180
181 for key, prop in self.klass.__dict__.iteritems():
182 if isinstance(prop, property) and key in attrs.keys():
183 if prop.fset is None:
184 del attrs[key]
185
186 pyamf.util.set_attrs(obj, attrs)
187
189 """
190 @rtype: C{bool}
191 """
192 if not isinstance(klass, type):
193 klass = type(klass)
194
195 try:
196 class_mapper(klass)
197 except UnmappedInstanceError:
198 return False
199
200 return True
201
202 pyamf.register_alias_type(SaMappedClassAlias, is_class_sa_mapped)
203
204 pyamf.add_type(collections.InstrumentedList, util.to_list)
205 pyamf.add_type(collections.InstrumentedDict, util.to_dict)
206 pyamf.add_type(collections.InstrumentedSet, util.to_set)
207