1   
  2  r""" 
  3  :Copyright: 
  4   
  5   Copyright 2006 - 2015 
  6   Andr\xe9 Malo or his licensors, as applicable 
  7   
  8  :License: 
  9   
 10   Licensed under the Apache License, Version 2.0 (the "License"); 
 11   you may not use this file except in compliance with the License. 
 12   You may obtain a copy of the License at 
 13   
 14       http://www.apache.org/licenses/LICENSE-2.0 
 15   
 16   Unless required by applicable law or agreed to in writing, software 
 17   distributed under the License is distributed on an "AS IS" BASIS, 
 18   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 19   See the License for the specific language governing permissions and 
 20   limitations under the License. 
 21   
 22  ================ 
 23   Model Adapters 
 24  ================ 
 25   
 26  Model adapter implementations. 
 27  """ 
 28  if __doc__: 
 29       
 30      __doc__ = __doc__.encode('ascii').decode('unicode_escape') 
 31  __author__ = r"Andr\xe9 Malo".encode('ascii').decode('unicode_escape') 
 32  __docformat__ = "restructuredtext en" 
 33   
 34  from ._exceptions import ModelMissingError 
 35  from . import interfaces as _interfaces 
 39      """ 
 40      Regular Render-Adapter implementation 
 41   
 42      :See: `ModelAdapterInterface` 
 43      """ 
 44      __implements__ = [_interfaces.ModelAdapterInterface] 
 45   
 46 -    def __new__(cls, model, requiremethods=False, requirescopes=False): 
  47          """ 
 48          Construct 
 49   
 50          :Parameters: 
 51            `model` : any 
 52              User model 
 53   
 54            `requiremethods` : ``bool`` 
 55              Require methods to exist? 
 56   
 57            `requirescopes` : ``bool`` 
 58              Require scopes to exist? 
 59   
 60          :Return: Render adapter 
 61          :Rtype: `ModelAdapterInterface` 
 62          """ 
 63          self = object.__new__(cls) 
 64   
 65          requiremethods = bool(requiremethods) 
 66          requirescopes = bool(requirescopes) 
 67          getattr_ = getattr 
 68          models = {'': model} 
 69   
 70          class unset(object): 
 71               
 72              pass 
  73          unset = unset() 
 74   
 75          def new(model): 
 76              """ Create adapter for a new model """ 
 77              return cls( 
 78                  model, 
 79                  requiremethods=requiremethods, 
 80                  requirescopes=requirescopes, 
 81              ) 
  82   
 83          def modelmethod(prefix, name, scope, noauto): 
 84              """ 
 85              Build the method name from prefix and node name and resolve 
 86   
 87              This implements the default look up. 
 88   
 89              :Parameters: 
 90                `prefix` : ``str`` 
 91                  The method prefix (``render``, or ``separate``) 
 92   
 93                `name` : ``str`` 
 94                  The node name 
 95   
 96                `scope` : ``str`` 
 97                  Scope 
 98   
 99                `noauto` : ``bool`` 
100                  No automatic method calling? 
101   
102              :Return: The method or ``None`` 
103              :Rtype: ``callable`` 
104   
105              :Exceptions: 
106                - `ModelMissingError` : The method was not found, but all 
107                  methods are required 
108              """ 
109              if name is None or noauto: 
110                  return None 
111              if scope in models: 
112                  model = models[scope] 
113              else: 
114                  model = models[''] 
115                  scope_part = None 
116                  for part in scope.split('.'): 
117                      if not scope_part: 
118                          scope_part = part 
119                      else: 
120                          scope_part = '%s.%s' % (scope_part, part) 
121                      if scope_part in models: 
122                          model = models[scope_part] 
123                      else: 
124                          model = getattr_(model, 'scope_' + part, unset) 
125                          if model is unset: 
126                              if requirescopes: 
127                                  raise ModelMissingError(scope_part) 
128                              model = None 
129                          models[scope_part] = model 
130   
131              method = getattr_(model, "%s_%s" % (prefix, name), unset) 
132              if method is unset: 
133                  if requiremethods: 
134                      raise ModelMissingError("%s_%s" % (prefix, name)) 
135                  method = None 
136              return method 
137   
138          self.modelmethod = modelmethod 
139          self.new = new 
140          self.emit_escaped = False 
141   
142          return self 
143   
144      @classmethod 
146          """ 
147          Create prerender adapter from model 
148   
149          :Parameters: 
150            `model` : any 
151              User model 
152   
153            `attr` : ``dict`` 
154              Attribute name mapping. The keys 'scope' and 'tdi' are recognized. 
155              If omitted or ``None``, the default attribute names are applied 
156              ('tdi:scope' and 'tdi'). 
157   
158          :Return: Prerender adapter 
159          :Rtype: `ModelAdapterInterface` 
160          """ 
161          return PreRenderWrapper(cls(model), attr=attr) 
 162   
