Index: third_party/cherrypy/__init__.py |
=================================================================== |
--- third_party/cherrypy/__init__.py (revision 0) |
+++ third_party/cherrypy/__init__.py (revision 0) |
@@ -0,0 +1,624 @@ |
+"""CherryPy is a pythonic, object-oriented HTTP framework. |
+ |
+ |
+CherryPy consists of not one, but four separate API layers. |
+ |
+The APPLICATION LAYER is the simplest. CherryPy applications are written as |
+a tree of classes and methods, where each branch in the tree corresponds to |
+a branch in the URL path. Each method is a 'page handler', which receives |
+GET and POST params as keyword arguments, and returns or yields the (HTML) |
+body of the response. The special method name 'index' is used for paths |
+that end in a slash, and the special method name 'default' is used to |
+handle multiple paths via a single handler. This layer also includes: |
+ |
+ * the 'exposed' attribute (and cherrypy.expose) |
+ * cherrypy.quickstart() |
+ * _cp_config attributes |
+ * cherrypy.tools (including cherrypy.session) |
+ * cherrypy.url() |
+ |
+The ENVIRONMENT LAYER is used by developers at all levels. It provides |
+information about the current request and response, plus the application |
+and server environment, via a (default) set of top-level objects: |
+ |
+ * cherrypy.request |
+ * cherrypy.response |
+ * cherrypy.engine |
+ * cherrypy.server |
+ * cherrypy.tree |
+ * cherrypy.config |
+ * cherrypy.thread_data |
+ * cherrypy.log |
+ * cherrypy.HTTPError, NotFound, and HTTPRedirect |
+ * cherrypy.lib |
+ |
+The EXTENSION LAYER allows advanced users to construct and share their own |
+plugins. It consists of: |
+ |
+ * Hook API |
+ * Tool API |
+ * Toolbox API |
+ * Dispatch API |
+ * Config Namespace API |
+ |
+Finally, there is the CORE LAYER, which uses the core API's to construct |
+the default components which are available at higher layers. You can think |
+of the default components as the 'reference implementation' for CherryPy. |
+Megaframeworks (and advanced users) may replace the default components |
+with customized or extended components. The core API's are: |
+ |
+ * Application API |
+ * Engine API |
+ * Request API |
+ * Server API |
+ * WSGI API |
+ |
+These API's are described in the CherryPy specification: |
+http://www.cherrypy.org/wiki/CherryPySpec |
+""" |
+ |
+__version__ = "3.2.2" |
+ |
+from cherrypy._cpcompat import urljoin as _urljoin, urlencode as _urlencode |
+from cherrypy._cpcompat import basestring, unicodestr, set |
+ |
+from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect |
+from cherrypy._cperror import NotFound, CherryPyException, TimeoutError |
+ |
+from cherrypy import _cpdispatch as dispatch |
+ |
+from cherrypy import _cptools |
+tools = _cptools.default_toolbox |
+Tool = _cptools.Tool |
+ |
+from cherrypy import _cprequest |
+from cherrypy.lib import httputil as _httputil |
+ |
+from cherrypy import _cptree |
+tree = _cptree.Tree() |
+from cherrypy._cptree import Application |
+from cherrypy import _cpwsgi as wsgi |
+ |
+from cherrypy import process |
+try: |
+ from cherrypy.process import win32 |
+ engine = win32.Win32Bus() |
+ engine.console_control_handler = win32.ConsoleCtrlHandler(engine) |
+ del win32 |
+except ImportError: |
+ engine = process.bus |
+ |
+ |
+# Timeout monitor. We add two channels to the engine |
+# to which cherrypy.Application will publish. |
+engine.listeners['before_request'] = set() |
+engine.listeners['after_request'] = set() |
+ |
+class _TimeoutMonitor(process.plugins.Monitor): |
+ |
+ def __init__(self, bus): |
+ self.servings = [] |
+ process.plugins.Monitor.__init__(self, bus, self.run) |
+ |
+ def before_request(self): |
+ self.servings.append((serving.request, serving.response)) |
+ |
+ def after_request(self): |
+ try: |
+ self.servings.remove((serving.request, serving.response)) |
+ except ValueError: |
+ pass |
+ |
+ def run(self): |
+ """Check timeout on all responses. (Internal)""" |
+ for req, resp in self.servings: |
+ resp.check_timeout() |
+engine.timeout_monitor = _TimeoutMonitor(engine) |
+engine.timeout_monitor.subscribe() |
+ |
+engine.autoreload = process.plugins.Autoreloader(engine) |
+engine.autoreload.subscribe() |
+ |
+engine.thread_manager = process.plugins.ThreadManager(engine) |
+engine.thread_manager.subscribe() |
+ |
+engine.signal_handler = process.plugins.SignalHandler(engine) |
+ |
+ |
+from cherrypy import _cpserver |
+server = _cpserver.Server() |
+server.subscribe() |
+ |
+ |
+def quickstart(root=None, script_name="", config=None): |
+ """Mount the given root, start the builtin server (and engine), then block. |
+ |
+ root: an instance of a "controller class" (a collection of page handler |
+ methods) which represents the root of the application. |
+ script_name: a string containing the "mount point" of the application. |
+ This should start with a slash, and be the path portion of the URL |
+ at which to mount the given root. For example, if root.index() will |
+ handle requests to "http://www.example.com:8080/dept/app1/", then |
+ the script_name argument would be "/dept/app1". |
+ |
+ It MUST NOT end in a slash. If the script_name refers to the root |
+ of the URI, it MUST be an empty string (not "/"). |
+ config: a file or dict containing application config. If this contains |
+ a [global] section, those entries will be used in the global |
+ (site-wide) config. |
+ """ |
+ if config: |
+ _global_conf_alias.update(config) |
+ |
+ tree.mount(root, script_name, config) |
+ |
+ if hasattr(engine, "signal_handler"): |
+ engine.signal_handler.subscribe() |
+ if hasattr(engine, "console_control_handler"): |
+ engine.console_control_handler.subscribe() |
+ |
+ engine.start() |
+ engine.block() |
+ |
+ |
+from cherrypy._cpcompat import threadlocal as _local |
+ |
+class _Serving(_local): |
+ """An interface for registering request and response objects. |
+ |
+ Rather than have a separate "thread local" object for the request and |
+ the response, this class works as a single threadlocal container for |
+ both objects (and any others which developers wish to define). In this |
+ way, we can easily dump those objects when we stop/start a new HTTP |
+ conversation, yet still refer to them as module-level globals in a |
+ thread-safe way. |
+ """ |
+ |
+ request = _cprequest.Request(_httputil.Host("127.0.0.1", 80), |
+ _httputil.Host("127.0.0.1", 1111)) |
+ """ |
+ The request object for the current thread. In the main thread, |
+ and any threads which are not receiving HTTP requests, this is None.""" |
+ |
+ response = _cprequest.Response() |
+ """ |
+ The response object for the current thread. In the main thread, |
+ and any threads which are not receiving HTTP requests, this is None.""" |
+ |
+ def load(self, request, response): |
+ self.request = request |
+ self.response = response |
+ |
+ def clear(self): |
+ """Remove all attributes of self.""" |
+ self.__dict__.clear() |
+ |
+serving = _Serving() |
+ |
+ |
+class _ThreadLocalProxy(object): |
+ |
+ __slots__ = ['__attrname__', '__dict__'] |
+ |
+ def __init__(self, attrname): |
+ self.__attrname__ = attrname |
+ |
+ def __getattr__(self, name): |
+ child = getattr(serving, self.__attrname__) |
+ return getattr(child, name) |
+ |
+ def __setattr__(self, name, value): |
+ if name in ("__attrname__", ): |
+ object.__setattr__(self, name, value) |
+ else: |
+ child = getattr(serving, self.__attrname__) |
+ setattr(child, name, value) |
+ |
+ def __delattr__(self, name): |
+ child = getattr(serving, self.__attrname__) |
+ delattr(child, name) |
+ |
+ def _get_dict(self): |
+ child = getattr(serving, self.__attrname__) |
+ d = child.__class__.__dict__.copy() |
+ d.update(child.__dict__) |
+ return d |
+ __dict__ = property(_get_dict) |
+ |
+ def __getitem__(self, key): |
+ child = getattr(serving, self.__attrname__) |
+ return child[key] |
+ |
+ def __setitem__(self, key, value): |
+ child = getattr(serving, self.__attrname__) |
+ child[key] = value |
+ |
+ def __delitem__(self, key): |
+ child = getattr(serving, self.__attrname__) |
+ del child[key] |
+ |
+ def __contains__(self, key): |
+ child = getattr(serving, self.__attrname__) |
+ return key in child |
+ |
+ def __len__(self): |
+ child = getattr(serving, self.__attrname__) |
+ return len(child) |
+ |
+ def __nonzero__(self): |
+ child = getattr(serving, self.__attrname__) |
+ return bool(child) |
+ # Python 3 |
+ __bool__ = __nonzero__ |
+ |
+# Create request and response object (the same objects will be used |
+# throughout the entire life of the webserver, but will redirect |
+# to the "serving" object) |
+request = _ThreadLocalProxy('request') |
+response = _ThreadLocalProxy('response') |
+ |
+# Create thread_data object as a thread-specific all-purpose storage |
+class _ThreadData(_local): |
+ """A container for thread-specific data.""" |
+thread_data = _ThreadData() |
+ |
+ |
+# Monkeypatch pydoc to allow help() to go through the threadlocal proxy. |
+# Jan 2007: no Googleable examples of anyone else replacing pydoc.resolve. |
+# The only other way would be to change what is returned from type(request) |
+# and that's not possible in pure Python (you'd have to fake ob_type). |
+def _cherrypy_pydoc_resolve(thing, forceload=0): |
+ """Given an object or a path to an object, get the object and its name.""" |
+ if isinstance(thing, _ThreadLocalProxy): |
+ thing = getattr(serving, thing.__attrname__) |
+ return _pydoc._builtin_resolve(thing, forceload) |
+ |
+try: |
+ import pydoc as _pydoc |
+ _pydoc._builtin_resolve = _pydoc.resolve |
+ _pydoc.resolve = _cherrypy_pydoc_resolve |
+except ImportError: |
+ pass |
+ |
+ |
+from cherrypy import _cplogging |
+ |
+class _GlobalLogManager(_cplogging.LogManager): |
+ """A site-wide LogManager; routes to app.log or global log as appropriate. |
+ |
+ This :class:`LogManager<cherrypy._cplogging.LogManager>` implements |
+ cherrypy.log() and cherrypy.log.access(). If either |
+ function is called during a request, the message will be sent to the |
+ logger for the current Application. If they are called outside of a |
+ request, the message will be sent to the site-wide logger. |
+ """ |
+ |
+ def __call__(self, *args, **kwargs): |
+ """Log the given message to the app.log or global log as appropriate.""" |
+ # Do NOT use try/except here. See http://www.cherrypy.org/ticket/945 |
+ if hasattr(request, 'app') and hasattr(request.app, 'log'): |
+ log = request.app.log |
+ else: |
+ log = self |
+ return log.error(*args, **kwargs) |
+ |
+ def access(self): |
+ """Log an access message to the app.log or global log as appropriate.""" |
+ try: |
+ return request.app.log.access() |
+ except AttributeError: |
+ return _cplogging.LogManager.access(self) |
+ |
+ |
+log = _GlobalLogManager() |
+# Set a default screen handler on the global log. |
+log.screen = True |
+log.error_file = '' |
+# Using an access file makes CP about 10% slower. Leave off by default. |
+log.access_file = '' |
+ |
+def _buslog(msg, level): |
+ log.error(msg, 'ENGINE', severity=level) |
+engine.subscribe('log', _buslog) |
+ |
+# Helper functions for CP apps # |
+ |
+ |
+def expose(func=None, alias=None): |
+ """Expose the function, optionally providing an alias or set of aliases.""" |
+ def expose_(func): |
+ func.exposed = True |
+ if alias is not None: |
+ if isinstance(alias, basestring): |
+ parents[alias.replace(".", "_")] = func |
+ else: |
+ for a in alias: |
+ parents[a.replace(".", "_")] = func |
+ return func |
+ |
+ import sys, types |
+ if isinstance(func, (types.FunctionType, types.MethodType)): |
+ if alias is None: |
+ # @expose |
+ func.exposed = True |
+ return func |
+ else: |
+ # func = expose(func, alias) |
+ parents = sys._getframe(1).f_locals |
+ return expose_(func) |
+ elif func is None: |
+ if alias is None: |
+ # @expose() |
+ parents = sys._getframe(1).f_locals |
+ return expose_ |
+ else: |
+ # @expose(alias="alias") or |
+ # @expose(alias=["alias1", "alias2"]) |
+ parents = sys._getframe(1).f_locals |
+ return expose_ |
+ else: |
+ # @expose("alias") or |
+ # @expose(["alias1", "alias2"]) |
+ parents = sys._getframe(1).f_locals |
+ alias = func |
+ return expose_ |
+ |
+def popargs(*args, **kwargs): |
+ """A decorator for _cp_dispatch |
+ (cherrypy.dispatch.Dispatcher.dispatch_method_name). |
+ |
+ Optional keyword argument: handler=(Object or Function) |
+ |
+ Provides a _cp_dispatch function that pops off path segments into |
+ cherrypy.request.params under the names specified. The dispatch |
+ is then forwarded on to the next vpath element. |
+ |
+ Note that any existing (and exposed) member function of the class that |
+ popargs is applied to will override that value of the argument. For |
+ instance, if you have a method named "list" on the class decorated with |
+ popargs, then accessing "/list" will call that function instead of popping |
+ it off as the requested parameter. This restriction applies to all |
+ _cp_dispatch functions. The only way around this restriction is to create |
+ a "blank class" whose only function is to provide _cp_dispatch. |
+ |
+ If there are path elements after the arguments, or more arguments |
+ are requested than are available in the vpath, then the 'handler' |
+ keyword argument specifies the next object to handle the parameterized |
+ request. If handler is not specified or is None, then self is used. |
+ If handler is a function rather than an instance, then that function |
+ will be called with the args specified and the return value from that |
+ function used as the next object INSTEAD of adding the parameters to |
+ cherrypy.request.args. |
+ |
+ This decorator may be used in one of two ways: |
+ |
+ As a class decorator: |
+ @cherrypy.popargs('year', 'month', 'day') |
+ class Blog: |
+ def index(self, year=None, month=None, day=None): |
+ #Process the parameters here; any url like |
+ #/, /2009, /2009/12, or /2009/12/31 |
+ #will fill in the appropriate parameters. |
+ |
+ def create(self): |
+ #This link will still be available at /create. Defined functions |
+ #take precedence over arguments. |
+ |
+ Or as a member of a class: |
+ class Blog: |
+ _cp_dispatch = cherrypy.popargs('year', 'month', 'day') |
+ #... |
+ |
+ The handler argument may be used to mix arguments with built in functions. |
+ For instance, the following setup allows different activities at the |
+ day, month, and year level: |
+ |
+ class DayHandler: |
+ def index(self, year, month, day): |
+ #Do something with this day; probably list entries |
+ |
+ def delete(self, year, month, day): |
+ #Delete all entries for this day |
+ |
+ @cherrypy.popargs('day', handler=DayHandler()) |
+ class MonthHandler: |
+ def index(self, year, month): |
+ #Do something with this month; probably list entries |
+ |
+ def delete(self, year, month): |
+ #Delete all entries for this month |
+ |
+ @cherrypy.popargs('month', handler=MonthHandler()) |
+ class YearHandler: |
+ def index(self, year): |
+ #Do something with this year |
+ |
+ #... |
+ |
+ @cherrypy.popargs('year', handler=YearHandler()) |
+ class Root: |
+ def index(self): |
+ #... |
+ |
+ """ |
+ |
+ #Since keyword arg comes after *args, we have to process it ourselves |
+ #for lower versions of python. |
+ |
+ handler = None |
+ handler_call = False |
+ for k,v in kwargs.items(): |
+ if k == 'handler': |
+ handler = v |
+ else: |
+ raise TypeError( |
+ "cherrypy.popargs() got an unexpected keyword argument '{0}'" \ |
+ .format(k) |
+ ) |
+ |
+ import inspect |
+ |
+ if handler is not None \ |
+ and (hasattr(handler, '__call__') or inspect.isclass(handler)): |
+ handler_call = True |
+ |
+ def decorated(cls_or_self=None, vpath=None): |
+ if inspect.isclass(cls_or_self): |
+ #cherrypy.popargs is a class decorator |
+ cls = cls_or_self |
+ setattr(cls, dispatch.Dispatcher.dispatch_method_name, decorated) |
+ return cls |
+ |
+ #We're in the actual function |
+ self = cls_or_self |
+ parms = {} |
+ for arg in args: |
+ if not vpath: |
+ break |
+ parms[arg] = vpath.pop(0) |
+ |
+ if handler is not None: |
+ if handler_call: |
+ return handler(**parms) |
+ else: |
+ request.params.update(parms) |
+ return handler |
+ |
+ request.params.update(parms) |
+ |
+ #If we are the ultimate handler, then to prevent our _cp_dispatch |
+ #from being called again, we will resolve remaining elements through |
+ #getattr() directly. |
+ if vpath: |
+ return getattr(self, vpath.pop(0), None) |
+ else: |
+ return self |
+ |
+ return decorated |
+ |
+def url(path="", qs="", script_name=None, base=None, relative=None): |
+ """Create an absolute URL for the given path. |
+ |
+ If 'path' starts with a slash ('/'), this will return |
+ (base + script_name + path + qs). |
+ If it does not start with a slash, this returns |
+ (base + script_name [+ request.path_info] + path + qs). |
+ |
+ If script_name is None, cherrypy.request will be used |
+ to find a script_name, if available. |
+ |
+ If base is None, cherrypy.request.base will be used (if available). |
+ Note that you can use cherrypy.tools.proxy to change this. |
+ |
+ Finally, note that this function can be used to obtain an absolute URL |
+ for the current request path (minus the querystring) by passing no args. |
+ If you call url(qs=cherrypy.request.query_string), you should get the |
+ original browser URL (assuming no internal redirections). |
+ |
+ If relative is None or not provided, request.app.relative_urls will |
+ be used (if available, else False). If False, the output will be an |
+ absolute URL (including the scheme, host, vhost, and script_name). |
+ If True, the output will instead be a URL that is relative to the |
+ current request path, perhaps including '..' atoms. If relative is |
+ the string 'server', the output will instead be a URL that is |
+ relative to the server root; i.e., it will start with a slash. |
+ """ |
+ if isinstance(qs, (tuple, list, dict)): |
+ qs = _urlencode(qs) |
+ if qs: |
+ qs = '?' + qs |
+ |
+ if request.app: |
+ if not path.startswith("/"): |
+ # Append/remove trailing slash from path_info as needed |
+ # (this is to support mistyped URL's without redirecting; |
+ # if you want to redirect, use tools.trailing_slash). |
+ pi = request.path_info |
+ if request.is_index is True: |
+ if not pi.endswith('/'): |
+ pi = pi + '/' |
+ elif request.is_index is False: |
+ if pi.endswith('/') and pi != '/': |
+ pi = pi[:-1] |
+ |
+ if path == "": |
+ path = pi |
+ else: |
+ path = _urljoin(pi, path) |
+ |
+ if script_name is None: |
+ script_name = request.script_name |
+ if base is None: |
+ base = request.base |
+ |
+ newurl = base + script_name + path + qs |
+ else: |
+ # No request.app (we're being called outside a request). |
+ # We'll have to guess the base from server.* attributes. |
+ # This will produce very different results from the above |
+ # if you're using vhosts or tools.proxy. |
+ if base is None: |
+ base = server.base() |
+ |
+ path = (script_name or "") + path |
+ newurl = base + path + qs |
+ |
+ if './' in newurl: |
+ # Normalize the URL by removing ./ and ../ |
+ atoms = [] |
+ for atom in newurl.split('/'): |
+ if atom == '.': |
+ pass |
+ elif atom == '..': |
+ atoms.pop() |
+ else: |
+ atoms.append(atom) |
+ newurl = '/'.join(atoms) |
+ |
+ # At this point, we should have a fully-qualified absolute URL. |
+ |
+ if relative is None: |
+ relative = getattr(request.app, "relative_urls", False) |
+ |
+ # See http://www.ietf.org/rfc/rfc2396.txt |
+ if relative == 'server': |
+ # "A relative reference beginning with a single slash character is |
+ # termed an absolute-path reference, as defined by <abs_path>..." |
+ # This is also sometimes called "server-relative". |
+ newurl = '/' + '/'.join(newurl.split('/', 3)[3:]) |
+ elif relative: |
+ # "A relative reference that does not begin with a scheme name |
+ # or a slash character is termed a relative-path reference." |
+ old = url(relative=False).split('/')[:-1] |
+ new = newurl.split('/') |
+ while old and new: |
+ a, b = old[0], new[0] |
+ if a != b: |
+ break |
+ old.pop(0) |
+ new.pop(0) |
+ new = (['..'] * len(old)) + new |
+ newurl = '/'.join(new) |
+ |
+ return newurl |
+ |
+ |
+# import _cpconfig last so it can reference other top-level objects |
+from cherrypy import _cpconfig |
+# Use _global_conf_alias so quickstart can use 'config' as an arg |
+# without shadowing cherrypy.config. |
+config = _global_conf_alias = _cpconfig.Config() |
+config.defaults = { |
+ 'tools.log_tracebacks.on': True, |
+ 'tools.log_headers.on': True, |
+ 'tools.trailing_slash.on': True, |
+ 'tools.encode.on': True |
+ } |
+config.namespaces["log"] = lambda k, v: setattr(log, k, v) |
+config.namespaces["checker"] = lambda k, v: setattr(checker, k, v) |
+# Must reset to get our defaults applied. |
+config.reset() |
+ |
+from cherrypy import _cpchecker |
+checker = _cpchecker.Checker() |
+engine.subscribe('start', checker) |
Property changes on: third_party/cherrypy/__init__.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |