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 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
68 for prop in mapper.iterate_properties:
69 self.static_attrs.append(prop.key)
70
71 dynamic_attrs = []
72
73 for key in obj.__dict__.keys():
74 if key in self.EXCLUDED_ATTRS:
75 continue
76
77 if key not in self.static_attrs:
78 dynamic_attrs.append(key)
79
80 return self.static_attrs, dynamic_attrs
81
83 """
84 Returns a C{tuple} containing a dict of static and dynamic attributes
85 for C{obj}.
86 """
87 mapper = self._getMapper(obj)
88
89 if mapper is None:
90 return pyamf.ClassAlias.getAttributes(self, obj, *args, **kwargs)
91
92 static_attrs = {}
93 dynamic_attrs = {}
94 lazy_attrs = []
95
96 static_attr_names, dynamic_attr_names = self.getAttrs(obj)
97
98
99
100 static_attrs[self.KEY_ATTR] = mapper.primary_key_from_instance(obj)
101
102 for attr in static_attr_names:
103 if attr in obj.__dict__:
104 static_attrs[attr] = getattr(obj, attr)
105
106 continue
107
108 if attr in [self.KEY_ATTR, self.LAZY_ATTR]:
109 continue
110
111
112 lazy_attrs.append(attr)
113 static_attrs[attr] = pyamf.Undefined
114
115 for attr in dynamic_attr_names:
116 if attr in obj.__dict__:
117 dynamic_attrs[attr] = getattr(obj, attr)
118
119 static_attrs[self.LAZY_ATTR] = lazy_attrs
120
121 return static_attrs, dynamic_attrs
122
124 """
125 Add decoded attributes to instance.
126 """
127 mapper = self._getMapper(obj)
128
129 if mapper is None:
130 pyamf.ClassAlias.applyAttributes(self, obj, attrs, *args, **kwargs)
131
132 return
133
134
135
136
137
138
139
140
141
142
143 if self.LAZY_ATTR in attrs:
144 obj_state = None
145
146 if hasattr(sqlalchemy.orm.attributes, 'instance_state'):
147 obj_state = sqlalchemy.orm.attributes.instance_state(obj)
148
149 for lazy_attr in attrs[self.LAZY_ATTR]:
150 if lazy_attr in obj.__dict__:
151
152
153 del obj.__dict__[lazy_attr]
154
155
156
157
158
159
160
161 if obj_state is not None:
162 if lazy_attr in obj_state.committed_state:
163 del obj_state.committed_state[lazy_attr]
164 if lazy_attr in obj_state.dict:
165 del obj_state.dict[lazy_attr]
166
167 if lazy_attr in attrs:
168 del attrs[lazy_attr]
169
170 del attrs[self.LAZY_ATTR]
171
172 if self.KEY_ATTR in attrs:
173 del attrs[self.KEY_ATTR]
174
175 pyamf.util.set_attrs(obj, attrs)
176
178 if not isinstance(klass, type):
179 klass = type(klass)
180
181 try:
182 class_mapper(klass)
183 except UnmappedInstanceError:
184 return False
185
186 return True
187
188 pyamf.register_alias_type(SaMappedClassAlias, is_class_sa_mapped)
189
190 pyamf.add_type(collections.InstrumentedList, util.to_list)
191 pyamf.add_type(collections.InstrumentedDict, util.to_dict)
192 pyamf.add_type(collections.InstrumentedSet, util.to_set)
193