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

Side by Side Diff: third_party/cherrypy/__init__.py

Issue 9368042: Add CherryPy to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build/
Patch Set: '' Created 8 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
« no previous file with comments | « third_party/cherrypy/README.chromium ('k') | third_party/cherrypy/_cpchecker.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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.2.2"
61
62 from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode
63 from cherrypy._cpcompat import basestring, unicodestr, set
64
65 from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect
66 from cherrypy._cperror import NotFound, CherryPyException, TimeoutError
67
68 from cherrypy import _cpdispatch as dispatch
69
70 from cherrypy import _cptools
71 tools = _cptools.default_toolbox
72 Tool = _cptools.Tool
73
74 from cherrypy import _cprequest
75 from cherrypy.lib import httputil as _httputil
76
77 from cherrypy import _cptree
78 tree = _cptree.Tree()
79 from cherrypy._cptree import Application
80 from cherrypy import _cpwsgi as wsgi
81
82 from cherrypy import process
83 try:
84 from cherrypy.process import win32
85 engine = win32.Win32Bus()
86 engine.console_control_handler = win32.ConsoleCtrlHandler(engine)
87 del win32
88 except ImportError:
89 engine = process.bus
90
91
92 # Timeout monitor. We add two channels to the engine
93 # to which cherrypy.Application will publish.
94 engine.listeners['before_request'] = set()
95 engine.listeners['after_request'] = set()
96
97 class _TimeoutMonitor(process.plugins.Monitor):
98
99 def __init__(self, bus):
100 self.servings = []
101 process.plugins.Monitor.__init__(self, bus, self.run)
102
103 def before_request(self):
104 self.servings.append((serving.request, serving.response))
105
106 def after_request(self):
107 try:
108 self.servings.remove((serving.request, serving.response))
109 except ValueError:
110 pass
111
112 def run(self):
113 """Check timeout on all responses. (Internal)"""
114 for req, resp in self.servings:
115 resp.check_timeout()
116 engine.timeout_monitor = _TimeoutMonitor(engine)
117 engine.timeout_monitor.subscribe()
118
119 engine.autoreload = process.plugins.Autoreloader(engine)
120 engine.autoreload.subscribe()
121
122 engine.thread_manager = process.plugins.ThreadManager(engine)
123 engine.thread_manager.subscribe()
124
125 engine.signal_handler = process.plugins.SignalHandler(engine)
126
127
128 from cherrypy import _cpserver
129 server = _cpserver.Server()
130 server.subscribe()
131
132
133 def quickstart(root=None, script_name="", config=None):
134 """Mount the given root, start the builtin server (and engine), then block.
135
136 root: an instance of a "controller class" (a collection of page handler
137 methods) which represents the root of the application.
138 script_name: a string containing the "mount point" of the application.
139 This should start with a slash, and be the path portion of the URL
140 at which to mount the given root. For example, if root.index() will
141 handle requests to "http://www.example.com:8080/dept/app1/", then
142 the script_name argument would be "/dept/app1".
143
144 It MUST NOT end in a slash. If the script_name refers to the root
145 of the URI, it MUST be an empty string (not "/").
146 config: a file or dict containing application config. If this contains
147 a [global] section, those entries will be used in the global
148 (site-wide) config.
149 """
150 if config:
151 _global_conf_alias.update(config)
152
153 tree.mount(root, script_name, config)
154
155 if hasattr(engine, "signal_handler"):
156 engine.signal_handler.subscribe()
157 if hasattr(engine, "console_control_handler"):
158 engine.console_control_handler.subscribe()
159
160 engine.start()
161 engine.block()
162
163
164 from cherrypy._cpcompat import threadlocal as _local
165
166 class _Serving(_local):
167 """An interface for registering request and response objects.
168
169 Rather than have a separate "thread local" object for the request and
170 the response, this class works as a single threadlocal container for
171 both objects (and any others which developers wish to define). In this
172 way, we can easily dump those objects when we stop/start a new HTTP
173 conversation, yet still refer to them as module-level globals in a
174 thread-safe way.
175 """
176
177 request = _cprequest.Request(_httputil.Host("127.0.0.1", 80),
178 _httputil.Host("127.0.0.1", 1111))
179 """
180 The request object for the current thread. In the main thread,
181 and any threads which are not receiving HTTP requests, this is None."""
182
183 response = _cprequest.Response()
184 """
185 The response object for the current thread. In the main thread,
186 and any threads which are not receiving HTTP requests, this is None."""
187
188 def load(self, request, response):
189 self.request = request
190 self.response = response
191
192 def clear(self):
193 """Remove all attributes of self."""
194 self.__dict__.clear()
195
196 serving = _Serving()
197
198
199 class _ThreadLocalProxy(object):
200
201 __slots__ = ['__attrname__', '__dict__']
202
203 def __init__(self, attrname):
204 self.__attrname__ = attrname
205
206 def __getattr__(self, name):
207 child = getattr(serving, self.__attrname__)
208 return getattr(child, name)
209
210 def __setattr__(self, name, value):
211 if name in ("__attrname__", ):
212 object.__setattr__(self, name, value)
213 else:
214 child = getattr(serving, self.__attrname__)
215 setattr(child, name, value)
216
217 def __delattr__(self, name):
218 child = getattr(serving, self.__attrname__)
219 delattr(child, name)
220
221 def _get_dict(self):
222 child = getattr(serving, self.__attrname__)
223 d = child.__class__.__dict__.copy()
224 d.update(child.__dict__)
225 return d
226 __dict__ = property(_get_dict)
227
228 def __getitem__(self, key):
229 child = getattr(serving, self.__attrname__)
230 return child[key]
231
232 def __setitem__(self, key, value):
233 child = getattr(serving, self.__attrname__)
234 child[key] = value
235
236 def __delitem__(self, key):
237 child = getattr(serving, self.__attrname__)
238 del child[key]
239
240 def __contains__(self, key):
241 child = getattr(serving, self.__attrname__)
242 return key in child
243
244 def __len__(self):
245 child = getattr(serving, self.__attrname__)
246 return len(child)
247
248 def __nonzero__(self):
249 child = getattr(serving, self.__attrname__)
250 return bool(child)
251 # Python 3
252 __bool__ = __nonzero__
253
254 # Create request and response object (the same objects will be used
255 # throughout the entire life of the webserver, but will redirect
256 # to the "serving" object)
257 request = _ThreadLocalProxy('request')
258 response = _ThreadLocalProxy('response')
259
260 # Create thread_data object as a thread-specific all-purpose storage
261 class _ThreadData(_local):
262 """A container for thread-specific data."""
263 thread_data = _ThreadData()
264
265
266 # Monkeypatch pydoc to allow help() to go through the threadlocal proxy.
267 # Jan 2007: no Googleable examples of anyone else replacing pydoc.resolve.
268 # The only other way would be to change what is returned from type(request)
269 # and that's not possible in pure Python (you'd have to fake ob_type).
270 def _cherrypy_pydoc_resolve(thing, forceload=0):
271 """Given an object or a path to an object, get the object and its name."""
272 if isinstance(thing, _ThreadLocalProxy):
273 thing = getattr(serving, thing.__attrname__)
274 return _pydoc._builtin_resolve(thing, forceload)
275
276 try:
277 import pydoc as _pydoc
278 _pydoc._builtin_resolve = _pydoc.resolve
279 _pydoc.resolve = _cherrypy_pydoc_resolve
280 except ImportError:
281 pass
282
283
284 from cherrypy import _cplogging
285
286 class _GlobalLogManager(_cplogging.LogManager):
287 """A site-wide LogManager; routes to app.log or global log as appropriate.
288
289 This :class:`LogManager<cherrypy._cplogging.LogManager>` implements
290 cherrypy.log() and cherrypy.log.access(). If either
291 function is called during a request, the message will be sent to the
292 logger for the current Application. If they are called outside of a
293 request, the message will be sent to the site-wide logger.
294 """
295
296 def __call__(self, *args, **kwargs):
297 """Log the given message to the app.log or global log as appropriate."""
298 # Do NOT use try/except here. See http://www.cherrypy.org/ticket/945
299 if hasattr(request, 'app') and hasattr(request.app, 'log'):
300 log = request.app.log
301 else:
302 log = self
303 return log.error(*args, **kwargs)
304
305 def access(self):
306 """Log an access message to the app.log or global log as appropriate."""
307 try:
308 return request.app.log.access()
309 except AttributeError:
310 return _cplogging.LogManager.access(self)
311
312
313 log = _GlobalLogManager()
314 # Set a default screen handler on the global log.
315 log.screen = True
316 log.error_file = ''
317 # Using an access file makes CP about 10% slower. Leave off by default.
318 log.access_file = ''
319
320 def _buslog(msg, level):
321 log.error(msg, 'ENGINE', severity=level)
322 engine.subscribe('log', _buslog)
323
324 # Helper functions for CP apps #
325
326
327 def expose(func=None, alias=None):
328 """Expose the function, optionally providing an alias or set of aliases."""
329 def expose_(func):
330 func.exposed = True
331 if alias is not None:
332 if isinstance(alias, basestring):
333 parents[alias.replace(".", "_")] = func
334 else:
335 for a in alias:
336 parents[a.replace(".", "_")] = func
337 return func
338
339 import sys, types
340 if isinstance(func, (types.FunctionType, types.MethodType)):
341 if alias is None:
342 # @expose
343 func.exposed = True
344 return func
345 else:
346 # func = expose(func, alias)
347 parents = sys._getframe(1).f_locals
348 return expose_(func)
349 elif func is None:
350 if alias is None:
351 # @expose()
352 parents = sys._getframe(1).f_locals
353 return expose_
354 else:
355 # @expose(alias="alias") or
356 # @expose(alias=["alias1", "alias2"])
357 parents = sys._getframe(1).f_locals
358 return expose_
359 else:
360 # @expose("alias") or
361 # @expose(["alias1", "alias2"])
362 parents = sys._getframe(1).f_locals
363 alias = func
364 return expose_
365
366 def popargs(*args, **kwargs):
367 """A decorator for _cp_dispatch
368 (cherrypy.dispatch.Dispatcher.dispatch_method_name).
369
370 Optional keyword argument: handler=(Object or Function)
371
372 Provides a _cp_dispatch function that pops off path segments into
373 cherrypy.request.params under the names specified. The dispatch
374 is then forwarded on to the next vpath element.
375
376 Note that any existing (and exposed) member function of the class that
377 popargs is applied to will override that value of the argument. For
378 instance, if you have a method named "list" on the class decorated with
379 popargs, then accessing "/list" will call that function instead of popping
380 it off as the requested parameter. This restriction applies to all
381 _cp_dispatch functions. The only way around this restriction is to create
382 a "blank class" whose only function is to provide _cp_dispatch.
383
384 If there are path elements after the arguments, or more arguments
385 are requested than are available in the vpath, then the 'handler'
386 keyword argument specifies the next object to handle the parameterized
387 request. If handler is not specified or is None, then self is used.
388 If handler is a function rather than an instance, then that function
389 will be called with the args specified and the return value from that
390 function used as the next object INSTEAD of adding the parameters to
391 cherrypy.request.args.
392
393 This decorator may be used in one of two ways:
394
395 As a class decorator:
396 @cherrypy.popargs('year', 'month', 'day')
397 class Blog:
398 def index(self, year=None, month=None, day=None):
399 #Process the parameters here; any url like
400 #/, /2009, /2009/12, or /2009/12/31
401 #will fill in the appropriate parameters.
402
403 def create(self):
404 #This link will still be available at /create. Defined functions
405 #take precedence over arguments.
406
407 Or as a member of a class:
408 class Blog:
409 _cp_dispatch = cherrypy.popargs('year', 'month', 'day')
410 #...
411
412 The handler argument may be used to mix arguments with built in functions.
413 For instance, the following setup allows different activities at the
414 day, month, and year level:
415
416 class DayHandler:
417 def index(self, year, month, day):
418 #Do something with this day; probably list entries
419
420 def delete(self, year, month, day):
421 #Delete all entries for this day
422
423 @cherrypy.popargs('day', handler=DayHandler())
424 class MonthHandler:
425 def index(self, year, month):
426 #Do something with this month; probably list entries
427
428 def delete(self, year, month):
429 #Delete all entries for this month
430
431 @cherrypy.popargs('month', handler=MonthHandler())
432 class YearHandler:
433 def index(self, year):
434 #Do something with this year
435
436 #...
437
438 @cherrypy.popargs('year', handler=YearHandler())
439 class Root:
440 def index(self):
441 #...
442
443 """
444
445 #Since keyword arg comes after *args, we have to process it ourselves
446 #for lower versions of python.
447
448 handler = None
449 handler_call = False
450 for k,v in kwargs.items():
451 if k == 'handler':
452 handler = v
453 else:
454 raise TypeError(
455 "cherrypy.popargs() got an unexpected keyword argument '{0}'" \
456 .format(k)
457 )
458
459 import inspect
460
461 if handler is not None \
462 and (hasattr(handler, '__call__') or inspect.isclass(handler)):
463 handler_call = True
464
465 def decorated(cls_or_self=None, vpath=None):
466 if inspect.isclass(cls_or_self):
467 #cherrypy.popargs is a class decorator
468 cls = cls_or_self
469 setattr(cls, dispatch.Dispatcher.dispatch_method_name, decorated)
470 return cls
471
472 #We're in the actual function
473 self = cls_or_self
474 parms = {}
475 for arg in args:
476 if not vpath:
477 break
478 parms[arg] = vpath.pop(0)
479
480 if handler is not None:
481 if handler_call:
482 return handler(**parms)
483 else:
484 request.params.update(parms)
485 return handler
486
487 request.params.update(parms)
488
489 #If we are the ultimate handler, then to prevent our _cp_dispatch
490 #from being called again, we will resolve remaining elements through
491 #getattr() directly.
492 if vpath:
493 return getattr(self, vpath.pop(0), None)
494 else:
495 return self
496
497 return decorated
498
499 def url(path="", qs="", script_name=None, base=None, relative=None):
500 """Create an absolute URL for the given path.
501
502 If 'path' starts with a slash ('/'), this will return
503 (base + script_name + path + qs).
504 If it does not start with a slash, this returns
505 (base + script_name [+ request.path_info] + path + qs).
506
507 If script_name is None, cherrypy.request will be used
508 to find a script_name, if available.
509
510 If base is None, cherrypy.request.base will be used (if available).
511 Note that you can use cherrypy.tools.proxy to change this.
512
513 Finally, note that this function can be used to obtain an absolute URL
514 for the current request path (minus the querystring) by passing no args.
515 If you call url(qs=cherrypy.request.query_string), you should get the
516 original browser URL (assuming no internal redirections).
517
518 If relative is None or not provided, request.app.relative_urls will
519 be used (if available, else False). If False, the output will be an
520 absolute URL (including the scheme, host, vhost, and script_name).
521 If True, the output will instead be a URL that is relative to the
522 current request path, perhaps including '..' atoms. If relative is
523 the string 'server', the output will instead be a URL that is
524 relative to the server root; i.e., it will start with a slash.
525 """
526 if isinstance(qs, (tuple, list, dict)):
527 qs = _urlencode(qs)
528 if qs:
529 qs = '?' + qs
530
531 if request.app:
532 if not path.startswith("/"):
533 # Append/remove trailing slash from path_info as needed
534 # (this is to support mistyped URL's without redirecting;
535 # if you want to redirect, use tools.trailing_slash).
536 pi = request.path_info
537 if request.is_index is True:
538 if not pi.endswith('/'):
539 pi = pi + '/'
540 elif request.is_index is False:
541 if pi.endswith('/') and pi != '/':
542 pi = pi[:-1]
543
544 if path == "":
545 path = pi
546 else:
547 path = _urljoin(pi, path)
548
549 if script_name is None:
550 script_name = request.script_name
551 if base is None:
552 base = request.base
553
554 newurl = base + script_name + path + qs
555 else:
556 # No request.app (we're being called outside a request).
557 # We'll have to guess the base from server.* attributes.
558 # This will produce very different results from the above
559 # if you're using vhosts or tools.proxy.
560 if base is None:
561 base = server.base()
562
563 path = (script_name or "") + path
564 newurl = base + path + qs
565
566 if './' in newurl:
567 # Normalize the URL by removing ./ and ../
568 atoms = []
569 for atom in newurl.split('/'):
570 if atom == '.':
571 pass
572 elif atom == '..':
573 atoms.pop()
574 else:
575 atoms.append(atom)
576 newurl = '/'.join(atoms)
577
578 # At this point, we should have a fully-qualified absolute URL.
579
580 if relative is None:
581 relative = getattr(request.app, "relative_urls", False)
582
583 # See http://www.ietf.org/rfc/rfc2396.txt
584 if relative == 'server':
585 # "A relative reference beginning with a single slash character is
586 # termed an absolute-path reference, as defined by <abs_path>..."
587 # This is also sometimes called "server-relative".
588 newurl = '/' + '/'.join(newurl.split('/', 3)[3:])
589 elif relative:
590 # "A relative reference that does not begin with a scheme name
591 # or a slash character is termed a relative-path reference."
592 old = url(relative=False).split('/')[:-1]
593 new = newurl.split('/')
594 while old and new:
595 a, b = old[0], new[0]
596 if a != b:
597 break
598 old.pop(0)
599 new.pop(0)
600 new = (['..'] * len(old)) + new
601 newurl = '/'.join(new)
602
603 return newurl
604
605
606 # import _cpconfig last so it can reference other top-level objects
607 from cherrypy import _cpconfig
608 # Use _global_conf_alias so quickstart can use 'config' as an arg
609 # without shadowing cherrypy.config.
610 config = _global_conf_alias = _cpconfig.Config()
611 config.defaults = {
612 'tools.log_tracebacks.on': True,
613 'tools.log_headers.on': True,
614 'tools.trailing_slash.on': True,
615 'tools.encode.on': True
616 }
617 config.namespaces["log"] = lambda k, v: setattr(log, k, v)
618 config.namespaces["checker"] = lambda k, v: setattr(checker, k, v)
619 # Must reset to get our defaults applied.
620 config.reset()
621
622 from cherrypy import _cpchecker
623 checker = _cpchecker.Checker()
624 engine.subscribe('start', checker)
OLDNEW
« no previous file with comments | « third_party/cherrypy/README.chromium ('k') | third_party/cherrypy/_cpchecker.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698