diff options
Diffstat (limited to 'homepage')
41 files changed, 1114 insertions, 0 deletions
diff --git a/homepage/app.py b/homepage/app.py new file mode 100755 index 0000000..5cf94e9 --- /dev/null +++ b/homepage/app.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python2.6 +# -*- coding: utf-8 -*- +from bottle import route, abort, view +import bottle +import markdown +import os.path +import sys +import re +import codecs + +# Static files + +@route('/:filename#.+\.(css|js|ico|png|txt|html)#') +def static(filename): + bottle.send_file(filename, root='./static/') + +# Bottle Pages + +pagedir = './pages' +cachedir = './cache' + +@route('/') +@route('/page/:name#[a-zA-Z0-9_]{3,65}#') +@view('pagemask') +def page(name='start'): + orig = os.path.join(pagedir, name+'.md') + cache = os.path.join(cachedir, name+'.html') + if not os.path.exists(orig): + abort(404, 'Page %s not found.' % name) + if not os.path.exists(cache) \ + or os.path.getmtime(orig) > os.path.getmtime(cache): + with codecs.open(orig, encoding='utf8') as f: + html = markdown.markdown(f.read(), ['codehilite(force_linenos=True)','wikilink(base_url=/page/)','toc']) + with open(cache, 'w') as f: + f.write(html.encode('utf-8')) + with open(cache) as f: + return dict(content=f.read(), pagename=name.title()) + +# Start server +#bottle.debug(True) +bottle.run(host='0.0.0.0', reloader=True, port=int(sys.argv[1]), server=bottle.PasteServer) diff --git a/homepage/pages/contact.md b/homepage/pages/contact.md new file mode 100644 index 0000000..c89b504 --- /dev/null +++ b/homepage/pages/contact.md @@ -0,0 +1,15 @@ +Kontakt und Impressum +===================== + +Impressum und Kontaktdaten nach [§5 TMG](http://bundesrecht.juris.de/tmg/__5.html). +Die Nutzung der folgenden Kontaktdaten ist ausschließlich für die +Kontaktaufnahme mit dem Betreiber dieser Webseite bei rechtlichen +Problemen vorgesehen. Insbesondere die Nutzung zu Werbe- oder ähnlichen +Zwecken ist ausdrücklich untersagt. + + * **Betreiber**: Marcel Hellkamp + * **Ort**: D - 37075 Göttingen + * **Strasse**: Theodor-Heuss Strasse 13 + * **Telefon**: +49 (0) 551 2509854 + * **E-Mail**: bottle [ät] paws.de + diff --git a/homepage/pages/docs.md b/homepage/pages/docs.md new file mode 100644 index 0000000..b755670 --- /dev/null +++ b/homepage/pages/docs.md @@ -0,0 +1,461 @@ +[TOC] + +Bottle Documentation +==================== + +This document is a work in progress. If you have questions not answered here, +please file a ticket at bottle's [issue +tracker](http://github.com/defnull/bottle/issues). + +## Basic Routes + +Routes are used to map request URLs to callables that generate the response content. Bottle has a `route()` decorator to do that. + + #!Python + from bottle import route, run + @route('/hello') + def hello(): + return "Hello World!" + run() # This starts the HTTP server + +Run this script, visit <http://localhost:8080/hello> and you will see "Hello World!" in your Browser. + + + +### GET, POST, HEAD, ... + +The route decorator has an optional keyword argument `method` which defaults to `method='GET'`. +Possible values are `POST`, `PUT`, `DELETE`, `HEAD` or any other HTTP request method you want to listen to. + + #!Python + from bottle import route, request + @route('/form/submit', method='POST') + def form_submit(): + form_data = request.POST + do_something(form_data) + return "Done" + + + + + + + + +## Dynamic Routes + +You can extract parts of the URL and create dynamic routes with an easy syntax. + + #!Python + @route('/hello/:name') + def hello(name): + return "Hello %s!" % name + +By default, a `:placeholder` matches everything up to the next +slash. To change that, you can add some regular expression in between `#`s: + + #!Python + @route('/get_object/:id#[0-9]+#') + def get(id): + return "Object ID: %d" % int(id) + +or even use full features regular expressions with named groups: + + #!Python + @route('/get_object/(?P<id>[0-9]+)') + def get(id): + return "Object ID: %d" % int(id) + +As you can see, URL parameters remain strings, even if they are +configured to only match digits. You have to explicitly cast them into +the type you need. + +### The @validate() decorator + +Bottle offers a handy decorator called `validate()` to check and manipulate URL parameters. +It takes callables as keyword arguments and filters every URL parameter +through the corresponding callable before they are passed to your +request handler. + + #!Python + from bottle import route, validate + # /test/validate/1/2.3/4,5,6,7 + @route('/test/validate/:i/:f/:csv') + @validate(i=int, f=float, csv=lambda x: map(int, x.split(','))) + def validate_test(i, f, csv): + return "Int: %d, Float:%f, List:%s" % (i, f, repr(csv)) + +You may raise `ValueError` in your custom callable if the parameter +does not validate. + + + + + +## Returning files and JSON + +The WSGI specification expects an iterable list of strings and can't handle file +objects or plain strings. Bottle automatically converts them to iterables, so +you don't have to. The following example will work with Bottle, but won't work +with pure WSGI. + + #!Python + @route('/get_string') + def get_string(): + return "This is not a list of strings, but a single string" + @route('/file') + def get_file(): + return open('some/file.txt','r') + +Even dictionaries are allowed. They are converted to +[json](http://de.wikipedia.org/wiki/JavaScript_Object_Notation) and returned +as `Content-Type: application/json`. + + #!Python + @route('/api/status') + def api_status(): + return {'status':'online', 'servertime':time.time()} + +You can turn off this feature: `bottle.default_app().autojson = False` + +## HTTP errors and redirects + + #!Python + from bottle import redirect, abort + + @route('/wrong/url') + def wrong(): + redirect("/right/url") + + @route('/restricted') + def restricted(): + abort(401, "Sorry, access denied.") + + +## Static files + + #!Python + from bottle import send_file + + @route('/static/:filename') + def static_file(filename): + send_file(filename, root='/path/to/static/files') + + +## Cookies + +Bottle stores cookies sent by the client in a dictionary called `request.COOKIES`. To create new cookies, +the method `response.set_cookie(name, value[, **params])` is used. It accepts additional parameters as long as they are valid +cookie attributes supported by [SimpleCookie](http://docs.python.org/library/cookie.html#morsel-objects). + + #!Python + from bottle import response + response.set_cookie('key','value', path='/', domain='example.com', secure=True, expires=+500, ...) + +To set the `max-age` attribute (which is not a valid Python parameter name) you can directly access an instance of +[cookie.SimpleCookie](http://docs.python.org/library/cookie.html#Cookie.SimpleCookie) in `response.COOKIES`. + + #!Python + from bottle import response + response.COOKIES['key'] = 'value' + response.COOKIES['key']['max-age'] = 500 + + + + + + + + + + + +## Templates + +Bottle uses its own little template engine by default. You can use a template by +calling `template(template_name, **template_arguments)` and returning +the result. + + #!Python + @route('/hello/:name') + def hello(name): + return template('hello_template', username=name) + +This will load the template `hello_template.tpl` with the `username` variable set to the URL `:name` part and return the result as a string. + +The `hello_template.tpl` file could look like this: + + #!html + <h1>Hello {{username}}</h1> + <p>How are you?</p> + +### Template search path + +The list `bottle.TEMPLATE_PATH` is used to map template names to actual +file names. By default, this list contains `['./%s.tpl', './views/%s.tpl']`. + +### Template caching + +Templates are cached in memory after compilation. Modifications made to +the template file will have no affect until you clear the template +cache. Call `bottle.TEMPLATES.clear()` to do so. + + + + + + + + + + + +## Template Syntax + +The template syntax is a very thin layer around the Python language. +It's main purpose is to ensure correct indention of blocks, so you +can format your template without worrying about indentions. Here is the +complete syntax description: + + * `%...` starts a line of python code. You don't have to worry about indentions. Bottle handles that for you. + * `%end` closes a Python block opened by `%if ...`, `%for ...` or other block statements. Explicitly closing of blocks is required. + * `{{...}}` prints the result of the included python statement. + * `%include template_name optional_arguments` allows you to include other templates. + * Every other line is returned as text. + +Example: + + #!html + %header = 'Test Template' + %items = [1,2,3,'fly'] + %include http_header title=header, use_js=['jquery.js', 'default.js'] + <h1>{{header.title()}}</h1> + <ul> + %for item in items: + <li> + %if isinstance(item, int): + Zahl: {{item}} + %else: + %try: + Other type: ({{type(item).__name__}}) {{repr(item)}} + %except: + Error: Item has no string representation. + %end try-block (yes, you may add comments here) + %end + </li> + %end + </ul> + %include http_footer + + + + + + + + + + + + + +## Key/Value Databases + +Bottle (>0.4.6) offers a persistent key/value database accessible through the +`bottle.db` module variable. You can use key or attribute syntax to store or +fetch any pickle-able object to the database. Both +`bottle.db.bucket_name.key_name` and `bottle.db[bucket_name][key_name]` +will work. + +Missing buckets are created on demand. You don't have to check for +their existence before using them. Just be sure to use alphanumeric +bucket-names. + +The bucket objects behave like mappings (dictionaries), except that +only strings are allowed for keys and values must be pickle-able. +Printing a bucket object doesn't print the keys and values, and the +`items()` and `values()` methods are not supported. Missing keys will raise +`KeyError` as expected. + +### Persistence +During a request live-cycle, all changes are cached in thread-local memory. At +the end of the request, the changes are saved automatically so the next request +will have access to the updated values. Each bucket is stored in a separate file +in `bottle.DB_PATH`. Be sure to allow write-access to this path and use bucket +names that are allowed in filenames. + +### Race conditions +You don't have do worry about file corruption but race conditions are still a +problem in multi-threaded or forked environments. You can call +`bottle.db.save()` or `botle.db.bucket_name.save()` to flush the thread-local +memory cache to disk, but there is no way to detect database changes made in +other threads until these threads call `bottle.db.save()` or leave the current +request cycle. + +### Example + + #!Python + from bottle import route, db + @route('/db/counter') + def db_counter(): + if 'hits' not in db.counter: + db.counter.hits = 0 + db['counter']['hits'] += 1 + return "Total hits: %d!" % db.counter.hits + + + + + + + + + + +## Using WSGI and Middleware + +A call to `bottle.default_app()` returns your WSGI application. After applying as many WSGI middleware modules as you like, you can tell +`bottle.run()` to use your wrapped application, instead of the default one. + + #!Python + from bottle import default_app, run + app = default_app() + newapp = YourMiddleware(app) + run(app=newapp) + +### How default_app() works + +Bottle creates a single instance of `bottle.Bottle()` and uses it as a default for most of the modul-level decorators and the `bottle.run()` routine. +`bottle.default_app()` returns (or changes) this default. You may, however, create your own instances of `bottle.Bottle()`. + + #!Python + from bottle import Bottle, run + mybottle = Bottle() + @mybottle.route('/') + def index(): + return 'default_app' + run(app=mybottle) + + +## Deployment + +Bottle uses the build-in `wsgiref.SimpleServer` by default. This non-threading +HTTP server is perfectly fine for development and early production, +but may become a performance bottleneck when server load increases. + +There are three ways to eliminate this bottleneck: + + * Use a multi-threaded server adapter + * Spread the load between multiple bottle instances + * Do both + +### Multi-Threaded Server + +The easiest way to increase performance is to install a multi-threaded and +WSGI-capable HTTP server like [Paste][paste], [flup][flup], [cherrypy][cherrypy] +or [fapws3][fapws3] and use the corresponding bottle server-adapter. + + #!Python + from bottle import PasteServer, FlupServer, FapwsServer, CherryPyServer + bottle.run(server=PasteServer) # Example + +If bottle is missing an adapter for your favorite server or you want to tweak +the server settings, you may want to manually set up your HTTP server and use +`bottle.default_app()` to access your WSGI application. + + #!Python + def run_custom_paste_server(self, host, port): + myapp = bottle.default_app() + from paste import httpserver + httpserver.serve(myapp, host=host, port=port) + +### Multiple Server Processes + +A single Python process can only utilize one CPU at a time, even if +there are more CPU cores available. The trick is to balance the load +between multiple independent Python processes to utilize all of your +CPU cores. + +Instead of a single Bottle application server, you start one instances +of your server for each CPU core available using different local port +(localhost:8080, 8081, 8082, ...). Then a high performance load +balancer acts as a reverse proxy and forwards each new requests to +a random Bottle processes, spreading the load between all available +backed server instances. This way you can use all of your CPU cores and +even spread out the load between different physical servers. + +But there are a few drawbacks: + + * You can't easily share data between multiple Python processes. + * It takes a lot of memory to run several copies of Python and Bottle +at the same time. + +One of the fastest load balancer available is [pound](http://www.apsis.ch/pound/) but most common web servers have a proxy-module that can do the work just fine. + +I'll add examples for [lighttpd](http://www.lighttpd.net/) and +[Apache](http://www.apache.org/) web servers soon. + +### Apache mod_wsgi + +Instead of running your own HTTP server from within Bottle, you can +attach Bottle applications to an [Apache server][apache] using +[mod_wsgi][] and Bottles WSGI interface. + +All you need is an `app.wsgi` file that provides an +`application` object. This object is used by mod_wsgi to start your +application and should be a WSGI conform Python callable. + + #!Python + # File: /var/www/yourapp/app.wsgi + + # Change working directory so relative paths (and template lookup) work again + os.chdir(os.path.dirname(__file__)) + + import bottle + # ... add or import your bottle app code here ... + # Do NOT use bottle.run() with mod_wsgi + application = bottle.default_app() + +The Apache configuration may look like this: + + #!ApacheConf + <VirtualHost *> + ServerName example.com + + WSGIDaemonProcess yourapp user=www-data group=www-data processes=1 threads=5 + WSGIScriptAlias / /var/www/yourapp/app.wsgi + + <Directory /var/www/yourapp> + WSGIProcessGroup yourapp + WSGIApplicationGroup %{GLOBAL} + Order deny,allow + Allow from all + </Directory> + </VirtualHost> + + +### Google AppEngine + + #!Python + import bottle + from google.appengine.ext.webapp import util + # ... add or import your bottle app code here ... + # Do NOT use bottle.run() with AppEngine + util.run_wsgi_app(bottle.default_app()) + +### Good old CGI + +CGI is slow as hell, but it works. + + #!Python + import bottle + # ... add or import your bottle app code here ... + bottle.run(server=bottle.CGIServer) + +[mako]: http://www.makotemplates.org/ +[cherrypy]: http://www.cherrypy.org/ +[flup]: http://trac.saddi.com/flup +[paste]: http://pythonpaste.org/ +[fapws3]: http://github.com/william-os4y/fapws3 +[apache]: http://www.apache.org/ +[mod_wsgi]: http://code.google.com/p/modwsgi/ diff --git a/homepage/pages/faq.md b/homepage/pages/faq.md new file mode 100644 index 0000000..1aa114d --- /dev/null +++ b/homepage/pages/faq.md @@ -0,0 +1,49 @@ +[TOC] + +Frequently Asked Questions +========================== + + +## How to Ignore Tailing Slashes? + +Bottle does not ignore tailing slashes by default. +To handle URLs like `/example` and `/example/` the same, +you could add two `@route` decorators (fast when using static routes) + + #!Python + @route('/test') + @route('/test/') + def test(): pass + +or use dynamic routes + + #!Python + @route('/test/?') + def test(): pass + +or add a WSGI middleware that strips tailing '/' from URLs + + #!Python + class StripPathMiddleware(object): + def __init__(self, app): + self.app = app + def __call__(self, e, h): + e['PATH_INFO'] = e['PATH_INFO'].rstrip('/') + return self.app(e,h) + + app = bottle.default_app() + app = StripPathMiddleware(app) + bottle.run(app=app) + + + + + +## Apache/mod_python and Template Not Found? + +Templates are searched in "./" or "./views/" but Apaches mod_python +changes your working directory. You can use + + bottle.TEMPLATE_PATH.insert(0,'/absolut/path/to/templates/%s.tpl') + +to add an absolute search path. diff --git a/homepage/pages/logos.md b/homepage/pages/logos.md new file mode 100644 index 0000000..b484a09 --- /dev/null +++ b/homepage/pages/logos.md @@ -0,0 +1,31 @@ +Bottle Logo +=========== + +The official color is: + +<img src="/logo_130.png" /> + +But ... + +<div style="text-align: center"> +<img src="/logo_10.png" alt='color logo 1' width='10%' /> +<img src="/logo_20.png" alt='color logo 2' width='10%' /> +<img src="/logo_30.png" alt='color logo 3' width='10%' /> +<img src="/logo_40.png" alt='color logo 4' width='10%' /> +<img src="/logo_50.png" alt='color logo 5' width='10%' /> +<img src="/logo_60.png" alt='color logo 6' width='10%' /> +<img src="/logo_70.png" alt='color logo 7' width='10%' /> +<img src="/logo_80.png" alt='color logo 8' width='10%' /> +<img src="/logo_90.png" alt='color logo 9' width='10%' /> +<img src="/logo_100.png" alt='color logo 10' width='10%' /> +<img src="/logo_110.png" alt='color logo 11' width='10%' /> +<img src="/logo_120.png" alt='color logo 12' width='10%' /> +<img src="/logo_130.png" alt='color logo 14' width='10%' /> +<img src="/logo_140.png" alt='color logo 14' width='10%' /> +<img src="/logo_150.png" alt='color logo 15' width='10%' /> +<img src="/logo_160.png" alt='color logo 16' width='10%' /> +<img src="/logo_170.png" alt='color logo 17' width='10%' /> +<img src="/logo_180.png" alt='color logo 18' width='10%' /> +<img src="/logo_190.png" alt='color logo 19' width='10%' /> +<img src="/logo_200.png" alt='color logo 20' width='10%' /> +</div> diff --git a/homepage/pages/release.md b/homepage/pages/release.md new file mode 100644 index 0000000..4a3d62c --- /dev/null +++ b/homepage/pages/release.md @@ -0,0 +1,17 @@ +# Bottle Release Strategy + +## Version Numbers and Releases + +Bottles version number breaks into three parts: Major release, minor release and revision. +Major releases are very rare and only happen on significant jumps in functionality. +Minor releases introduce new functionality and may break compatibility with previous releases in some places, but are mostly API compatible. +Revisions may fix bugs, improve performance or introduce minor new features, but (hopefully) never break compatibility. + +It is save and recommended to update to new revisions. You should consider updateng to new releases as well, because I don't have the time and enegry to support old releases. + +In all three parts, a zero indicates 'beta' status. Bottle-X.X.0 is a release candidate. Bottle-X.0.X is a preview for the next major release. Use them with care. + +## Development + +The 'master' branch on github always contains the latest release candidate. New features and bugfixes are developed and tested in separate branches or forks until they are merged into bottle/master. +You can use 'master' for testing. It should work most of the time. diff --git a/homepage/pages/start.md b/homepage/pages/start.md new file mode 100644 index 0000000..dffd638 --- /dev/null +++ b/homepage/pages/start.md @@ -0,0 +1,218 @@ +Bottle Web Framework +==================== + +<div style="float: right; padding: 0px 0px 2em 2em"><img src="/bottle-logo.png" alt="Botle Logo" /></div> + +Bottle is a fast and simple [WSGI][wsgi]-framework for the [Python Programming Language][py]. It +offers request dispatching with url parameter support ([routes](/page/docs#basic_routes)), [templates](/page/docs#templates), key/value +[databases](/page/docs#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. + + [wsgi]: http://www.wsgi.org/wsgi/ + [py]: http://python.org/ + [bottle-dl]: http://github.com/defnull/bottle/raw/master/bottle.py + +### Installation and Dependencies + +You can install the latest stable release with `easy_install -U bottle` or just download the newest [bottle.py][bottle-dl] and place it in your project directory. There are no (hard) dependencies other than the Python standard library. Bottle runs with **Python 2.5+ and 3.x** (using 2to3) + +<!-- + +## News + +<ul id='newshere'><li><i>Loading...</i></li><li> </li><li> </li><li> </li><li> </li></ul> +<script type="text/javascript"> + $('#newshere').load('http://bottle.paws.de/news.html') +</script> + +--> + +## Features and Examples + +### Small and Lightweight + +No installation or configuration required. No dependencies other than +the Python standard library. Just get a copy of bottle.py and start +coding! A basic "Hello World" application in Bottle looks like this: + + #!Python + from bottle import route, run + + @route('/') + def index(): + return 'Hello World!' + + run(host='localhost', port=8080) + +That's it. Start it up and go to <http://localhost:8080/>. + +### Nice looking URLs + +Extract data out of dynamic URLs with a simple route syntax. + + #!Python + @route('/hello/:name') + def hello(name): + return 'Hello, %s' % name + +Or use full featured regular expressions to do so. + + #!Python + @route('/friends/(?<name>(Alice|Bob))') + def friends(name): + return 'Hello, %s! Good to see you :)' % name + +### Static Files, Redirects and HTTP Errors + +Use these handy helpers for regular tasks. + + #!Python + from bottle import send_file, redirect, abort + + @route('/static/:filename') + def static_file(filename): + send_file(filename, root='/path/to/static/files') + + @route('/wrong/url') + def wrong(): + redirect("/right/url") + + @route('/restricted') + def restricted(): + abort(401, "Sorry, access denied.") + +### POST, GET, Header and Cookies + +As easy as using a `dict()` + + #!Python + from bottle import request, response + + @route('/hello/cookie') + def cookie(): + name = request.COOKIES.get('name', 'Stranger') + response.header['Content-Type'] = 'text/plain' + return 'Hello, %s' % name + + @route('/hello/cookie', method='POST') + def set_cookie(): + if 'name' in request.POST: + name = request.POST['name'] + response.COOKIES['name'] = name + return 'OK' + +### Templates + +Bottle includes a simple and lightning fast template engine + + #!Python + @get('/hello/template/:names') + def pretty_hello(names): + names = names.split(',') + return template('hello', title='Hello World', names=names) + +And here is the template: + + #!html + <html> + <head> + <title>{{title}}</title> + </head> + <body> + %for name in names: + <p>Hello, <strong>{{name}}</strong></p> + %end + </body> + </html> + +Use [mako][] it you need more features + + #!Python + from bottle import mako_template as template + +### HTTP Server + +Bottle has a HTTP Server build in but also supports [cherrypy][], +[flup][], [paste][] and [fapws3][] as alternatives. + + #!Python + from bottle import PasteServer + run(server=PasteServer) + + +### Non-Features and Known Bugs + +Bottle does **not** include (yet): + + * Models and ORMs: Choose your own (SQLAlchemy, Elixir) + * HTML-Helper, Session, Identification and Authentication: Do it yourself + * Scaffolding: No, sorry + +Some things don't work (yet): + + * Multipart File Uploads do not work with Python 3.x because the cgi.FileStorage is broken. + +[mako]: http://www.makotemplates.org/ +[cherrypy]: http://www.cherrypy.org/ +[flup]: http://trac.saddi.com/flup +[paste]: http://pythonpaste.org/ +[fapws3]: http://github.com/william-os4y/fapws3 + + + + + +## Voices + +[Kaelin](http://bitbucket.org/kaelin), 2009-10-22, [PyPi Comment](http://pypi.python.org/pypi/bottle): + +> Bottle rocks! The fastest path I've found between idea and implementation for simple Web applications. + +[Seth](http://blog.curiasolutions.com/about/) in his [blog](http://blog.curiasolutions.com/2009/09/the-great-web-development-shootout/) [posts](http://blog.curiasolutions.com/2009/10/the-great-web-technology-shootout-round-3-better-faster-and-shinier/) about common web framework performance: + +> As you can see, there was practically no difference in speed between Bottle and pure WSGI in a basic “hello world” test. Even with the addition of Mako and SQLAlchemy, Bottle performed significantly faster than a bare Pylons or Django setup. On a side note, adding a sample template using Bottle’s default templating package didn’t seem to change these numbers at all. + +## Projects using Bottle + + * [flugzeit-rechner.de](http://www.flugzeit-rechner.de/) runs on Bottle and Jinja2. + * [Cuttlefish](http://bitbucket.org/kaelin/cuttlefish/) is a browser-based search tool for quickly `grep`ing source code. + * [Torque](http://github.com/jreid42/torque) is a multiuser collaborative interface for torrenting. + * [Message in a Bottle](http://github.com/kennyshen/MIAB) - a simple community messaging app using Bottle and Cassandra. + + +## Thanks to + +In chronological order of their last contribution (DESC). + + * [Damien Degois](http://github.com/babs) for his `If-Modified-Since` support in `send_file()` and his excellent bug reports + * [Stefan Matthias Aust](http://github.com/sma) for his contribution to `SimpleTemplate` and `Jinja2Template` + * [DauerBaustelle](http://github.com/dauerbaustelle) for his ideas + * [smallfish](http://pynotes.appspot.com/) for his chinese translation of the bottle documentation + * [Johannes Schönberger](http://www.python-forum.de/user-6026.html) for his auto reloading code + * [clutchski](http://github.com/clutchski) for his `CGIAdapter` and CGI support + * huanguan1978 for his windows `send_file()` bug report and patch + * The [German Python Community](http://www.python-forum.de/topic-19451.html) for their support and motivation + + +## 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. + diff --git a/homepage/static/blockquote.png b/homepage/static/blockquote.png Binary files differnew file mode 100644 index 0000000..74d7cdd --- /dev/null +++ b/homepage/static/blockquote.png diff --git a/homepage/static/bottle-logo.png b/homepage/static/bottle-logo.png Binary files differnew file mode 100644 index 0000000..9afb050 --- /dev/null +++ b/homepage/static/bottle-logo.png diff --git a/homepage/static/bottle-sig.png b/homepage/static/bottle-sig.png Binary files differnew file mode 100644 index 0000000..6d3a625 --- /dev/null +++ b/homepage/static/bottle-sig.png diff --git a/homepage/static/bottle.png b/homepage/static/bottle.png Binary files differnew file mode 100644 index 0000000..0b54911 --- /dev/null +++ b/homepage/static/bottle.png diff --git a/homepage/static/favicon.ico b/homepage/static/favicon.ico Binary files differnew file mode 100644 index 0000000..ad2abbe --- /dev/null +++ b/homepage/static/favicon.ico diff --git a/homepage/static/logo.png b/homepage/static/logo.png Binary files differnew file mode 100644 index 0000000..29d2467 --- /dev/null +++ b/homepage/static/logo.png diff --git a/homepage/static/logo_10.png b/homepage/static/logo_10.png Binary files differnew file mode 100644 index 0000000..c79c516 --- /dev/null +++ b/homepage/static/logo_10.png diff --git a/homepage/static/logo_100.png b/homepage/static/logo_100.png Binary files differnew file mode 100644 index 0000000..d2914cc --- /dev/null +++ b/homepage/static/logo_100.png diff --git a/homepage/static/logo_110.png b/homepage/static/logo_110.png Binary files differnew file mode 100644 index 0000000..81f8317 --- /dev/null +++ b/homepage/static/logo_110.png diff --git a/homepage/static/logo_120.png b/homepage/static/logo_120.png Binary files differnew file mode 100644 index 0000000..3f8062f --- /dev/null +++ b/homepage/static/logo_120.png diff --git a/homepage/static/logo_130.png b/homepage/static/logo_130.png Binary files differnew file mode 100644 index 0000000..8cfc1b4 --- /dev/null +++ b/homepage/static/logo_130.png diff --git a/homepage/static/logo_140.png b/homepage/static/logo_140.png Binary files differnew file mode 100644 index 0000000..33bc394 --- /dev/null +++ b/homepage/static/logo_140.png diff --git a/homepage/static/logo_150.png b/homepage/static/logo_150.png Binary files differnew file mode 100644 index 0000000..b088667 --- /dev/null +++ b/homepage/static/logo_150.png diff --git a/homepage/static/logo_160.png b/homepage/static/logo_160.png Binary files differnew file mode 100644 index 0000000..06b3384 --- /dev/null +++ b/homepage/static/logo_160.png diff --git a/homepage/static/logo_170.png b/homepage/static/logo_170.png Binary files differnew file mode 100644 index 0000000..ecbcb7b --- /dev/null +++ b/homepage/static/logo_170.png diff --git a/homepage/static/logo_180.png b/homepage/static/logo_180.png Binary files differnew file mode 100644 index 0000000..4506202 --- /dev/null +++ b/homepage/static/logo_180.png diff --git a/homepage/static/logo_190.png b/homepage/static/logo_190.png Binary files differnew file mode 100644 index 0000000..3b32256 --- /dev/null +++ b/homepage/static/logo_190.png diff --git a/homepage/static/logo_20.png b/homepage/static/logo_20.png Binary files differnew file mode 100644 index 0000000..23e7fd6 --- /dev/null +++ b/homepage/static/logo_20.png diff --git a/homepage/static/logo_200.png b/homepage/static/logo_200.png Binary files differnew file mode 100644 index 0000000..c2c483d --- /dev/null +++ b/homepage/static/logo_200.png diff --git a/homepage/static/logo_30.png b/homepage/static/logo_30.png Binary files differnew file mode 100644 index 0000000..883a818 --- /dev/null +++ b/homepage/static/logo_30.png diff --git a/homepage/static/logo_40.png b/homepage/static/logo_40.png Binary files differnew file mode 100644 index 0000000..00b32ae --- /dev/null +++ b/homepage/static/logo_40.png diff --git a/homepage/static/logo_50.png b/homepage/static/logo_50.png Binary files differnew file mode 100644 index 0000000..a9d1a76 --- /dev/null +++ b/homepage/static/logo_50.png diff --git a/homepage/static/logo_60.png b/homepage/static/logo_60.png Binary files differnew file mode 100644 index 0000000..d0d6548 --- /dev/null +++ b/homepage/static/logo_60.png diff --git a/homepage/static/logo_70.png b/homepage/static/logo_70.png Binary files differnew file mode 100644 index 0000000..31d4137 --- /dev/null +++ b/homepage/static/logo_70.png diff --git a/homepage/static/logo_80.png b/homepage/static/logo_80.png Binary files differnew file mode 100644 index 0000000..9fe5601 --- /dev/null +++ b/homepage/static/logo_80.png diff --git a/homepage/static/logo_90.png b/homepage/static/logo_90.png Binary files differnew file mode 100644 index 0000000..408a222 --- /dev/null +++ b/homepage/static/logo_90.png diff --git a/homepage/static/logo_bg.png b/homepage/static/logo_bg.png Binary files differnew file mode 100644 index 0000000..b664b06 --- /dev/null +++ b/homepage/static/logo_bg.png diff --git a/homepage/static/main.css b/homepage/static/main.css new file mode 100644 index 0000000..32a68cc --- /dev/null +++ b/homepage/static/main.css @@ -0,0 +1,138 @@ +* { + margin: 0px; + padding: 0px; +} + +html { + background-color: #fff; + background: #eee url('/logo_bg.png') no-repeat 0px 0px; + padding: 20px 20px 20px 200px; +} + +body { + border: 1px solid #bbb; + background-color: #eee; + background-color: #fff; + padding: 25px 20px 20px 20px; + font-size: 14px; + font-family: sans-serif; + line-height: 1.5em; + color:#000; +} + +h1, h2, h3, h4, h5 { + margin: 1em 0em 0.5em 0em; + padding: 2px 0px; +} + +h1 { + margin: 0em 0em 0.5em 0em; + border-bottom: 3px solid #033; +} + +h2 { + margin: 2em 0em 0.5em 0em; + border-bottom: 3px solid #033; +} + +p { + margin-bottom: 1em; + text-align: justify; +} + +ul, ol { + margin: 0 0 1em 1.5em; +} + +a { + color: #056; +} + +a:hover { + color: #000; +} + +img { + border: 0; +} + +form div { + clear:left; +} + +form div label { + display:block; + float:left; + width:150px; +} + +input, textarea { + border:1px solid #bbb; + background-color:#eee; + padding:1px; + margin:1px; + vertical-align:middle; +} + +input:hover, textarea:hover { + background-color:white; +} + +input:focus, textarea:focus { + border:1px solid #055; + background-color:white; +} + +ul.error { + color:red; +} + +blockquote { + margin: 22px 40px; + upadding: 3px; + color: #575757; + padding: 0 50px; + background: transparent url("blockquote.png") no-repeat 0 0; +} + +.small { + font-size:75%; +} + +#footer { + border-top: 3px solid #033; + text-align: center; + padding-top: 1em; +} + +#navigation { + position: absolute; + width: 150px; + left: 25px; +} + +#navigation h1 { + font-size: 1em; +} + +div.toc { + float: right; + border: 1px solid #ddd; + background-color: #fff; + padding: 1em; + margin: 0 0 2em 2em; + line-height: 1.4em; +} + +div.toc ul { + margin: 0 0 0 1em; +} + +div.toc ul ul { + font-size: 0.8em; +} + +div.toc ul ul ul { + display: none; +} + diff --git a/homepage/static/news.html b/homepage/static/news.html new file mode 100644 index 0000000..2e44f32 --- /dev/null +++ b/homepage/static/news.html @@ -0,0 +1,5 @@ +<li><a href="https://twitter.com/bottlepy/status/5068803778">bottlepy</a>: Bottle 0.6.4 released! http://bottle.paws.de (13:16 today)</li> +<li><a href="https://twitter.com/bottlepy/status/5068781146">bottlepy</a>: git commit: Version bump. This is a bugfix release. (13:15 today)</li> +<li><a href="https://twitter.com/bottlepy/status/5068752312">bottlepy</a>: git commit: HEAD should never return content. Removed the clearhead parameter (13:13 today)</li> +<li><a href="https://twitter.com/bottlepy/status/5068561951">bottlepy</a>: By the way: A new bottle release is coming. Mostly bug fixes this time. (13:03 today)</li> +<li><a href="https://twitter.com/bottlepy/status/5068529786">bottlepy</a>: Just uploaded a new profile picture. This twitter account should be more than just a #git commit message log. What do you think? (13:01 today)</li> diff --git a/homepage/static/pygments.css b/homepage/static/pygments.css new file mode 100644 index 0000000..f5d5647 --- /dev/null +++ b/homepage/static/pygments.css @@ -0,0 +1,100 @@ +table.codehilitetable { + margin: 1em; +} + +table.codehilitetable td.linenos { + width: 2em; + color: #ccc; + text-align: right; +} + +table.codehilitetable td.linenos pre { + padding-right: 0.5em; + background-color: #fff; +} + +table.codehilitetable td.code pre { + border: 1px solid #ccc; + background-color: #eee; + padding: 0 3em 0 1em; + overflow: auto; +} + + + +code { + font-family: Monaco, "Courier New", monospace; + background-color: #eee; + padding: 0px 0.1em; +} + +table.codehilitetable { +# border: 1px solid #ccc; +# background-color: #eee; +# margin: 1em 2em; +# overflow: auto; +# line-height: 125%; +} + + +div.codehilite .hll { background-color: #ffffcc } +div.codehilite .c { color: #408080; font-style: italic } /* Comment */ +div.codehilite .err { border: 1px solid #FF0000 } /* Error */ +div.codehilite .k { color: #008000; font-weight: bold } /* Keyword */ +div.codehilite .o { color: #666666 } /* Operator */ +div.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +div.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */ +div.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */ +div.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */ +div.codehilite .gd { color: #A00000 } /* Generic.Deleted */ +div.codehilite .ge { font-style: italic } /* Generic.Emph */ +div.codehilite .gr { color: #FF0000 } /* Generic.Error */ +div.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +div.codehilite .gi { color: #00A000 } /* Generic.Inserted */ +div.codehilite .go { color: #808080 } /* Generic.Output */ +div.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +div.codehilite .gs { font-weight: bold } /* Generic.Strong */ +div.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +div.codehilite .gt { color: #0040D0 } /* Generic.Traceback */ +div.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +div.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +div.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +div.codehilite .kp { color: #008000 } /* Keyword.Pseudo */ +div.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +div.codehilite .kt { color: #B00040 } /* Keyword.Type */ +div.codehilite .m { color: #666666 } /* Literal.Number */ +div.codehilite .s { color: #BA2121 } /* Literal.String */ +div.codehilite .na { color: #7D9029 } /* Name.Attribute */ +div.codehilite .nb { color: #008000 } /* Name.Builtin */ +div.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +div.codehilite .no { color: #880000 } /* Name.Constant */ +div.codehilite .nd { color: #AA22FF } /* Name.Decorator */ +div.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */ +div.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +div.codehilite .nf { color: #0000FF } /* Name.Function */ +div.codehilite .nl { color: #A0A000 } /* Name.Label */ +div.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +div.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */ +div.codehilite .nv { color: #19177C } /* Name.Variable */ +div.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +div.codehilite .w { color: #bbbbbb } /* Text.Whitespace */ +div.codehilite .mf { color: #666666 } /* Literal.Number.Float */ +div.codehilite .mh { color: #666666 } /* Literal.Number.Hex */ +div.codehilite .mi { color: #666666 } /* Literal.Number.Integer */ +div.codehilite .mo { color: #666666 } /* Literal.Number.Oct */ +div.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */ +div.codehilite .sc { color: #BA2121 } /* Literal.String.Char */ +div.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +div.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */ +div.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +div.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */ +div.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +div.codehilite .sx { color: #008000 } /* Literal.String.Other */ +div.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */ +div.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */ +div.codehilite .ss { color: #19177C } /* Literal.String.Symbol */ +div.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */ +div.codehilite .vc { color: #19177C } /* Name.Variable.Class */ +div.codehilite .vg { color: #19177C } /* Name.Variable.Global */ +div.codehilite .vi { color: #19177C } /* Name.Variable.Instance */ +div.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/homepage/static/robots.txt b/homepage/static/robots.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/homepage/static/robots.txt diff --git a/homepage/views/footer.tpl b/homepage/views/footer.tpl new file mode 100644 index 0000000..63d176a --- /dev/null +++ b/homepage/views/footer.tpl @@ -0,0 +1,9 @@ +<div id='footer'> +<div>Powered by <a href="/"><img src="/bottle-sig.png" /></a></div> +<div>Browse sources at <a href="http://github.com/defnull/bottle">GitHub</a></div> +<div><a href="/page/contact"><small>Kontakt und Impressum</small></a></div> + + +</div> +</body> +</html> diff --git a/homepage/views/header.tpl b/homepage/views/header.tpl new file mode 100644 index 0000000..f01e51a --- /dev/null +++ b/homepage/views/header.tpl @@ -0,0 +1,25 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title>{{title or 'Homepage'}} - Bottle Web Framework</title> + <link type="text/css" rel="stylesheet" href="/main.css" /> + <link type="text/css" rel="stylesheet" href="/pygments.css" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" > + <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script> +</head> +<body> +<div id="navigation"> + <h1>Pages</h1> + <ul> + <li><a href="/">Home</a></li> + <li><a href="/page/docs">Documentation</a></li> + </ul> + <h1>Links</h1> + <ul> + <li><a target="_blank" href="http://pypi.python.org/pypi/bottle">Download</a></li> + <li><a target="_blank" href="http://github.com/defnull/bottle">GitHub Repository</a></li> + <li><a target="_blank" href="http://github.com/defnull/bottle/issues">Issue Tracker</a></li> + <li><a target="_blank" href="http://groups.google.de/group/bottlepy">Google Groups</a></li> + <li><a target="_blank" href="http://twitter.com/bottlepy">Twitter</a></li> + </ul> +</div> diff --git a/homepage/views/pagemask.tpl b/homepage/views/pagemask.tpl new file mode 100644 index 0000000..07ac18b --- /dev/null +++ b/homepage/views/pagemask.tpl @@ -0,0 +1,5 @@ +%include header title=pagename.title() +<div id='mdpage'> +{{content}} +</div> +%include footer |