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

Side by Side Diff: third_party/twisted_8_1/twisted/web/woven/template.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 #
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6
7 """
8 DOMTemplate
9
10 Most templating systems provide commands that you embed
11 in the HTML to repeat elements, include fragments from other
12 files, etc. This works fairly well for simple constructs and people
13 tend to get a false sense of simplicity from this. However, in my
14 experience, as soon as the programmer wants to make the logic
15 even slightly more complicated, the templating system must be
16 bent and abused in ways it was never meant to be used.
17
18 The theory behind DOMTemplate is that Python code instead
19 of template syntax in the HTML should be used to manipulate
20 the structure of the HTML. DOMTemplate uses the DOM, a w3c
21 standard tree-based representation of an HTML document that
22 provides an API that allows you to traverse nodes in the tree,
23 examine their attributes, move, add, and delete them. It is a
24 fairly low level API, meaning it takes quite a bit of code to get
25 a bit done, but it is standard -- learn the DOM once, you can
26 use it from ActionScript, JavaScript, Java, C++, whatever.
27
28 A DOMTemplate subclass must do two things: indicate which
29 template it wants to use, and indicate which elements it is
30 interested in.
31
32 A short example::
33
34 | class Test(DOMTemplate):
35 | template = '''
36 | <html><head><title>Foo</title></head><body>
37 |
38 | <div view="Test">
39 | This test node will be replaced
40 | </div>
41 |
42 | </body></html>
43 | '''
44 |
45 | def factory_test(self, request, node):
46 | '''
47 | The test method will be called with the request and the
48 | DOM node that the test method was associated with.
49 | '''
50 | # self.d has been bound to the main DOM "document" object
51 | newNode = self.d.createTextNode("Testing, 1,2,3")
52 |
53 | # Replace the test node with our single new text node
54 | return newNode
55 """
56
57 import warnings
58
59 try:
60 import cPickle as pickle
61 except ImportError:
62 import pickle
63
64 import string, os, sys, stat, types
65 from twisted.web import microdom
66
67 from twisted.python import components
68 from twisted.web import resource, html
69 from twisted.web.resource import Resource
70 from twisted.web.woven import controller, utils, interfaces
71
72 from twisted.internet import defer
73 from twisted.python import failure
74 from twisted.internet import reactor, defer
75 from twisted.python import log
76 from zope.interface import implements, Interface
77
78 from twisted.web.server import NOT_DONE_YET
79 STOP_RENDERING = 1
80 RESTART_RENDERING = 2
81
82
83
84 class INodeMutator(Interface):
85 """A component that implements NodeMutator knows how to mutate
86 DOM based on the instructions in the object it wraps.
87 """
88 def generate(request, node):
89 """The generate method should do the work of mutating the DOM
90 based on the object this adapter wraps.
91 """
92 pass
93
94
95 class NodeMutator:
96 implements(INodeMutator)
97 def __init__(self, data):
98 self.data = data
99
100 class NodeNodeMutator(NodeMutator):
101 """A NodeNodeMutator replaces the node that is passed in to generate
102 with the node it adapts.
103 """
104 def __init__(self, data):
105 assert data is not None
106 NodeMutator.__init__(self, data)
107
108 def generate(self, request, node):
109 if self.data is not node:
110 parent = node.parentNode
111 if parent:
112 parent.replaceChild(self.data, node)
113 else:
114 log.msg("Warning: There was no parent for node %s; node not muta ted." % node)
115 return self.data
116
117
118 class NoneNodeMutator(NodeMutator):
119 def generate(self, request, node):
120 return node # do nothing
121 child = request.d.createTextNode("None")
122 node.parentNode.replaceChild(child, node)
123
124
125 class StringNodeMutator(NodeMutator):
126 """A StringNodeMutator replaces the node that is passed in to generate
127 with the string it adapts.
128 """
129 def generate(self, request, node):
130 if self.data:
131 try:
132 child = microdom.parseString(self.data)
133 except Exception, e:
134 log.msg("Error parsing return value, probably invalid xml:", e)
135 child = request.d.createTextNode(self.data)
136 else:
137 child = request.d.createTextNode(self.data)
138 nodeMutator = NodeNodeMutator(child)
139 return nodeMutator.generate(request, node)
140
141
142 components.registerAdapter(NodeNodeMutator, microdom.Node, INodeMutator)
143 components.registerAdapter(NoneNodeMutator, type(None), INodeMutator)
144 components.registerAdapter(StringNodeMutator, type(""), INodeMutator)
145
146
147 class DOMTemplate(Resource):
148 """A resource that renders pages using DOM."""
149
150 isLeaf = 1
151 templateFile = ''
152 templateDirectory = ''
153 template = ''
154 _cachedTemplate = None
155
156 def __init__(self, templateFile = None):
157 """
158 @param templateFile: The name of a file containing a template.
159 @type templateFile: String
160 """
161 Resource.__init__(self)
162 if templateFile:
163 self.templateFile = templateFile
164
165 self.outstandingCallbacks = 0
166 self.failed = 0
167
168 def render(self, request):
169 template = self.getTemplate(request)
170 if template:
171 self.d = microdom.parseString(template)
172 else:
173 if not self.templateFile:
174 raise AttributeError, "%s does not define self.templateFile to o perate on" % self.__class__
175 self.d = self.lookupTemplate(request)
176 self.handleDocument(request, self.d)
177 return NOT_DONE_YET
178
179 def getTemplate(self, request):
180 """
181 Override this if you want to have your subclass look up its template
182 using a different method.
183 """
184 return self.template
185
186 def lookupTemplate(self, request):
187 """
188 Use acquisition to look up the template named by self.templateFile,
189 located anywhere above this object in the heirarchy, and use it
190 as the template. The first time the template is used it is cached
191 for speed.
192 """
193 if self.template:
194 return microdom.parseString(self.template)
195 if not self.templateDirectory:
196 mod = sys.modules[self.__module__]
197 if hasattr(mod, '__file__'):
198 self.templateDirectory = os.path.split(mod.__file__)[0]
199 # First see if templateDirectory + templateFile is a file
200 templatePath = os.path.join(self.templateDirectory, self.templateFile)
201 # Check to see if there is an already compiled copy of it
202 templateName = os.path.splitext(self.templateFile)[0]
203 compiledTemplateName = '.' + templateName + '.pxp'
204 compiledTemplatePath = os.path.join(self.templateDirectory, compiledTemp lateName)
205 # No? Compile and save it
206 if (not os.path.exists(compiledTemplatePath) or
207 os.stat(compiledTemplatePath)[stat.ST_MTIME] < os.stat(templatePath)[sta t.ST_MTIME]):
208 compiledTemplate = microdom.parse(templatePath)
209 pickle.dump(compiledTemplate, open(compiledTemplatePath, 'wb'), 1)
210 else:
211 compiledTemplate = pickle.load(open(compiledTemplatePath, "rb"))
212 return compiledTemplate
213
214 def setUp(self, request, document):
215 pass
216
217 def handleDocument(self, request, document):
218 """
219 Handle the root node, and send the page if there are no
220 outstanding callbacks when it returns.
221 """
222 try:
223 request.d = document
224 self.setUp(request, document)
225 # Don't let outstandingCallbacks get to 0 until the
226 # entire tree has been recursed
227 # If you don't do this, and any callback has already
228 # completed by the time the dispatchResultCallback
229 # is added in dispachResult, then sendPage will be
230 # called prematurely within dispatchResultCallback
231 # resulting in much gnashing of teeth.
232 self.outstandingCallbacks += 1
233 for node in document.childNodes:
234 request.currentParent = node
235 self.handleNode(request, node)
236 self.outstandingCallbacks -= 1
237 if not self.outstandingCallbacks:
238 return self.sendPage(request)
239 except:
240 self.renderFailure(None, request)
241
242 def dispatchResult(self, request, node, result):
243 """
244 Check a given result from handling a node and hand it to a process*
245 method which will convert the result into a node and insert it
246 into the DOM tree. Return the new node.
247 """
248 if not isinstance(result, defer.Deferred):
249 adapter = INodeMutator(result, None)
250 if adapter is None:
251 raise NotImplementedError(
252 "Your factory method returned %s, but there is no "
253 "INodeMutator adapter registerred for %s." %
254 (result, getattr(result, "__class__",
255 None) or type(result)))
256 result = adapter.generate(request, node)
257 if isinstance(result, defer.Deferred):
258 self.outstandingCallbacks += 1
259 result.addCallback(self.dispatchResultCallback, request, node)
260 result.addErrback(self.renderFailure, request)
261 # Got to wait until the callback comes in
262 return result
263
264 def recurseChildren(self, request, node):
265 """
266 If this node has children, handle them.
267 """
268 request.currentParent = node
269 if not node: return
270 if type(node.childNodes) == type(""): return
271 if node.hasChildNodes():
272 for child in node.childNodes:
273 self.handleNode(request, child)
274
275 def dispatchResultCallback(self, result, request, node):
276 """
277 Deal with a callback from a deferred, dispatching the result
278 and recursing children.
279 """
280 self.outstandingCallbacks -= 1
281 node = self.dispatchResult(request, node, result)
282 self.recurseChildren(request, node)
283 if not self.outstandingCallbacks:
284 return self.sendPage(request)
285
286 def handleNode(self, request, node):
287 """
288 Handle a single node by looking up a method for it, calling the method
289 and dispatching the result.
290
291 Also, handle all childNodes of this node using recursion.
292 """
293 if not hasattr(node, 'getAttribute'): # text node?
294 return node
295
296 viewName = node.getAttribute('view')
297 if viewName:
298 method = getattr(self, "factory_" + viewName, None)
299 if not method:
300 raise NotImplementedError, "You specified view name %s on a node , but no factory_%s method was found." % (viewName, viewName)
301
302 result = method(request, node)
303 node = self.dispatchResult(request, node, result)
304
305 if not isinstance(node, defer.Deferred):
306 self.recurseChildren(request, node)
307
308 def sendPage(self, request):
309 """
310 Send the results of the DOM mutation to the browser.
311 """
312 page = str(self.d.toxml())
313 request.write(page)
314 request.finish()
315 return page
316
317 def renderFailure(self, failure, request):
318 try:
319 xml = request.d.toxml()
320 except:
321 xml = ""
322 # if not hasattr(request, 'channel'):
323 # log.msg("The request got away from me before I could render an err or page.")
324 # log.err(failure)
325 # return failure
326 if not self.failed:
327 self.failed = 1
328 if failure:
329 request.write("<html><head><title>%s: %s</title></head><body>\n" % (html.escape(str(failure.type)), html.escape(str(failure.value))))
330 else:
331 request.write("<html><head><title>Failure!</title></head><body>\ n")
332 utils.renderFailure(failure, request)
333 request.write("<h3>Here is the partially processed DOM:</h3>")
334 request.write("\n<pre>\n")
335 request.write(html.escape(xml))
336 request.write("\n</pre>\n")
337 request.write("</body></html>")
338 request.finish()
339 return failure
340
341 ##########################################
342 # Deprecation zone
343 # Wear a hard hat
344 ##########################################
345
346
347 # DOMView is now deprecated since the functionality was merged into domtemplate
348 DOMView = DOMTemplate
349
350 # DOMController is now renamed woven.controller.Controller
351 class DOMController(controller.Controller, Resource):
352 """
353 A simple controller that automatically passes responsibility on to the view
354 class registered for the model. You can override render to perform
355 more advanced template lookup logic.
356 """
357
358 def __init__(self, *args, **kwargs):
359 log.msg("DeprecationWarning: DOMController is deprecated; it has been re named twisted.web.woven.controller.Controller.\n")
360 controller.Controller.__init__(self, *args, **kwargs)
361 Resource.__init__(self)
362
363 def setUp(self, request):
364 pass
365
366 def render(self, request):
367 self.setUp(request)
368 self.view = interfaces.IView(self.model, None)
369 self.view.setController(self)
370 return self.view.render(request)
371
372 def process(self, request, **kwargs):
373 log.msg("Processing results: ", kwargs)
374 return RESTART_RENDERING
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/web/woven/tapestry.py ('k') | third_party/twisted_8_1/twisted/web/woven/utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698