Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Side by Side Diff: third_party/twisted_8_1/twisted/web/woven/model.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.web.test.test_woven -*-
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 __version__ = "$Revision: 1.53 $"[11:-2]
7
8 import types
9 import weakref
10 import warnings
11
12 from zope.interface import implements
13
14 from twisted.python import components, reflect
15 from twisted.internet import defer
16
17 from twisted.web.woven import interfaces
18
19 class _Nothing: pass
20
21 def adaptToIModel(m, parent=None, submodel=None):
22 adapted = interfaces.IModel(m, None)
23 if adapted is None:
24 adapted = Wrapper(m)
25 adapted.parent = parent
26 adapted.name = submodel
27 return adapted
28
29
30 class Model:
31 """
32 A Model which keeps track of views which are looking at it in order
33 to notify them when the model changes.
34 """
35 implements(interfaces.IModel)
36
37 def __init__(self, *args, **kwargs):
38 if len(args):
39 self.original = args[0]
40 else:
41 self.original = self
42 self.name = ''
43 self.parent = None
44 self.views = []
45 self.subviews = {}
46 self.submodels = {}
47 self._getter = kwargs.get('getter')
48 self._setter = kwargs.get('setter')
49 self.cachedFor = None
50 self.initialize(*args, **kwargs)
51
52 def __getstate__(self):
53 self.views = []
54 self.subviews = {}
55 self.submodels = {}
56 return self.__dict__
57
58 def invalidateCache(self):
59 """Invalidate the cache for this object, so the next time
60 getData is called, it's getter method is called again.
61 """
62 self.cachedFor = None
63
64 def initialize(self, *args, **kwargs):
65 """
66 Hook for subclasses to initialize themselves without having to
67 mess with the __init__ chain.
68 """
69 pass
70
71 def addView(self, view):
72 """
73 Add a view for the model to keep track of.
74 """
75 if view not in [ref() for ref in self.views]:
76 self.views.append(weakref.ref(view))
77
78 def addSubview(self, name, subview):
79 subviewList = self.subviews.get(name, [])
80 subviewList.append(weakref.ref(subview))
81 self.subviews[name] = subviewList
82
83 def removeView(self, view):
84 """
85 Remove a view that the model no longer should keep track of.
86 """
87 # AM: loop on a _copy_ of the list, since we're changing it!!!
88 for weakref in list(self.views):
89 ref = weakref()
90 if ref is view or ref is None:
91 self.views.remove(weakref)
92
93 def setGetter(self, getter):
94 self._getter = getter
95
96 def setSetter(self, setter):
97 self._setter = setter
98
99 def notify(self, changed=None):
100 """
101 Notify all views that something was changed on me.
102 Passing a dictionary of {'attribute': 'new value'} in changed
103 will pass this dictionary to the view for increased performance.
104 If you don't want to do this, don't, and just use the traditional
105 MVC paradigm of querying the model for things you're interested
106 in.
107 """
108 self.cachedFor = None
109 if changed is None: changed = {}
110 retVal = []
111 # AM: loop on a _copy_ of the list, since we're changing it!!!
112 for view in list(self.views):
113 ref = view()
114 if ref is not None:
115 retVal.append((ref, ref.modelChanged(changed)))
116 else:
117 self.views.remove(view)
118 for key, value in self.subviews.items():
119 if value.wantsAllNotifications or changed.has_key(key):
120 for item in list(value):
121 ref = item()
122 if ref is not None:
123 retVal.append((ref, ref.modelChanged(changed)))
124 else:
125 value.remove(item)
126 return retVal
127
128 protected_names = ['initialize', 'addView', 'addSubview', 'removeView', 'not ify', 'getSubmodel', 'setSubmodel', 'getData', 'setData']
129 allowed_names = []
130
131 def lookupSubmodel(self, request, submodelName):
132 """
133 Look up a full submodel name. I will split on `/' and call
134 L{getSubmodel} on each element in the 'path'.
135
136 Override me if you don't want 'traversing'-style lookup, but
137 would rather like to look up a model based on the entire model
138 name specified.
139
140 If you override me to return Deferreds, make sure I look up
141 values in a cache (created by L{setSubmodel}) before doing a
142 regular Deferred lookup.
143
144 XXX: Move bits of this docstring to interfaces.py
145 """
146 if not submodelName:
147 return None
148
149 # Special case: If the first character is /
150 # Start at the bottom of the model stack
151 currentModel = self
152 if submodelName[0] == '/':
153 while currentModel.parent is not None:
154 currentModel = currentModel.parent
155 submodelName = submodelName[1:]
156
157 submodelList = submodelName.split('/') #[:-1]
158 # print "submodelList", submodelList
159 for element in submodelList:
160 if element == '.' or element == '':
161 continue
162 elif element == '..':
163 currentModel = currentModel.parent
164 else:
165 currentModel = currentModel.getSubmodel(request, element)
166 if currentModel is None:
167 return None
168 return currentModel
169
170 def submodelCheck(self, request, name):
171 """Check if a submodel name is allowed. Subclass me to implement a
172 name security policy.
173 """
174 if self.allowed_names:
175 return (name in self.allowed_names)
176 else:
177 return (name and name[0] != '_' and name not in self.protected_names )
178
179
180 def submodelFactory(self, request, name):
181 warnings.warn("Warning: default Model lookup strategy is changing:"
182 "use either AttributeModel or MethodModel for now.",
183 DeprecationWarning)
184 if hasattr(self, name):
185 return getattr(self, name)
186 else:
187 return None
188
189 def getSubmodel(self, request, name):
190 """
191 Get the submodel `name' of this model. If I ever return a
192 Deferred, then I ought to check for cached values (created by
193 L{setSubmodel}) before doing a regular Deferred lookup.
194 """
195 if self.submodels.has_key(name):
196 return self.submodels[name]
197 if not self.submodelCheck(request, name):
198 return None
199 m = self.submodelFactory(request, name)
200 if m is None:
201 return None
202 sm = adaptToIModel(m, self, name)
203 self.submodels[name] = sm
204 return sm
205
206 def setSubmodel(self, request=None, name=None, value=None):
207 """
208 Set a submodel on this model. If getSubmodel or lookupSubmodel
209 ever return a Deferred, I ought to set this in a place that
210 lookupSubmodel/getSubmodel know about, so they can use it as a
211 cache.
212 """
213 if self.submodelCheck(request, name):
214 if self.submodels.has_key(name):
215 del self.submodels[name]
216 setattr(self, name, value)
217
218 def dataWillChange(self):
219 pass
220
221 def getData(self, request):
222 if self.cachedFor != id(request) and self._getter is not None:
223 self.cachedFor = id(request)
224 self.dataWillChange()
225 self.orig = self.original = self._getter(request)
226 return self.original
227
228 def setData(self, request, data):
229 if self._setter is not None:
230 self.cachedFor = None
231 return self._setter(request, data)
232 else:
233 if hasattr(self, 'parent') and self.parent:
234 self.parent.setSubmodel(request, self.name, data)
235 self.orig = self.original = data
236
237
238 class MethodModel(Model):
239 """Look up submodels with wmfactory_* methods.
240 """
241
242 def submodelCheck(self, request, name):
243 """Allow any submodel for which I have a submodel.
244 """
245 return hasattr(self, "wmfactory_"+name)
246
247 def submodelFactory(self, request, name):
248 """Call a wmfactory_name method on this model.
249 """
250 meth = getattr(self, "wmfactory_"+name)
251 return meth(request)
252
253 def getSubmodel(self, request=None, name=None):
254 if name is None:
255 warnings.warn("Warning! getSubmodel should now take the request as t he first argument")
256 name = request
257 request = None
258
259 cached = self.submodels.has_key(name)
260 sm = Model.getSubmodel(self, request, name)
261 if sm is not None:
262 if not cached:
263 sm.cachedFor = id(request)
264 sm._getter = getattr(self, "wmfactory_"+name)
265 return sm
266
267
268 class AttributeModel(Model):
269 """Look up submodels as attributes with hosts.allow/deny-style security.
270 """
271 def submodelFactory(self, request, name):
272 if hasattr(self, name):
273 return getattr(self, name)
274 else:
275 return None
276
277
278 #backwards compatibility
279 WModel = Model
280
281
282 class Wrapper(Model):
283 """
284 I'm a generic wrapper to provide limited interaction with the
285 Woven models and submodels.
286 """
287 parent = None
288 name = None
289 def __init__(self, orig):
290 Model.__init__(self)
291 self.orig = self.original = orig
292
293 def dataWillChange(self):
294 pass
295
296 def __repr__(self):
297 myLongName = reflect.qual(self.__class__)
298 return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName,
299 id(self), self.origi nal)
300
301
302 class ListModel(Wrapper):
303 """
304 I wrap a Python list and allow it to interact with the Woven
305 models and submodels.
306 """
307 def dataWillChange(self):
308 self.submodels = {}
309
310 def getSubmodel(self, request=None, name=None):
311 if name is None and type(request) is type(""):
312 warnings.warn("Warning!")
313 name = request
314 request = None
315 if self.submodels.has_key(name):
316 return self.submodels[name]
317 orig = self.original
318 try:
319 i = int(name)
320 except:
321 return None
322 if i > len(orig):
323 return None
324 sm = adaptToIModel(orig[i], self, name)
325 self.submodels[name] = sm
326 return sm
327
328 def setSubmodel(self, request=None, name=None, value=None):
329 if value is None:
330 warnings.warn("Warning!")
331 value = name
332 name = request
333 request = None
334 self.original[int(name)] = value
335
336 def __len__(self):
337 return len(self.original)
338
339 def __getitem__(self, name):
340 return self.getSubmodel(None, str(name))
341
342 def __setitem__(self, name, value):
343 self.setSubmodel(None, str(name), value)
344
345 def __repr__(self):
346 myLongName = reflect.qual(self.__class__)
347 return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName,
348 id(self), self.origi nal)
349
350
351 class StringModel(ListModel):
352
353 """ I wrap a Python string and allow it to interact with the Woven models
354 and submodels. """
355
356 def setSubmodel(self, request=None, name=None, value=None):
357 raise ValueError("Strings are immutable.")
358
359
360 # pyPgSQL returns "PgResultSet" instances instead of lists, which look, act
361 # and breathe just like lists. pyPgSQL really shouldn't do this, but this works
362 try:
363 from pyPgSQL import PgSQL
364 components.registerAdapter(ListModel, PgSQL.PgResultSet, interfaces.IModel)
365 except:
366 pass
367
368 class DictionaryModel(Wrapper):
369 """
370 I wrap a Python dictionary and allow it to interact with the Woven
371 models and submodels.
372 """
373 def dataWillChange(self):
374 self.submodels = {}
375
376 def getSubmodel(self, request=None, name=None):
377 if name is None and type(request) is type(""):
378 warnings.warn("getSubmodel must get a request argument now")
379 name = request
380 request = None
381 if self.submodels.has_key(name):
382 return self.submodels[name]
383 orig = self.original
384 if name not in orig:
385 return None
386 sm = adaptToIModel(orig[name], self, name)
387 self.submodels[name] = sm
388 return sm
389
390 def setSubmodel(self, request=None, name=None, value=None):
391 if value is None:
392 warnings.warn("Warning!")
393 value = name
394 name = request
395 request = None
396 self.original[name] = value
397
398
399 class AttributeWrapper(Wrapper):
400 """
401 I wrap an attribute named "name" of the given parent object.
402 """
403 def __init__(self, parent, name):
404 self.original = None
405 parent = ObjectWrapper(parent)
406 Wrapper.__init__(self, parent.getSubmodel(None, name))
407 self.parent = parent
408 self.name = name
409
410
411 class ObjectWrapper(Wrapper):
412 """
413 I may wrap an object and allow it to interact with the Woven models
414 and submodels. By default, I am not registered for use with anything.
415 """
416 def getSubmodel(self, request=None, name=None):
417 if name is None and type(request) is type(""):
418 warnings.warn("Warning!")
419 name = request
420 request = None
421 if self.submodels.has_key(name):
422 return self.submodels[name]
423 sm = adaptToIModel(getattr(self.original, name), self, name)
424 self.submodels[name] = sm
425 return sm
426
427 def setSubmodel(self, request=None, name=None, value=None):
428 if value is None:
429 warnings.warn("Warning!")
430 value = name
431 name = request
432 request = None
433 setattr(self.original, name, value)
434
435 class UnsafeObjectWrapper(ObjectWrapper):
436 """
437 I may wrap an object and allow it to interact with the Woven models
438 and submodels. By default, I am not registered for use with anything.
439 I am unsafe because I allow methods to be called. In fact, I am
440 dangerously unsafe. Be wary or I will kill your security model!
441 """
442 def getSubmodel(self, request=None, name=None):
443 if name is None and type(request) is type(""):
444 warnings.warn("Warning!")
445 name = request
446 request = None
447 if self.submodels.has_key(name):
448 return self.submodels[name]
449 value = getattr(self.original, name)
450 if callable(value):
451 return value()
452 sm = adaptToIModel(value, self, name)
453 self.submodels = sm
454 return sm
455
456
457 class DeferredWrapper(Wrapper):
458 def setData(self, request=None, data=_Nothing):
459 if data is _Nothing:
460 warnings.warn("setData should be called with request as first arg")
461 data = request
462 request = None
463 if isinstance(data, defer.Deferred):
464 self.original = data
465 else:
466 views, subviews = self.views, self.subviews
467 new = adaptToIModel(data, self.parent, self.name)
468 self.__class__ = new.__class__
469 self.__dict__ = new.__dict__
470 self.views, self.subviews = views, subviews
471
472 class Link(AttributeModel):
473 def __init__(self, href, text):
474 AttributeModel.__init__(self)
475 self.href = href
476 self.text = text
477
478 try:
479 components.registerAdapter(StringModel, types.StringType, interfaces.IModel)
480 components.registerAdapter(ListModel, types.ListType, interfaces.IModel)
481 components.registerAdapter(ListModel, types.TupleType, interfaces.IModel)
482 components.registerAdapter(DictionaryModel, types.DictionaryType, interfaces .IModel)
483 components.registerAdapter(DeferredWrapper, defer.Deferred, interfaces.IMode l)
484 components.registerAdapter(DeferredWrapper, defer.DeferredList, interfaces.I Model)
485 except ValueError:
486 # The adapters were already registered
487 pass
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/web/woven/interfaces.py ('k') | third_party/twisted_8_1/twisted/web/woven/page.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698