1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 ================
19 Model Adapters
20 ================
21
22 Model adapter implementations.
23 """
24 __author__ = u"Andr\xe9 Malo"
25 __docformat__ = "restructuredtext en"
26
27 from tdi import ModelMissingError
28 from tdi import interfaces as _interfaces
29
30
32 """
33 Regular Render-Adapter implementation
34
35 :See: `ModelAdapterInterface`
36 """
37 __implements__ = [_interfaces.ModelAdapterInterface]
38
39 emit_escaped = False
40
41 - def __new__(cls, model, requiremethods=False):
42 """
43 Construct
44
45 :Parameters:
46 `model` : any
47 User model
48
49 `requiremethods` : ``bool``
50 Require methods to exist?
51
52 :Return: Render adapter
53 :Rtype: `ModelAdapterInterface`
54 """
55 self = object.__new__(cls)
56
57 require = bool(requiremethods)
58 models = {'': model}
59 def modelmethod(prefix, name, scope, noauto):
60 """
61 Build the method name from prefix and node name and resolve
62
63 This implements the default look up.
64
65 :Parameters:
66 `prefix` : ``str``
67 The method prefix (``render``, or ``separate``)
68
69 `name` : ``str``
70 The node name
71
72 `scope` : ``str``
73 Scope
74
75 `noauto` : ``bool``
76 No automatic method calling?
77
78 :Return: The method or ``None``
79 :Rtype: ``callable``
80
81 :Exceptions:
82 - `ModelMissingError` : The method was not found, but all
83 methods are required
84 """
85 if name is None or noauto:
86 return None
87 if scope in models:
88 model = models[scope]
89 else:
90 model = models['']
91 scope_part = None
92 for part in scope.split('.'):
93 if not scope_part:
94 scope_part = part
95 else:
96 scope_part = '%s.%s' % (scope_part, part)
97 if scope_part in models:
98 model = models[scope_part]
99 else:
100 model = getattr(model, 'scope_' + part, None)
101 models[scope_part] = model
102
103 method = getattr(model, "%s_%s" % (prefix, name), None)
104 if method is None and require:
105 raise ModelMissingError(name)
106 return method
107
108 self.modelmethod = modelmethod
109 return self
110
112 """
113 Create prerender adapter from model
114
115 :Parameters:
116 `model` : any
117 User model
118
119 `attr` : ``dict``
120 Attribute name mapping. The keys 'scope' and 'tdi' are recognized.
121 If omitted or ``None``, the default attribute names are applied
122 ('tdi:scope' and 'tdi').
123
124 :Return: Prerender adapter
125 :Rtype: `ModelAdapterInterface`
126 """
127 return PreRenderWrapper(cls(model), attr=attr)
128 for_prerender = classmethod(for_prerender)
129
130
132 """
133 Pre-render wrapper adapter
134
135 :See: `ModelAdapterInterface`
136 """
137 __implements__ = [_interfaces.ModelAdapterInterface]
138
139 emit_escaped = True
140
141 - def __new__(cls, adapter, attr=None):
142 """
143 Construct
144
145 :Parameters:
146 `adapter` : `ModelAdapterInterface`
147 model adapter for resolving methods
148
149 `attr` : ``dict``
150 Attribute name mapping. The keys 'scope' and 'tdi' are recognized.
151 If omitted or ``None``, the default attribute names are applied
152 ('tdi:scope' and 'tdi').
153
154 :Return: Render adapter
155 :Rtype: `ModelAdapterInterface`
156 """
157
158 self = object.__new__(cls)
159
160 scope_attr = 'tdi:scope'
161 tdi_attr = 'tdi'
162 if attr is not None:
163 scope_attr = attr.get('scope', scope_attr)
164 tdi_attr = attr.get('tdi', tdi_attr)
165
166 omethod = adapter.modelmethod
167 def modelmethod(prefix, name, scope, noauto):
168 """
169 Build the method name from prefix and node name and resolve
170
171 This asks the passed adapter and if the particular method is not
172 found it generates its own, which restores the tdi attributes
173 (but not tdi:overlay).
174
175 :Parameters:
176 `prefix` : ``str``
177 The method prefix (``render``, or ``separate``)
178
179 `name` : ``str``
180 The node name
181
182 `scope` : ``str``
183 Scope
184
185 `noauto` : ``bool``
186 No automatic method calling?
187
188 :Return: The method
189 :Rtype: ``callable``
190 """
191 method = omethod(prefix, name, scope, noauto)
192 if method is not None:
193 return method
194
195
196
197
198
199 if prefix == 'separate':
200 return None
201
202
203
204
205
206
207
208 def repeat(node, item, ctx):
209 """ Repeater """
210 if item:
211 return node.remove()
212 node.ctx = ctx
213
214 def setscope(node, scope=scope):
215 """ Special attribute helper """
216 node[scope_attr] = (
217 '=' + (node.hiddenelement and '-' or '+') + scope
218 )
219
220 def render(node, name=name, sep=False):
221 """ Generated render method """
222 try:
223 toremove = node['tdi:prerender'] == 'remove-node'
224 del node['tdi:prerender']
225 except KeyError:
226 toremove = False
227
228 setscope(node)
229 if not toremove:
230 if name is not None:
231 flags = node.hiddenelement and '-' or '+'
232 if noauto:
233 flags += '*'
234 if sep:
235 flags += ':'
236 node[tdi_attr] = flags + name
237 node.hiddenelement = False
238
239 def separate(node, ctx):
240 """ Separator """
241 node.ctx = ctx
242 return render(node, sep=True)
243
244 node.repeat(repeat, (0, 1), node.ctx, separate=separate)
245
246 if name is None:
247 return setscope
248 return render
249
250 self.modelmethod = modelmethod
251 return self
252
253
254 from tdi import c
255 c = c.load('impl')
256 if c is not None:
257 RenderAdapter = c.RenderAdapter
258 del c
259