1 # -*- test-case-name: twisted.web.test.test_script -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
6 I contain PythonScript, which is a very simple python script resource.
12 import cStringIO as StringIO
16 from twisted import copyright
17 from twisted.web import http, server, static, resource, html
20 rpyNoResource = """<p>You forgot to assign to the variable "resource" in your script. For example:</p>
24 import mygreatresource
26 resource = mygreatresource.MyGreatResource()
30 class AlreadyCached(Exception):
31 """This exception is raised when a path has already been cached.
35 def __init__(self, path, registry):
37 self.registry = registry
41 c = self.registry.getCachedPath(self.path)
43 raise AlreadyCached(c)
49 noRsrc = resource.ErrorPage(500, "Whoops! Internal Error", rpyNoResource)
51 def ResourceScript(path, registry):
53 I am a normal py file which must define a 'resource' global, which should
54 be an instance of (a subclass of) web.resource.Resource; it will be
57 cs = CacheScanner(path, registry)
58 glob = {'__file__': path,
62 'recache': cs.recache}
64 execfile(path, glob, glob)
65 except AlreadyCached, ac:
67 rsrc = glob['resource']
68 if cs.doCache and rsrc is not noRsrc:
69 registry.cachePath(path, rsrc)
72 def ResourceTemplate(path, registry):
73 from quixote import ptl_compile
75 glob = {'__file__': path,
76 'resource': resource.ErrorPage(500, "Whoops! Internal Error",
80 e = ptl_compile.compile_template(open(path), path)
82 return glob['resource']
85 class ResourceScriptWrapper(resource.Resource):
87 def __init__(self, path, registry=None):
88 resource.Resource.__init__(self)
90 self.registry = registry or static.Registry()
92 def render(self, request):
93 res = ResourceScript(self.path, self.registry)
94 return res.render(request)
96 def getChildWithDefault(self, path, request):
97 res = ResourceScript(self.path, self.registry)
98 return res.getChildWithDefault(path, request)
102 class ResourceScriptDirectory(resource.Resource):
104 L{ResourceScriptDirectory} is a resource which serves scripts from a
105 filesystem directory. File children of a L{ResourceScriptDirectory} will
106 be served using L{ResourceScript}. Directory children will be served using
107 another L{ResourceScriptDirectory}.
109 @ivar path: A C{str} giving the filesystem path in which children will be
112 @ivar registry: A L{static.Registry} instance which will be used to decide
113 how to interpret scripts found as children of this resource.
115 def __init__(self, pathname, registry=None):
116 resource.Resource.__init__(self)
118 self.registry = registry or static.Registry()
120 def getChild(self, path, request):
121 fn = os.path.join(self.path, path)
123 if os.path.isdir(fn):
124 return ResourceScriptDirectory(fn, self.registry)
125 if os.path.exists(fn):
126 return ResourceScript(fn, self.registry)
127 return resource.NoResource()
129 def render(self, request):
130 return resource.NoResource().render(request)
133 class PythonScript(resource.Resource):
134 """I am an extremely simple dynamic resource; an embedded python script.
136 This will execute a file (usually of the extension '.epy') as Python code,
137 internal to the webserver.
140 def __init__(self, filename, registry):
141 """Initialize me with a script name.
143 self.filename = filename
144 self.registry = registry
146 def render(self, request):
147 """Render me to a web client.
149 Load my file, execute it in a special namespace (with 'request' and
150 '__file__' global vars) and finish the request. Output to the web-page
151 will NOT be handled with print - standard output goes to the log - but
154 request.setHeader("x-powered-by","Twisted/%s" % copyright.version)
155 namespace = {'request': request,
156 '__file__': self.filename,
157 'registry': self.registry}
159 execfile(self.filename, namespace, namespace)
161 if e.errno == 2: #file not found
162 request.setResponseCode(http.NOT_FOUND)
163 request.write(resource.NoResource("File not found.").render(request))
165 io = StringIO.StringIO()
166 traceback.print_exc(file=io)
167 request.write(html.PRE(io.getvalue()))
169 return server.NOT_DONE_YET