1 """CherryPy is a pythonic, object-oriented HTTP framework.
2
3
4 CherryPy consists of not one, but four separate API layers.
5
6 The APPLICATION LAYER is the simplest. CherryPy applications are written as
7 a tree of classes and methods, where each branch in the tree corresponds to
8 a branch in the URL path. Each method is a 'page handler', which receives
9 GET and POST params as keyword arguments, and returns or yields the (HTML)
10 body of the response. The special method name 'index' is used for paths
11 that end in a slash, and the special method name 'default' is used to
12 handle multiple paths via a single handler. This layer also includes:
13
14 * the 'exposed' attribute (and cherrypy.expose)
15 * cherrypy.quickstart()
16 * _cp_config attributes
17 * cherrypy.tools (including cherrypy.session)
18 * cherrypy.url()
19
20 The ENVIRONMENT LAYER is used by developers at all levels. It provides
21 information about the current request and response, plus the application
22 and server environment, via a (default) set of top-level objects:
23
24 * cherrypy.request
25 * cherrypy.response
26 * cherrypy.engine
27 * cherrypy.server
28 * cherrypy.tree
29 * cherrypy.config
30 * cherrypy.thread_data
31 * cherrypy.log
32 * cherrypy.HTTPError, NotFound, and HTTPRedirect
33 * cherrypy.lib
34
35 The EXTENSION LAYER allows advanced users to construct and share their own
36 plugins. It consists of:
37
38 * Hook API
39 * Tool API
40 * Toolbox API
41 * Dispatch API
42 * Config Namespace API
43
44 Finally, there is the CORE LAYER, which uses the core API's to construct
45 the default components which are available at higher layers. You can think
46 of the default components as the 'reference implementation' for CherryPy.
47 Megaframeworks (and advanced users) may replace the default components
48 with customized or extended components. The core API's are:
49
50 * Application API
51 * Engine API
52 * Request API
53 * Server API
54 * WSGI API
55
56 These API's are described in the CherryPy specification:
57 http://www.cherrypy.org/wiki/CherryPySpec
58 """
59
60 __version__ = "3.0.2"
61
62 from urlparse import urljoin as _urljoin
63
64
66 """Metaclass for declaring docstrings for class attributes."""
67
68
69
71 '''Metaclass for declaring docstrings for class attributes.
72
73 Base Python doesn't provide any syntax for setting docstrings on
74 'data attributes' (non-callables). This metaclass allows class
75 definitions to follow the declaration of a data attribute with
76 a docstring for that attribute; the attribute docstring will be
77 popped from the class dict and folded into the class docstring.
78
79 The naming convention for attribute docstrings is: <attrname> + "__doc".
80 For example:
81
82 class Thing(object):
83 """A thing and its properties."""
84
85 __metaclass__ = cherrypy._AttributeDocstrings
86
87 height = 50
88 height__doc = """The height of the Thing in inches."""
89
90 In which case, help(Thing) starts like this:
91
92 >>> help(mod.Thing)
93 Help on class Thing in module pkg.mod:
94
95 class Thing(__builtin__.object)
96 | A thing and its properties.
97 |
98 | height [= 50]:
99 | The height of the Thing in inches.
100 |
101
102 The benefits of this approach over hand-edited class docstrings:
103 1. Places the docstring nearer to the attribute declaration.
104 2. Makes attribute docs more uniform ("name (default): doc").
105 3. Reduces mismatches of attribute _names_ between
106 the declaration and the documentation.
107 4. Reduces mismatches of attribute default _values_ between
108 the declaration and the documentation.
109
110 The benefits of a metaclass approach over other approaches:
111 1. Simpler ("less magic") than interface-based solutions.
112 2. __metaclass__ can be specified at the module global level
113 for classic classes.
114
115 The type of the attribute is intentionally not included, because
116 that's not How Python Works. Quack.
117 '''
118
119 newdoc = [cls.__doc__ or ""]
120
121 dctnames = dct.keys()
122 dctnames.sort()
123
124 for name in dctnames:
125 if name.endswith("__doc"):
126
127 if hasattr(cls, name):
128 delattr(cls, name)
129
130
131 val = dct[name]
132 try:
133 import inspect
134 val = inspect.getdoc(property(doc=val)).strip()
135 except:
136 pass
137
138
139 val = '\n'.join([' ' + line.rstrip()
140 for line in val.split('\n')])
141
142
143 attrname = name[:-5]
144 try:
145 attrval = getattr(cls, attrname)
146 except AttributeError:
147 attrval = "missing"
148
149
150 newdoc.append("%s [= %r]:\n%s" % (attrname, attrval, val))
151
152
153 cls.__doc__ = "\n\n".join(newdoc)
154
155
156 from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect
157 from cherrypy._cperror import NotFound, CherryPyException, TimeoutError
158
159 from cherrypy import _cpdispatch as dispatch
160 from cherrypy import _cprequest
161 from cherrypy.lib import http as _http
162 from cherrypy import _cpengine
163 engine = _cpengine.Engine()
164
165 from cherrypy import _cptools
166 tools = _cptools.default_toolbox
167 Tool = _cptools.Tool
168
169 from cherrypy import _cptree
170 tree = _cptree.Tree()
171 from cherrypy._cptree import Application
172 from cherrypy import _cpwsgi as wsgi
173 from cherrypy import _cpserver
174 server = _cpserver.Server()
175
176 -def quickstart(root, script_name="", config=None):
183
184
185 try:
186 from threading import local as _local
187 except ImportError:
188 from cherrypy._cpthreadinglocal import local as _local
189
191 """An interface for registering request and response objects.
192
193 Rather than have a separate "thread local" object for the request and
194 the response, this class works as a single threadlocal container for
195 both objects (and any others which developers wish to define). In this
196 way, we can easily dump those objects when we stop/start a new HTTP
197 conversation, yet still refer to them as module-level globals in a
198 thread-safe way.
199 """
200
201 __metaclass__ = _AttributeDocstrings
202
203 request = _cprequest.Request(_http.Host("localhost", 80),
204 _http.Host("localhost", 1111))
205 request__doc = """
206 The request object for the current thread. In the main thread,
207 and any threads which are not receiving HTTP requests, this is None."""
208
209 response = _cprequest.Response()
210 response__doc = """
211 The response object for the current thread. In the main thread,
212 and any threads which are not receiving HTTP requests, this is None."""
213
214 - def load(self, request, response):
217
219 """Remove all attributes of self."""
220 self.__dict__.clear()
221
222
223 serving = _serving = _Serving()
224
225
227
228 __slots__ = ['__attrname__', '__dict__']
229
232
236
243
247
253 __dict__ = property(_get_dict)
254
258
262
266
270
271
272
273
274
275 request = _ThreadLocalProxy('request')
276 response = _ThreadLocalProxy('response')
277
278
280 """A container for thread-specific data."""
281 thread_data = _ThreadData()
282
283
284
285
286
287
289 """Given an object or a path to an object, get the object and its name."""
290 if isinstance(thing, _ThreadLocalProxy):
291 thing = getattr(serving, thing.__attrname__)
292 return pydoc._builtin_resolve(thing, forceload)
293
294 try:
295 import pydoc
296 pydoc._builtin_resolve = pydoc.resolve
297 pydoc.resolve = _cherrypy_pydoc_resolve
298 except ImportError:
299 pass
300
301
302 from cherrypy import _cplogging
303
318
319
320 log = _GlobalLogManager()
321
322 log.screen = True
323 log.error_file = ''
324
325 log.access_file = ''
326
327
328
329
330
331 -def expose(func=None, alias=None):
332 """Expose the function, optionally providing an alias or set of aliases."""
333
334 def expose_(func):
335 func.exposed = True
336 if alias is not None:
337 if isinstance(alias, basestring):
338 parents[alias.replace(".", "_")] = func
339 else:
340 for a in alias:
341 parents[a.replace(".", "_")] = func
342 return func
343
344 import sys, types
345 if isinstance(func, (types.FunctionType, types.MethodType)):
346
347 parents = sys._getframe(1).f_locals
348 return expose_(func)
349 else:
350 if alias is None:
351
352 func.exposed = True
353 return func
354 else:
355
356 parents = sys._getframe(1).f_locals
357 return expose_
358
359 -def url(path="", qs="", script_name=None, base=None, relative=False):
360 """Create an absolute URL for the given path.
361
362 If 'path' starts with a slash ('/'), this will return
363 (base + script_name + path + qs).
364 If it does not start with a slash, this returns
365 (base + script_name [+ request.path_info] + path + qs).
366
367 If script_name is None, cherrypy.request will be used
368 to find a script_name, if available.
369
370 If base is None, cherrypy.request.base will be used (if available).
371 Note that you can use cherrypy.tools.proxy to change this.
372
373 Finally, note that this function can be used to obtain an absolute URL
374 for the current request path (minus the querystring) by passing no args.
375 If you call url(qs=cherrypy.request.query_string), you should get the
376 original browser URL (assuming no Internal redirections).
377
378 If relative is False (the default), the output will be an absolute URL
379 (usually including the scheme, host, vhost, and script_name).
380 If relative is True, the output will instead be a URL that is relative
381 to the current request path, perhaps including '..' atoms.
382 """
383 if qs:
384 qs = '?' + qs
385
386 if request.app:
387 if not path.startswith("/"):
388
389
390
391 pi = request.path_info
392 if request.is_index is True:
393 if not pi.endswith('/'):
394 pi = pi + '/'
395 elif request.is_index is False:
396 if pi.endswith('/') and pi != '/':
397 pi = pi[:-1]
398
399 if path == "":
400 path = pi
401 else:
402 path = _urljoin(pi, path)
403
404 if script_name is None:
405 script_name = request.app.script_name
406 if base is None:
407 base = request.base
408
409 newurl = base + script_name + path + qs
410 else:
411
412
413
414
415 if base is None:
416 base = server.base()
417
418 path = (script_name or "") + path
419 newurl = base + path + qs
420
421 if './' in newurl:
422
423 atoms = []
424 for atom in newurl.split('/'):
425 if atom == '.':
426 pass
427 elif atom == '..':
428 atoms.pop()
429 else:
430 atoms.append(atom)
431 newurl = '/'.join(atoms)
432
433 if relative:
434 old = url().split('/')[:-1]
435 new = newurl.split('/')
436 while old and new:
437 a, b = old[0], new[0]
438 if a != b:
439 break
440 old.pop(0)
441 new.pop(0)
442 new = (['..'] * len(old)) + new
443 newurl = '/'.join(new)
444
445 return newurl
446
447
448
449 from cherrypy import _cpconfig
450
451
452 config = _global_conf_alias = _cpconfig.Config()
453
454 from cherrypy import _cpchecker
455 checker = _cpchecker.Checker()
456