165      """ 
166      Pre-render wrapper adapter 
167   
168      :See: `ModelAdapterInterface` 
169      """ 
170      __implements__ = [_interfaces.ModelAdapterInterface] 
171   
172 -    def __new__(cls, adapter, attr=None): 
 173          """ 
174          Construct 
175   
176          :Parameters: 
177            `adapter` : `ModelAdapterInterface` 
178              model adapter for resolving methods 
179   
180            `attr` : ``dict`` 
181              Attribute name mapping. The keys 'scope' and 'tdi' are recognized. 
182              If omitted or ``None``, the default attribute names are applied 
183              ('tdi:scope' and 'tdi'). 
184   
185          :Return: Render adapter 
186          :Rtype: `ModelAdapterInterface` 
187          """ 
188          self = object.__new__(cls) 
189   
190          scope_attr = 'tdi:scope' 
191          tdi_attr = 'tdi' 
192          if attr is not None: 
193              scope_attr = attr.get('scope', scope_attr) 
194              tdi_attr = attr.get('tdi', tdi_attr) 
195              attr = dict(tdi=tdi_attr, scope=scope_attr) 
196   
197          def new(model): 
198              """ Create adapter for a new model """ 
199              return cls(adapter.new(model), attr=attr) 
 200   
201          def modelmethod(prefix, name, scope, noauto): 
202              """ 
203              Build the method name from prefix and node name and resolve 
204   
205              This asks the passed adapter and if the particular method is not 
206              found it generates its own, which restores the tdi attributes 
207              (but not tdi:overlay). 
208   
209              :Parameters: 
210                `prefix` : ``str`` 
211                  The method prefix (``render``, or ``separate``) 
212   
213                `name` : ``str`` 
214                  The node name 
215   
216                `scope` : ``str`` 
217                  Scope 
218   
219                `noauto` : ``bool`` 
220                  No automatic method calling? 
221   
222              :Return: The method or ``None`` 
223              :Rtype: ``callable`` 
224              """ 
225              try: 
226                  method = adapter.modelmethod(prefix, name, scope, noauto) 
227              except ModelMissingError: 
228                  pass 
229              else: 
230                  if method is not None: 
231                      return method 
232   
233               
234               
235               
236               
237              if prefix == 'separate': 
238                  return None 
239   
240               
241               
242               
243   
244               
245               
246              def repeat(node, item, ctx): 
247                  """ Repeater """ 
248                  if item: 
249                      return node.remove() 
250                  node.ctx = ctx 
 251   
252              def setscope(node, scope=scope): 
253                  """ Special attribute helper """ 
254                  node[scope_attr] = ( 
255                      '=' + (node.hiddenelement and '-' or '+') + scope 
256                  ) 
257   
258              def render(node, name=name, sep=False): 
259                  """ Generated render method """ 
260                  try: 
261                      toremove = node['tdi:prerender'] == 'remove-node' 
262                      del node['tdi:prerender'] 
263                  except KeyError: 
264                      toremove = False 
265   
266                  setscope(node) 
267                  if not toremove: 
268                      if name is not None: 
269                          flags = node.hiddenelement and '-' or '+' 
270                          if noauto: 
271                              flags += '*' 
272                          if sep: 
273                              flags += ':' 
274                          node[tdi_attr] = flags + name 
275                          node.hiddenelement = False 
276   
277                  def separate(node, ctx): 
278                      """ Separator """ 
279                      node.ctx = ctx 
280                      return render(node, sep=True) 
281   
282                  node.repeat(repeat, (0, 1), node.ctx, separate=separate) 
283   
284              if name is None: 
285                  return setscope 
286              return render 
287   
288          self.modelmethod = modelmethod 
289          self.new = new 
290          self.emit_escaped = True 
291   
292          return self 
293   
294   
295  from . import c 
296  c = c.load('impl') 
297  if c is not None: 
298      RenderAdapter = c.RenderAdapter   
299      PreRenderWrapper = c.PreRenderWrapper   
300  del c 
301