Package tdi :: Module model_adapters
[frames] | no frames]

Source Code for Module tdi.model_adapters

  1  # -*- coding: ascii -*- 
  2  # 
  3  # Copyright 2006 - 2012 
  4  # Andr\xe9 Malo or his licensors, as applicable 
  5  # 
  6  # Licensed under the Apache License, Version 2.0 (the "License"); 
  7  # you may not use this file except in compliance with the License. 
  8  # You may obtain a copy of the License at 
  9  # 
 10  #     http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, software 
 13  # distributed under the License is distributed on an "AS IS" BASIS, 
 14  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 15  # See the License for the specific language governing permissions and 
 16  # limitations under the License. 
 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   
31 -class RenderAdapter(object):
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
111 - def for_prerender(cls, model, attr=None):
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
131 -class PreRenderWrapper(object):
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 # pylint: disable = R0912 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 # These methods we only see of the model repeats a node, but 196 # doesn't define a separator logic. We do not want to write out 197 # the special node stuff in this case (since the separators would 198 # be alone after that). 199 if prefix == 'separate': 200 return None 201 202 # The node is repeated in order to get our hands on 203 # a possible separator. The second iteration of the node is simply 204 # removed, so we keep the node itself and its separator. 205 206 # However, by repeating the node we override an existing context 207 # of the node. So we pass it explicitly and override it again. 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