diff options
author | mkaay <mkaay@mkaay.de> | 2010-01-27 20:05:23 +0100 |
---|---|---|
committer | mkaay <mkaay@mkaay.de> | 2010-01-27 20:05:23 +0100 |
commit | 6d1ec2baa795b0d90d5da33b0447120b50f10c17 (patch) | |
tree | 5fceb5474c83e709fda396f70121a6923b0be106 /module/web/bottle.py | |
parent | First Version, works but doesn't reconnect (diff) | |
parent | fix (diff) | |
download | pyload-6d1ec2baa795b0d90d5da33b0447120b50f10c17.tar.xz |
merge
Diffstat (limited to 'module/web/bottle.py')
-rw-r--r-- | module/web/bottle.py | 886 |
1 files changed, 0 insertions, 886 deletions
diff --git a/module/web/bottle.py b/module/web/bottle.py deleted file mode 100644 index 66ceb527f..000000000 --- a/module/web/bottle.py +++ /dev/null @@ -1,886 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Bottle is a fast and simple mirco-framework for small web-applications. It -offers request dispatching (Routes) with url parameter support, Templates, -key/value Databases, a build-in HTTP Server and adapters for many third party -WSGI/HTTP-server and template engines. All in a single file and with no -dependencies other than the Python Standard Library. - -Homepage and documentation: http://wiki.github.com/defnull/bottle - -Special thanks to Stefan Matthias Aust [http://github.com/sma] - for his contribution to SimpelTemplate - -Licence (MIT) -------------- - - Copyright (c) 2009, Marcel Hellkamp. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - -Example -------- - - from bottle import route, run, request, response, send_file, abort - - @route('/') - def hello_world(): - return 'Hello World!' - - @route('/hello/:name') - def hello_name(name): - return 'Hello %s!' % name - - @route('/hello', method='POST') - def hello_post(): - name = request.POST['name'] - return 'Hello %s!' % name - - @route('/static/:filename#.*#') - def static_file(filename): - send_file(filename, root='/path/to/static/files/') - - run(host='localhost', port=8080) - -""" - -__author__ = 'Marcel Hellkamp' -__version__ = '0.5.7' -__license__ = 'MIT' - -import sys -import cgi -import mimetypes -import os -import os.path -import traceback -import re -import random -import threading -import time -from wsgiref.headers import Headers as HeaderWrapper -from Cookie import SimpleCookie -import anydbm as dbm - -try: - from urlparse import parse_qs -except ImportError: - from cgi import parse_qs - -try: - import cPickle as pickle -except ImportError: - import pickle as pickle - -try: - try: - from json import dumps as json_dumps - except ImportError: - from simplejson import dumps as json_dumps -except ImportError: - json_dumps = None - - - - - - -# Exceptions and Events - -class BottleException(Exception): - """ A base class for exceptions used by bottle.""" - pass - - -class HTTPError(BottleException): - """ A way to break the execution and instantly jump to an error handler. """ - def __init__(self, status, text): - self.output = text - self.http_status = int(status) - - def __repr__(self): - return "HTTPError(%d,%s)" % (self.http_status, repr(self.output)) - - def __str__(self): - out = [] - status = self.http_status - name = HTTP_CODES.get(status,'Unknown').title() - url = request.path - out.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">') - out.append('<html><head><title>Error %d: %s</title>' % (status, name)) - out.append('</head><body><h1>Error %d: %s</h1>' % (status, name)) - out.append('<p>Sorry, the requested URL "%s" caused an error.</p>' % url) - out.append(''.join(list(self.output))) - out.append('</body></html>') - return "\n".join(out) - - -class BreakTheBottle(BottleException): - """ Not an exception, but a straight jump out of the controller code. - - Causes the Bottle to instantly call start_response() and return the - content of output """ - def __init__(self, output): - self.output = output - - - - - - -# WSGI abstraction: Request and response management - -_default_app = None -def default_app(newapp = None): - ''' Returns the current default app or sets a new one. - Defaults to an instance of Bottle ''' - global _default_app - if newapp: - _default_app = newapp - if not _default_app: - _default_app = Bottle() - return _default_app - - -class Bottle(object): - - def __init__(self, catchall=True, debug=False, optimize=False, autojson=True): - self.simple_routes = {} - self.regexp_routes = {} - self.error_handler = {} - self.optimize = optimize - self.debug = debug - self.autojson = autojson - self.catchall = catchall - - def match_url(self, url, method='GET'): - """Returns the first matching handler and a parameter dict or (None, None) """ - url = url.strip().lstrip("/ ") - # Search for static routes first - route = self.simple_routes.get(method,{}).get(url,None) - if route: - return (route, {}) - - routes = self.regexp_routes.get(method,[]) - for i in range(len(routes)): - match = routes[i][0].match(url) - if match: - handler = routes[i][1] - if i > 0 and self.optimize and random.random() <= 0.001: - routes[i-1], routes[i] = routes[i], routes[i-1] - return (handler, match.groupdict()) - return (None, None) - - def add_route(self, route, handler, method='GET', simple=False): - """ Adds a new route to the route mappings. """ - method = method.strip().upper() - route = route.strip().lstrip('$^/ ').rstrip('$^ ') - if re.match(r'^(\w+/)*\w*$', route) or simple: - self.simple_routes.setdefault(method, {})[route] = handler - else: - route = re.sub(r':([a-zA-Z_]+)(?P<uniq>[^\w/])(?P<re>.+?)(?P=uniq)',r'(?P<\1>\g<re>)',route) - route = re.sub(r':([a-zA-Z_]+)',r'(?P<\1>[^/]+)', route) - route = re.compile('^%s$' % route) - self.regexp_routes.setdefault(method, []).append([route, handler]) - - def route(self, url, **kargs): - """ Decorator for request handler. Same as add_route(url, handler, **kargs).""" - def wrapper(handler): - self.add_route(url, handler, **kargs) - return handler - return wrapper - - def set_error_handler(self, code, handler): - """ Adds a new error handler. """ - code = int(code) - self.error_handler[code] = handler - - def error(self, code=500): - """ Decorator for error handler. Same as set_error_handler(code, handler).""" - def wrapper(handler): - self.set_error_handler(code, handler) - return handler - return wrapper - - def __call__(self, environ, start_response): - """ The bottle WSGI-interface .""" - request.bind(environ) - response.bind() - try: # Unhandled Exceptions - try: # Bottle Error Handling - handler, args = self.match_url(request.path, request.method) - if not handler: raise HTTPError(404, "Not found") - output = handler(**args) - db.close() - except BreakTheBottle, e: - output = e.output - except HTTPError, e: - response.status = e.http_status - output = self.error_handler.get(response.status, str)(e) - # output casting - if hasattr(output, 'read'): - output = environ.get('wsgi.file_wrapper', lambda x: iter(lambda: x.read(8192), ''))(output) - elif self.autojson and json_dumps and isinstance(output, dict): - output = json_dumps(output) - response.content_type = 'application/json' - if isinstance(output, str): - response.header['Content-Length'] = str(len(output)) - output = [output] - except (KeyboardInterrupt, SystemExit, MemoryError): - raise - except Exception, e: - response.status = 500 - if self.catchall: - err = "Unhandled Exception: %s\n" % (repr(e)) - if self.debug: - err += "<h2>Traceback:</h2>\n<pre>\n" - err += traceback.format_exc(10) - err += "\n</pre>" - output = str(HTTPError(500, err)) - request._environ['wsgi.errors'].write(err) - else: - raise - status = '%d %s' % (response.status, HTTP_CODES[response.status]) - start_response(status, response.wsgiheaders()) - return output - - - -class Request(threading.local): - """ Represents a single request using thread-local namespace. """ - - def bind(self, environ): - """ Binds the enviroment of the current request to this request handler """ - self._environ = environ - self._GET = None - self._POST = None - self._GETPOST = None - self._COOKIES = None - self.path = self._environ.get('PATH_INFO', '/').strip() - if not self.path.startswith('/'): - self.path = '/' + self.path - - @property - def method(self): - ''' Returns the request method (GET,POST,PUT,DELETE,...) ''' - return self._environ.get('REQUEST_METHOD', 'GET').upper() - - @property - def query_string(self): - ''' Content of QUERY_STRING ''' - return self._environ.get('QUERY_STRING', '') - - @property - def input_length(self): - ''' Content of CONTENT_LENGTH ''' - try: - return int(self._environ.get('CONTENT_LENGTH', '0')) - except ValueError: - return 0 - - @property - def GET(self): - """Returns a dict with GET parameters.""" - if self._GET is None: - data = parse_qs(self.query_string, keep_blank_values=True) - self._GET = {} - for key, value in data.iteritems(): - if len(value) == 1: - self._GET[key] = value[0] - else: - self._GET[key] = value - return self._GET - - @property - def POST(self): - """Returns a dict with parsed POST or PUT data.""" - if self._POST is None: - data = cgi.FieldStorage(fp=self._environ['wsgi.input'], environ=self._environ, keep_blank_values=True) - self._POST = {} - for item in data.list: - name = item.name - if not item.filename: - item = item.value - self._POST.setdefault(name, []).append(item) - for key in self._POST: - if len(self._POST[key]) == 1: - self._POST[key] = self._POST[key][0] - return self._POST - - @property - def params(self): - ''' Returns a mix of GET and POST data. POST overwrites GET ''' - if self._GETPOST is None: - self._GETPOST = dict(self.GET) - self._GETPOST.update(dict(self.POST)) - return self._GETPOST - - @property - def COOKIES(self): - """Returns a dict with COOKIES.""" - if self._COOKIES is None: - raw_dict = SimpleCookie(self._environ.get('HTTP_COOKIE','')) - self._COOKIES = {} - for cookie in raw_dict.itervalues(): - self._COOKIES[cookie.key] = cookie.value - return self._COOKIES - - def HEADER(self, header): - """Returns HTTP header""" - return self._environ.get(header, '') - -class Response(threading.local): - """ Represents a single response using thread-local namespace. """ - - def bind(self): - """ Clears old data and creates a brand new Response object """ - self._COOKIES = None - self.status = 200 - self.header_list = [] - self.header = HeaderWrapper(self.header_list) - self.content_type = 'text/html' - self.error = None - - def wsgiheaders(self): - ''' Returns a wsgi conform list of header/value pairs ''' - for c in self.COOKIES.itervalues(): - self.header.add_header('Set-Cookie', c.OutputString()) - return [(h.title(), str(v)) for h, v in self.header.items()] - - @property - def COOKIES(self): - if not self._COOKIES: - self._COOKIES = SimpleCookie() - return self._COOKIES - - def set_cookie(self, key, value, **kargs): - """ Sets a Cookie. Optional settings: expires, path, comment, domain, max-age, secure, version, httponly """ - self.COOKIES[key] = value - for k in kargs: - self.COOKIES[key][k] = kargs[k] - - def get_content_type(self): - '''Gives access to the 'Content-Type' header and defaults to 'text/html'.''' - return self.header['Content-Type'] - - def set_content_type(self, value): - self.header['Content-Type'] = value - - content_type = property(get_content_type, set_content_type, None, get_content_type.__doc__) - - -def abort(code=500, text='Unknown Error: Appliction stopped.'): - """ Aborts execution and causes a HTTP error. """ - raise HTTPError(code, text) - - -def redirect(url, code=307): - """ Aborts execution and causes a 307 redirect """ - response.status = code - response.header['Location'] = url - raise BreakTheBottle("") - - -def send_file(filename, root, guessmime = True, mimetype = 'text/plain'): - """ Aborts execution and sends a static files as response. """ - root = os.path.abspath(root) + '/' - filename = os.path.normpath(filename).strip('/') - filename = os.path.join(root, filename) - - if not filename.startswith(root): - abort(401, "Access denied.") - if not os.path.exists(filename) or not os.path.isfile(filename): - abort(404, "File does not exist.") - if not os.access(filename, os.R_OK): - abort(401, "You do not have permission to access this file.") - - if guessmime: - guess = mimetypes.guess_type(filename)[0] - if guess: - response.content_type = guess - elif mimetype: - response.content_type = mimetype - elif mimetype: - response.content_type = mimetype - - stats = os.stat(filename) - # TODO: HTTP_IF_MODIFIED_SINCE -> 304 (Thu, 02 Jul 2009 23:16:31 CEST) - if 'Content-Length' not in response.header: - response.header['Content-Length'] = stats.st_size - if 'Last-Modified' not in response.header: - ts = time.gmtime(stats.st_mtime) - ts = time.strftime("%a, %d %b %Y %H:%M:%S +0000", ts) - response.header['Last-Modified'] = ts - - raise BreakTheBottle(open(filename, 'r')) - - - - - - -# Decorators - -def validate(**vkargs): - ''' Validates and manipulates keyword arguments by user defined callables - and handles ValueError and missing arguments by raising HTTPError(403) ''' - def decorator(func): - def wrapper(**kargs): - for key in vkargs: - if key not in kargs: - abort(403, 'Missing parameter: %s' % key) - try: - kargs[key] = vkargs[key](kargs[key]) - except ValueError, e: - abort(403, 'Wrong parameter format for: %s' % key) - return func(**kargs) - return wrapper - return decorator - - -def route(url, **kargs): - """ Decorator for request handler. Same as add_route(url, handler, **kargs).""" - return default_app().route(url, **kargs) - - -def error(code=500): - """ Decorator for error handler. Same as set_error_handler(code, handler).""" - return default_app().error(code) - - - - - - -# Server adapter - -class ServerAdapter(object): - def __init__(self, host='127.0.0.1', port=8080, **kargs): - self.host = host - self.port = int(port) - self.options = kargs - - def __repr__(self): - return "%s (%s:%d)" % (self.__class__.__name__, self.host, self.port) - - def run(self, handler): - pass - - -class WSGIRefServer(ServerAdapter): - def run(self, handler): - from wsgiref.simple_server import make_server - srv = make_server(self.host, self.port, handler) - srv.serve_forever() - - -class CherryPyServer(ServerAdapter): - def run(self, handler): - from cherrypy import wsgiserver - server = wsgiserver.CherryPyWSGIServer((self.host, self.port), handler) - server.start() - - -class FlupServer(ServerAdapter): - def run(self, handler): - from flup.server.fcgi import WSGIServer - WSGIServer(handler, bindAddress=(self.host, self.port)).run() - - -class PasteServer(ServerAdapter): - def run(self, handler): - from paste import httpserver - from paste.translogger import TransLogger - app = TransLogger(handler) - httpserver.serve(app, host=self.host, port=str(self.port)) - - -class FapwsServer(ServerAdapter): - """ Extreamly fast Webserver using libev (see http://william-os4y.livejournal.com/) - Experimental ... """ - def run(self, handler): - import fapws._evwsgi as evwsgi - from fapws import base - import sys - evwsgi.start(self.host, self.port) - evwsgi.set_base_module(base) - def app(environ, start_response): - environ['wsgi.multiprocess'] = False - return handler(environ, start_response) - evwsgi.wsgi_cb(('',app)) - evwsgi.run() - - -def run(app=None, server=WSGIRefServer, host='127.0.0.1', port=8080, **kargs): - """ Runs bottle as a web server, using Python's built-in wsgiref implementation by default. - - You may choose between WSGIRefServer, CherryPyServer, FlupServer and - PasteServer or write your own server adapter. - """ - if not app: - app = default_app() - - quiet = bool('quiet' in kargs and kargs['quiet']) - - # Instanciate server, if it is a class instead of an instance - if isinstance(server, type) and issubclass(server, ServerAdapter): - server = server(host=host, port=port, **kargs) - - if not isinstance(server, ServerAdapter): - raise RuntimeError("Server must be a subclass of ServerAdapter") - - if not quiet: - print 'Bottle server starting up (using %s)...' % repr(server) - print 'Listening on http://%s:%d/' % (server.host, server.port) - print 'Use Ctrl-C to quit.' - print - - try: - server.run(app) - except KeyboardInterrupt: - print "Shuting down..." - - - - - - -# Templates - -class BaseTemplate(object): - def __init__(self, template='', filename=None): - self.source = filename - if self.source: - fp = open(filename) - template = fp.read() - fp.close() - self.parse(template) - - def parse(self, template): raise NotImplementedError - def render(self, **args): raise NotImplementedError - - @classmethod - def find(cls, name): - for path in TEMPLATE_PATH: - if os.path.isfile(path % name): - return cls(filename = path % name) - return None - - -class MakoTemplate(BaseTemplate): - def parse(self, template): - from mako.template import Template - self.tpl = Template(template) - - def render(self, **args): - return self.tpl.render(**args) - - -class CheetahTemplate(BaseTemplate): - def parse(self, template): - from Cheetah.Template import Template - self.context = threading.local() - self.context.vars = {} - self.tpl = Template(source = template, searchList=[self.context.vars]) - - def render(self, **args): - self.context.vars.update(args) - out = str(self.tpl) - self.context.vars.clear() - return out - - -class SimpleTemplate(BaseTemplate): - re_python = re.compile(r'^\s*%\s*(?:(if|elif|else|try|except|finally|for|while|with|def|class)|(include)|(end)|(.*))') - re_inline = re.compile(r'\{\{(.*?)\}\}') - dedent_keywords = ('elif', 'else', 'except', 'finally') - - def translate(self, template): - indent = 0 - strbuffer = [] - code = [] - self.subtemplates = {} - class PyStmt(str): - def __repr__(self): return 'str(' + self + ')' - def flush(allow_nobreak=False): - if len(strbuffer): - if allow_nobreak and strbuffer[-1].endswith("\\\\\n"): - strbuffer[-1]=strbuffer[-1][:-3] - code.append(" " * indent + "stdout.append(%s)" % repr(''.join(strbuffer))) - code.append((" " * indent + "\n") * len(strbuffer)) # to preserve line numbers - del strbuffer[:] - for line in template.splitlines(True): - m = self.re_python.match(line) - if m: - flush(allow_nobreak=True) - keyword, include, end, statement = m.groups() - if keyword: - if keyword in self.dedent_keywords: - indent -= 1 - code.append(" " * indent + line[m.start(1):]) - indent += 1 - elif include: - tmp = line[m.end(2):].strip().split(None, 1) - name = tmp[0] - args = tmp[1:] and tmp[1] or '' - self.subtemplates[name] = SimpleTemplate.find(name) - code.append(" " * indent + "stdout.append(_subtemplates[%s].render(%s))\n" % (repr(name), args)) - elif end: - indent -= 1 - code.append(" " * indent + '#' + line[m.start(3):]) - elif statement: - code.append(" " * indent + line[m.start(4):]) - else: - splits = self.re_inline.split(line) # text, (expr, text)* - if len(splits) == 1: - strbuffer.append(line) - else: - flush() - for i in range(1, len(splits), 2): - splits[i] = PyStmt(splits[i]) - splits = [x for x in splits if bool(x)] - code.append(" " * indent + "stdout.extend(%s)\n" % repr(splits)) - flush() - return ''.join(code) - - def parse(self, template): - code = self.translate(template) - self.co = compile(code, self.source or '<template>', 'exec') - - def render(self, **args): - ''' Returns the rendered template using keyword arguments as local variables. ''' - args['stdout'] = [] - args['_subtemplates'] = self.subtemplates - eval(self.co, args) - return ''.join(args['stdout']) - - -def template(template, template_adapter=SimpleTemplate, **args): - ''' Returns a string from a template ''' - if template not in TEMPLATES: - if template.find("\n") == template.find("{") == template.find("%") == -1: - TEMPLATES[template] = template_adapter.find(template) - else: - TEMPLATES[template] = template_adapter(template) - if not TEMPLATES[template]: - abort(500, 'Template not found') - args['abort'] = abort - args['request'] = request - args['response'] = response - return TEMPLATES[template].render(**args) - - -def mako_template(template_name, **args): return template(template_name, template_adapter=MakoTemplate, **args) - -def cheetah_template(template_name, **args): return template(template_name, template_adapter=CheetahTemplate, **args) - - - - - - -# Database - -class BottleBucket(object): - '''Memory-caching wrapper around anydbm''' - def __init__(self, name): - self.__dict__['name'] = name - self.__dict__['db'] = dbm.open(DB_PATH + '/%s.db' % name, 'c') - self.__dict__['mmap'] = {} - - def __getitem__(self, key): - if key not in self.mmap: - self.mmap[key] = pickle.loads(self.db[key]) - return self.mmap[key] - - def __setitem__(self, key, value): - self.mmap[key] = value - - def __delitem__(self, key): - if key in self.mmap: - del self.mmap[key] - del self.db[key] - - def __getattr__(self, key): - try: return self[key] - except KeyError: raise AttributeError(key) - - def __setattr__(self, key, value): - self[key] = value - - def __delattr__(self, key): - try: del self[key] - except KeyError: raise AttributeError(key) - - def __iter__(self): - return iter(self.ukeys()) - - def __contains__(self, key): - return key in self.ukeys() - - def __len__(self): - return len(self.ukeys()) - - def keys(self): - return list(self.ukeys()) - - def ukeys(self): - return set(self.db.keys()) | set(self.mmap.keys()) - - def save(self): - self.close() - self.__init__(self.name) - - def close(self): - for key in self.mmap: - pvalue = pickle.dumps(self.mmap[key], pickle.HIGHEST_PROTOCOL) - if key not in self.db or pvalue != self.db[key]: - self.db[key] = pvalue - self.mmap.clear() - self.db.close() - - def clear(self): - for key in self.db: - del self.db[key] - self.mmap.clear() - - def update(self, other): - self.mmap.update(other) - - def get(self, key, default=None): - try: - return self[key] - except KeyError: - if default: - return default - raise - - -class BottleDB(threading.local): - '''Holds multible BottleBucket instances in a thread-local way.''' - def __init__(self): - self.__dict__['open'] = {} - - def __getitem__(self, key): - if key not in self.open and not key.startswith('_'): - self.open[key] = BottleBucket(key) - return self.open[key] - - def __setitem__(self, key, value): - if isinstance(value, BottleBucket): - self.open[key] = value - elif hasattr(value, 'items'): - if key not in self.open: - self.open[key] = BottleBucket(key) - self.open[key].clear() - for k, v in value.iteritems(): - self.open[key][k] = v - else: - raise ValueError("Only dicts and BottleBuckets are allowed.") - - def __delitem__(self, key): - if key not in self.open: - self.open[key].clear() - self.open[key].save() - del self.open[key] - - def __getattr__(self, key): - try: return self[key] - except KeyError: raise AttributeError(key) - - def __setattr__(self, key, value): - self[key] = value - - def __delattr__(self, key): - try: del self[key] - except KeyError: raise AttributeError(key) - - def save(self): - self.close() - self.__init__() - - def close(self): - for db in self.open: - self.open[db].close() - self.open.clear() - - - - - - -# Modul initialization and configuration - -DB_PATH = './' -TEMPLATE_PATH = ['./%s.tpl', './views/%s.tpl'] -TEMPLATES = {} -HTTP_CODES = { - 100: 'CONTINUE', - 101: 'SWITCHING PROTOCOLS', - 200: 'OK', - 201: 'CREATED', - 202: 'ACCEPTED', - 203: 'NON-AUTHORITATIVE INFORMATION', - 204: 'NO CONTENT', - 205: 'RESET CONTENT', - 206: 'PARTIAL CONTENT', - 300: 'MULTIPLE CHOICES', - 301: 'MOVED PERMANENTLY', - 302: 'FOUND', - 303: 'SEE OTHER', - 304: 'NOT MODIFIED', - 305: 'USE PROXY', - 306: 'RESERVED', - 307: 'TEMPORARY REDIRECT', - 400: 'BAD REQUEST', - 401: 'UNAUTHORIZED', - 402: 'PAYMENT REQUIRED', - 403: 'FORBIDDEN', - 404: 'NOT FOUND', - 405: 'METHOD NOT ALLOWED', - 406: 'NOT ACCEPTABLE', - 407: 'PROXY AUTHENTICATION REQUIRED', - 408: 'REQUEST TIMEOUT', - 409: 'CONFLICT', - 410: 'GONE', - 411: 'LENGTH REQUIRED', - 412: 'PRECONDITION FAILED', - 413: 'REQUEST ENTITY TOO LARGE', - 414: 'REQUEST-URI TOO LONG', - 415: 'UNSUPPORTED MEDIA TYPE', - 416: 'REQUESTED RANGE NOT SATISFIABLE', - 417: 'EXPECTATION FAILED', - 500: 'INTERNAL SERVER ERROR', - 501: 'NOT IMPLEMENTED', - 502: 'BAD GATEWAY', - 503: 'SERVICE UNAVAILABLE', - 504: 'GATEWAY TIMEOUT', - 505: 'HTTP VERSION NOT SUPPORTED', -} - -request = Request() -response = Response() -db = BottleDB() -local = threading.local() - -def debug(mode=True): default_app().debug = bool(mode) -def optimize(mode=True): default_app().optimize = bool(mode) - - |