Package cherrypy
[hide private]
[frames] | no frames]

Source Code for Package cherrypy

  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   
65 -class _AttributeDocstrings(type):
66 """Metaclass for declaring docstrings for class attributes.""" 67 # The full docstring for this type is down in the __init__ method so 68 # that it doesn't show up in help() for every consumer class. 69
70 - def __init__(cls, name, bases, dct):
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 # Remove the magic doc attribute. 127 if hasattr(cls, name): 128 delattr(cls, name) 129 130 # Get an inspect-style docstring if possible (usually so). 131 val = dct[name] 132 try: 133 import inspect 134 val = inspect.getdoc(property(doc=val)).strip() 135 except: 136 pass 137 138 # Indent the docstring. 139 val = '\n'.join([' ' + line.rstrip() 140 for line in val.split('\n')]) 141 142 # Get the default value. 143 attrname = name[:-5] 144 try: 145 attrval = getattr(cls, attrname) 146 except AttributeError: 147 attrval = "missing" 148 149 # Add the complete attribute docstring to our list. 150 newdoc.append("%s [= %r]:\n%s" % (attrname, attrval, val)) 151 152 # Add our list of new docstrings to the class docstring. 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):
177 """Mount the given root, start the engine and builtin server, then block.""" 178 if config: 179 _global_conf_alias.update(config) 180 tree.mount(root, script_name, config) 181 server.quickstart() 182 engine.start()
183 184 185 try: 186 from threading import local as _local 187 except ImportError: 188 from cherrypy._cpthreadinglocal import local as _local 189
190 -class _Serving(_local):
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):
215 self.request = request 216 self.response = response
217
218 - def clear(self):
219 """Remove all attributes of self.""" 220 self.__dict__.clear()
221 222 # The name "_serving" should be removed in 3.1. 223 serving = _serving = _Serving() 224 225
226 -class _ThreadLocalProxy(object):
227 228 __slots__ = ['__attrname__', '__dict__'] 229
230 - def __init__(self, attrname):
231 self.__attrname__ = attrname
232
233 - def __getattr__(self, name):
234 child = getattr(serving, self.__attrname__) 235 return getattr(child, name)
236
237 - def __setattr__(self, name, value):
238 if name in ("__attrname__", ): 239 object.__setattr__(self, name, value) 240 else: 241 child = getattr(serving, self.__attrname__) 242 setattr(child, name, value)
243
244 - def __delattr__(self, name):
245 child = getattr(serving, self.__attrname__) 246 delattr(child, name)
247
248 - def _get_dict(self):
249 child = getattr(serving, self.__attrname__) 250 d = child.__class__.__dict__.copy() 251 d.update(child.__dict__) 252 return d
253 __dict__ = property(_get_dict) 254
255 - def __getitem__(self, key):
256 child = getattr(serving, self.__attrname__) 257 return child[key]
258
259 - def __setitem__(self, key, value):
260 child = getattr(serving, self.__attrname__) 261 child[key] = value
262
263 - def __delitem__(self, key):
264 child = getattr(serving, self.__attrname__) 265 del child[key]
266
267 - def __contains__(self, key):
268 child = getattr(serving, self.__attrname__) 269 return key in child
270 271 272 # Create request and response object (the same objects will be used 273 # throughout the entire life of the webserver, but will redirect 274 # to the "serving" object) 275 request = _ThreadLocalProxy('request') 276 response = _ThreadLocalProxy('response') 277 278 # Create thread_data object as a thread-specific all-purpose storage
279 -class _ThreadData(_local):
280 """A container for thread-specific data."""
281 thread_data = _ThreadData() 282 283 284 # Monkeypatch pydoc to allow help() to go through the threadlocal proxy. 285 # Jan 2007: no Googleable examples of anyone else replacing pydoc.resolve. 286 # The only other way would be to change what is returned from type(request) 287 # and that's not possible in pure Python (you'd have to fake ob_type).
288 -def _cherrypy_pydoc_resolve(thing, forceload=0):
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
304 -class _GlobalLogManager(_cplogging.LogManager):
305
306 - def __call__(self, *args, **kwargs):
307 try: 308 log = request.app.log 309 except AttributeError: 310 log = self 311 return log.error(*args, **kwargs)
312
313 - def access(self):
314 try: 315 return request.app.log.access() 316 except AttributeError: 317 return _cplogging.LogManager.access(self)
318 319 320 log = _GlobalLogManager() 321 # Set a default screen handler on the global log. 322 log.screen = True 323 log.error_file = '' 324 # Using an access file makes CP about 10% slower. Leave off by default. 325 log.access_file = '' 326 327 328 # Helper functions for CP apps # 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 # expose is being called directly, before the method has been bound 347 parents = sys._getframe(1).f_locals 348 return expose_(func) 349 else: 350 if alias is None: 351 # expose is being called as a decorator "@expose" 352 func.exposed = True 353 return func 354 else: 355 # expose is returning a decorator "@expose(alias=...)" 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 # Append/remove trailing slash from path_info as needed 389 # (this is to support mistyped URL's without redirecting; 390 # if you want to redirect, use tools.trailing_slash). 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 # No request.app (we're being called outside a request). 412 # We'll have to guess the base from server.* attributes. 413 # This will produce very different results from the above 414 # if you're using vhosts or tools.proxy. 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 # Normalize the URL by removing ./ and ../ 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 # import _cpconfig last so it can reference other top-level objects 449 from cherrypy import _cpconfig 450 # Use _global_conf_alias so quickstart can use 'config' as an arg 451 # without shadowing cherrypy.config. 452 config = _global_conf_alias = _cpconfig.Config() 453 454 from cherrypy import _cpchecker 455 checker = _cpchecker.Checker() 456