`_.
This tutorial should give a brief introduction to the Bottle_ WSGI Framework. The main goal is to be able, after reading through this tutorial, to create a project using Bottle. Within this document, not all abilities will be shown, but at least the main and important ones like routing, utilizing the Bottle template abilities to format output and handling GET / POST parameters.
To understand the content here, it is not necessary to have a basic knowledge of WSGI, as Bottle tries to keep WSGI away from the user anyway. You should have a fair understanding of the Python_ programming language. Furthermore, the example used in the tutorial retrieves and stores data in a SQL databse, so a basic idea about SQL helps, but is not a must to understand the concepts of Bottle. Right here, SQLite_ is used. The output of Bottle sent to the browser is formatted in some examples by the help of HTML. Thus, a basic idea about the common HTML tags does help as well.
For the sake of introducing Bottle, the Python code "in between" is kept short, in order to keep the focus. Also all code within the tutorial is working fine, but you may not necessarily use it "in the wild", e.g. on a public web server. In order to do so, you may add e.g. more error handling, protect the database with a password, test and escape the input etc.
.. contents:: Table of Contents
Goals
===========
At the end of this tutorial, we will have a simple, web-based ToDo list. The list contains a text (with max 100 characters) and a status (0 for closed, 1 for open) for each item. Through the web-based user interface, open items can be view and edited and new items can be added.
During development, all pages will be available on ``localhost`` only, but later on it will be shown how to adapt the application for a "real" server, including how to use with Apache's mod_wsgi.
Bottle will do the routing and format the output, with the help of templates. The items of the list will be stored inside a SQLite database. Reading and writing the database will be done by Python code.
We will end up with an application with the following pages and functionality:
* start page ``http://localhost:8080/todo``
* adding new items to the list: ``http://localhost:8080/new``
* page for editing items: ``http://localhost:8080/edit/:no``
* validating data assigned by dynamic routes with the @validate decorator
* catching errors
Before We Start...
====================
.. rubric:: Install Bottle
Assuming that you have a fairly new installation of Python (version 2.5 or higher), you only need to install Bottle in addition to that. Bottle has no other dependencies than Python itself.
You can either manually install Bottle or use Python's easy_install: ``easy_install bottle``
.. rubric:: Further Software Necessities
As we use SQLite3 as a database, make sure it is installed. On Linux systems, most distributions have SQLite3 installed by default. SQLite is available for Windows and MacOS X as well and the `sqlite3` module is part of the python standard library.
.. rubric:: Create An SQL Database
First, we need to create the database we use later on. To do so, save the following script in your project directory and run it with python. You can use the interactive interpreter too::
import sqlite3
con = sqlite3.connect('todo.db') # Warning: This file is created in the current directory
con.execute("CREATE TABLE todo (id INTEGER PRIMARY KEY, task char(100) NOT NULL, status bool NOT NULL)")
con.execute("INSERT INTO todo (task,status) VALUES ('Read A-byte-of-python to get a good introduction into Python',0)")
con.execute("INSERT INTO todo (task,status) VALUES ('Visit the Python website',1)")
con.execute("INSERT INTO todo (task,status) VALUES ('Test various editors for and check the syntax highlighting',1)")
con.execute("INSERT INTO todo (task,status) VALUES ('Choose your favorite WSGI-Framework',0)")
con.commit()
This generates a database-file `todo.db` with tables called ``todo`` and three columns ``id``, ``task``, and ``status``. ``id`` is a unique id for each row, which is used later on to reference the rows. The column ``task`` holds the text which describes the task, it can be max 100 characters long. Finally, the column ``status`` is used to mark a task as open (value 1) or closed (value 0).
Using Bottle for a Web-Based ToDo List
================================================
Now it is time to introduce Bottle in order to create a web-based application. But first, we need to look into a basic concept of Bottle: routes.
.. rubric:: Understanding routes
Basically, each page visible in the browser is dynamically generated when the page address is called. Thus, there is no static content. That is exactly what is called a "route" within Bottle: a certain address on the server. So, for example, when the page ``http://localhost:8080/todo`` is called from the browser, Bottle "grabs" the call and checks if there is any (Python) function defined for the route "todo". If so, Bottle will execute the corresponding Python code and return its result.
.. rubric:: First Step - Showing All Open Items
So, after understanding the concept of routes, let's create the first one. The goal is to see all open items from the ToDo list::
import sqlite3
from bottle import route, run
@route('/todo')
def todo_list():
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT id, task FROM todo WHERE status LIKE '1'")
result = c.fetchall()
return str(result)
run()
Save the code a ``todo.py``, preferably in the same directory as the file ``todo.db``. Otherwise, you need to add the path to ``todo.db`` in the ``sqlite3.connect()`` statement.
Let's have a look what we just did: We imported the necessary module ``sqlite3`` to access to SQLite database and from Bottle we imported ``route`` and ``run``. The ``run()`` statement simply starts the web server included in Bottle. By default, the web server serves the pages on localhost and port 8080. Furthermore, we imported ``route``, which is the function responsible for Bottle's routing. As you can see, we defined one function, ``todo_list()``, with a few lines of code reading from the database. The important point is the `decorator statement`_ ``@route('/todo')`` right before the ``def todo_list()`` statement. By doing this, we bind this function to the route ``/todo``, so every time the browsers calls ``http://localhost:8080/todo``, Bottle returns the result of the function ``todo_list()``. That is how routing within bottle works.
Actually you can bind more than one route to a function. So the following code::
@route('/todo')
@route('/my_todo_list')
def todo_list():
...
will work fine, too. What will not work is to bind one route to more than one function.
What you will see in the browser is what is returned, thus the value given by the ``return`` statement. In this example, we need to convert ``result`` in to a string by ``str()``, as Bottle expects a string or a list of strings from the return statement. But here, the result of the database query is a list of tuples, which is the standard defined by the `Python DB API`_.
Now, after understanding the little script above, it is time to execute it and watch the result yourself. Remember that on Linux- / Unix-based systems the file ``todo.py`` needs to be executable first. Then, just run ``python todo.py`` and call the page ``http://localhost:8080/todo`` in your browser. In case you made no mistake writing the script, the output should look like this::
[(2, u'Visit the Python website'), (3, u'Test various editors for and check the syntax highlighting')]
If so - congratulations! You are now a successful user of Bottle. In case it did not work and you need to make some changes to the script, remember to stop Bottle serving the page, otherwise the revised version will not be loaded.
Actually, the output is not really exciting nor nice to read. It is the raw result returned from the SQL query.
So, in the next step we format the output in a nicer way. But before we do that, we make our life easier.
.. rubric:: Debugging and Auto-Reload
Maybe you already noticed that Bottle sends a short error message to the browser in case something within the script is wrong, e.g. the connection to the database is not working. For debugging purposes it is quite helpful to get more details. This can be easily achieved by adding the following statement to the script::
from bottle import run, route, debug
...
#add this at the very end:
debug(True)
run()
By enabling "debug", you will get a full stacktrace of the Python interpreter, which usually contains useful information for finding bugs. Furthermore, templates (see below) are not cached, thus changes to templates will take effect without stopping the server.
.. warning::
That ``debug(True)`` is supposed to be used for development only, it should *not* be used in production environments.
Another quite nice feature is auto-reloading, which is enabled by modifying the ``run()`` statement to
::
run(reloader=True)
This will automatically detect changes to the script and reload the new version once it is called again, without the need to stop and start the server.
Again, the feature is mainly supposed to be used while developing, not on production systems.
.. rubric:: Bottle Template To Format The Output
Now let's have a look at casting the output of the script into a proper format.
Actually Bottle expects to receive a string or a list of strings from a function and returns them by the help of the built-in server to the browser. Bottle does not bother about the content of the string itself, so it can be text formatted with HTML markup, too.
Bottle brings its own easy-to-use template engine with it. Templates are stored as separate files having a ``.tpl`` extension. The template can be called then from within a function. Templates can contain any type of text (which will be most likely HTML-markup mixed with Python statements). Furthermore, templates can take arguments, e.g. the result set of a database query, which will be then formatted nicely within the template.
Right here, we are going to cast the result of our query showing the open ToDo items into a simple table with two columns: the first column will contain the ID of the item, the second column the text. The result set is, as seen above, a list of tuples, each tuple contains one set of results.
To include the template in our example, just add the following lines::
from bottle import route, run, debug, template
...
result = c.fetchall()
c.close()
output = template('make_table', rows=result)
return output
...
So we do here two things: first, we import ``template`` from Bottle in order to be able to use templates. Second, we assign the output of the template ``make_table`` to the variable ``output``, which is then returned. In addition to calling the template, we assign ``result``, which we received from the database query, to the variable ``rows``, which is later on used within the template. If necessary, you can assign more than one variable / value to a template.
Templates always return a list of strings, thus there is no need to convert anything. Of course, we can save one line of code by writing ``return template('make_table', rows=result)``, which gives exactly the same result as above.
Now it is time to write the corresponding template, which looks like this::
%#template to generate a HTML table from a list of tuples (or list of lists, or tuple of tuples or ...)
The open items are as follows:
%for row in rows:
%for col in row:
{{col}} |
%end
%end
Save the code as ``make_table.tpl`` in the same directory where ``todo.py`` is stored.
Let's have a look at the code: every line starting with % is interpreted as Python code. Please note that, of course, only valid Python statements are allowed, otherwise the template will raise an exception, just as any other Python code. The other lines are plain HTML markup.
As you can see, we use Python's ``for`` statement two times, in order to go through ``rows``. As seen above, ``rows`` is a variable which holds the result of the database query, so it is a list of tuples. The first ``for`` statement accesses the tuples within the list, the second one the items within the tuple, which are put each into a cell of the table. It is important that you close all ``for``, ``if``, ``while`` etc. statements with ``%end``, otherwise the output may not be what you expect.
If you need to access a variable within a non-Python code line inside the template, you need to put it into double curly braces. This tells the template to insert the actual value of the variable right in place.
Run the script again and look at the output. Still not really nice, but at least more readable than the list of tuples. Of course, you can spice-up the very simple HTML markup above, e.g. by using in-line styles to get a better looking output.
.. rubric:: Using GET and POST Values
As we can review all open items properly, we move to the next step, which is adding new items to the ToDo list. The new item should be received from a regular HTML-based form, which sends its data by the GET method.
To do so, we first add a new route to our script and tell the route that it should get GET data::
from bottle import route, run, debug, template, request
...
return template('make_table', rows=result)
...
@route('/new', method='GET')
def new_item():
new = request.GET.get('task', '').strip()
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("INSERT INTO todo (task,status) VALUES (?,?)", (new,1))
new_id = c.lastrowid
conn.commit()
c.close()
return 'The new task was inserted into the database, the ID is %s
' % new_id
To access GET (or POST) data, we need to import ``request`` from Bottle. To assign the actual data to a variable, we use the statement ``request.GET.get('task','').strip()`` statement, where ``task`` is the name of the GET data we want to access. That's all. If your GET data has more than one variable, multiple ``request.GET.get()`` statements can be used and assigned to other variables.
The rest of this piece of code is just processing of the gained data: writing to the database, retrieve the corresponding id from the database and generate the output.
But where do we get the GET data from? Well, we can use a static HTML page holding the form. Or, what we do right now, is to use a template which is output when the route ``/new`` is called without GET data.
The code needs to be extended to::
...
@route('/new', method='GET')
def new_item():
if request.GET.get('save','').strip():
new = request.GET.get('task', '').strip()
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("INSERT INTO todo (task,status) VALUES (?,?)", (new,1))
new_id = c.lastrowid
conn.commit()
c.close()
return 'The new task was inserted into the database, the ID is %s
' % new_id
else:
return template('new_task.tpl')
``new_task.tpl`` looks like this::
Add a new task to the ToDo list:
That's all. As you can see, the template is plain HTML this time.
Now we are able to extend our to do list.
By the way, if you prefer to use POST data: this works exactly the same way, just use ``request.POST.get()`` instead.
.. rubric:: Editing Existing Items
The last point to do is to enable editing of existing items.
By using only the routes we know so far it is possible, but may be quite tricky. But Bottle knows something called "dynamic routes", which makes this task quite easy.
The basic statement for a dynamic route looks like this::
@route('/myroute/:something')
The key point here is the colon. This tells Bottle to accept for ``:something`` any string up to the next slash. Furthermore, the value of ``something`` will be passed to the function assigned to that route, so the data can be processed within the function.
For our ToDo list, we will create a route ``@route('/edit/:no)``, where ``no`` is the id of the item to edit.
The code looks like this::
@route('/edit/:no', method='GET')
def edit_item(no):
if request.GET.get('save','').strip():
edit = request.GET.get('task','').strip()
status = request.GET.get('status','').strip()
if status == 'open':
status = 1
else:
status = 0
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("UPDATE todo SET task = ?, status = ? WHERE id LIKE ?", (edit, status, no))
conn.commit()
return 'The item number %s was successfully updated
' % no
else:
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT task FROM todo WHERE id LIKE ?", (str(no)))
cur_data = c.fetchone()
return template('edit_task', old=cur_data, no=no)
It is basically pretty much the same what we already did above when adding new items, like using ``GET`` data etc. The main addition here is using the dynamic route ``:no``, which here passes the number to the corresponding function. As you can see, ``no`` is used within the function to access the right row of data within the database.
The template ``edit_task.tpl`` called within the function looks like this::
%#template for editing a task
%#the template expects to receive a value for "no" as well a "old", the text of the selected ToDo item
Edit the task with ID = {{no}}
Again, this template is a mix of Python statements and HTML, as already explained above.
A last word on dynamic routes: you can even use a regular expression for a dynamic route, as demonstrated later.
.. rubric:: Validating Dynamic Routes
Using dynamic routes is fine, but for many cases it makes sense to validate the dynamic part of the route. For example, we expect an integer number in our route for editing above. But if a float, characters or so are received, the Python interpreter throws an exception, which is not what we want.
For those cases, Bottle offers the ``@validate`` decorator, which validates the "input" prior to passing it to the function. In order to apply the validator, extend the code as follows::
from bottle import route, run, debug, template, request, validate
...
@route('/edit/:no', method='GET')
@validate(no=int)
def edit_item(no):
...
At first, we imported ``validate`` from the Bottle framework, than we apply the @validate-decorator. Right here, we validate if ``no`` is an integer. Basically, the validation works with all types of data like floats, lists etc.
Save the code and call the page again using a "403 forbidden" value for ``:no``, e.g. a float. You will receive not an exception, but a "403 - Forbidden" error, saying that an integer was expected.
.. rubric:: Dynamic Routes Using Regular Expressions
Bottle can also handle dynamic routes, where the "dynamic part" of the route can be a regular expression.
So, just to demonstrate that, let's assume that all single items in our ToDo list should be accessible by their plain number, by a term like e.g. "item1". For obvious reasons, you do not want to create a route for every item. Furthermore, the simple dynamic routes do not work either, as part of the route, the term "item" is static.
As said above, the solution is a regular expression::
@route('/item:item#[0-9]+#')
def show_item(item):
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT task FROM todo WHERE id LIKE ?", (item))
result = c.fetchall()
c.close()
if not result:
return 'This item number does not exist!'
else:
return 'Task: %s' %result[0]
Of course, this example is somehow artificially constructed - it would be easier to use a plain dynamic route only combined with a validation. Nevertheless, we want to see how regular expression routes work: the line ``@route(/item:item_#[0-9]+#)`` starts like a normal route, but the part surrounded by # is interpreted as a regular expression, which is the dynamic part of the route. So in this case, we want to match any digit between 0 and 9. The following function "show_item" just checks whether the given item is present in the database or not. In case it is present, the corresponding text of the task is returned. As you can see, only the regular expression part of the route is passed forward. Furthermore, it is always forwarded as a string, even if it is a plain integer number, like in this case.
.. rubric:: Returning Static Files
Sometimes it may become necessary to associate a route not to a Python function, but just return a static file. So if you have for example a help page for your application, you may want to return this page as plain HTML. This works as follows::
from bottle import route, run, debug, template, request, validate, static_file
@route('/help')
def help():
return static_file('help.html', root='/path/to/file')
At first, we need to import the ``static_file`` function from Bottle. As you can see, the ``return static_file`` statement replaces the ``return`` statement. It takes at least two arguments: the name of the file to be returned and the path to the file. Even if the file is in the same directory as your application, the path needs to be stated. But in this case, you can use ``'.'`` as a path, too. Bottle guesses the MIME-type of the file automatically, but in case you like to state it explicitly, add a third argument to ``static_file``, which would be here ``mimetype='text/html'``. ``static_file`` works with any type of route, including the dynamic ones.
.. rubric:: Returning JSON Data
There may be cases where you do not want your application to generate the output directly, but return data to be processed further on, e.g. by JavaScript. For those cases, Bottle offers the possibility to return JSON objects, which is sort of standard for exchanging data between web applications. Furthermore, JSON can be processed by many programming languages, including Python
So, let's assume we want to return the data generated in the regular expression route example as a JSON object. The code looks like this::
@route('/json:json#[0-9]+#')
def show_json(json):
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT task FROM todo WHERE id LIKE ?", (json))
result = c.fetchall()
c.close()
if not result:
return {'task':'This item number does not exist!'}
else:
return {'Task': result[0]}
As you can, that is fairly simple: just return a regular Python dictionary and Bottle will convert it automatically into a JSON object prior to sending. So if you e.g. call "http://localhost/json1" Bottle should in this case return the JSON object ``{"Task": ["Read A-byte-of-python to get a good introduction into Python"]}``.
.. rubric:: Catching Errors
The next step may is to catch the error with Bottle itself, to keep away any type of error message from the user of your application. To do that, Bottle has an "error-route", which can be a assigned to a HTML-error.
In our case, we want to catch a 403 error. The code is as follows::
from bottle import error
@error(403)
def mistake(code):
return 'The parameter you passed has the wrong format!'
So, at first we need to import ``error`` from Bottle and define a route by ``error(403)``, which catches all "403 forbidden" errors. The function "mistake" is assigned to that. Please note that ``error()`` always passes the error-code to the function - even if you do not need it. Thus, the function always needs to accept one argument, otherwise it will not work.
Again, you can assign more than one error-route to a function, or catch various errors with one function each. So this code::
@error(404)
@error(403)
def mistake(code):
return 'There is something wrong!'
works fine, the following one as well::
@error(403)
def mistake403(code):
return 'The parameter you passed has the wrong format!'
@error(404)
def mistake404(code):
return 'Sorry, this page does not exist!'
.. rubric:: Summary
After going through all the sections above, you should have a brief understanding how the Bottle WSGI framework works. Furthermore you have all the knowledge necessary to use Bottle for your applications.
The following chapter give a short introduction how to adapt Bottle for larger projects. Furthermore, we will show how to operate Bottle with web servers which perform better on a higher load / more web traffic than the one we used so far.
Server Setup
================================
So far, we used the standard server used by Bottle, which is the `WSGI reference Server`_ shipped along with Python. Although this server is perfectly suitable for development purposes, it is not really suitable for larger applications. But before we have a look at the alternatives, let's have a look how to tweak the settings of the standard server first.
.. rubric:: Running Bottle on a different port and IP
As standard, Bottle serves the pages on the IP adress 127.0.0.1, also known as ``localhost``, and on port ``8080``. To modify the setting is pretty simple, as additional parameters can be passed to Bottle's ``run()`` function to change the port and the address.
To change the port, just add ``port=portnumber`` to the run command. So, for example::
run(port=80)
would make Bottle listen to port 80.
To change the IP address where Bottle is listening::
run(host='123.45.67.89')
Of course, both parameters can be combined, like::
run(port=80, host='123.45.67.89')
The ``port`` and ``host`` parameter can also be applied when Bottle is running with a different server, as shown in the following section.
.. rubric:: Running Bottle with a different server
As said above, the standard server is perfectly suitable for development, personal use or a small group of people only using your application based on Bottle. For larger tasks, the standard server may become a bottleneck, as it is single-threaded, thus it can only serve one request at a time.
But Bottle has already various adapters to multi-threaded servers on board, which perform better on higher load. Bottle supports Cherrypy_, Fapws3_, Flup_ and Paste_.
If you want to run for example Bottle with the Paste server, use the following code::
from bottle import PasteServer
...
run(server=PasteServer)
This works exactly the same way with ``FlupServer``, ``CherryPyServer`` and ``FapwsServer``.
.. rubric:: Running Bottle on Apache with mod_wsgi
Maybe you already have an Apache_ or you want to run a Bottle-based application large scale - then it is time to think about Apache with mod_wsgi_.
We assume that your Apache server is up and running and mod_wsgi is working fine as well. On a lot of Linux distributions, mod_wsgi can be easily installed via whatever package management system is in use.
Bottle brings an adapter for mod_wsgi with it, so serving your application is an easy task.
In the following example, we assume that you want to make your application "ToDo list" accessible through ``http://www.mypage.com/todo`` and your code, templates and SQLite database are stored in the path ``/var/www/todo``.
When you run your application via mod_wsgi, it is imperative to remove the ``run()`` statement from your code, otherwise it won't work here.
After that, create a file called ``adapter.wsgi`` with the following content::
import sys, os, bottle
sys.path = ['/var/www/todo/'] + sys.path
os.chdir(os.path.dirname(__file__))
import todo # This loads your application
application = bottle.default_app()
and save it in the same path, ``/var/www/todo``. Actually the name of the file can be anything, as long as the extension is ``.wsgi``. The name is only used to reference the file from your virtual host.
Finally, we need to add a virtual host to the Apache configuration, which looks like this::
ServerName mypage.com
WSGIDaemonProcess todo user=www-data group=www-data processes=1 threads=5
WSGIScriptAlias / /var/www/todo/adapter.wsgi
WSGIProcessGroup todo
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
After restarting the server, your ToDo list should be accessible at ``http://www.mypage.com/todo``
Final Words
=========================
Now we are at the end of this introduction and tutorial to Bottle. We learned about the basic concepts of Bottle and wrote a first application using the Bottle framework. In addition to that, we saw how to adapt Bottle for large tasks and serve Bottle through an Apache web server with mod_wsgi.
As said in the introduction, this tutorial is not showing all shades and possibilities of Bottle. What we skipped here is e.g. receiving file objects and streams and how to handle authentication data. Furthermore, we did not show how templates can be called from within another template. For an introduction into those points, please refer to the full `Bottle documentation`_ .
Complete Example Listing
=========================
As the ToDo list example was developed piece by piece, here is the complete listing:
Main code for the application ``todo.py``::
import sqlite3
from bottle import route, run, debug, template, request, validate, static_file, error
# only needed when you run Bottle on mod_wsgi
from bottle import default_app
@route('/todo')
def todo_list():
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT id, task FROM todo WHERE status LIKE '1';")
result = c.fetchall()
c.close()
output = template('make_table', rows=result)
return output
@route('/new', method='GET')
def new_item():
if request.GET.get('save','').strip():
new = request.GET.get('task', '').strip()
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("INSERT INTO todo (task,status) VALUES (?,?)", (new,1))
new_id = c.lastrowid
conn.commit()
c.close()
return 'The new task was inserted into the database, the ID is %s
' % new_id
else:
return template('new_task.tpl')
@route('/edit/:no', method='GET')
@validate(no=int)
def edit_item(no):
if request.GET.get('save','').strip():
edit = request.GET.get('task','').strip()
status = request.GET.get('status','').strip()
if status == 'open':
status = 1
else:
status = 0
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("UPDATE todo SET task = ?, status = ? WHERE id LIKE ?", (edit,status,no))
conn.commit()
return 'The item number %s was successfully updated
' %no
else:
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT task FROM todo WHERE id LIKE ?", (str(no)))
cur_data = c.fetchone()
return template('edit_task', old = cur_data, no = no)
@route('/item:item#[0-9]+#')
def show_item(item):
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT task FROM todo WHERE id LIKE ?", (item))
result = c.fetchall()
c.close()
if not result:
return 'This item number does not exist!'
else:
return 'Task: %s' %result[0]
@route('/help')
def help():
static_file('help.html', root='.')
@route('/json:json#[0-9]+#')
def show_json(json):
conn = sqlite3.connect('todo.db')
c = conn.cursor()
c.execute("SELECT task FROM todo WHERE id LIKE ?", (json))
result = c.fetchall()
c.close()
if not result:
return {'task':'This item number does not exist!'}
else:
return {'Task': result[0]}
@error(403)
def mistake403(code):
return 'There is a mistake in your url!'
@error(404)
def mistake404(code):
return 'Sorry, this page does not exist!'
debug(True)
run(reloader=True)
#remember to remove reloader=True and debug(True) when you move your application from development to a productive environment
Template ``make_table.tpl``::
%#template to generate a HTML table from a list of tuples (or list of lists, or tuple of tuples or ...)
The open items are as follows:
%for row in rows:
%for col in row:
{{col}} |
%end
%end
Template ``edit_task.tpl``::
%#template for editing a task
%#the template expects to receive a value for "no" as well a "old", the text of the selected ToDo item
Edit the task with ID = {{no}}
Template ``new_task.tpl``::
%#template for the form for a new task
Add a new task to the ToDo list:
bottle-0.12.7/docs/plugindev.rst 0000755 0001750 0001750 00000032746 12327760172 015167 0 ustar fede fede .. module:: bottle
========================
Plugin Development Guide
========================
This guide explains the plugin API and how to write custom plugins. I suggest reading :ref:`plugins` first if you have not done that already. You might also want to have a look at the :doc:`/plugins/index` for some practical examples.
.. note::
This is a draft. If you see any errors or find that a specific part is not explained clear enough, please tell the `mailing-list `_ or file a `bug report `_.
How Plugins Work: The Basics
============================
The plugin API builds on the concept of `decorators `_. To put it briefly, a plugin is a decorator applied to every single route callback of an application.
Of course, this is just a simplification. Plugins can do a lot more than just decorating route callbacks, but it is a good starting point. Lets have a look at some code::
from bottle import response, install
import time
def stopwatch(callback):
def wrapper(*args, **kwargs):
start = time.time()
body = callback(*args, **kwargs)
end = time.time()
response.headers['X-Exec-Time'] = str(end - start)
return body
return wrapper
install(stopwatch)
This plugin measures the execution time for each request and adds an appropriate ``X-Exec-Time`` header to the response. As you can see, the plugin returns a wrapper and the wrapper calls the original callback recursively. This is how decorators usually work.
The last line tells Bottle to install the plugin to the default application. This causes the plugin to be automatically applied to all routes of that application. In other words, ``stopwatch()`` is called once for each route callback and the return value is used as a replacement for the original callback.
Plugins are applied on demand, that is, as soon as a route is requested for the first time. For this to work properly in multi-threaded environments, the plugin should be thread-safe. This is not a problem most of the time, but keep it in mind.
Once all plugins are applied to a route, the wrapped callback is cached and subsequent requests are handled by the cached version directly. This means that a plugin is usually applied only once to a specific route. That cache, however, is cleared every time the list of installed plugins changes. Your plugin should be able to decorate the same route more than once.
The decorator API is quite limited, though. You don't know anything about the route being decorated or the associated application object and have no way to efficiently store data that is shared among all routes. But fear not! Plugins are not limited to just decorator functions. Bottle accepts anything as a plugin as long as it is callable or implements an extended API. This API is described below and gives you a lot of control over the whole process.
Plugin API
==========
:class:`Plugin` is not a real class (you cannot import it from :mod:`bottle`) but an interface that plugins are expected to implement. Bottle accepts any object of any type as a plugin, as long as it conforms to the following API.
.. class:: Plugin(object)
Plugins must be callable or implement :meth:`apply`. If :meth:`apply` is defined, it is always preferred over calling the plugin directly. All other methods and attributes are optional.
.. attribute:: name
Both :meth:`Bottle.uninstall` and the `skip` parameter of :meth:`Bottle.route()` accept a name string to refer to a plugin or plugin type. This works only for plugins that have a name attribute.
.. attribute:: api
The Plugin API is still evolving. This integer attribute tells bottle which version to use. If it is missing, bottle defaults to the first version. The current version is ``2``. See :ref:`plugin-changelog` for details.
.. method:: setup(self, app)
Called as soon as the plugin is installed to an application (see :meth:`Bottle.install`). The only parameter is the associated application object.
.. method:: __call__(self, callback)
As long as :meth:`apply` is not defined, the plugin itself is used as a decorator and applied directly to each route callback. The only parameter is the callback to decorate. Whatever is returned by this method replaces the original callback. If there is no need to wrap or replace a given callback, just return the unmodified callback parameter.
.. method:: apply(self, callback, route)
If defined, this method is used in favor of :meth:`__call__` to decorate route callbacks. The additional `route` parameter is an instance of :class:`Route` and provides a lot of meta-information and context for that route. See :ref:`route-context` for details.
.. method:: close(self)
Called immediately before the plugin is uninstalled or the application is closed (see :meth:`Bottle.uninstall` or :meth:`Bottle.close`).
Both :meth:`Plugin.setup` and :meth:`Plugin.close` are *not* called for plugins that are applied directly to a route via the :meth:`Bottle.route()` decorator, but only for plugins installed to an application.
.. _plugin-changelog:
Plugin API changes
------------------
The Plugin API is still evolving and changed with Bottle 0.10 to address certain issues with the route context dictionary. To ensure backwards compatibility with 0.9 Plugins, we added an optional :attr:`Plugin.api` attribute to tell bottle which API to use. The API differences are summarized here.
* **Bottle 0.9 API 1** (:attr:`Plugin.api` not present)
* Original Plugin API as described in the 0.9 docs.
* **Bottle 0.10 API 2** (:attr:`Plugin.api` equals 2)
* The `context` parameter of the :meth:`Plugin.apply` method is now an instance of :class:`Route` instead of a context dictionary.
.. _route-context:
The Route Context
=================
The :class:`Route` instance passed to :meth:`Plugin.apply` provides detailed informations about the associated route. The most important attributes are summarized here:
=========== =================================================================
Attribute Description
=========== =================================================================
app The application object this route is installed to.
rule The rule string (e.g. ``/wiki/:page``).
method The HTTP method as a string (e.g. ``GET``).
callback The original callback with no plugins applied. Useful for
introspection.
name The name of the route (if specified) or ``None``.
plugins A list of route-specific plugins. These are applied in addition to
application-wide plugins. (see :meth:`Bottle.route`).
skiplist A list of plugins to not apply to this route (again, see
:meth:`Bottle.route`).
config Additional keyword arguments passed to the :meth:`Bottle.route`
decorator are stored in this dictionary. Used for route-specific
configuration and meta-data.
=========== =================================================================
For your plugin, :attr:`Route.config` is probably the most important attribute. Keep in mind that this dictionary is local to the route, but shared between all plugins. It is always a good idea to add a unique prefix or, if your plugin needs a lot of configuration, store it in a separate namespace within the `config` dictionary. This helps to avoid naming collisions between plugins.
Changing the :class:`Route` object
----------------------------------
While some :class:`Route` attributes are mutable, changes may have unwanted effects on other plugins. It is most likely a bad idea to monkey-patch a broken route instead of providing a helpful error message and let the user fix the problem.
In some rare cases, however, it might be justifiable to break this rule. After you made your changes to the :class:`Route` instance, raise :exc:`RouteReset` as an exception. This removes the current route from the cache and causes all plugins to be re-applied. The router is not updated, however. Changes to `rule` or `method` values have no effect on the router, but only on plugins. This may change in the future, though.
Runtime optimizations
=====================
Once all plugins are applied to a route, the wrapped route callback is cached to speed up subsequent requests. If the behavior of your plugin depends on configuration, and you want to be able to change that configuration at runtime, you need to read the configuration on each request. Easy enough.
For performance reasons, however, it might be worthwhile to choose a different wrapper based on current needs, work with closures, or enable or disable a plugin at runtime. Let's take the built-in HooksPlugin as an example: If no hooks are installed, the plugin removes itself from all affected routes and has virtaully no overhead. As soon as you install the first hook, the plugin activates itself and takes effect again.
To achieve this, you need control over the callback cache: :meth:`Route.reset` clears the cache for a single route and :meth:`Bottle.reset` clears all caches for all routes of an application at once. On the next request, all plugins are re-applied to the route as if it were requested for the first time.
Both methods won't affect the current request if called from within a route callback, of cause. To force a restart of the current request, raise :exc:`RouteReset` as an exception.
Plugin Example: SQLitePlugin
============================
This plugin provides an sqlite3 database connection handle as an additional keyword argument to wrapped callbacks, but only if the callback expects it. If not, the route is ignored and no overhead is added. The wrapper does not affect the return value, but handles plugin-related exceptions properly. :meth:`Plugin.setup` is used to inspect the application and search for conflicting plugins.
::
import sqlite3
import inspect
class SQLitePlugin(object):
''' This plugin passes an sqlite3 database handle to route callbacks
that accept a `db` keyword argument. If a callback does not expect
such a parameter, no connection is made. You can override the database
settings on a per-route basis. '''
name = 'sqlite'
api = 2
def __init__(self, dbfile=':memory:', autocommit=True, dictrows=True,
keyword='db'):
self.dbfile = dbfile
self.autocommit = autocommit
self.dictrows = dictrows
self.keyword = keyword
def setup(self, app):
''' Make sure that other installed plugins don't affect the same
keyword argument.'''
for other in app.plugins:
if not isinstance(other, SQLitePlugin): continue
if other.keyword == self.keyword:
raise PluginError("Found another sqlite plugin with "\
"conflicting settings (non-unique keyword).")
def apply(self, callback, context):
# Override global configuration with route-specific values.
conf = context.config.get('sqlite') or {}
dbfile = conf.get('dbfile', self.dbfile)
autocommit = conf.get('autocommit', self.autocommit)
dictrows = conf.get('dictrows', self.dictrows)
keyword = conf.get('keyword', self.keyword)
# Test if the original callback accepts a 'db' keyword.
# Ignore it if it does not need a database handle.
args = inspect.getargspec(context.callback)[0]
if keyword not in args:
return callback
def wrapper(*args, **kwargs):
# Connect to the database
db = sqlite3.connect(dbfile)
# This enables column access by name: row['column_name']
if dictrows: db.row_factory = sqlite3.Row
# Add the connection handle as a keyword argument.
kwargs[keyword] = db
try:
rv = callback(*args, **kwargs)
if autocommit: db.commit()
except sqlite3.IntegrityError, e:
db.rollback()
raise HTTPError(500, "Database Error", e)
finally:
db.close()
return rv
# Replace the route callback with the wrapped one.
return wrapper
This plugin is actually useful and very similar to the version bundled with Bottle. Not bad for less than 60 lines of code, don't you think? Here is a usage example::
sqlite = SQLitePlugin(dbfile='/tmp/test.db')
bottle.install(sqlite)
@route('/show/:page')
def show(page, db):
row = db.execute('SELECT * from pages where name=?', page).fetchone()
if row:
return template('showpage', page=row)
return HTTPError(404, "Page not found")
@route('/static/:fname#.*#')
def static(fname):
return static_file(fname, root='/some/path')
@route('/admin/set/:db#[a-zA-Z]+#', skip=[sqlite])
def change_dbfile(db):
sqlite.dbfile = '/tmp/%s.db' % db
return "Switched DB to %s.db" % db
The first route needs a database connection and tells the plugin to create a handle by requesting a ``db`` keyword argument. The second route does not need a database and is therefore ignored by the plugin. The third route does expect a 'db' keyword argument, but explicitly skips the sqlite plugin. This way the argument is not overruled by the plugin and still contains the value of the same-named url argument.
bottle-0.12.7/docs/development.rst 0000644 0001750 0001750 00000026655 12327760172 015513 0 ustar fede fede Developer Notes
=================
This document is intended for developers and package maintainers interested in the bottle development and release workflow. If you want to contribute, you are just right!
Get involved
------------
There are several ways to join the community and stay up to date. Here are some of them:
* **Mailing list**: Join our mailing list by sending an email to `bottlepy+subscribe@googlegroups.com `_ (no google account required).
* **Twitter**: `Follow us on Twitter `_ or search for the `#bottlepy `_ tag.
* **IRC**: Join `#bottlepy on irc.freenode.net `_ or use the `web chat interface `_.
* **Google plus**: We sometimes `blog about Bottle, releases and technical stuff `_ on our Google+ page.
Get the Sources
---------------
The bottle `development repository `_ and the `issue tracker `_ are both hosted at `github `_. If you plan to contribute, it is a good idea to create an account there and fork the main repository. This way your changes and ideas are visible to other developers and can be discussed openly. Even without an account, you can clone the repository or just download the latest development version as a source archive.
* **git:** ``git clone git://github.com/defnull/bottle.git``
* **git/https:** ``git clone https://github.com/defnull/bottle.git``
* **Download:** Development branch as `tar archive `_ or `zip file `_.
Releases and Updates
--------------------
Bottle is released at irregular intervals and distributed through `PyPI `_. Release candidates and bugfix-revisions of outdated releases are only available from the git repository mentioned above. Some Linux distributions may offer packages for outdated releases, though.
The Bottle version number splits into three parts (**major.minor.revision**). These are *not* used to promote new features but to indicate important bug-fixes and/or API changes. Critical bugs are fixed in at least the two latest minor releases and announced in all available channels (mailinglist, twitter, github). Non-critical bugs or features are not guaranteed to be backported. This may change in the future, through.
Major Release (x.0)
The major release number is increased on important milestones or updates that completely break backward compatibility. You probably have to work over your entire application to use a new release. These releases are very rare, through.
Minor Release (x.y)
The minor release number is increased on updates that change the API or behaviour in some way. You might get some depreciation warnings any may have to tweak some configuration settings to restore the old behaviour, but in most cases these changes are designed to be backward compatible for at least one minor release. You should update to stay up do date, but don't have to. An exception is 0.8, which *will* break backward compatibility hard. (This is why 0.7 was skipped). Sorry about that.
Revision (x.y.z)
The revision number is increased on bug-fixes and other patches that do not change the API or behaviour. You can safely update without editing your application code. In fact, you really should as soon as possible, because important security fixes are released this way.
Pre-Release Versions
Release candidates are marked by an ``rc`` in their revision number. These are API stable most of the time and open for testing, but not officially released yet. You should not use these for production.
Repository Structure
--------------------
The source repository is structured as follows:
``master`` branch
This is the integration, testing and development branch. All changes that are planned to be part of the next release are merged and tested here.
``release-x.y`` branches
As soon as the master branch is (almost) ready for a new release, it is branched into a new release branch. This "release candidate" is feature-frozen but may receive bug-fixes and last-minute changes until it is considered production ready and officially released. From that point on it is called a "support branch" and still receives bug-fixes, but only important ones. The revision number is increased on each push to these branches, so you can keep up with important changes.
``bugfix_name-x.y`` branches
These branches are only temporary and used to develop and share non-trivial bug-fixes for existing releases. They are merged into the corresponding release branch and deleted soon after that.
Feature branches
All other branches are feature branches. These are based on the master branch and only live as long as they are still active and not merged back into ``master``.
.. rubric:: What does this mean for a developer?
If you want to add a feature, create a new branch from ``master``. If you want to fix a bug, branch ``release-x.y`` for each affected release. Please use a separate branch for each feature or bug to make integration as easy as possible. Thats all. There are git workflow examples at the bottom of this page.
Oh, and never ever change the release number. We'll do that on integration. You never know in which order we pull pending requests anyway :)
.. rubric:: What does this mean for a maintainer ?
Watch the tags (and the mailing list) for bug-fixes and new releases. If you want to fetch a specific release from the git repository, trust the tags, not the branches. A branch may contain changes that are not released yet, but a tag marks the exact commit which changed the version number.
Submitting Patches
------------------
The best way to get your changes integrated into the main development branch is to fork the main repository at github, create a new feature-branch, apply your changes and send a pull-request. Further down this page is a small collection of git workflow examples that may guide you. Submitting git-compatible patches to the mailing list is fine too. In any case, please follow some basic rules:
* **Documentation:** Tell us what your patch does. Comment your code. If you introduced a new feature, add to the documentation so others can learn about it.
* **Test:** Write tests to prove that your code works as expected and does not break anything. If you fixed a bug, write at least one test-case that triggers the bug. Make sure that all tests pass before you submit a patch.
* **One patch at a time:** Only fix one bug or add one feature at a time. Design your patches so that they can be applyed as a whole. Keep your patches clean, small and focused.
* **Sync with upstream:** If the ``upstream/master`` branch changed while you were working on your patch, rebase or pull to make sure that your patch still applies without conflicts.
Building the Documentation
--------------------------
You need a recent version of Sphinx to build the documentation. The recommended way is to install :command:`virtualenv` using your distribution package repository and install sphinx manually to get an up-to-date version.
.. code-block:: bash
# Install prerequisites
which virtualenv || sudo apt-get install python-virtualenv
virtualenv --no-site-dependencies venv
./venv/pip install -U sphinx
# Clone or download bottle from github
git clone https://github.com/defnull/bottle.git
# Activate build environment
source ./venv/bin/activate
# Build HTML docs
cd bottle/docs
make html
# Optional: Install prerequisites for PDF generation
sudo apt-get install texlive-latex-extra \
texlive-latex-recommended \
texlive-fonts-recommended
# Optional: Build the documentation as PDF
make latex
cd ../build/docs/latex
make pdf
GIT Workflow Examples
---------------------
The following examples assume that you have an (free) `github account `_. This is not mandatory, but makes things a lot easier.
First of all you need to create a fork (a personal clone) of the official repository. To do this, you simply click the "fork" button on the `bottle project page `_. When the fork is done, you will be presented with a short introduction to your new repository.
The fork you just created is hosted at github and read-able by everyone, but write-able only by you. Now you need to clone the fork locally to actually make changes to it. Make sure you use the private (read-write) URL and *not* the public (read-only) one::
git clone git@github.com:your_github_account/bottle.git
Once the clone is complete your repository will have a remote named "origin" that points to your fork on github. Don’t let the name confuse you, this does not point to the original bottle repository, but to your own fork. To keep track of the official repository, add another remote named "upstream"::
cd bottle
git remote add upstream git://github.com/defnull/bottle.git
git fetch upstream
Note that "upstream" is a public clone URL, which is read-only. You cannot push changes directly to it. Instead, we will pull from your public repository. This is described later.
.. rubric:: Submit a Feature
New features are developed in separate feature-branches to make integration easy. Because they are going to be integrated into the ``master`` branch, they must be based on ``upstream/master``. To create a new feature-branch, type the following::
git checkout -b cool_feature upstream/master
Now implement your feature, write tests, update the documentation, make sure that all tests pass and commit your changes::
git commit -a -m "Cool Feature"
If the ``upstream/master`` branch changed in the meantime, there may be conflicts with your changes. To solve these, 'rebase' your feature-branch onto the top of the updated ``upstream/master`` branch::
git fetch upstream
git rebase upstream
This is equivalent to undoing all your changes, updating your branch to the latest version and reapplying all your patches again. If you released your branch already (see next step), this is not an option because it rewrites your history. You can do a normal pull instead. Resolve any conflicts, run the tests again and commit.
Now you are almost ready to send a pull request. But first you need to make your feature-branch public by pushing it to your github fork::
git push origin cool_feature
After you’ve pushed your commit(s) you need to inform us about the new feature. One way is to send a pull-request using github. Another way would be to start a thread in the mailing-list, which is recommended. It allows other developers to see and discuss your patches and you get some feedback for free :)
If we accept your patch, we will integrate it into the official development branch and make it part of the next release.
.. rubric:: Fix a Bug
The workflow for bug-fixes is very similar to the one for features, but there are some differences:
1) Branch off of the affected release branches instead of just the development branch.
2) Write at least one test-case that triggers the bug.
3) Do this for each affected branch including ``upstream/master`` if it is affected. ``git cherry-pick`` may help you reducing repetitive work.
4) Name your branch after the release it is based on to avoid confusion. Examples: ``my_bugfix-x.y`` or ``my_bugfix-dev``.
bottle-0.12.7/docs/deployment.rst 0000644 0001750 0001750 00000023052 12327760172 015335 0 ustar fede fede .. _flup: http://trac.saddi.com/flup
.. _gae: http://code.google.com/appengine/docs/python/overview.html
.. _wsgiref: http://docs.python.org/library/wsgiref.html
.. _cherrypy: http://www.cherrypy.org/
.. _paste: http://pythonpaste.org/
.. _rocket: http://pypi.python.org/pypi/rocket
.. _gunicorn: http://pypi.python.org/pypi/gunicorn
.. _fapws3: http://www.fapws.org/
.. _tornado: http://www.tornadoweb.org/
.. _twisted: http://twistedmatrix.com/
.. _diesel: http://dieselweb.org/
.. _meinheld: http://pypi.python.org/pypi/meinheld
.. _bjoern: http://pypi.python.org/pypi/bjoern
.. _gevent: http://www.gevent.org/
.. _eventlet: http://eventlet.net/
.. _waitress: http://readthedocs.org/docs/waitress/en/latest/
.. _apache: http://httpd.apache.org/
.. _mod_wsgi: http://code.google.com/p/modwsgi/
.. _pound: http://www.apsis.ch/pound
.. _tutorial-deployment:
================================================================================
Deployment
================================================================================
The bottle :func:`run` function, when called without any parameters, starts a local development server on port 8080. You can access and test your application via http://localhost:8080/ if you are on the same host.
To get your application available to the outside world, specify the IP of the interface the server should listen to (e.g. ``run(host='192.168.0.1')``) or let the server listen to all interfaces at once (e.g. ``run(host='0.0.0.0')``). The listening port can be changed in a similar way, but you need root or admin rights to choose a port below 1024. Port 80 is the standard for HTTP servers::
run(host='0.0.0.0', port=80) # Listen to HTTP requests on all interfaces
Server Options
================================================================================
The built-in default server is based on `wsgiref WSGIServer `_. 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 different server that is either multi-threaded or asynchronous.
* Start multiple server processes and spread the load with a load-balancer.
* Do both.
**Multi-threaded** servers are the 'classic' way to do it. They are very robust, reasonably fast and easy to manage. As a drawback, they can only handle a limited number of connections at the same time and utilize only one CPU core due to the "Global Interpreter Lock" (GIL). This does not hurt most applications, they are waiting for network IO most of the time anyway, but may slow down CPU intensive tasks (e.g. image processing).
**Asynchronous** servers are very fast, can handle a virtually unlimited number of concurrent connections and are easy to manage, but can get a bit tricky. To take full advantage of their potential, you need to design your application accordingly and understand the concepts of the specific server.
**Multi-processing** (forking) servers are not limited by the GIL and utilize more than one CPU core, but make communication between server instances more expensive. You need a database or external message query to share state between processes, or design your application so that it does not need any shared state. The setup is also a bit more complicated, but there are good tutorials available.
Switching the Server Backend
================================================================================
The easiest way to increase performance is to install a multi-threaded server library like paste_ or cherrypy_ and tell Bottle to use that instead of the single-threaded server::
bottle.run(server='paste')
Bottle ships with a lot of ready-to-use adapters for the most common WSGI servers and automates the setup process. Here is an incomplete list:
======== ============ ======================================================
Name Homepage Description
======== ============ ======================================================
cgi Run as CGI script
flup flup_ Run as FastCGI process
gae gae_ Helper for Google App Engine deployments
wsgiref wsgiref_ Single-threaded default server
cherrypy cherrypy_ Multi-threaded and very stable
paste paste_ Multi-threaded, stable, tried and tested
rocket rocket_ Multi-threaded
waitress waitress_ Multi-threaded, poweres Pyramid
gunicorn gunicorn_ Pre-forked, partly written in C
eventlet eventlet_ Asynchronous framework with WSGI support.
gevent gevent_ Asynchronous (greenlets)
diesel diesel_ Asynchronous (greenlets)
fapws3 fapws3_ Asynchronous (network side only), written in C
tornado tornado_ Asynchronous, powers some parts of Facebook
twisted twisted_ Asynchronous, well tested but... twisted
meinheld meinheld_ Asynchronous, partly written in C
bjoern bjoern_ Asynchronous, very fast and written in C
auto Automatically selects an available server adapter
======== ============ ======================================================
The full list is available through :data:`server_names`.
If there is no adapter for your favorite server or if you need more control over the server setup, you may want to start the server manually. Refer to the server documentation on how to run WSGI applications. Here is an example for paste_::
application = bottle.default_app()
from paste import httpserver
httpserver.serve(application, host='0.0.0.0', port=80)
Apache mod_wsgi
--------------------------------------------------------------------------------
Instead of running your own HTTP server from within Bottle, you can attach Bottle applications to an `Apache server `_ using mod_wsgi_.
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-compatible Python callable.
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
# ... build or import your bottle application here ...
# Do NOT use bottle.run() with mod_wsgi
application = bottle.default_app()
The Apache configuration may look like this::
ServerName example.com
WSGIDaemonProcess yourapp user=www-data group=www-data processes=1 threads=5
WSGIScriptAlias / /var/www/yourapp/app.wsgi
WSGIProcessGroup yourapp
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
Google AppEngine
--------------------------------------------------------------------------------
.. versionadded:: 0.9
The ``gae`` server adapter is used to run applications on Google App Engine. It works similar to the ``cgi`` adapter in that it does not start a new HTTP server, but prepares and optimizes your application for Google App Engine and makes sure it conforms to their API::
bottle.run(server='gae') # No need for a host or port setting.
It is always a good idea to let GAE serve static files directly. Here is example for a working ``app.yaml``::
application: myapp
version: 1
runtime: python
api_version: 1
handlers:
- url: /static
static_dir: static
- url: /.*
script: myapp.py
Load Balancer (Manual Setup)
--------------------------------------------------------------------------------
A single Python process can utilize only 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 instance for each CPU core available using different local port (localhost:8080, 8081, 8082, ...). You can choose any server adapter you want, even asynchronous ones. Then a high performance load balancer acts as a reverse proxy and forwards each new requests to a random port, spreading the load between all available back-ends. This way you can use all of your CPU cores and even spread out the load between different physical servers.
One of the fastest load balancers available is Pound_ but most common web servers have a proxy-module that can do the work just fine.
Pound example::
ListenHTTP
Address 0.0.0.0
Port 80
Service
BackEnd
Address 127.0.0.1
Port 8080
End
BackEnd
Address 127.0.0.1
Port 8081
End
End
End
Apache example::
BalancerMember http://192.168.1.50:80
BalancerMember http://192.168.1.51:80
ProxyPass / balancer://mycluster
Lighttpd example::
server.modules += ( "mod_proxy" )
proxy.server = (
"" => (
"wsgi1" => ( "host" => "127.0.0.1", "port" => 8080 ),
"wsgi2" => ( "host" => "127.0.0.1", "port" => 8081 )
)
)
Good old CGI
================================================================================
A CGI server starts a new process for each request. This adds a lot of overhead but is sometimes the only option, especially on cheap hosting packages. The `cgi` server adapter does not actually start a CGI server, but transforms your bottle application into a valid CGI application::
bottle.run(server='cgi')
bottle-0.12.7/docs/stpl.rst 0000755 0001750 0001750 00000020055 12327760172 014142 0 ustar fede fede ======================
SimpleTemplate Engine
======================
.. currentmodule:: bottle
Bottle comes with a fast, powerful and easy to learn built-in template engine called *SimpleTemplate* or *stpl* for short. It is the default engine used by the :func:`view` and :func:`template` helpers but can be used as a stand-alone general purpose template engine too. This document explains the template syntax and shows examples for common use cases.
.. rubric:: Basic API Usage:
:class:`SimpleTemplate` implements the :class:`BaseTemplate` API::
>>> from bottle import SimpleTemplate
>>> tpl = SimpleTemplate('Hello {{name}}!')
>>> tpl.render(name='World')
u'Hello World!'
In this document we use the :func:`template` helper in examples for the sake of simplicity::
>>> from bottle import template
>>> template('Hello {{name}}!', name='World')
u'Hello World!'
Just keep in mind that compiling and rendering templates are two different actions, even if the :func:`template` helper hides this fact. Templates are usually compiled only once and cached internally, but rendered many times with different keyword arguments.
:class:`SimpleTemplate` Syntax
==============================
Python is a very powerful language but its whitespace-aware syntax makes it difficult to use as a template language. SimpleTemplate removes some of these restrictions and allows you to write clean, readable and maintainable templates while preserving full access to the features, libraries and speed of the Python language.
.. warning::
The :class:`SimpleTemplate` syntax compiles directly to python bytecode and is executed on each :meth:`SimpleTemplate.render` call. Do not render untrusted templates! They may contain and execute harmful python code.
Inline Expressions
------------------
You already learned the use of the ``{{...}}`` syntax from the "Hello World!" example above, but there is more: any python expression is allowed within the curly brackets as long as it evaluates to a string or something that has a string representation::
>>> template('Hello {{name}}!', name='World')
u'Hello World!'
>>> template('Hello {{name.title() if name else "stranger"}}!', name=None)
u'Hello stranger!'
>>> template('Hello {{name.title() if name else "stranger"}}!', name='mArC')
u'Hello Marc!'
The contained python expression is executed at render-time and has access to all keyword arguments passed to the :meth:`SimpleTemplate.render` method. HTML special characters are escaped automatically to prevent `XSS `_ attacks. You can start the expression with an exclamation mark to disable escaping for that expression::
>>> template('Hello {{name}}!', name='World')
u'Hello <b>World</b>!'
>>> template('Hello {{!name}}!', name='World')
u'Hello World!'
Embedded python code
--------------------
.. highlight:: html+django
The template engine allows you to embed lines or blocks of python code within your template. Code lines start with ``%`` and code blocks are surrounded by ``<%`` and ``%>`` tokens::
% name = "Bob" # a line of python code
Some plain text in between
<%
# A block of python code
name = name.title().strip()
%>
More plain text
Embedded python code follows regular python syntax, but with two additional syntax rules:
* **Indentation is ignored.** You can put as much whitespace in front of statements as you want. This allows you to align your code with the surrounding markup and can greatly improve readability.
* Blocks that are normally indented now have to be closed explicitly with an ``end`` keyword.
::
% for item in basket:
- {{item}}
% end
Both the ``%`` and the ``<%`` tokens are only recognized if they are the first non-whitespace characters in a line. You don't have to escape them if they appear mid-text in your template markup. Only if a line of text starts with one of these tokens, you have to escape it with a backslash. In the rare case where the backslash + token combination appears in your markup at the beginning of a line, you can always help yourself with a string literal in an inline expression::
This line contains % and <% but no python code.
\% This text-line starts with the '%' token.
\<% Another line that starts with a token but is rendered as text.
{{'\\%'}} this line starts with an escaped token.
If you find yourself to escape a lot, consider using :ref:`custom tokens `.
Whitespace Control
-----------------------
Code blocks and code lines always span the whole line. Whitespace in front of after a code segment is stripped away. You won't see empty lines or dangling whitespace in your template because of embedded code::
% if True:
content
% end
This snippet renders to clean and compact html::
content
But embedding code still requires you to start a new line, which may not what you want to see in your rendered template. To skip the newline in front of a code segment, end the text line with a double-backslash::
\\
%if True:
content\\
%end
THis time the rendered template looks like this::
content
This only works directly in front of code segments. In all other places you can control the whitespace yourself and don't need any special syntax.
Template Functions
==================
Each template is preloaded with a bunch of functions that help with the most common use cases. These functions are always available. You don't have to import or provide them yourself. For everything not covered here there are probably good python libraries available. Remember that you can ``import`` anything you want within your templates. They are python programs after all.
.. currentmodule:: stpl
.. versionchanged:: 0.12
Prior to this release, :func:`include` and :func:`rebase` were sytnax keywords, not functions.
.. function:: include(sub_template, **variables)
Render a sub-template with the specified variables and insert the resulting text into the current template. The function returns a dictionary containing the local variables passed to or defined within the sub-template::
% include('header.tpl', title='Page Title')
Page Content
% include('foother.tpl')
.. function:: rebase(name, **variables)
Mark the current template to be later included into a different template. After the current template is rendered, its resulting text is stored in a variable named ``base`` and passed to the base-template, which is then rendered. This can be used to `wrap` a template with surrounding text, or simulate the inheritance feature found in other template engines::
% rebase('base.tpl', title='Page Title')
Page Content ...
This can be combined with the following ``base.tpl``::
{{title or 'No title'}}
{{base}}
Accessing undefined variables in a template raises :exc:`NameError` and
stops rendering immediately. This is standard python behavior and nothing new,
but vanilla python lacks an easy way to check the availability of a variable.
This quickly gets annoying if you want to support flexible inputs or use the
same template in different situations. These functions may help:
.. function:: defined(name)
Return True if the variable is defined in the current template namespace,
False otherwise.
.. function:: get(name, default=None)
Return the variable, or a default value.
.. function:: setdefault(name, default)
If the variable is not defined, create it with the given default value.
Return the variable.
Here is an example that uses all three functions to implement optional template
variables in different ways::
% setdefault('text', 'No Text')
{{get('title', 'No Title')}}
{{ text }}
% if defined('author'):
By {{ author }}
% end
.. currentmodule:: bottle
:class:`SimpleTemplate` API
==============================
.. autoclass:: SimpleTemplate
:members:
bottle-0.12.7/docs/recipes.rst 0000755 0001750 0001750 00000023550 12327760172 014615 0 ustar fede fede .. module:: bottle
.. _beaker: http://beaker.groovie.org/
.. _mod_python: http://www.modpython.org/
.. _mod_wsgi: http://code.google.com/p/modwsgi/
.. _werkzeug: http://werkzeug.pocoo.org/documentation/dev/debug.html
.. _paste: http://pythonpaste.org/modules/evalexception.html
.. _pylons: http://pylonshq.com/
.. _gevent: http://www.gevent.org/
.. _compression: https://github.com/defnull/bottle/issues/92
.. _GzipFilter: http://www.cherrypy.org/wiki/GzipFilter
.. _cherrypy: http://www.cherrypy.org
.. _heroku: http://heroku.com
Recipes
=============
This is a collection of code snippets and examples for common use cases.
Keeping track of Sessions
----------------------------
There is no built-in support for sessions because there is no *right* way to do it (in a micro framework). Depending on requirements and environment you could use beaker_ middleware with a fitting backend or implement it yourself. Here is an example for beaker sessions with a file-based backend::
import bottle
from beaker.middleware import SessionMiddleware
session_opts = {
'session.type': 'file',
'session.cookie_expires': 300,
'session.data_dir': './data',
'session.auto': True
}
app = SessionMiddleware(bottle.app(), session_opts)
@bottle.route('/test')
def test():
s = bottle.request.environ.get('beaker.session')
s['test'] = s.get('test',0) + 1
s.save()
return 'Test counter: %d' % s['test']
bottle.run(app=app)
Debugging with Style: Debugging Middleware
--------------------------------------------------------------------------------
Bottle catches all Exceptions raised in your app code to prevent your WSGI server from crashing. If the built-in :func:`debug` mode is not enough and you need exceptions to propagate to a debugging middleware, you can turn off this behaviour::
import bottle
app = bottle.app()
app.catchall = False #Now most exceptions are re-raised within bottle.
myapp = DebuggingMiddleware(app) #Replace this with a middleware of your choice (see below)
bottle.run(app=myapp)
Now, bottle only catches its own exceptions (:exc:`HTTPError`, :exc:`HTTPResponse` and :exc:`BottleException`) and your middleware can handle the rest.
The werkzeug_ and paste_ libraries both ship with very powerful debugging WSGI middleware. Look at :class:`werkzeug.debug.DebuggedApplication` for werkzeug_ and :class:`paste.evalexception.middleware.EvalException` for paste_. They both allow you do inspect the stack and even execute python code within the stack context, so **do not use them in production**.
Unit-Testing Bottle Applications
--------------------------------------------------------------------------------
Unit-testing is usually performed against methods defined in your web application without running a WSGI environment.
A simple example using `Nose `_::
import bottle
@bottle.route('/')
def index():
return 'Hi!'
if __name__ == '__main__':
bottle.run()
Test script::
import mywebapp
def test_webapp_index():
assert mywebapp.index() == 'Hi!'
In the example the Bottle route() method is never executed - only index() is tested.
Functional Testing Bottle Applications
--------------------------------------------------------------------------------
Any HTTP-based testing system can be used with a running WSGI server, but some testing frameworks work more intimately with WSGI, and provide the ability the call WSGI applications in a controlled environment, with tracebacks and full use of debugging tools. `Testing tools for WSGI `_ is a good starting point.
Example using `WebTest `_ and `Nose `_::
from webtest import TestApp
import mywebapp
def test_functional_login_logout():
app = TestApp(mywebapp.app)
app.post('/login', {'user': 'foo', 'pass': 'bar'}) # log in and get a cookie
assert app.get('/admin').status == '200 OK' # fetch a page successfully
app.get('/logout') # log out
app.reset() # drop the cookie
# fetch the same page, unsuccessfully
assert app.get('/admin').status == '401 Unauthorized'
Embedding other WSGI Apps
--------------------------------------------------------------------------------
This is not the recommend way (you should use a middleware in front of bottle to do this) but you can call other WSGI applications from within your bottle app and let bottle act as a pseudo-middleware. Here is an example::
from bottle import request, response, route
subproject = SomeWSGIApplication()
@route('/subproject/:subpath#.*#', method='ANY')
def call_wsgi(subpath):
new_environ = request.environ.copy()
new_environ['SCRIPT_NAME'] = new_environ.get('SCRIPT_NAME','') + '/subproject'
new_environ['PATH_INFO'] = '/' + subpath
def start_response(status, headerlist):
response.status = int(status.split()[0])
for key, value in headerlist:
response.add_header(key, value)
return app(new_environ, start_response)
Again, this is not the recommend way to implement subprojects. It is only here because many people asked for this and to show how bottle maps to WSGI.
Ignore trailing slashes
--------------------------------------------------------------------------------
For Bottle, ``/example`` and ``/example/`` are two different routes [1]_. To treat both URLs the same you can add two ``@route`` decorators::
@route('/test')
@route('/test/')
def test(): return 'Slash? no?'
or add a WSGI middleware that strips trailing slashes from all URLs::
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.app()
myapp = StripPathMiddleware(app)
bottle.run(app=myapp)
.. rubric:: Footnotes
.. [1] Because they are. See
Keep-alive requests
-------------------
.. note::
For a more detailed explanation, see :doc:`async`.
Several "push" mechanisms like XHR multipart need the ability to write response data without closing the connection in conjunction with the response header "Connection: keep-alive". WSGI does not easily lend itself to this behavior, but it is still possible to do so in Bottle by using the gevent_ async framework. Here is a sample that works with either the gevent_ HTTP server or the paste_ HTTP server (it may work with others, but I have not tried). Just change ``server='gevent'`` to ``server='paste'`` to use the paste_ server::
from gevent import monkey; monkey.patch_all()
import time
from bottle import route, run
@route('/stream')
def stream():
yield 'START'
time.sleep(3)
yield 'MIDDLE'
time.sleep(5)
yield 'END'
run(host='0.0.0.0', port=8080, server='gevent')
If you browse to ``http://localhost:8080/stream``, you should see 'START', 'MIDDLE', and 'END' show up one at a time (rather than waiting 8 seconds to see them all at once).
Gzip Compression in Bottle
--------------------------
.. note::
For a detailed discussion, see compression_
A common feature request is for Bottle to support Gzip compression, which speeds up sites by compressing static resources (like CSS and JS files) during a request.
Supporting Gzip compression is not a straightforward proposition, due to a number of corner cases that crop up frequently. A proper Gzip implementation must:
* Compress on the fly and be fast doing so.
* Do not compress for browsers that don't support it.
* Do not compress files that are compressed already (images, videos).
* Do not compress dynamic files.
* Support two differed compression algorithms (gzip and deflate).
* Cache compressed files that don't change often.
* De-validate the cache if one of the files changed anyway.
* Make sure the cache does not get to big.
* Do not cache small files because a disk seek would take longer than on-the-fly compression.
Because of these requirements, it is the recommendation of the Bottle project that Gzip compression is best handled by the WSGI server Bottle runs on top of. WSGI servers such as cherrypy_ provide a GzipFilter_ middleware that can be used to accomplish this.
Using the hooks plugin
----------------------
For example, if you want to allow Cross-Origin Resource Sharing for
the content returned by all of your URL, you can use the hook
decorator and setup a callback function::
from bottle import hook, response, route
@hook('after_request')
def enable_cors():
response.headers['Access-Control-Allow-Origin'] = '*'
@route('/foo')
def say_foo():
return 'foo!'
@route('/bar')
def say_bar():
return {'type': 'friendly', 'content': 'Hi!'}
You can also use the ``before_request`` to take an action before
every function gets called.
Using Bottle with Heroku
------------------------
Heroku_, a popular cloud application platform now provides support
for running Python applications on their infastructure.
This recipe is based upon the `Heroku Quickstart
`_,
with Bottle specific code replacing the
`Write Your App `_
section of the `Getting Started with Python on Heroku/Cedar
`_ guide::
import os
from bottle import route, run
@route("/")
def hello_world():
return "Hello World!"
run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
Heroku's app stack passes the port that the application needs to
listen on for requests, using the `os.environ` dictionary.
bottle-0.12.7/docs/index.rst 0000755 0001750 0001750 00000006622 12327760172 014273 0 ustar fede fede .. highlight:: python
.. currentmodule:: bottle
.. _mako: http://www.makotemplates.org/
.. _cheetah: http://www.cheetahtemplate.org/
.. _jinja2: http://jinja.pocoo.org/
.. _paste: http://pythonpaste.org/
.. _fapws3: https://github.com/william-os4y/fapws3
.. _bjoern: https://github.com/jonashaag/bjoern
.. _flup: http://trac.saddi.com/flup
.. _cherrypy: http://www.cherrypy.org/
.. _WSGI: http://www.wsgi.org/
.. _Python: http://python.org/
.. _testing: https://github.com/defnull/bottle/raw/master/bottle.py
.. _issue_tracker: https://github.com/defnull/bottle/issues
.. _PyPI: http://pypi.python.org/pypi/bottle
============================
Bottle: Python Web Framework
============================
Bottle is a fast, simple and lightweight WSGI_ micro web-framework for Python_. It is distributed as a single file module and has no dependencies other than the `Python Standard Library `_.
* **Routing:** Requests to function-call mapping with support for clean and dynamic URLs.
* **Templates:** Fast and pythonic :ref:`built-in template engine ` and support for mako_, jinja2_ and cheetah_ templates.
* **Utilities:** Convenient access to form data, file uploads, cookies, headers and other HTTP-related metadata.
* **Server:** Built-in HTTP development server and support for paste_, fapws3_, bjoern_, `Google App Engine `_, cherrypy_ or any other WSGI_ capable HTTP server.
.. rubric:: Example: "Hello World" in a bottle
::
from bottle import route, run, template
@route('/hello/')
def index(name):
return template('Hello {{name}}!', name=name)
run(host='localhost', port=8080)
Run this script or paste it into a Python console, then point your browser to ``_. That's it.
.. rubric:: Download and Install
.. _download:
.. __: https://github.com/defnull/bottle/raw/master/bottle.py
Install the latest stable release via PyPI_ (``easy_install -U bottle``) or download `bottle.py`__ (unstable) into your project directory. There are no hard [1]_ dependencies other than the Python standard library. Bottle runs with **Python 2.5+ and 3.x**.
User's Guide
===============
Start here if you want to learn how to use the bottle framework for web development. If you have any questions not answered here, feel free to ask the `mailing list `_.
.. toctree::
:maxdepth: 2
tutorial
configuration
routing
stpl
api
plugins/index
Knowledge Base
==============
A collection of articles, guides and HOWTOs.
.. toctree::
:maxdepth: 2
tutorial_app
async
recipes
faq
Development and Contribution
============================
These chapters are intended for developers interested in the bottle development and release workflow.
.. toctree::
:maxdepth: 2
changelog
development
plugindev
.. toctree::
:hidden:
plugins/index
License
==================
Code and documentation are available according to the MIT License:
.. include:: ../LICENSE
:literal:
The Bottle logo however is *NOT* covered by that license. It is allowed to
use the logo as a link to the bottle homepage or in direct context with
the unmodified library. In all other cases please ask first.
.. rubric:: Footnotes
.. [1] Usage of the template or server adapter classes of course requires the corresponding template or server modules.
bottle-0.12.7/docs/api.rst 0000755 0001750 0001750 00000013023 12327760172 013726 0 ustar fede fede ==============================
API Reference
==============================
.. module:: bottle
:platform: Unix, Windows
:synopsis: WSGI micro framework
.. moduleauthor:: Marcel Hellkamp
This is a mostly auto-generated API. If you are new to bottle, you might find the
narrative :doc:`tutorial` more helpful.
Module Contents
=====================================
The module defines several functions, constants, and an exception.
.. autofunction:: debug
.. autofunction:: run
.. autofunction:: load
.. autofunction:: load_app
.. autodata:: request
.. autodata:: response
.. autodata:: HTTP_CODES
.. function:: app()
default_app()
Return the current :ref:`default-app`. Actually, these are callable instances of :class:`AppStack` and implement a stack-like API.
Routing
-------------------
Bottle maintains a stack of :class:`Bottle` instances (see :func:`app` and :class:`AppStack`) and uses the top of the stack as a *default application* for some of the module-level functions and decorators.
.. function:: route(path, method='GET', callback=None, **options)
get(...)
post(...)
put(...)
delete(...)
Decorator to install a route to the current default application. See :meth:`Bottle.route` for details.
.. function:: error(...)
Decorator to install an error handler to the current default application. See :meth:`Bottle.error` for details.
WSGI and HTTP Utilities
----------------------------
.. autofunction:: parse_date
.. autofunction:: parse_auth
.. autofunction:: cookie_encode
.. autofunction:: cookie_decode
.. autofunction:: cookie_is_encoded
.. autofunction:: yieldroutes
.. autofunction:: path_shift
Data Structures
----------------------
.. autoclass:: MultiDict
:members:
.. autoclass:: HeaderDict
:members:
.. autoclass:: FormsDict
:members:
.. autoclass:: WSGIHeaderDict
:members:
.. autoclass:: AppStack
:members:
.. method:: pop()
Return the current default application and remove it from the stack.
.. autoclass:: ResourceManager
:members:
.. autoclass:: FileUpload
:members:
Exceptions
---------------
.. autoexception:: BottleException
:members:
The :class:`Bottle` Class
=========================
.. autoclass:: Bottle
:members:
.. autoclass:: Route
:members:
The :class:`Request` Object
===================================================
The :class:`Request` class wraps a WSGI environment and provides helpful methods to parse and access form data, cookies, file uploads and other metadata. Most of the attributes are read-only.
.. autoclass:: Request
:members:
.. autoclass:: BaseRequest
:members:
The module-level :data:`bottle.request` is a proxy object (implemented in :class:`LocalRequest`) and always refers to the `current` request, or in other words, the request that is currently processed by the request handler in the current thread. This `thread locality` ensures that you can safely use a global instance in a multi-threaded environment.
.. autoclass:: LocalRequest
:members:
.. autodata:: request
The :class:`Response` Object
===================================================
The :class:`Response` class stores the HTTP status code as well as headers and cookies that are to be sent to the client. Similar to :data:`bottle.request` there is a thread-local :data:`bottle.response` instance that can be used to adjust the `current` response. Moreover, you can instantiate :class:`Response` and return it from your request handler. In this case, the custom instance overrules the headers and cookies defined in the global one.
.. autoclass:: Response
:members:
.. autoclass:: BaseResponse
:members:
.. autoclass:: LocalResponse
:members:
The following two classes can be raised as an exception. The most noticeable difference is that bottle invokes error handlers for :class:`HTTPError`, but not for :class:`HTTPResponse` or other response types.
.. autoexception:: HTTPResponse
:members:
.. autoexception:: HTTPError
:members:
Templates
=========
All template engines supported by :mod:`bottle` implement the :class:`BaseTemplate` API. This way it is possible to switch and mix template engines without changing the application code at all.
.. autoclass:: BaseTemplate
:members:
.. automethod:: __init__
.. autofunction:: view
.. autofunction:: template
You can write your own adapter for your favourite template engine or use one of the predefined adapters. Currently there are four fully supported template engines:
======================== =============================== ==================== ========================
Class URL Decorator Render function
======================== =============================== ==================== ========================
:class:`SimpleTemplate` :doc:`stpl` :func:`view` :func:`template`
:class:`MakoTemplate` http://www.makotemplates.org :func:`mako_view` :func:`mako_template`
:class:`CheetahTemplate` http://www.cheetahtemplate.org/ :func:`cheetah_view` :func:`cheetah_template`
:class:`Jinja2Template` http://jinja.pocoo.org/ :func:`jinja2_view` :func:`jinja2_template`
======================== =============================== ==================== ========================
To use :class:`MakoTemplate` as your default template engine, just import its specialised decorator and render function::
from bottle import mako_view as view, mako_template as template
bottle-0.12.7/docs/async.rst 0000644 0001750 0001750 00000020205 12327760172 014267 0 ustar fede fede Primer to Asynchronous Applications
===================================
Asynchronous design patterns don't mix well with the synchronous nature of `WSGI `_. This is why most asynchronous frameworks (tornado, twisted, ...) implement a specialized API to expose their asynchronous features. Bottle is a WSGI framework and shares the synchronous nature of WSGI, but thanks to the awesome `gevent project `_, it is still possible to write asynchronous applications with bottle. This article documents the usage of Bottle with Asynchronous WSGI.
The Limits of Synchronous WSGI
-------------------------------
Briefly worded, the `WSGI specification (pep 3333) `_ defines a request/response circle as follows: The application callable is invoked once for each request and must return a body iterator. The server then iterates over the body and writes each chunk to the socket. As soon as the body iterator is exhausted, the client connection is closed.
Simple enough, but there is a snag: All this happens synchronously. If your application needs to wait for data (IO, sockets, databases, ...), it must either yield empty strings (busy wait) or block the current thread. Both solutions occupy the handling thread and prevent it from answering new requests. There is consequently only one ongoing request per thread.
Most servers limit the number of threads to avoid their relatively high overhead. Pools of 20 or less threads are common. As soon as all threads are occupied, any new connection is stalled. The server is effectively dead for everyone else. If you want to implement a chat that uses long-polling ajax requests to get real-time updates, you'd reach the limited at 20 concurrent connections. That's a pretty small chat.
Greenlets to the rescue
------------------------
Most servers limit the size of their worker pools to a relatively low number of concurrent threads, due to the high overhead involved in switching between and creating new threads. While threads are cheap compared to processes (forks), they are still expensive to create for each new connection.
The `gevent `_ module adds *greenlets* to the mix. Greenlets behave similar to traditional threads, but are very cheap to create. A gevent-based server can spawn thousands of greenlets (one for each connection) with almost no overhead. Blocking individual greenlets has no impact on the servers ability to accept new requests. The number of concurrent connections is virtually unlimited.
This makes creating asynchronous applications incredibly easy, because they look and feel like synchronous applications. A gevent-based server is actually not asynchronous, but massively multi-threaded. Here is an example::
from gevent import monkey; monkey.patch_all()
from time import sleep
from bottle import route, run
@route('/stream')
def stream():
yield 'START'
sleep(3)
yield 'MIDDLE'
sleep(5)
yield 'END'
run(host='0.0.0.0', port=8080, server='gevent')
The first line is important. It causes gevent to monkey-patch most of Python's blocking APIs to not block the current thread, but pass the CPU to the next greenlet instead. It actually replaces Python's threading with gevent-based pseudo-threads. This is why you can still use ``time.sleep()`` which would normally block the whole thread. If you don't feel comfortable with monkey-patching python built-ins, you can use the corresponding gevent functions (``gevent.sleep()`` in this case).
If you run this script and point your browser to ``http://localhost:8080/stream``, you should see `START`, `MIDDLE`, and `END` show up one by one (rather than waiting 8 seconds to see them all at once). It works exactly as with normal threads, but now your server can handle thousands of concurrent requests without any problems.
.. note::
Some browsers buffer a certain amount of data before they start rendering a
page. You might need to yield more than a few bytes to see an effect in
these browsers. Additionally, many browsers have a limit of one concurrent
connection per URL. If this is the case, you can use a second browser or a
benchmark tool (e.g. `ab` or `httperf`) to measure performance.
Event Callbacks
---------------
A very common design pattern in asynchronous frameworks (including tornado, twisted, node.js and friends) is to use non-blocking APIs and bind callbacks to asynchronous events. The socket object is kept open until it is closed explicitly to allow callbacks to write to the socket at a later point. Here is an example based on the `tornado library `_::
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
worker = SomeAsyncWorker()
worker.on_data(lambda chunk: self.write(chunk))
worker.on_finish(lambda: self.finish())
The main benefit is that the request handler terminates early. The handling thread can move on and accept new requests while the callbacks continue to write to sockets of previous requests. This is how these frameworks manage to process a lot of concurrent requests with only a small number of OS threads.
With Gevent+WSGI, things are different: First, terminating early has no benefit because we have an unlimited pool of (pseudo)threads to accept new connections. Second, we cannot terminate early because that would close the socket (as required by WSGI). Third, we must return an iterable to conform to WSGI.
In order to conform to the WSGI standard, all we have to do is to return a body iterable that we can write to asynchronously. With the help of `gevent.queue `_, we can *simulate* a detached socket and rewrite the previous example as follows::
@route('/fetch')
def fetch():
body = gevent.queue.Queue()
worker = SomeAsyncWorker()
worker.on_data(body.put)
worker.on_finish(lambda: body.put(StopIteration))
worker.start()
return body
From the server perspective, the queue object is iterable. It blocks if empty and stops as soon as it reaches ``StopIteration``. This conforms to WSGI. On the application side, the queue object behaves like a non-blocking socket. You can write to it at any time, pass it around and even start a new (pseudo)thread that writes to it asynchronously. This is how long-polling is implemented most of the time.
Finally: WebSockets
-------------------
Lets forget about the low-level details for a while and speak about WebSockets. Since you are reading this article, you probably know what WebSockets are: A bidirectional communication channel between a browser (client) and a web application (server).
Thankfully the `gevent-websocket `_ package does all the hard work for us. Here is a simple WebSocket endpoint that receives messages and just sends them back to the client::
from bottle import request, Bottle, abort
app = Bottle()
@app.route('/websocket')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
while True:
try:
message = wsock.receive()
wsock.send("Your message was: %r" % message)
except WebSocketError:
break
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketHandler, WebSocketError
server = WSGIServer(("0.0.0.0", 8080), app,
handler_class=WebSocketHandler)
server.serve_forever()
The while-loop runs until the client closes the connection. You get the idea :)
The client-site JavaScript API is really straight forward, too::
bottle-0.12.7/docs/configuration.rst 0000644 0001750 0001750 00000014157 12327760172 016032 0 ustar fede fede =====================
Configuration (DRAFT)
=====================
.. currentmodule:: bottle
Bottle applications can store their configuration in :attr:`Bottle.config`, a dict-like object and central place for application specific settings. This dictionary controls many aspects of the framework, tells (newer) plugins what to do, and can be used to store your own configuration as well.
Configuration Basics
====================
The :attr:`Bottle.config` object behaves a lot like an ordinary dictionary. All the common dict methods work as expected. Let us start with some examples::
import bottle
app = bottle.default_app() # or bottle.Bottle() if you prefer
app.config['autojson'] = False # Turns off the "autojson" feature
app.config['sqlite.db'] = ':memory:' # Tells the sqlite plugin which db to use
app.config['myapp.param'] = 'value' # Example for a custom config value.
# Change many values at once
app.config.update({
'autojson': False,
'sqlite.db': ':memory:',
'myapp.param': 'value'
})
# Add default values
app.config.setdefault('myapp.param2', 'some default')
# Receive values
param = app.config['myapp.param']
param2 = app.config.get('myapp.param2', 'fallback value')
# An example route using configuration values
@app.route('/about', view='about.rst')
def about():
email = app.config.get('my.email', 'nomail@example.com')
return {'email': email}
The app object is not always available, but as long as you are within a request context, you can use the `request` object to get the current application and its configuration::
from bottle import request
def is_admin(user):
return user == request.app.config['myapp.admin_user']
Naming Convention
=================
To make life easier, plugins and applications should follow some simple rules when it comes to config parameter names:
- All keys should be lowercase strings and follow the rules for python identifiers (no special characters but the underscore).
- Namespaces are separated by dots (e.g. ``namespace.field`` or ``namespace.subnamespace.field``).
- Bottle uses the root namespace for its own configuration. Plugins should store all their variables in their own namespace (e.g. ``sqlite.db`` or ``werkzeug.use_debugger``).
- Your own application should use a separate namespace (e.g. ``myapp.*``).
Loading Configuration from a File
=================================
.. versionadded 0.12
Configuration files are useful if you want to enable non-programmers to configure your application,
or just don't want to hack python module files just to change the database port. A very common syntax for configuration files is shown here:
.. code-block:: ini
[bottle]
debug = True
[sqlite]
db = /tmp/test.db
commit = auto
[myapp]
admin_user = defnull
With :meth:`ConfigDict.load_config` you can load these ``*.ini`` style configuration
files from disk and import their values into your existing configuration::
app.config.load_config('/etc/myapp.conf')
Loading Configuration from a nested :class:`dict`
=================================================
.. versionadded 0.12
Another useful method is :meth:`ConfigDict.load_dict`. This method takes
an entire structure of nested dictionaries and turns it into a flat list of keys and values with namespaced keys::
# Load an entire dict structure
app.config.load_dict({
'autojson': False,
'sqlite': { 'db': ':memory:' },
'myapp': {
'param': 'value',
'param2': 'value2'
}
})
assert app.config['myapp.param'] == 'value'
# Load configuration from a json file
with open('/etc/myapp.json') as fp:
app.config.load_dict(json.load(fp))
Listening to configuration changes
==================================
.. versionadded 0.12
The ``config`` hook on the application object is triggered each time a value in :attr:`Bottle.config` is changed. This hook can be used to react on configuration changes at runtime, for example reconnect to a new database, change the debug settings on a background service or resize worker thread pools. The hook callback receives two arguments (key, new_value) and is called before the value is actually changed in the dictionary. Raising an exception from a hook callback cancels the change and the old value is preserved.
::
@app.hook('config')
def on_config_change(key, value):
if key == 'debug':
switch_own_debug_mode_to(value)
The hook callbacks cannot *change* the value that is to be stored to the dictionary. That is what filters are for.
.. conf-meta:
Filters and other Meta Data
===========================
.. versionadded 0.12
:class:`ConfigDict` allows you to store meta data along with configuration keys. Two meta fields are currently defined:
help
A help or description string. May be used by debugging, introspection or
admin tools to help the site maintainer configuring their application.
filter
A callable that accepts and returns a single value. If a filter is defined for a key, any new value stored to that key is first passed through the filter callback. The filter can be used to cast the value to a different type, check for invalid values (throw a ValueError) or trigger side effects.
This feature is most useful for plugins. They can validate their config parameters or trigger side effects using filters and document their configuration via ``help`` fields::
class SomePlugin(object):
def setup(app):
app.config.meta_set('some.int', 'filter', int)
app.config.meta_set('some.list', 'filter',
lambda val: str(val).split(';'))
app.config.meta_set('some.list', 'help',
'A semicolon separated list.')
def apply(self, callback, route):
...
import bottle
app = bottle.default_app()
app.install(SomePlugin())
app.config['some.list'] = 'a;b;c' # Actually stores ['a', 'b', 'c']
app.config['some.int'] = 'not an int' # raises ValueError
API Documentation
=================
.. versionadded 0.12
.. autoclass:: ConfigDict
:members:
bottle-0.12.7/docs/changelog.rst 0000755 0001750 0001750 00000020703 12327760172 015107 0 ustar fede fede .. highlight:: python
.. currentmodule:: bottle
===========================
Release Notes and Changelog
===========================
Release 0.12
==============
* New SimpleTemplate parser implementation
* Support for multi-line code blocks (`<% ... %>`).
* The keywords `include` and `rebase` are functions now and can accept variable template names.
* The new :meth:`BaseRequest.route` property returns the :class:`Route` that originally matched the request.
* Removed the ``BaseRequest.MAX_PARAMS`` limit. The hash collision bug in CPythons dict() implementation was fixed over a year ago. If you are still using Python 2.5 in production, consider upgrading or at least make sure that you get security fixed from your distributor.
* New :class:`ConfigDict` API (see :doc:`configuration`)
More information can be found in this `development blog post `_.
Release 0.11
==============
* Native support for Python 2.x and 3.x syntax. No need to run 2to3 anymore.
* Support for partial downloads (``Range`` header) in :func:`static_file`.
* The new :class:`ResourceManager` interface helps locating files bundled with an application.
* Added a server adapter for `waitress `_.
* New :meth:`Bottle.merge` method to install all routes from one application into another.
* New :attr:`BaseRequest.app` property to get the application object that handles a request.
* Added :meth:`FormsDict.decode()` to get an all-unicode version (needed by WTForms).
* :class:`MultiDict` and subclasses are now pickle-able.
.. rubric:: API Changes
* :attr:`Response.status` is a read-write property that can be assigned either a numeric status code or a status string with a reason phrase (``200 OK``). The return value is now a string to better match existing APIs (WebOb, werkzeug). To be absolutely clear, you can use the read-only properties :attr:`BaseResponse.status_code` and :attr:`BaseResponse.status_line`.
.. rubric:: API Deprecations
* :class:`SimpleTALTemplate` is now deprecating. There seems to be no demand.
Release 0.10
==============
* Plugin API v2
* To use the new API, set :attr:`Plugin.api` to ``2``.
* :meth:`Plugin.apply` receives a :class:`Route` object instead of a context dictionary as second parameter. The new object offers some additional information and may be extended in the future.
* Plugin names are considered unique now. The topmost plugin with a given name on a given route is installed, all other plugins with the same name are silently ignored.
* The Request/Response Objects
* Added :attr:`BaseRequest.json`, :attr:`BaseRequest.remote_route`, :attr:`BaseRequest.remote_addr`, :attr:`BaseRequest.query` and :attr:`BaseRequest.script_name`.
* Added :attr:`BaseResponse.status_line` and :attr:`BaseResponse.status_code` attributes. In future releases, :attr:`BaseResponse.status` will return a string (e.g. ``200 OK``) instead of an integer to match the API of other common frameworks. To make the transition as smooth as possible, you should use the verbose attributes from now on.
* Replaced :class:`MultiDict` with a specialized :class:`FormsDict` in many places. The new dict implementation allows attribute access and handles unicode form values transparently.
* Templates
* Added three new functions to the SimpleTemplate default namespace that handle undefined variables: :func:`stpl.defined`, :func:`stpl.get` and :func:`stpl.setdefault`.
* The default escape function for SimpleTemplate now additionally escapes single and double quotes.
* Routing
* A new route syntax (e.g. ``/object/``) and support for route wildcard filters.
* Four new wildcard filters: `int`, `float`, `path` and `re`.
* Other changes
* Added command line interface to load applications and start servers.
* Introduced a :class:`ConfigDict` that makes accessing configuration a lot easier (attribute access and auto-expanding namespaces).
* Added support for raw WSGI applications to :meth:`Bottle.mount`.
* :meth:`Bottle.mount` parameter order changed.
* :meth:`Bottle.route` now accpets an import string for the ``callback`` parameter.
* Dropped Gunicorn 0.8 support. Current supported version is 0.13.
* Added custom options to Gunicorn server.
* Finally dropped support for type filters. Replace with a custom plugin of needed.
Release 0.9
============
.. rubric:: Whats new?
* A brand new plugin-API. See :ref:`plugins` and :doc:`plugindev` for details.
* The :func:`route` decorator got a lot of new features. See :meth:`Bottle.route` for details.
* New server adapters for `gevent `_, `meinheld `_ and `bjoern `_.
* Support for SimpleTAL templates.
* Better runtime exception handling for mako templates in debug mode.
* Lots of documentation, fixes and small improvements.
* A new :data:`Request.urlparts` property.
.. rubric:: Performance improvements
* The :class:`Router` now special-cases ``wsgi.run_once`` environments to speed up CGI.
* Reduced module load time by ~30% and optimized template parser. See `8ccb2d `_, `f72a7c `_ and `b14b9a `_ for details.
* Support for "App Caching" on Google App Engine. See `af93ec `_.
* Some of the rarely used or deprecated features are now plugins that avoid overhead if the feature is not used.
.. rubric:: API changes
This release is mostly backward compatible, but some APIs are marked deprecated now and will be removed for the next release. Most noteworthy:
* The ``static`` route parameter is deprecated. You can escape wild-cards with a backslash.
* Type-based output filters are deprecated. They can easily be replaced with plugins.
Release 0.8
============
.. rubric:: API changes
These changes may break compatibility with previous versions.
* The built-in Key/Value database is not available anymore. It is marked deprecated since 0.6.4
* The Route syntax and behaviour changed.
* Regular expressions must be encapsulated with ``#``. In 0.6 all non-alphanumeric characters not present in the regular expression were allowed.
* Regular expressions not part of a route wildcard are escaped automatically. You don't have to escape dots or other regular control characters anymore. In 0.6 the whole URL was interpreted as a regular expression. You can use anonymous wildcards (``/index:#(\.html)?#``) to achieve a similar behaviour.
* The ``BreakTheBottle`` exception is gone. Use :class:`HTTPResponse` instead.
* The :class:`SimpleTemplate` engine escapes HTML special characters in ``{{bad_html}}`` expressions automatically. Use the new ``{{!good_html}}`` syntax to get old behaviour (no escaping).
* The :class:`SimpleTemplate` engine returns unicode strings instead of lists of byte strings.
* ``bottle.optimize()`` and the automatic route optimization is obsolete.
* Some functions and attributes were renamed:
* :attr:`Request._environ` is now :attr:`Request.environ`
* :attr:`Response.header` is now :attr:`Response.headers`
* :func:`default_app` is obsolete. Use :func:`app` instead.
* The default :func:`redirect` code changed from 307 to 303.
* Removed support for ``@default``. Use ``@error(404)`` instead.
.. rubric:: New features
This is an incomplete list of new features and improved functionality.
* The :class:`Request` object got new properties: :attr:`Request.body`, :attr:`Request.auth`, :attr:`Request.url`, :attr:`Request.header`, :attr:`Request.forms`, :attr:`Request.files`.
* The :meth:`Response.set_cookie` and :meth:`Request.get_cookie` methods are now able to encode and decode python objects. This is called a *secure cookie* because the encoded values are signed and protected from changes on client side. All pickle-able data structures are allowed.
* The new :class:`Router` class drastically improves performance for setups with lots of dynamic routes and supports named routes (named route + dict = URL string).
* It is now possible (and recommended) to return :exc:`HTTPError` and :exc:`HTTPResponse` instances or other exception objects instead of raising them.
* The new function :func:`static_file` equals :func:`send_file` but returns a :exc:`HTTPResponse` or :exc:`HTTPError` instead of raising it. :func:`send_file` is deprecated.
* New :func:`get`, :func:`post`, :func:`put` and :func:`delete` decorators.
* The :class:`SimpleTemplate` engine got full unicode support.
* Lots of non-critical bugfixes.
============
Contributors
============
.. include:: ../AUTHORS
bottle-0.12.7/docs/conf.py 0000644 0001750 0001750 00000001311 12327760172 013714 0 ustar fede fede # -*- coding: utf-8 -*-
import sys, os, time
bottle_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),'../'))
sys.path.insert(0, bottle_dir)
import bottle
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode']
master_doc = 'index'
project = u'Bottle'
copyright = u'2009-%s, %s' % (time.strftime('%Y'), bottle.__author__)
version = ".".join(bottle.__version__.split(".")[:2])
release = bottle.__version__
add_function_parentheses = True
add_module_names = False
pygments_style = 'sphinx'
intersphinx_mapping = {'python': ('http://docs.python.org/', None),
'werkzeug': ('http://werkzeug.pocoo.org/docs/', None)}
autodoc_member_order = 'bysource'
bottle-0.12.7/docs/_locale/ 0000755 0001750 0001750 00000000000 12327760172 014017 5 ustar fede fede bottle-0.12.7/docs/_locale/README.txt 0000644 0001750 0001750 00000001174 12327760172 015520 0 ustar fede fede ======================
Requirements and Setup
======================
You need python-sphinx (pip install sphinx) and gettext (for msgmerge and msgfmt).
A translation file editor (e.g. poedit) helps a lot.
Translation Workflow
====================
Run docs/_locale/update.sh before and after editing *.po files to merge new
sentences and check for errors.
Do not add *.mo files to the repository, even if your editor creates them.
We only need the *.po files.
Add a new language
==================
Add your language (two-letter code) to 'update.sh' and run it. A new
two-letter directory will appear with all the *.po files in it.
bottle-0.12.7/docs/_locale/zh_CN/ 0000755 0001750 0001750 00000000000 12327760172 015020 5 ustar fede fede bottle-0.12.7/docs/_locale/zh_CN/contact.po 0000644 0001750 0001750 00000005457 12327760172 017026 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-11-09 18:23\n"
"PO-Revision-Date: 2012-11-09 15:38+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# f4707b618d7b443f85b8f842370cb1e1
#: ../../contact.rst:3
msgid "Contact"
msgstr "联系方式"
# d122ed5151f54e3489fad9c7753f799f
#: ../../contact.rst:6
msgid "About the Autor"
msgstr ""
# 7e41b0691bdb4e19b2b09ecafeac593b
#: ../../contact.rst:11
msgid ""
"Hi, I'm *Marcel Hellkamp* (aka *defnull*), author of Bottle and the guy "
"behind this website. I'm 27 years old and studying computer science at the "
"Georg-August-University in Göttingen, Germany. Python is my favorite "
"language, but I also code in ruby and JavaScript a lot. Watch me on `twitter "
"`_ or visit my profile at `GitHub `_ to get in contact. A `mailinglist `_ is open for Bottle related questions, too."
msgstr ""
# 5f6e942bf2fe4511802f58da1e762996
#: ../../contact.rst:14
msgid "About Bottle"
msgstr ""
# dddfc8ac04dc4b6fa9919ae61b2b0542
#: ../../contact.rst:15
msgid ""
"This is my first open source project so far. It started and a small "
"experiment but soon got so much positive feedback I decided to make "
"something real out of it. Here it is."
msgstr ""
# 37534297e1d145afbd8687385d35769e
#: ../../contact.rst:18
msgid "Impressum und Kontaktdaten"
msgstr ""
# 0b2be9f1bbe149b59b5218ba0bab3657
#: ../../contact.rst:19
msgid ""
"(This is required by `German law `_)"
msgstr ""
# bb4cda2c571e4d4d9f95c83dea349a44
#: ../../contact.rst:21
msgid ""
"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."
msgstr ""
# a68aba235abf46ad9da80f849585f0a0
#: ../../contact.rst:26
msgid "**Betreiber**: Marcel Hellkamp"
msgstr ""
# d89eb5fcd19a4cb897d2b83b6d00e97a
#: ../../contact.rst:27
msgid "**Ort**: D - 37075 Göttingen"
msgstr ""
# 05e1a92f52fb43a3a654c82a21f6c651
#: ../../contact.rst:28
msgid "**Strasse**: Theodor-Heuss Strasse 13"
msgstr ""
# 6c28fcf7c51e406f8049b547b9c4d439
#: ../../contact.rst:29
msgid "**Telefon**: +49 (0) 551 20005915"
msgstr ""
# c53635e76e854d45870d9ae45b9c124f
#: ../../contact.rst:30
msgid "**E-Mail**: marc at gsites dot de"
msgstr ""
bottle-0.12.7/docs/_locale/zh_CN/changelog.po 0000644 0001750 0001750 00000051717 12327760172 017322 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-09 17:22\n"
"PO-Revision-Date: 2012-11-09 16:39+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# e3b13e4c346c4c4987654e4efa0d199b
#: ../../changelog.rst:6
msgid "Release Notes and Changelog"
msgstr "发布摘要和更改历史(不译)"
# 5ecfd3788a134d88916d9e28aac8ad2e
#: ../../changelog.rst:11
msgid "Release 0.12"
msgstr ""
# 5e23fcb10b5f47fda6e625beec56df44
#: ../../changelog.rst:15
msgid ""
"New SimpleTemplate parser implementation * Support for multi-line code "
"blocks (`<% ... %>`). * The keywords `include` and `rebase` are functions "
"now and can accept variable template names."
msgstr ""
# a109362aa7f44d64adb92bb0b9823353
#: ../../changelog.rst:18
msgid ""
"The new :meth:`BaseRequest.route` property returns the :class:`Route` that "
"matched the request."
msgstr ""
# a97673c7116a4c3b8743eebe4b2d5a3e
#: ../../changelog.rst:21
msgid "Release 0.11"
msgstr ""
# 6731700ec87a44e788d995610cedd01c
#: ../../changelog.rst:25
msgid ""
"Native support for Python 2.x and 3.x syntax. No need to run 2to3 anymore."
msgstr ""
# 6b9ce1b8ed83434ab1f16a966e20e8f9
#: ../../changelog.rst:26
msgid ""
"Support for partial downloads (``Range`` header) in :func:`static_file`."
msgstr ""
# e5bb007545f84215afaeabbf80c32589
#: ../../changelog.rst:27
msgid ""
"The new :class:`ResourceManager` interface helps locating files bundled with "
"an application."
msgstr ""
# db95b112ec664973b25c1651b6b599d0
#: ../../changelog.rst:28
msgid ""
"Added a server adapter for `waitress `_."
msgstr ""
# f5b8dfb81e8446ac8133d757d683d667
#: ../../changelog.rst:29
msgid ""
"New :meth:`Bottle.merge` method to install all routes from one application "
"into another."
msgstr ""
# a109362aa7f44d64adb92bb0b9823353
#: ../../changelog.rst:30
msgid ""
"New :attr:`BaseRequest.app` property to get the application object that "
"handles a request."
msgstr ""
# 6b57a33990c64361b1ad2db50f53b000
#: ../../changelog.rst:31
msgid ""
"Added :meth:`FormsDict.decode()` to get an all-unicode version (needed by "
"WTForms)."
msgstr ""
# c20daa7d47b54d8a822c0bf71decf822
#: ../../changelog.rst:32
msgid ":class:`MultiDict` and subclasses are now pickle-able."
msgstr ""
# e86dad3a34f6465c89f5637165bc312c
#: ../../changelog.rst:35
msgid "API Changes"
msgstr ""
# 73bb02534f0b49ec9c08de53ccbd60a8
#: ../../changelog.rst:36
msgid ""
":attr:`Response.status` is a read-write property that can be assigned either "
"a numeric status code or a status string with a reason phrase (``200 OK``). "
"The return value is now a string to better match existing APIs (WebOb, "
"werkzeug). To be absolutely clear, you can use the read-only properties :"
"attr:`BaseResponse.status_code` and :attr:`BaseResponse.status_line`."
msgstr ""
# 5772862eb6624e688fbc4af59dd1988c
#: ../../changelog.rst:39
msgid "API Deprecations"
msgstr ""
# b4e888031c9e4efabda02834f1f21867
#: ../../changelog.rst:40
msgid ""
":class:`SimpleTALTemplate` is now deprecating. There seems to be no demand."
msgstr ""
# 44359592bf86402aa2d88d227a948cff
#: ../../changelog.rst:43
msgid "Release 0.10"
msgstr ""
# 4dec1a937025421dbc41cc67f1f57bf5
#: ../../changelog.rst:45
msgid "Plugin API v2"
msgstr ""
# a23578035d494816ab995e2fea0cc4a8
#: ../../changelog.rst:47
msgid "To use the new API, set :attr:`Plugin.api` to ``2``."
msgstr ""
# 9b6f06b4607c4a83b128c436635c0e7b
#: ../../changelog.rst:48
msgid ""
":meth:`Plugin.apply` receives a :class:`Route` object instead of a context "
"dictionary as second parameter. The new object offers some additional "
"information and may be extended in the future."
msgstr ""
# 736de72390b847b0b094c61446e3b83d
#: ../../changelog.rst:49
msgid ""
"Plugin names are considered unique now. The topmost plugin with a given name "
"on a given route is installed, all other plugins with the same name are "
"silently ignored."
msgstr ""
# 065c1f375b0d47f8a8851d6df581722c
#: ../../changelog.rst:51
msgid "The Request/Response Objects"
msgstr ""
# 566c0eab00e54295939eef631f59d2f8
#: ../../changelog.rst:53
msgid ""
"Added :attr:`BaseRequest.json`, :attr:`BaseRequest.remote_route`, :attr:"
"`BaseRequest.remote_addr`, :attr:`BaseRequest.query` and :attr:`BaseRequest."
"script_name`."
msgstr ""
# c830c4ee4ad848f1b1f205ed53e05870
#: ../../changelog.rst:54
msgid ""
"Added :attr:`BaseResponse.status_line` and :attr:`BaseResponse.status_code` "
"attributes. In future releases, :attr:`BaseResponse.status` will return a "
"string (e.g. ``200 OK``) instead of an integer to match the API of other "
"common frameworks. To make the transition as smooth as possible, you should "
"use the verbose attributes from now on."
msgstr ""
# 45f4cc97a9fc4d4c88ede6131214b378
#: ../../changelog.rst:55
msgid ""
"Replaced :class:`MultiDict` with a specialized :class:`FormsDict` in many "
"places. The new dict implementation allows attribute access and handles "
"unicode form values transparently."
msgstr ""
# 9ed871a4ef814b268c9e32e6a0a98493
#: ../../changelog.rst:57
msgid "Templates"
msgstr ""
# 55e66477c8414856a940b14cc9fbf01f
#: ../../changelog.rst:59
msgid ""
"Added three new functions to the SimpleTemplate default namespace that "
"handle undefined variables: :func:`stpl.defined`, :func:`stpl.get` and :func:"
"`stpl.setdefault`."
msgstr ""
# 6231999b3223400281c6f121c3ec9539
#: ../../changelog.rst:60
msgid ""
"The default escape function for SimpleTemplate now additionally escapes "
"single and double quotes."
msgstr ""
# d5da0048d0e54adcbf4a6eca77d24b03
#: ../../changelog.rst:62
msgid "Routing"
msgstr ""
# 4f100bf5c0244f6b844b9c80458afd78
#: ../../changelog.rst:64
msgid ""
"A new route syntax (e.g. ``/object/``) and support for route "
"wildcard filters."
msgstr ""
# 76bf73f4d1154f699127453d3305cf41
#: ../../changelog.rst:65
msgid "Four new wildcard filters: `int`, `float`, `path` and `re`."
msgstr ""
# 453b79ee2f6847459a473af285884aa7
#: ../../changelog.rst:67
msgid "Other changes"
msgstr ""
# 4e05013ef2554d89b298d321a0c130bf
#: ../../changelog.rst:69
msgid "Added command line interface to load applications and start servers."
msgstr ""
# 0d60ba54697545d6b867c274f4d05833
#: ../../changelog.rst:70
msgid ""
"Introduced a :class:`ConfigDict` that makes accessing configuration a lot "
"easier (attribute access and auto-expanding namespaces)."
msgstr ""
# 124fc7cd3d784edc8c2a4cd522393e85
#: ../../changelog.rst:71
msgid "Added support for raw WSGI applications to :meth:`Bottle.mount`."
msgstr ""
# 83811d6a04d544c18508b3dd75c18391
#: ../../changelog.rst:72
msgid ":meth:`Bottle.mount` parameter order changed."
msgstr ""
# 85e4e2d1c2c2476ca6125a5f4cfb467c
#: ../../changelog.rst:73
msgid ""
":meth:`Bottle.route` now accpets an import string for the ``callback`` "
"parameter."
msgstr ""
# 824284a34edd4f99ad16418c4ab77790
#: ../../changelog.rst:74
msgid "Dropped Gunicorn 0.8 support. Current supported version is 0.13."
msgstr ""
# 8ff0d29768f34cf3b525c2330139e146
#: ../../changelog.rst:75
msgid "Added custom options to Gunicorn server."
msgstr ""
# 9deeaef2ec5a4b7a803c705792b9dda8
#: ../../changelog.rst:76
msgid ""
"Finally dropped support for type filters. Replace with a custom plugin of "
"needed."
msgstr ""
# 4f1fed330d1d47168ae311e0e3a8f8ac
#: ../../changelog.rst:80
msgid "Release 0.9"
msgstr ""
# d5d0f375fb4749a69c9403412a7eb5ae
#: ../../changelog.rst:83
msgid "Whats new?"
msgstr ""
# 8b8a0a81954b4ba1b74a6ee31ca3a53c
#: ../../changelog.rst:84
msgid ""
"A brand new plugin-API. See :ref:`plugins` and :doc:`plugindev` for details."
msgstr ""
# 7507729af5ec4cb88c6e5cf549cc93e3
#: ../../changelog.rst:85
msgid ""
"The :func:`route` decorator got a lot of new features. See :meth:`Bottle."
"route` for details."
msgstr ""
# 207cf445fdd34b639c2ae07ac6a85090
#: ../../changelog.rst:86
msgid ""
"New server adapters for `gevent `_, `meinheld "
"`_ and `bjoern `_."
msgstr ""
# daa55ce0e10f45d183c1b365dc2ccba0
#: ../../changelog.rst:87
msgid "Support for SimpleTAL templates."
msgstr ""
# 1905b888cb7b4a1b9d3ebe3c0ef7a66f
#: ../../changelog.rst:88
msgid "Better runtime exception handling for mako templates in debug mode."
msgstr ""
# 9a81aa701ae24a6aa4a26e0aa3567d32
#: ../../changelog.rst:89
msgid "Lots of documentation, fixes and small improvements."
msgstr ""
# 4321fbe631844b8d84ca43fad60e8b27
#: ../../changelog.rst:90
msgid "A new :data:`Request.urlparts` property."
msgstr ""
# 4e839c60c903480690fd424f143c3757
#: ../../changelog.rst:93
msgid "Performance improvements"
msgstr ""
# 85fe44152baa4daca39a7b1e93c00ad4
#: ../../changelog.rst:94
msgid ""
"The :class:`Router` now special-cases ``wsgi.run_once`` environments to "
"speed up CGI."
msgstr ""
# b909340087724797bd7bf31da068edaa
#: ../../changelog.rst:95
msgid ""
"Reduced module load time by ~30% and optimized template parser. See `8ccb2d "
"`_, `f72a7c `_ and `b14b9a `_ for details."
msgstr ""
# 72e73bff954c4217a09e2401bac9674c
#: ../../changelog.rst:96
msgid ""
"Support for \"App Caching\" on Google App Engine. See `af93ec `_."
msgstr ""
# d9923a5832b142f6afaa67f61a3d3fcf
#: ../../changelog.rst:97
msgid ""
"Some of the rarely used or deprecated features are now plugins that avoid "
"overhead if the feature is not used."
msgstr ""
# 1139037ba4c74e8dbacb963e86b1734a
# 70b7ae6d681745ec8f6d7bae78a2d9b3
#: ../../changelog.rst:100 ../../changelog.rst:111
msgid "API changes"
msgstr ""
# 7a0ea9dcf798416e8870410cf7c67aef
#: ../../changelog.rst:101
msgid ""
"This release is mostly backward compatible, but some APIs are marked "
"deprecated now and will be removed for the next release. Most noteworthy:"
msgstr ""
# 5e21a9d02a434dd582e322125054fd88
#: ../../changelog.rst:103
msgid ""
"The ``static`` route parameter is deprecated. You can escape wild-cards with "
"a backslash."
msgstr ""
# 1b6da094ff5d4e7f9aa311c9b7b3491b
#: ../../changelog.rst:104
msgid ""
"Type-based output filters are deprecated. They can easily be replaced with "
"plugins."
msgstr ""
# b0f7b728309c4b7690e2e4225a4b8a2e
#: ../../changelog.rst:108
msgid "Release 0.8"
msgstr ""
# 5c282c9843094792a4307b3034967be9
#: ../../changelog.rst:112
msgid "These changes may break compatibility with previous versions."
msgstr ""
# 684f663e070f4b09b48180ca47839c75
#: ../../changelog.rst:114
msgid ""
"The built-in Key/Value database is not available anymore. It is marked "
"deprecated since 0.6.4"
msgstr ""
# ab818cf68d8a4e9ba07ffbabfd3339de
#: ../../changelog.rst:115
msgid "The Route syntax and behaviour changed."
msgstr ""
# 1e6b6b4d1d3a42a09840dd65a3329a8f
#: ../../changelog.rst:117
msgid ""
"Regular expressions must be encapsulated with ``#``. In 0.6 all non-"
"alphanumeric characters not present in the regular expression were allowed."
msgstr ""
# 71c8af4451404191b1f0d4cbe8c5e4ec
#: ../../changelog.rst:118
msgid ""
"Regular expressions not part of a route wildcard are escaped automatically. "
"You don't have to escape dots or other regular control characters anymore. "
"In 0.6 the whole URL was interpreted as a regular expression. You can use "
"anonymous wildcards (``/index:#(\\.html)?#``) to achieve a similar behaviour."
msgstr ""
# 27f16af5e0ca47a5a555d1b193780839
#: ../../changelog.rst:120
msgid ""
"The ``BreakTheBottle`` exception is gone. Use :class:`HTTPResponse` instead."
msgstr ""
# a4d29013e8bd4e0d8ab3a69f2d215b0c
#: ../../changelog.rst:121
msgid ""
"The :class:`SimpleTemplate` engine escapes HTML special characters in "
"``{{bad_html}}`` expressions automatically. Use the new ``{{!good_html}}`` "
"syntax to get old behaviour (no escaping)."
msgstr ""
# 0ca575ecd26446f981bedadf96ca4075
#: ../../changelog.rst:122
msgid ""
"The :class:`SimpleTemplate` engine returns unicode strings instead of lists "
"of byte strings."
msgstr ""
# 44edac6789ef4e09a8ce012c161b5143
#: ../../changelog.rst:123
msgid "``bottle.optimize()`` and the automatic route optimization is obsolete."
msgstr ""
# 9d76cc1eee7d4ffc8856e7cc36b03afb
#: ../../changelog.rst:124
msgid "Some functions and attributes were renamed:"
msgstr ""
# 2476d07cfb614c1589d293b030ead391
#: ../../changelog.rst:126
msgid ":attr:`Request._environ` is now :attr:`Request.environ`"
msgstr ""
# 078eea95ecef4111a9c366da245647bb
#: ../../changelog.rst:127
msgid ":attr:`Response.header` is now :attr:`Response.headers`"
msgstr ""
# 521c767a85e748848aa22a37b85824b0
#: ../../changelog.rst:128
msgid ":func:`default_app` is obsolete. Use :func:`app` instead."
msgstr ""
# c06f82820b6647a69b2ba0a5bf7fc709
#: ../../changelog.rst:130
msgid "The default :func:`redirect` code changed from 307 to 303."
msgstr ""
# 023b03a59c374d43b8abfd0b2c67985a
#: ../../changelog.rst:131
msgid "Removed support for ``@default``. Use ``@error(404)`` instead."
msgstr ""
# 0f3f04e5fb1f4e8abddb03e2420cbdfe
#: ../../changelog.rst:135
msgid "New features"
msgstr ""
# 68ec57e76d7c464fa97c2adb8fa7782a
#: ../../changelog.rst:136
msgid "This is an incomplete list of new features and improved functionality."
msgstr ""
# a371732ab6744c0f9dfa6d9ac04e5f83
#: ../../changelog.rst:138
msgid ""
"The :class:`Request` object got new properties: :attr:`Request.body`, :attr:"
"`Request.auth`, :attr:`Request.url`, :attr:`Request.header`, :attr:`Request."
"forms`, :attr:`Request.files`."
msgstr ""
# c21e44bb8b464528ac46f154770df091
#: ../../changelog.rst:139
msgid ""
"The :meth:`Response.set_cookie` and :meth:`Request.get_cookie` methods are "
"now able to encode and decode python objects. This is called a *secure "
"cookie* because the encoded values are signed and protected from changes on "
"client side. All pickle-able data structures are allowed."
msgstr ""
# a87aa779e91b44ca985910e27559bb56
#: ../../changelog.rst:140
msgid ""
"The new :class:`Router` class drastically improves performance for setups "
"with lots of dynamic routes and supports named routes (named route + dict = "
"URL string)."
msgstr ""
# 3dcf1f0ad1684a1bbeec83c1432f51cc
#: ../../changelog.rst:141
msgid ""
"It is now possible (and recommended) to return :exc:`HTTPError` and :exc:"
"`HTTPResponse` instances or other exception objects instead of raising them."
msgstr ""
# 5bbedf45b10e4286a457b982a9be595f
#: ../../changelog.rst:142
msgid ""
"The new function :func:`static_file` equals :func:`send_file` but returns a :"
"exc:`HTTPResponse` or :exc:`HTTPError` instead of raising it. :func:"
"`send_file` is deprecated."
msgstr ""
# a25f7ad0c1c94ddaa447da64fe73c796
#: ../../changelog.rst:143
msgid ""
"New :func:`get`, :func:`post`, :func:`put` and :func:`delete` decorators."
msgstr ""
# 569fa16a63714dddb16fe9d53f06dec4
#: ../../changelog.rst:144
msgid "The :class:`SimpleTemplate` engine got full unicode support."
msgstr ""
# 981b75a9f823425cb1ad7f074d56570d
#: ../../changelog.rst:145
msgid "Lots of non-critical bugfixes."
msgstr ""
# 29d64452b9d54e018ffb4749c7a406cf
#: ../../changelog.rst:151
msgid "Contributors"
msgstr ""
# 3d3c594c340c4de0bff6b459a58406ba
#: ../../../AUTHORS:1
msgid ""
"Bottle is written and maintained by Marcel Hellkamp ."
msgstr ""
# 54e9ee881fd6495c8b23f616e0406769
#: ../../../AUTHORS:3
msgid ""
"Thanks to all the people who found bugs, sent patches, spread the word, "
"helped each other on the mailing-list and made this project possible. I hope "
"the following (alphabetically sorted) list is complete. If you miss your "
"name on that list (or want your name removed) please :doc:`tell me "
"` or add it yourself."
msgstr ""
# 0980c1626a8447c6b813c2829f9677ad
#: ../../../AUTHORS:5
msgid "acasajus"
msgstr ""
# 7e09ffa00aa947148c0011dd33888fd9
#: ../../../AUTHORS:6
msgid "Adam R. Smith"
msgstr ""
# 6eb2f1d5d1a34670a4d411d0d58af6f8
#: ../../../AUTHORS:7
msgid "Alexey Borzenkov"
msgstr ""
# c0ef5ea8c83d4cb481e49273f090b7bd
#: ../../../AUTHORS:8
msgid "Alexis Daboville"
msgstr ""
# 7a83e67a90b54ba19296f5691f497f5a
#: ../../../AUTHORS:9
msgid "Anton I. Sipos"
msgstr ""
# cf41f70b82454d2f900cd67c7bf4859f
#: ../../../AUTHORS:10
msgid "Anton Kolechkin"
msgstr ""
# aaff5287411f4076b41c503b294423c3
#: ../../../AUTHORS:11
msgid "apexi200sx"
msgstr ""
# e1981576d3064a1d9fd0ee7d6c83c116
#: ../../../AUTHORS:12
msgid "apheage"
msgstr ""
# c83c4dcc9ddf44918a4d7b3f849e6920
#: ../../../AUTHORS:13
msgid "BillMa"
msgstr ""
# bdaa82d9c0fd4bffaef7c55e3e32bed5
#: ../../../AUTHORS:14
msgid "Brad Greenlee"
msgstr ""
# ed51155ae7f14b5f92c925d5fa8311f7
#: ../../../AUTHORS:15
msgid "Brandon Gilmore"
msgstr ""
# d0e6c599c71343b69cbdb40252364e19
#: ../../../AUTHORS:16
msgid "Branko Vukelic"
msgstr ""
# 703a026e74a64faabfa4b504272b57f5
#: ../../../AUTHORS:17
msgid "Brian Sierakowski"
msgstr ""
# b58c5a07eeb840e19be4f380d66a5ee1
#: ../../../AUTHORS:18
msgid "Brian Wickman"
msgstr ""
# 12879f4bf9bd460d94519f3cd9885b11
#: ../../../AUTHORS:19
msgid "Carl Scharenberg"
msgstr ""
# bb0bb95e445143288452a8c513af8769
#: ../../../AUTHORS:20
msgid "Damien Degois"
msgstr ""
# d8f9bba29e0e42e6bdda59792350c6fb
#: ../../../AUTHORS:21
msgid "David Buxton"
msgstr ""
# cc4e0bd070384814ba6f7f676379dfe9
#: ../../../AUTHORS:22
msgid "Duane Johnson"
msgstr ""
# 2532fe296cb54e65bcb3b922af4c3fe1
#: ../../../AUTHORS:23
msgid "fcamel"
msgstr ""
# 5c9cc99c634746e5997832a08952b471
#: ../../../AUTHORS:24
msgid "Frank Murphy"
msgstr ""
# 68194afa7d5c4ac3aa6a1922a3e209ef
#: ../../../AUTHORS:25
msgid "Frederic Junod"
msgstr ""
# 7adefaece3f649b88f4f55201e0f7ba7
#: ../../../AUTHORS:26
msgid "goldfaber3012"
msgstr ""
# b5d811568c4943499f00e1204087f181
#: ../../../AUTHORS:27
msgid "Greg Milby"
msgstr ""
# 41816fb927c74b3c87a99e7df2117d32
#: ../../../AUTHORS:28
msgid "gstein"
msgstr ""
# 2095ce633cc84e539d6b82bf8a62eb37
#: ../../../AUTHORS:29
msgid "Ian Davis"
msgstr ""
# d364ee9c173244829fcd7ed5a11025e4
#: ../../../AUTHORS:30
msgid "Itamar Nabriski"
msgstr ""
# 74d0129175cf4e6fbd34675523a82c70
#: ../../../AUTHORS:31
msgid "Iuri de Silvio"
msgstr ""
# 87f66bf393c44d08ae2d268ba591339c
#: ../../../AUTHORS:32
msgid "Jaimie Murdock"
msgstr ""
# c55c4c1c4b81437b8cfdff60bd0c1f31
#: ../../../AUTHORS:33
msgid "Jeff Nichols"
msgstr ""
# 0c2886a875204f7c8defe46bdedcbdb6
#: ../../../AUTHORS:34
msgid "Jeremy Kelley"
msgstr ""
# 988c4fb0e4854b8d923228060aee7433
#: ../../../AUTHORS:35
msgid "joegester"
msgstr ""
# 46ef0c492f5e4241bcb7fd2ebb6b4566
#: ../../../AUTHORS:36
msgid "Johannes Krampf"
msgstr ""
# 4783b01715ac4923b56fc45a2702dfe0
#: ../../../AUTHORS:37
msgid "Jonas Haag"
msgstr ""
# d306e7acdea84aacbe0ba7a3a15d192a
#: ../../../AUTHORS:38
msgid "Joshua Roesslein"
msgstr ""
# b7c3438ca6b3409fad9c56521b6829fb
#: ../../../AUTHORS:39
msgid "Karl"
msgstr ""
# 16e8c8a3acd941df86d72027380dfb04
#: ../../../AUTHORS:40
msgid "Kevin Zuber"
msgstr ""
# dd30a7419cdb43e8a3b3d7df3284674c
#: ../../../AUTHORS:41
msgid "Kraken"
msgstr ""
# a8b48d487cc8410baf152e2fb6d4fb01
#: ../../../AUTHORS:42
msgid "Kyle Fritz"
msgstr ""
# c681593665c243338c860eb7bb56c1ed
#: ../../../AUTHORS:43
msgid "m35"
msgstr ""
# aeb1e664f1f6451b94ddebf2000fdf2d
#: ../../../AUTHORS:44
msgid "Marcos Neves"
msgstr ""
# ec8999946da6404bbdb7b4fa5b0ed337
#: ../../../AUTHORS:45
msgid "masklinn"
msgstr ""
# fbe852481e8b4138a6cef43692ea4062
#: ../../../AUTHORS:46
msgid "Michael Labbe"
msgstr ""
# fb17691b091948fab45cae8c61fbcf68
#: ../../../AUTHORS:47
msgid "Michael Soulier"
msgstr ""
# 042352794f4948448ca9ae9829a8422b
#: ../../../AUTHORS:48
msgid "`reddit `_"
msgstr ""
# ab1ec82972f34bb790e729cbf8b98f3b
#: ../../../AUTHORS:49
msgid "Nicolas Vanhoren"
msgstr ""
# b574d39c3b054efcb935495e828c1b13
#: ../../../AUTHORS:50
msgid "Robert Rollins"
msgstr ""
# d0930b5536d6409fba2d2a3c58831cd0
#: ../../../AUTHORS:51
msgid "rogererens"
msgstr ""
# 9ec46b40921b4b60bd626f483591f11c
#: ../../../AUTHORS:52
msgid "rwxrwx"
msgstr ""
# 2fdc813656f4497ea4965094ee51bba4
#: ../../../AUTHORS:53
msgid "Santiago Gala"
msgstr ""
# a9c955e0e585492ba574bb32a2bb9e79
#: ../../../AUTHORS:54
msgid "Sean M. Collins"
msgstr ""
# e138be55fec543c588bf70059416a825
#: ../../../AUTHORS:55
msgid "Sebastian Wollrath"
msgstr ""
# 9e3e792a9ec341d291935a15b52cb90b
#: ../../../AUTHORS:56
msgid "Seth"
msgstr ""
# b51dd60ad0534314892b22af5c0db5e4
#: ../../../AUTHORS:57
msgid "Sigurd Høgsbro"
msgstr ""
# 74b5a20b53ed4401ac3207a0a7bf8cd5
#: ../../../AUTHORS:58
msgid "Stuart Rackham"
msgstr ""
# 0a6e3ab504794cb8a2e97d3445765ef1
#: ../../../AUTHORS:59
msgid "Sun Ning"
msgstr ""
# 609e3dc7fb6a48d087dfd3088f3c4868
#: ../../../AUTHORS:60
msgid "Tomás A. Schertel"
msgstr ""
# d613389827534583a72af33bb7e2665e
#: ../../../AUTHORS:61
msgid "Tristan Zajonc"
msgstr ""
# f2429875afcd40cdb26fc89dc3862aa0
#: ../../../AUTHORS:62
msgid "voltron"
msgstr ""
# b80391cec11646ed9e134e30fe1d3daa
#: ../../../AUTHORS:63
msgid "Wieland Hoffmann"
msgstr ""
# 4085ae7ae8f643c98689be3a5860b3b6
#: ../../../AUTHORS:64
msgid "zombat"
msgstr ""
bottle-0.12.7/docs/_locale/zh_CN/async.po 0000644 0001750 0001750 00000035120 12327760172 016476 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-11-09 18:23\n"
"PO-Revision-Date: 2012-11-09 15:37+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# 444d3f0f105f47b887bb0ba9822e1a1c
#: ../../async.rst:2
msgid "Primer to Asynchronous Applications"
msgstr "异步应用入门"
# 8d2cd170d03742b38a49e16d0f8b767f
#: ../../async.rst:4
msgid ""
"Asynchronous design patterns don't mix well with the synchronous nature of "
"`WSGI `_. This is why most "
"asynchronous frameworks (tornado, twisted, ...) implement a specialized API "
"to expose their asynchronous features. Bottle is a WSGI framework and shares "
"the synchronous nature of WSGI, but thanks to the awesome `gevent project "
"`_, it is still possible to write asynchronous "
"applications with bottle. This article documents the usage of Bottle with "
"Asynchronous WSGI."
msgstr ""
"异步设计模式和 `WSGI `_ 的同步本质"
"并不能很好地兼容。这就是为什么大部分的异步框架(tornado, twisted, ...)都实现了"
"专有的API来暴露它们的异步特征。Bottle是一个WSGI框架,也继承了WSGI的同步本质,"
"但是谢谢优秀的 `gevent项目 `_ ,我们可以使用Bottle来"
"编写异步应用。这份文档介绍了在Bottle中如何使用异步WSGI。"
# 9ba83091544148ce9ac672d1a4d08308
#: ../../async.rst:7
msgid "The Limits of Synchronous WSGI"
msgstr "同步WSGI的限制"
# d44c90a8c3454394a657b911f1ec85fc
#: ../../async.rst:9
msgid ""
"Briefly worded, the `WSGI specification (pep 3333) `_ defines a request/response circle as follows: The "
"application callable is invoked once for each request and must return a body "
"iterator. The server then iterates over the body and writes each chunk to "
"the socket. As soon as the body iterator is exhausted, the client connection "
"is closed."
msgstr ""
"简单来说, `WSGI标准 (pep 3333) `_ "
"定义了下面这一个request/response的循环:每次请求到达的时候,应用中的callable"
"会被调用一次,返回一个主体iterator。接着服务器会遍历该主体,分块写入socket。"
"遍历完整个主体,就关闭客户端的连接。"
# 2ad0d26fdfa044e595ce3b9ea29d94be
#: ../../async.rst:11
msgid ""
"Simple enough, but there is a snag: All this happens synchronously. If your "
"application needs to wait for data (IO, sockets, databases, ...), it must "
"either yield empty strings (busy wait) or block the current thread. Both "
"solutions occupy the handling thread and prevent it from answering new "
"requests. There is consequently only one ongoing request per thread."
msgstr ""
"足够简单,但是存在一个小问题:所有这些都是同步的。如果你的应用需要等待数据"
"(IO, socket, 数据库, ...),除了返回一个空字符串(忙等),就只能阻塞当前线程。两"
"种办法都会占用当前线程,导致线程不能处理新的请求,只能处理当前的一个请求。"
# efb55442c2a049e4a4b41f47636975d5
#: ../../async.rst:13
msgid ""
"Most servers limit the number of threads to avoid their relatively high "
"overhead. Pools of 20 or less threads are common. As soon as all threads are "
"occupied, any new connection is stalled. The server is effectively dead for "
"everyone else. If you want to implement a chat that uses long-polling ajax "
"requests to get real-time updates, you'd reach the limited at 20 concurrent "
"connections. That's a pretty small chat."
msgstr ""
"大部分服务器都限制了线程的数量,避免伴随它们而来的资源消耗。常见的是一个线程"
"池,内有20个或更少数量的线程。一旦所有的线程都被占用了,任何新的请求都会阻"
"塞。事实上,对于其他人来说,服务器已经宕机了。如果你想实现一个聊天程序,使用"
"ajax轮询来获取实时消息,很快你就会受到线程数量的限制。这样能同时服务的用户就"
"太少了。"
# 84d8e03c7dcf45699f0880f591ce42a1
#: ../../async.rst:16
msgid "Greenlets to the rescue"
msgstr "救星,Greenlet"
# a608984f3b0648d2acb892828a6c0f1a
#: ../../async.rst:18
msgid ""
"Most servers limit the size of their worker pools to a relatively low number "
"of concurrent threads, due to the high overhead involved in switching "
"between and creating new threads. While threads are cheap compared to "
"processes (forks), they are still expensive to create for each new "
"connection."
msgstr ""
"大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽"
"管和创建进程(fork)的代价比起来,线程还是挺便宜的。但是也没便宜到可以接受为每"
"一个请求创建一个线程。"
# 715dab2ec22040969dc0826db174d77d
#: ../../async.rst:20
msgid ""
"The `gevent `_ module adds *greenlets* to the mix. "
"Greenlets behave similar to traditional threads, but are very cheap to "
"create. A gevent-based server can spawn thousands of greenlets (one for each "
"connection) with almost no overhead. Blocking individual greenlets has no "
"impact on the servers ability to accept new requests. The number of "
"concurrent connections is virtually unlimited."
msgstr ""
"`gevent `_ 模块添加了 *greenlet* 的支持。greenlet和传"
"统的线程类似,但其创建只需消耗很少的资源。基于gevent的服务器可以生成成千上万"
"的greenlet,为每个连接分配一个greenlet也毫无压力。阻塞greenlet,也不会影响到"
"服务器接受新的请求。同时处理的连接数理论上是没有限制的。"
# 1c816479188a4c71995d01d1ca2d70d3
#: ../../async.rst:22
msgid ""
"This makes creating asynchronous applications incredibly easy, because they "
"look and feel like synchronous applications. A gevent-based server is "
"actually not asynchronous, but massively multi-threaded. Here is an example::"
msgstr ""
"这令创建异步应用难以置信的简单,因为它们看起来很想同步程序。基于gevent服务器"
"实际上不是异步的,是大规模多线程。下面是一个例子。"
# 71732a6c95b64c75af73cd0e090c3d25
#: ../../async.rst:39
msgid ""
"The first line is important. It causes gevent to monkey-patch most of "
"Python's blocking APIs to not block the current thread, but pass the CPU to "
"the next greenlet instead. It actually replaces Python's threading with "
"gevent-based pseudo-threads. This is why you can still use ``time.sleep()`` "
"which would normally block the whole thread. If you don't feel comfortable "
"with monkey-patching python built-ins, you can use the corresponding gevent "
"functions (``gevent.sleep()`` in this case)."
msgstr ""
"第一行很重要。它让gevent monkey-patch了大部分Python的阻塞API,让它们不阻塞当"
"前线程,将CPU让给下一个greenlet。它实际上用基于gevent的伪线程替换了Python的线"
"程。这就是你依然可以使用 ``time.sleep()`` 这个照常来说会阻塞线程的函数。如果"
"这种monkey-patch的方式感令你感到不舒服,你依然可以使用gevent中相应的函数 "
"``gevent.sleep()`` 。"
# 926721db7acd4a2485edfa8d60ad76e7
#: ../../async.rst:41
msgid ""
"If you run this script and point your browser to ``http://localhost:8080/"
"stream``, you should see `START`, `MIDDLE`, and `END` show up one by one "
"(rather than waiting 8 seconds to see them all at once). It works exactly as "
"with normal threads, but now your server can handle thousands of concurrent "
"requests without any problems."
msgstr ""
"如果你运行了上面的代码,接着访问 ``http://localhost:8080/stream`` ,你可看到 "
"`START`, `MIDDLE`, 和 `END` 这几个字样依次出现(用时大约8秒)。它像普通的线程一"
"样工作,但是现在你的服务器能同时处理成千上万的连接了。"
# b4f28934ee8344eb9e56ac7e4eb25c95
#: ../../async.rst:45
msgid ""
"Some browsers buffer a certain amount of data before they start rendering a "
"page. You might need to yield more than a few bytes to see an effect in "
"these browsers. Additionally, many browsers have a limit of one concurrent "
"connection per URL. If this is the case, you can use a second browser or a "
"benchmark tool (e.g. `ab` or `httperf`) to measure performance."
msgstr ""
"一些浏览器在开始渲染一个页面之前,会缓存确定容量的数据。在这些浏览器上,你需"
"要返回更多的数据才能看到效果。另外,很多浏览器限制一个URL只使用一个连接。在这"
"种情况下,你可以使用另外的浏览器,或性能测试工具(例如: `ab` 或 `httperf` )来"
"测试性能。"
# d05ad991545847cbb4200f76a4e8ec53
#: ../../async.rst:52
msgid "Event Callbacks"
msgstr "事件回调函数"
# 555abf8c45d04c9f8bf27aa654774f9b
#: ../../async.rst:54
msgid ""
"A very common design pattern in asynchronous frameworks (including tornado, "
"twisted, node.js and friends) is to use non-blocking APIs and bind callbacks "
"to asynchronous events. The socket object is kept open until it is closed "
"explicitly to allow callbacks to write to the socket at a later point. Here "
"is an example based on the `tornado library `_::"
msgstr ""
"异步框架的常见设计模式(包括 tornado, twisted, node.js 和 friends),是使用非阻"
"塞的API,绑定回调函数到异步事件上面。在显式地关闭之前,socket会保持打开,以便"
"稍后回调函数往socket里面写东西。下面是一个基于 `tornado `_ 的例子。"
# ff3f82109f784c47b1707ac9e3a5f831
#: ../../async.rst:63
msgid ""
"The main benefit is that the request handler terminates early. The handling "
"thread can move on and accept new requests while the callbacks continue to "
"write to sockets of previous requests. This is how these frameworks manage "
"to process a lot of concurrent requests with only a small number of OS "
"threads."
msgstr ""
"主要的好处就是MainHandler能早早结束,在回调函数继续写socket来响应之前的请求的"
"时候,当前线程能继续接受新的请求。这样就是为什么这类框架能同时处理很多请求,"
"只使用很少的操作系统线程。"
# 5e39762fd5df49a39faab304e9a290b1
#: ../../async.rst:65
msgid ""
"With Gevent+WSGI, things are different: First, terminating early has no "
"benefit because we have an unlimited pool of (pseudo)threads to accept new "
"connections. Second, we cannot terminate early because that would close the "
"socket (as required by WSGI). Third, we must return an iterable to conform "
"to WSGI."
msgstr ""
"对于Gevent和WSGI来说,情况就不一样了:首先,早早结束没有好处,因为我们的(伪)"
"线程池已经没有限制了。第二,我们不能早早结束,因为这样会关闭socket(WSGI要求如"
"此)。第三,我们必须返回一个iterator,以遵守WSGI的约定。"
# 0d083ebaebd841c1b677840fbb7e1829
#: ../../async.rst:67
msgid ""
"In order to conform to the WSGI standard, all we have to do is to return a "
"body iterable that we can write to asynchronously. With the help of `gevent."
"queue `_, we can *simulate* a "
"detached socket and rewrite the previous example as follows::"
msgstr ""
"为了遵循WSGI规范,我们只需返回一个iterable的实体,异步地将其写回客户端。在 "
"`gevent.queue `_ 的帮助下,我们可以 "
"*模拟* 一个脱管的socket,上面的例子可写成这样。"
# c2dc80f344ff438dae10bf531b546f54
#: ../../async.rst:77
msgid ""
"From the server perspective, the queue object is iterable. It blocks if "
"empty and stops as soon as it reaches ``StopIteration``. This conforms to "
"WSGI. On the application side, the queue object behaves like a non-blocking "
"socket. You can write to it at any time, pass it around and even start a new "
"(pseudo)thread that writes to it asynchronously. This is how long-polling is "
"implemented most of the time."
msgstr ""
"从服务器的角度来看,queue对象是iterable的。如果为空,则阻塞,一旦遇到 "
"``StopIteration`` 则停止。这符合WSGI规范。从应用的角度来看,queue对象表现的像"
"一个不会阻塞socket。你可以在任何时刻写入数据,pass it around,甚至启动一个新"
"的(伪)线程,异步写入。这是在大部分情况下,实现长轮询。"
# 8fbf44264bb54dca80871e505abd6fa2
#: ../../async.rst:81
msgid "Finally: WebSockets"
msgstr "最后: WebSockets"
# 07ae2daba04a4d888fbee239cbfdbbee
#: ../../async.rst:83
msgid ""
"Lets forget about the low-level details for a while and speak about "
"WebSockets. Since you are reading this article, you probably know what "
"WebSockets are: A bidirectional communication channel between a browser "
"(client) and a web application (server)."
msgstr ""
"让我们暂时忘记底层的细节,来谈谈WebSocket。既然你正在阅读这篇文章,你有可能已"
"经知道什么是WebSocket了,一个在浏览器(客户端)和Web应用(服务端)的双向的交流通"
"道。"
# 66508ae9eb304f00960be55668071c01
#: ../../async.rst:85
msgid ""
"Thankfully the `gevent-websocket `_ package does all the hard work for us. Here is a simple "
"WebSocket endpoint that receives messages and just sends them back to the "
"client::"
msgstr ""
"感谢 `gevent-websocket `_ 包帮"
"我们做的工作。下面是一个WebSocket的简单例子,接受消息然后将其发回客户端。"
# 0e40e6a944d144f7bffce3b8696fbcae
#: ../../async.rst:109
msgid ""
"The while-loop runs until the client closes the connection. You get the "
"idea :)"
msgstr "while循环直到客户端关闭连接的时候才会终止。You get the idea :)"
# 79623942975c406d9beb3f23fa1191ea
#: ../../async.rst:111
msgid "The client-site JavaScript API is really straight forward, too::"
msgstr "客户端的JavaScript API也十分简洁明了::"
# 14e90902f8e64556adcf90b146d2bd97
#, fuzzy
#~ msgid "new added linnnnnnne"
#~ msgstr "新加的一行"
bottle-0.12.7/docs/_locale/zh_CN/faq.po 0000644 0001750 0001750 00000012225 12327760172 016131 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-11-09 18:23\n"
"PO-Revision-Date: 2012-11-09 16:47+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# 7422025ba87c41df91aa766602d3562b
#: ../../faq.rst:10
msgid "Frequently Asked Questions"
msgstr "常见问题"
# 7b350c11f4bc4ff6a80dbab624890041
#: ../../faq.rst:13
msgid "About Bottle"
msgstr "关于Bottle"
# b3bd6fdbb6a24d22aaf160f45bdb69dd
#: ../../faq.rst:16
msgid "Is bottle suitable for complex applications?"
msgstr "Bottle适合用于复杂的应用吗?"
# 94af81a76cfd4133b6d2ba7794605511
#: ../../faq.rst:18
msgid ""
"Bottle is a *micro* framework designed for prototyping and building small "
"web applications and services. It stays out of your way and allows you to "
"get things done fast, but misses some advanced features and ready-to-use "
"solutions found in other frameworks (MVC, ORM, form validation, scaffolding, "
"XML-RPC). Although it *is* possible to add these features and build complex "
"applications with Bottle, you should consider using a full-stack Web "
"framework like pylons_ or paste_ instead."
msgstr ""
"Bottle是一个 *迷你* 框架,被设计来提供原型开发和创建小的Web应用和服务。它能快"
"速上手,并帮助你快速完成任务,但缺少一些高级功能和一些其他框架已提供的已知问"
"题解决方法(例如:MVC, ORM,表单验证,手脚架,XML-RPC)。尽管 *可以* 添加这些功"
"能,然后通过Bottle来开发复杂的应用,但我们还是建议你使用一些功能完备的Web框"
"架,例如 pylons_ 或 paste_ 。"
# 7cd9fb83437548a7a76a53a369052dd3
#: ../../faq.rst:22
msgid "Common Problems and Pitfalls"
msgstr "常见的,意料之外的问题"
# 8b95ed13f0554348813619adb56c61e6
#: ../../faq.rst:29
msgid "\"Template Not Found\" in mod_wsgi/mod_python"
msgstr "在mod_wsgi/mod_python中的 \"Template Not Found\" 错误"
# 966c583dc9144d6596cebc06f9240f1c
#: ../../faq.rst:31
msgid ""
"Bottle searches in ``./`` and ``./views/`` for templates. In a mod_python_ "
"or mod_wsgi_ environment, the working directory (``./``) depends on your "
"Apache settings. You should add an absolute path to the template search "
"path::"
msgstr ""
"Bottle会在 ``./`` 和 ``./views/`` 目录中搜索模板。在一个 mod_python_ 或 "
"mod_wsgi_ 环境,当前工作目录( ``./`` )是由Apache的设置决定的。你应该在模板的"
"搜索路径中添加一个绝对路径。"
# 915f4819cc2b414da8453921d84d0eda
#: ../../faq.rst:35
msgid "so bottle searches the right paths."
msgstr "这样,Bottle就能在正确的目录下搜索模板了"
# 0c24d7df42734c08a1a401c59692d47e
#: ../../faq.rst:38
msgid "Dynamic Routes and Slashes"
msgstr "动态route和反斜杠"
# ac001cb8786f475987c1cb542f5537cb
#: ../../faq.rst:40
msgid ""
"In :ref:`dynamic route syntax `, a placeholder "
"token (``:name``) matches everything up to the next slash. This equals to ``"
"[^/]+`` in regular expression syntax. To accept slashes too, you have to add "
"a custom regular pattern to the placeholder. An example: ``/images/:"
"filepath#.*#`` would match ``/images/icons/error.png`` but ``/images/:"
"filename`` won't."
msgstr ""
"在 :ref:`dynamic route syntax ` 中, ``:name`` 匹配"
"任何字符,直到出现一个反斜杠。工作方式相当与 ``[^/]+`` 这样一个正则表达式。为"
"了将反斜杠包涵进来,你必须在 ``:name`` 中添加一个自定义的正则表达式。例如: "
"``/images/:filepath#.*#`` 会匹配 ``/images/icons/error.png`` ,但不匹配 ``/"
"images/:filename`` 。"
# a88283ebbbe04b81b894882c8e4b6c02
#: ../../faq.rst:43
msgid "Problems with reverse proxies"
msgstr "反向代理的问题"
# 7aa118afe3be43ccb06933b955801d4b
#: ../../faq.rst:45
msgid ""
"Redirects and url-building only works if bottle knows the public address and "
"location of your application. If you run bottle locally behind a reverse "
"proxy or load balancer, some information might get lost along the way. For "
"example, the ``wsgi.url_scheme`` value or the ``Host`` header might reflect "
"the local request by your proxy, not the real request by the client. Here is "
"a small WSGI middleware snippet that helps to fix these values::"
msgstr ""
"只用Bottle知道公共地址和应用位置的情况下,重定向和url-building才会起作用。(译"
"者注:保留原文)Redirects and url-building only works if bottle knows the "
"public address and location of your application.如果Bottle应用运行在反向代理"
"或负载均衡后面,一些信息也许会丢失。例如, ``wsgi.url_scheme`` 的值或 "
"``Host`` 头或许只能获取到代理的请求信息,而不是真实的用户请求。下面是一个简单"
"的中间件代码片段,处理上面的问题,获取正确的值。"
bottle-0.12.7/docs/_locale/zh_CN/plugins.po 0000644 0001750 0001750 00000036335 12327760172 017053 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-16 21:45\n"
"PO-Revision-Date: 2012-11-09 15:59+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# 7f8e01d2a2e94efeaa90c3e429b1f67d
#: ../../plugins/index.rst:5
msgid "List of available Plugins"
msgstr "可用插件列表"
# 926c3d34f06a4efba51f28337c68f55a
#: ../../plugins/index.rst:7
msgid ""
"This is a list of third-party plugins that add extend Bottles core "
"functionality or integrate other libraries with the Bottle framework."
msgstr "这是一份第三方插件的列表,扩展Bottle的核心功能,或集成其它类库。"
# 998551b35dae49c4baf3844f3803ebbd
#: ../../plugins/index.rst:9
msgid ""
"Have a look at :ref:`plugins` for general questions about plugins "
"(installation, usage). If you plan to develop a new plugin, the :doc:`/"
"plugindev` may help you."
msgstr ""
"在 :ref:`plugins` 查看常见的插件问题(安装,使用)。如果你计划开发一个新的插"
"件, :doc:`/plugindev` 也许对你有帮助。"
# fb445e42b73949198b058b1f52f5258b
#: ../../plugins/index.rst:12
msgid "`Bottle-Cork `_"
msgstr ""
# 58f41b1d6aac4800bd5312e03b93c028
#: ../../plugins/index.rst:12
msgid ""
"Cork provides a simple set of methods to implement Authentication and "
"Authorization in web applications based on Bottle."
msgstr "Cork插件基于Bottle,提供了一些简单的方法来实现Web应用的权限验证。"
# fe631d4ca8544947ae22feafb3125dcb
#: ../../plugins/index.rst:15
msgid "`Bottle-Extras `_"
msgstr ""
# aff1d22e623a4776bcc5be08a0f5c569
#: ../../plugins/index.rst:15
msgid "Meta package to install the bottle plugin collection."
msgstr "安装Bottle插件的集合"
# 938a054fadf54609b09fadca18915629
#: ../../plugins/index.rst:18
msgid "`Bottle-Flash `_"
msgstr ""
# 746812f7a019498e87758355943a3193
#: ../../plugins/index.rst:18
msgid "flash plugin for bottle"
msgstr "Bottle的flash插件"
# dd53dc05c1e84435b86efb8411a5c41a
#: ../../plugins/index.rst:21
msgid "`Bottle-Hotqueue `_"
msgstr ""
# 535e939a040146ae8fab322db9025380
#: ../../plugins/index.rst:21
msgid "FIFO Queue for Bottle built upon redis"
msgstr "基于redis的FIFO队列服务"
# afafe43d5de6451a96b6b32ccb99fd00
#: ../../plugins/index.rst:24
msgid "`Macaron `_"
msgstr ""
# f6272745bb7a4b5286ad41059624da3c
#: ../../plugins/index.rst:24
msgid "Macaron is an object-relational mapper (ORM) for SQLite."
msgstr "Macaron是用于SQLite的ORM"
# 68c2f103e32d43fb952f052d3cb3a4e6
#: ../../plugins/index.rst:27
msgid "`Bottle-Memcache `_"
msgstr ""
# 02a84e17b8c6429984ebb78334ee31a5
#: ../../plugins/index.rst:27
msgid "Memcache integration for Bottle."
msgstr "Memcache集成"
# 64780d9112694cd09aab9de5283c5a3a
#: ../../plugins/index.rst:30
msgid "`Bottle-MongoDB `_"
msgstr ""
# e0e067d5ae414b7395a2192ca8b35cd3
#: ../../plugins/index.rst:30
msgid "MongoDB integration for Bottle"
msgstr "MongoDB集成"
# e2e6dc5ed6e44dd19b6d381c21ce4274
#: ../../plugins/index.rst:33
msgid "`Bottle-Redis `_"
msgstr ""
# 68bc58b5015c402d90ae0d5350260080
#: ../../plugins/index.rst:33
msgid "Redis integration for Bottle."
msgstr "Redis集成"
# c74f6cb622be491aa618c25d819a17dd
#: ../../plugins/index.rst:36
msgid "`Bottle-Renderer `_"
msgstr ""
# 2213271856294ba184e3d73817e7306d
#: ../../plugins/index.rst:36
msgid "Renderer plugin for bottle"
msgstr "Renderer插件"
# 4287e3df39264e7baab8f046b7b3353b
#: ../../plugins/index.rst:39
msgid "`Bottle-Servefiles `_"
msgstr ""
# e63027f3c7594930be7b6a2d3d9c8af1
#: ../../plugins/index.rst:39
msgid "A reusable app that serves static files for bottle apps"
msgstr "一个可重用的APP,为Bottle应用提供静态文件服务。"
# ea6c00ae10624fffa161c35bc588e09b
#: ../../plugins/index.rst:42
msgid "`Bottle-Sqlalchemy `_"
msgstr ""
# 2a76b62faec84b3684c2d8747fe06c35
#: ../../plugins/index.rst:42
msgid "SQLAlchemy integration for Bottle."
msgstr "SQLAlchemy集成"
# cab6769882cf4596bb782cb657b17f49
#: ../../plugins/index.rst:45
msgid "`Bottle-Sqlite `_"
msgstr ""
# ef35627e5de14711a12f782786de93d4
#: ../../plugins/index.rst:45
msgid "SQLite3 database integration for Bottle."
msgstr "SQLite3数据库集成"
# c3eb03bbe1ef4bc1b97c2eb850aed3c4
#: ../../plugins/index.rst:48
msgid "`Bottle-Web2pydal `_"
msgstr ""
# f01e53ed49544cd487224b2ae784236a
#: ../../plugins/index.rst:48
msgid "Web2py Dal integration for Bottle."
msgstr "Wbe2py的Dal集成"
# e1260f9c9c4d4ba5b5b0b6e67b853da1
#: ../../plugins/index.rst:51
msgid "`Bottle-Werkzeug `_"
msgstr ""
# ceb2ae912be74561b44d9b9a4a38d9b1
#: ../../plugins/index.rst:51
msgid ""
"Integrates the `werkzeug` library (alternative request and response objects, "
"advanced debugging middleware and more)."
msgstr ""
"集成 `werkzeug` (可选的request和response对象,更高级的调试中间件等等)"
# 8ec7fd1656ac47e0b2221f7cd28a3848
#: ../../plugins/index.rst:53
msgid ""
"Plugins listed here are not part of Bottle or the Bottle project, but "
"developed and maintained by third parties."
msgstr "这里列出的插件不属于Bottle或Bottle项目,是第三方开发并维护的。"
# 6f41cb4bdcdd4dbeb70a201ce81eb7f2
#: ../../../plugins/sqlite/README:3
msgid "Bottle-SQLite"
msgstr ""
# fe329bbcfc1c4bfba89ff822056ab5bd
#: ../../../plugins/sqlite/README:5
msgid ""
"SQLite is a self-contained SQL database engine that runs locally and does "
"not require any additional server software or setup. The sqlite3 module is "
"part of the Python standard library and already installed on most systems. "
"It it very useful for prototyping database-driven applications that are "
"later ported to larger databases such as PostgreSQL or MySQL."
msgstr ""
"SQLite是一个\"自包含\"的SQL数据库引擎,不需要任何其它服务器软件或安装过程。"
"sqlite3模块是Python标准库的一部分,在大部分系统上面已经安装了。在开发依赖数据"
"库的应用原型的时候,它是非常有用的,可在部署的时候再使用PostgreSQL或MySQL。"
# adebbc2b5b1b49b99c5d6c0451ffa759
#: ../../../plugins/sqlite/README:11
msgid ""
"This plugin simplifies the use of sqlite databases in your Bottle "
"applications. Once installed, all you have to do is to add a ``db`` keyword "
"argument (configurable) to route callbacks that need a database connection."
msgstr ""
"这个插件让在Bottle应用中使用sqlite数据库更简单了。一旦安装了,你只要在route的"
"回调函数里添加一个\"db\"参数(可更改为其它字符),就能使用数据库链接了。"
# 84f7e9a1e50149baacb76346df6e5508
# 3e410718c8d941eda9f78406a7d42e5d
#: ../../../plugins/sqlite/README:16 ../../../plugins/werkzeug/README:17
msgid "Installation"
msgstr "安装"
# 0f0622674c7648ce83878a26ca64bfbb
# 4c4bd042eeef48eb8fd0773aeb1ab132
#: ../../../plugins/sqlite/README:18 ../../../plugins/werkzeug/README:19
msgid "Install with one of the following commands::"
msgstr "下面两个命令任选一个"
# 42ea2e3ca2974198bb9d13e5fe2abf7f
# 695262e42ae143e396f0b49460772d9f
#: ../../../plugins/sqlite/README:23 ../../../plugins/werkzeug/README:24
msgid "or download the latest version from github::"
msgstr "或从github下载最新版本"
# d977670f6ce442f2b4fcf04e770f46ef
# 3b0cc3afff774774ae5f20510bda9c13
#: ../../../plugins/sqlite/README:30 ../../../plugins/werkzeug/README:33
msgid "Usage"
msgstr "使用"
# a4b8d2a6012f45babb7111735bc436a3
#: ../../../plugins/sqlite/README:32
msgid ""
"Once installed to an application, the plugin passes an open :class:`sqlite3."
"Connection` instance to all routes that require a ``db`` keyword argument::"
msgstr ""
"一旦安装到应用里面,如果route的回调函数包含一个名为\"db\"的参数,该插件会给该"
"参数传一个 :class:`sqlite3.Connection` 类的实例。"
# 2db3342cda76424583c6834397f8d47f
#: ../../../plugins/sqlite/README:49
msgid "Routes that do not expect a ``db`` keyword argument are not affected."
msgstr "不包含\"db\"参数的route不会受影响。"
# 17e3ad45eace4b15a012c8015862ed70
#: ../../../plugins/sqlite/README:51
msgid ""
"The connection handle is configured so that :class:`sqlite3.Row` objects can "
"be accessed both by index (like tuples) and case-insensitively by name. At "
"the end of the request cycle, outstanding transactions are committed and the "
"connection is closed automatically. If an error occurs, any changes to the "
"database since the last commit are rolled back to keep the database in a "
"consistent state."
msgstr ""
"可通过下标(像元组)来访问 :class:`sqlite3.Row` 对象,且对命名的大小写敏感。在"
"请求结束后,自动提交事务和关闭连接。如果出现任何错误,自上次提交后的所有更改"
"都会被回滚,以保证数据库的一致性。"
# 0a90c8f1724b4956ab9a1c7cacdce967
# de779571d3b3420bac73033b2017dbf5
#: ../../../plugins/sqlite/README:58 ../../../plugins/werkzeug/README:73
msgid "Configuration"
msgstr "配置"
# f1e6e51d894a466bbac469605d31dc81
# 274dd7703c074319a7be90073bf49ab6
#: ../../../plugins/sqlite/README:60 ../../../plugins/werkzeug/README:75
msgid "The following configuration options exist for the plugin class:"
msgstr "有下列可配置的选项:"
# de6b7d40dacd47fdb02ce3bceba09ff2
#: ../../../plugins/sqlite/README:62
msgid "**dbfile**: Database filename (default: in-memory database)."
msgstr "**dbfile**: 数据库文件 (默认: 存在在内存中)。"
# 079314db1cbb4547aa9cb1a6c1ce93cd
#: ../../../plugins/sqlite/README:63
msgid ""
"**keyword**: The keyword argument name that triggers the plugin (default: "
"'db')."
msgstr "**keyword**: route中使用数据库连接的参数 (默认: 'db')。"
# 63957028a426442ea914af5c5e5c268c
#: ../../../plugins/sqlite/README:64
msgid ""
"**autocommit**: Whether or not to commit outstanding transactions at the end "
"of the request cycle (default: True)."
msgstr "**autocommit**: 是否在请求结束后提交事务 (默认: True)。"
# fa70c63aea9b46e1bd63202184cc56b6
#: ../../../plugins/sqlite/README:65
msgid ""
"**dictrows**: Whether or not to support dict-like access to row objects "
"(default: True)."
msgstr "**dictrows**: 是否可像字典那样访问row对象 (默认: True)。"
# 4c44e12a0db14e85b99a84e543d99bf8
#: ../../../plugins/sqlite/README:67
msgid "You can override each of these values on a per-route basis::"
msgstr "你可在route里面覆盖这些默认值。"
# ae3acd995886447bb8cacadc3bf78584
#: ../../../plugins/sqlite/README:73
msgid ""
"or install two plugins with different ``keyword`` settings to the same "
"application::"
msgstr "或在同一个应用里面安装 ``keyword`` 参数不同的两个插件。"
# 4a92aa81a21345b5834f7bad349424df
#: ../../../plugins/werkzeug/README:3
msgid "Bottle-Werkzeug"
msgstr ""
# 740576d3ed414027a83492c42a850981
#: ../../../plugins/werkzeug/README:5
msgid ""
"`Werkzeug `_ is a powerful WSGI utility library "
"for Python. It includes an interactive debugger and feature-packed request "
"and response objects."
msgstr ""
"`Werkzeug `_ 是一个强大的WSGI类库。它包含一个交互"
"式的调试器和包装好的request和response对象。"
# f6d80c0515d9452ebc778f45c2f26156
#: ../../../plugins/werkzeug/README:9
msgid ""
"This plugin integrates :class:`werkzeug.wrappers.Request` and :class:"
"`werkzeug.wrappers.Response` as an alternative to the built-in "
"implementations, adds support for :mod:`werkzeug.exceptions` and replaces "
"the default error page with an interactive debugger."
msgstr ""
"这个插件集成了 :class:`werkzeug.wrappers.Request` 和 :class:`werkzeug."
"wrappers.Response` 用于取代内置的相应实现,支持 :mod:`werkzeug.exceptions` ,"
"用交互式的调试器替换了默认的错误页面。"
# 3fc241ca6b5647c095c06fd0cb51a9f4
#: ../../../plugins/werkzeug/README:35
msgid ""
"Once installed to an application, this plugin adds support for :class:"
"`werkzeug.wrappers.Response`, all kinds of :mod:`werkzeug.exceptions` and "
"provides a thread-local instance of :class:`werkzeug.wrappers.Request` that "
"is updated with each request. The plugin instance itself doubles as a "
"werkzeug module object, so you don't have to import werkzeug in your "
"application. Here is an example::"
msgstr ""
"一旦安装到应用中,该插件将支持 :class:`werkzeug.wrappers.Response` ,所有类型"
"的 :mod:`werkzeug.exceptions` 和thread-local的 :class:`werkzeug.wrappers."
"Request` 的实例(每次请求都更新)。插件它本身还扮演着werkzeug模块的角色,所以你"
"无需在应用中导入werkzeug。下面是一个例子。"
# 8ca3622eb42a4c2e8745f63cfc852b19
#: ../../../plugins/werkzeug/README:62
msgid "Using the Debugger"
msgstr "使用调试器"
# 48d4c47e99e94dc6b040641659af2e47
#: ../../../plugins/werkzeug/README:64
msgid ""
"This plugin replaces the default error page with an advanced debugger. If "
"you have the `evalex` feature enabled, you will get an interactive console "
"that allows you to inspect the error context in the browser. Please read "
"`Debugging Applications with werkzeug `_ before you enable "
"this feature."
msgstr ""
"该插件用一个更高级的调试器替换了默认的错误页面。如果你启用了 `evalex` 特性,"
"你可在浏览器中使用一个交互式的终端来检查错误。在你启用该特性之前,请看 `通过"
"werkzeug来调试 `_ 。"
# 4dd4d57c159f41028ce088a05dfaf886
#: ../../../plugins/werkzeug/README:77
msgid ""
"**evalex**: Enable the exception evaluation feature (interactive debugging). "
"This requires a non-forking server and is a security risk. Please read "
"`Debugging Applications with werkzeug `_. (default: False)"
msgstr ""
"**evalex**: 启用交互式的调试器。要求一个单进程的服务器,且有安全隐患。请看 `"
"通过werkzeug来调试 `_ (默认: False)"
# f7025d633d12487eb3075443df743bff
#: ../../../plugins/werkzeug/README:78
msgid "**request_class**: Defaults to :class:`werkzeug.wrappers.Request`"
msgstr "**request_class**: 默认是 :class:`werkzeug.wrappers.Request` 的实例"
# 565565f6d3884db196c5be214580f8a3
#: ../../../plugins/werkzeug/README:79
msgid ""
"**debugger_class**: Defaults to a subclass of :class:`werkzeug.debug."
"DebuggedApplication` which obeys the :data:`bottle.DEBUG` setting."
msgstr ""
"**debugger_class**: 默认是 :class:`werkzeug.debug.DebuggedApplication` 的子"
"类,遵守 :data:`bottle.DEBUG` 中的设置"
bottle-0.12.7/docs/_locale/zh_CN/configuration.po 0000644 0001750 0001750 00000026156 12327760172 020241 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2013, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-09 18:12\n"
"PO-Revision-Date: 2013-08-09 18:10+0800\n"
"Last-Translator: \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.7\n"
# c1741ba1cf24423d937ac8eb7155aa10
#: ../../configuration.rst:3
msgid "Configuration (DRAFT)"
msgstr "配置文件(初稿)"
# 95c5c5957b604396a280c4987b0be08d
#: ../../configuration.rst:8
msgid ""
"This is a draft for a new API. `Tell us `_ "
"what you think."
msgstr ""
"这是一个新的API, 可以 `告诉我们 `_ 你的想"
"法"
# abf17b8e32a84f119f89fd9e54ae738a
#: ../../configuration.rst:10
msgid ""
"Bottle applications can store their configuration in :attr:`Bottle.config`, "
"a dict-like object and central place for application specific settings. This "
"dictionary controls many aspects of the framework, tells (newer) plugins "
"what to do, and can be used to store your own configuration as well."
msgstr ""
"Bottle应用可以在 :attr:`Bottle.config` 这个类似于字典的对象中,存储它们的配"
"置。这个对象在很多方面,影响着Bottle框架和相应的插件。你也可以在这个对象中,"
"存储你的自定义配置。"
# d94af1e48ef146a3bf4b94258003de0f
#: ../../configuration.rst:13
msgid "Configuration Basics"
msgstr "基础知识"
# 8fa8b5ac47fb42ac93f250472bf34ba3
#: ../../configuration.rst:15
msgid ""
"The :attr:`Bottle.config` object behaves a lot like an ordinary dictionary. "
"All the common dict methods work as expected. Let us start with some "
"examples::"
msgstr ""
" :attr:`Bottle.config` 这个对象,可以当成一个字典来使用,让我们举个例子::"
# a10e871f1f0a42fd9e88a00777e031f8
#: ../../configuration.rst:44
msgid ""
"The app object is not always available, but as long as you are within a "
"request context, you can use the `request` object to get the current "
"application and its configuration::"
msgstr ""
"app对象不一定总是可用的,但只要你在处理一个请求,你可以使用 `request` 对象来"
"获得当前的应用对象和它的配置::"
# 4510b753e1f843ae839da666fa8a96ea
#: ../../configuration.rst:51
msgid "Naming Convention"
msgstr "命名约定"
# f71bac781b854687aa55c961bb0cd7c3
#: ../../configuration.rst:53
msgid ""
"To make life easier, plugins and applications should follow some simple "
"rules when it comes to config parameter names:"
msgstr ""
"方便起见,插件和应用应该遵循一些简单的规则,特别是在给配置参数命名的时候:"
# 4e47f429092a4402b928c616e1052bcd
#: ../../configuration.rst:55
msgid ""
"All keys should be lowercase strings and follow the rules for python "
"identifiers (no special characters but the underscore)."
msgstr ""
"所有的key都应该是小写的字符串,并符合Python的变量命名规则(除了下划线外,没有"
"特殊字符)。"
# 9162c80192d34a239d49822fde8ff2d5
#: ../../configuration.rst:56
msgid ""
"Namespaces are separated by dots (e.g. ``namespace.field`` or ``namespace."
"subnamespace.field``)."
msgstr ""
"命名空间通过点来区分(例如: ``namespace.field`` 或 ``namespace.subnamespacew."
"field`` )。"
# dc379020b8a7404fa4606731b772d9f8
#: ../../configuration.rst:57
msgid ""
"Bottle uses the root namespace for its own configuration. Plugins should "
"store all their variables in their own namespace (e.g. ``sqlite.db`` or "
"``werkzeug.use_debugger``)."
msgstr ""
"Bottle框架,使用根命名空间来存储它的配置。插件应该在它们自己的命名空间中存储"
"它们的变量(例如: `sqlite.db`` 或 ``werkzeug.use_debugger`` )。"
# 93d339420982447bb137607a1b05aa4e
#: ../../configuration.rst:58
msgid ""
"Your own application should use a separate namespace (e.g. ``myapp.*``)."
msgstr "你的应用应该使用一个独立的命名空间(例如: ``myapp.*`` )。"
# aff46481cbe04391926ec015d7aada17
#: ../../configuration.rst:62
msgid "Loading Configuration from a File"
msgstr "从文件中加载配置"
# 09f7f030d1054a308f955bd4f54221e6
#: ../../configuration.rst:66
msgid ""
"Configuration files are useful if you want to enable non-programmers to "
"configure your application, or just don't want to hack python module files "
"just to change the database port. A very common syntax for configuration "
"files is shown here:"
msgstr ""
"在你不想通过修改代码来修改配置的时候,配置文件是非常有用的。常见的配置文件语"
"法如下:"
# 7376404326fe4ae18113d7aa57c417a8
#: ../../configuration.rst:78
msgid ""
"With :meth:`ConfigDict.load_config` you can load these ``*.ini`` style "
"configuration files from disk and import their values into your existing "
"configuration::"
msgstr ""
"通过 :meth:`ConfigDict.load_config` 方法,你可以从一些ini文件中导入配置::"
# 7349ce363a5b424c97634c49c54c8f94
#: ../../configuration.rst:84
msgid "Loading Configuration from a nested :class:`dict`"
msgstr "从字典中加载配置"
# 5477eb75b0e54baf9afdd7013f946012
#: ../../configuration.rst:88
msgid ""
"Another useful method is :meth:`ConfigDict.load_dict`. This method takes an "
"entire structure of nested dictionaries and turns it into a flat list of "
"keys and values with namespaced keys::"
msgstr ""
"另外一个有用的方法,是 :meth:`ConfigDict.load_dict` 。将字典中的配置,放到各"
"自的命名空间下面::"
# d8ac42150deb4bf8a3417f70f15e7452
#: ../../configuration.rst:109
msgid "Listening to configuration changes"
msgstr "监听配置的变更"
# 0130fae477d3494cb5f90534260ac3a2
#: ../../configuration.rst:113
msgid ""
"The ``config`` hook on the application object is triggered each time a value "
"in :attr:`Bottle.config` is changed. This hook can be used to react on "
"configuration changes at runtime, for example reconnect to a new database, "
"change the debug settings on a background service or resize worker thread "
"pools. The hook callback receives two arguments (key, new_value) and is "
"called before the value is actually changed in the dictionary. Raising an "
"exception from a hook callback cancels the change and the old value is "
"preserved."
msgstr ""
"每次 :attr:`Bottle.config` 中的值有变更的时候,会触发 ``config`` 这个钩子。"
"这个钩子可以用于在运行时,对配置的改动做出响应,例如连接到一个新的数据库,改"
"变后台服务的debug配置,或更改线程池的大小。这个钩子接收两个参数(key, "
"new_value),在 :attr:`Bottle.config` 中的值被改动之前触发。如果这个钩子抛出了"
"异常,那么 :attr:`Bottle.config` 中的值将不会被改动。"
# 649c3d1653274f2b8447ff2e4c83e0d2
#: ../../configuration.rst:122
msgid ""
"The hook callbacks cannot *change* the value that is to be stored to the "
"dictionary. That is what filters are for."
msgstr ""
"这个钩子不能 *改变* 将要存到 :attr:`Bottle.config` 对象中的值。做这件事的是"
"filter(过滤器)。"
# c6eb3585a3214eaca881fbcc36bd6719
#: ../../configuration.rst:128
msgid "Filters and other Meta Data"
msgstr "过滤器和其它元数据"
# 5009754fd0a34a9baf4dddb9427176b1
#: ../../configuration.rst:132
msgid ""
":class:`ConfigDict` allows you to store meta data along with configuration "
"keys. Two meta fields are currently defined:"
msgstr ""
":class:`ConfigDict` 对象允许你给配置中每个key定义元数据。当前定义了help和"
"filter:"
# 3c150dd27a0343d3b27b76a2c497761a
#: ../../configuration.rst:136
msgid "help"
msgstr ""
# 6400abfe8a1046a1b8fc2d88411ed45e
#: ../../configuration.rst:135
msgid ""
"A help or description string. May be used by debugging, introspection or "
"admin tools to help the site maintainer configuring their application."
msgstr "一个描述字符串。可以被debug或管理工具利用,来帮助网站管理员填写配置。"
# e1fa67475b744125be6c8fd53881d5fd
#: ../../configuration.rst:139
msgid "filter"
msgstr ""
# 44aed643e8794ef59dcd36e1535562aa
#: ../../configuration.rst:139
msgid ""
"A callable that accepts and returns a single value. If a filter is defined "
"for a key, any new value stored to that key is first passed through the "
"filter callback. The filter can be used to cast the value to a different "
"type, check for invalid values (throw a ValueError) or trigger side effects."
msgstr ""
"一个可运行的对象,接受和返回一个值。如果一个key定义了一个filter,任何将要存到"
"这个key中的值,都会先传给filter的相应回调函数。在回调函数中,可做类型转换,有"
"效性检验等工作。"
# 75aca8a53b774765a6190e7113f09250
#: ../../configuration.rst:141
msgid ""
"This feature is most useful for plugins. They can validate their config "
"parameters or trigger side effects using filters and document their "
"configuration via ``help`` fields::"
msgstr ""
"这个功能比较适合被插件使用。它们可以检查它们的配置参数,或触发其它动作,或在 "
"``help`` 字段中,给配置添加说明::"
# 07ed111dcdf9476b9cc95fac5ca0826d
#: ../../configuration.rst:163
msgid "API Documentation"
msgstr ""
# 453a6899724348d887f2d5bd14a4e8c4
#: ../../../bottle.py:docstring of bottle.ConfigDict:1
msgid ""
"A dict-like configuration storage with additional support for namespaces, "
"validators, meta-data, on_change listeners and more."
msgstr ""
# 51f80fe3a49e49bb91e974a35ddfd599
#: ../../../bottle.py:docstring of bottle.ConfigDict.load_config:1
msgid "Load values from an *.ini style config file."
msgstr ""
# f43ab902d9dd4a5fb9cdffc36e0f0751
#: ../../../bottle.py:docstring of bottle.ConfigDict.load_config:3
msgid ""
"If the config file contains sections, their names are used as namespaces for "
"the values within. The two special sections ``DEFAULT`` and ``bottle`` refer "
"to the root namespace (no prefix)."
msgstr ""
# 73c203a5f128460ca20ed9c837cf2321
#: ../../../bottle.py:docstring of bottle.ConfigDict.load_dict:1
msgid ""
"Load values from a dictionary structure. Nesting can be used to represent "
"namespaces."
msgstr ""
# dfc61134b7e942749147859f5df7c3f9
#: ../../../bottle.py:docstring of bottle.ConfigDict.update:1
msgid ""
"If the first parameter is a string, all keys are prefixed with this "
"namespace. Apart from that it works just as the usual dict.update(). "
"Example: ``update('some.namespace', key='value')``"
msgstr ""
# fe2a8757060f427aab7545ff5ca638c2
#: ../../../bottle.py:docstring of bottle.ConfigDict.meta_get:1
msgid "Return the value of a meta field for a key."
msgstr ""
# aa48b60c60d94d0588afade295f2576d
#: ../../../bottle.py:docstring of bottle.ConfigDict.meta_set:1
msgid ""
"Set the meta field for a key to a new value. This triggers the on-change "
"handler for existing keys."
msgstr ""
# 75344d95f5874a6d89c05b64723ebf5d
#: ../../../bottle.py:docstring of bottle.ConfigDict.meta_list:1
msgid "Return an iterable of meta field names defined for a key."
msgstr ""
bottle-0.12.7/docs/_locale/zh_CN/recipes.po 0000644 0001750 0001750 00000035443 12327760172 017023 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-17 01:11\n"
"PO-Revision-Date: 2013-02-17 01:52+0800\n"
"Last-Translator: \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.4\n"
# 8487026bb92949c197608691e0682922
#: ../../recipes.rst:16
msgid "Recipes"
msgstr "秘诀"
# cfd0882653594f1eae8a9bef70324bc4
#: ../../recipes.rst:18
msgid ""
"This is a collection of code snippets and examples for common use cases."
msgstr "这里收集了一些常见用例的代码片段和例子."
# faa7771e7cda4492b891ae26152c932e
#: ../../recipes.rst:21
msgid "Keeping track of Sessions"
msgstr "使用Session"
# e3a652f4923841fbbdadcb5f3dc5f90d
#: ../../recipes.rst:23
msgid ""
"There is no built-in support for sessions because there is no *right* way to "
"do it (in a micro framework). Depending on requirements and environment you "
"could use beaker_ middleware with a fitting backend or implement it "
"yourself. Here is an example for beaker sessions with a file-based backend::"
msgstr ""
"Bottle自身并没有提供Session的支持,因为在一个迷你框架里面,没有合适的方法来实"
"现。根据需求和使用环境,你可以使用 beaker_ 中间件或自己来实现。下面是一个使用"
"beaker的例子,Session数据存放在\"./data\"目录里面::"
# a2d14fa0a98f44d4982d9d0b96fcbe80
#: ../../recipes.rst:46
msgid "Debugging with Style: Debugging Middleware"
msgstr "Debugging with Style: 调试中间件"
# 9cd203576e7043b484ee096450fed53d
#: ../../recipes.rst:48
msgid ""
"Bottle catches all Exceptions raised in your app code to prevent your WSGI "
"server from crashing. If the built-in :func:`debug` mode is not enough and "
"you need exceptions to propagate to a debugging middleware, you can turn off "
"this behaviour::"
msgstr ""
"Bottle捕获所有应用抛出的异常,防止异常导致WSGI服务器崩溃。如果内置的 :func:"
"`debug` 模式不能满足你的要求,你想在你自己写的中间件里面处理这些异常,那么你"
"可以关闭这个功能。"
# fbc746186f784972877b51c923365560
#: ../../recipes.rst:56
msgid ""
"Now, bottle only catches its own exceptions (:exc:`HTTPError`, :exc:"
"`HTTPResponse` and :exc:`BottleException`) and your middleware can handle "
"the rest."
msgstr ""
"现在,Bottle仅会捕获并处理它自己抛出的异常( :exc:`HTTPError` , :exc:"
"`HTTPResponse` 和 :exc:`BottleException` ),你的中间件可以处理剩下的那些异"
"常。"
# 36c1c52ece8c4f268a7dc278b274b829
#: ../../recipes.rst:58
msgid ""
"The werkzeug_ and paste_ libraries both ship with very powerful debugging "
"WSGI middleware. Look at :class:`werkzeug.debug.DebuggedApplication` for "
"werkzeug_ and :class:`paste.evalexception.middleware.EvalException` for "
"paste_. They both allow you do inspect the stack and even execute python "
"code within the stack context, so **do not use them in production**."
msgstr ""
"werkzeug_ 和 paste_ 这两个第三方库都提供了非常强大的调试中间件。如果是 "
"werkzeug_ ,可看看 :class:`werkzeug.debug.DebuggedApplication` ,如果是 "
"paste_ ,可看看 :class:`paste.evalexception.middleware.EvalException` 。它们"
"都可让你检查运行栈,甚至在保持运行栈上下文的情况下,执行Python代码。所以 **不"
"要在生产环境中使用它们** 。"
# 0bca874b50014d1aa55d3d5a122dad91
#: ../../recipes.rst:62
msgid "Unit-Testing Bottle Applications"
msgstr ""
# abb049c14147472ab7095e6a92438c68
#: ../../recipes.rst:64
msgid ""
"Unit-testing is usually performed against methods defined in your web "
"application without running a WSGI environment."
msgstr "Unit测试一般用于测试应用中的函数,但不需要一个WSGI环境。"
# 8db4441496bf46629c01f66929c54221
#: ../../recipes.rst:66
msgid "A simple example using `Nose `_::"
msgstr "使用 `Nose `_ 的简单例子。"
# 5215a5269ce1494b8bb619b73916b610
#: ../../recipes.rst:77
msgid "Test script::"
msgstr "测试代码::"
# 8fb6ca337895400991fdb334c3ef1659
#: ../../recipes.rst:84
msgid ""
"In the example the Bottle route() method is never executed - only index() is "
"tested."
msgstr "在这个例子中,Bottle的route()函数没有被执行,仅测试了index()函数。"
# 62f71facf6464ca68babf9bef0a0160a
#: ../../recipes.rst:88
msgid "Functional Testing Bottle Applications"
msgstr "功能测试"
# 39f2c3a094f84d1bb0974af018beaa6a
#: ../../recipes.rst:90
msgid ""
"Any HTTP-based testing system can be used with a running WSGI server, but "
"some testing frameworks work more intimately with WSGI, and provide the "
"ability the call WSGI applications in a controlled environment, with "
"tracebacks and full use of debugging tools. `Testing tools for WSGI `_ is a good starting point."
msgstr ""
"任何基于HTTP的测试系统都可用于测试WSGI服务器,但是有些测试框架与WSGI服务器工"
"作得更好。它们可以在一个可控环境里运行WSGI应用,充分利用traceback和调试工"
"具。 `Testing tools for WSGI `_ "
"是一个很好的上手工具。"
# 56ee442ef6714be38dcf951e95112c22
#: ../../recipes.rst:92
msgid ""
"Example using `WebTest `_ and `Nose `_::"
msgstr ""
"使用 `WebTest `_ 和 `Nose `_ 的例子。"
# 58fd7a3ba2494e059ba1f0157788af13
#: ../../recipes.rst:112
msgid "Embedding other WSGI Apps"
msgstr "嵌入其他WSGI应用"
# 5f0f337aca4e43a6ac2ad2d8dcb771c0
#: ../../recipes.rst:114
msgid ""
"This is not the recommend way (you should use a middleware in front of "
"bottle to do this) but you can call other WSGI applications from within your "
"bottle app and let bottle act as a pseudo-middleware. Here is an example::"
msgstr ""
"并不建议你使用这个方法,你应该在Bottle前面使用一个中间件来做这样的事情。但你"
"确实可以在Bottle里面调用其他WSGI应用,让Bottle扮演一个中间件的角色。下面是一"
"个例子。"
# a196f1d227dd4d5fbc2ad6f293b24b0e
#: ../../recipes.rst:130
msgid ""
"Again, this is not the recommend way to implement subprojects. It is only "
"here because many people asked for this and to show how bottle maps to WSGI."
msgstr ""
"再次强调,并不建议使用这种方法。之所以介绍这种方法,是因为很多人问起,如何在"
"Bottle中调用WSGI应用。"
# f25d4e33503c43148073e9f81decbf72
#: ../../recipes.rst:134
msgid "Ignore trailing slashes"
msgstr "忽略尾部的反斜杠"
# d28129334ef24183a739ec177f3a322a
#: ../../recipes.rst:136
msgid ""
"For Bottle, ``/example`` and ``/example/`` are two different routes [1]_. To "
"treat both URLs the same you can add two ``@route`` decorators::"
msgstr ""
"在Bottle看来, ``/example`` 和 ``/example/`` 是两个不同的route [1]_ 。为了一"
"致对待这两个URL,你应该添加两个route。"
# 2a6abd0a87e24a6e92fef547a4e3f0b4
#: ../../recipes.rst:142
msgid "or add a WSGI middleware that strips trailing slashes from all URLs::"
msgstr "或者添加一个WSGI中间件来处理这种情况。"
# ff6aaa5c70994fa3955888819121dfa3
#: ../../recipes.rst:156
msgid "Footnotes"
msgstr "脚注"
# 81148a89616b4d358ace32d79e576043
#: ../../recipes.rst:157
msgid "Because they are. See "
msgstr "因为确实如此,见 "
# 33f68df31e094ac2b967015004250f28
#: ../../recipes.rst:161
msgid "Keep-alive requests"
msgstr "Keep-alive 请求"
# 548edbc8dabe4ce4a00458bd74d72d74
#: ../../recipes.rst:165
msgid "For a more detailed explanation, see :doc:`async`."
msgstr "详见 :doc:`async` 。"
# 1ab0b644d6da4fcf943b67f77b19c330
#: ../../recipes.rst:167
msgid ""
"Several \"push\" mechanisms like XHR multipart need the ability to write "
"response data without closing the connection in conjunction with the "
"response header \"Connection: keep-alive\". WSGI does not easily lend itself "
"to this behavior, but it is still possible to do so in Bottle by using the "
"gevent_ async framework. Here is a sample that works with either the gevent_ "
"HTTP server or the paste_ HTTP server (it may work with others, but I have "
"not tried). Just change ``server='gevent'`` to ``server='paste'`` to use the "
"paste_ server::"
msgstr ""
"像XHR这样的\"push\"机制,需要在HTTP响应头中加入 \"Connection: keep-alive\" ,"
"以便在不关闭连接的情况下,写入响应数据。WSGI并不支持这种行为,但如果在Bottle"
"中使用 gevent_ 这个异步框架,还是可以实现的。下面是一个例子,可配合 gevent_ "
"HTTP服务器或 paste_ HTTP服务器使用(也许支持其他服务器,但是我没试过)。在run()"
"函数里面使用 ``server='gevent'`` 或 ``server='paste'`` 即可使用这两种服务器。"
# c7a5e20a91054b07ae82effa317c5b34
#: ../../recipes.rst:184
msgid ""
"If you browse to ``http://localhost:8080/stream``, you should see 'START', "
"'MIDDLE', and 'END' show up one at a time (rather than waiting 8 seconds to "
"see them all at once)."
msgstr ""
"通过浏览器访问 ``http://localhost:8080/stream`` ,可看到'START','MIDDLE',"
"和'END'这三个字眼依次出现,一共用了8秒。"
# fef7a41bbeb84056b2c0cd48f54b78bc
#: ../../recipes.rst:187
msgid "Gzip Compression in Bottle"
msgstr "Gzip压缩"
# cc030b164fa1422fbb0e7c605479a883
#: ../../recipes.rst:190
msgid "For a detailed discussion, see compression_"
msgstr "详见 compression_"
# a0873b5a4e4c4c71937843850c69f371
#: ../../recipes.rst:192
msgid ""
"A common feature request is for Bottle to support Gzip compression, which "
"speeds up sites by compressing static resources (like CSS and JS files) "
"during a request."
msgstr ""
"Gzip压缩,可加速网站静态资源(例如CSS和JS文件)的访问。人们希望Bottle支持Gzip压"
"缩,(但是不支持)......"
# 0cfc5b1cfe7b4f9a90907a25fd6655ca
#: ../../recipes.rst:194
msgid ""
"Supporting Gzip compression is not a straightforward proposition, due to a "
"number of corner cases that crop up frequently. A proper Gzip implementation "
"must:"
msgstr "支持Gzip压缩并不简单,一个合适的Gzip实现应该满足以下条件。"
# 43396b35b1eb43d0875bc745e4adbb6e
#: ../../recipes.rst:196
msgid "Compress on the fly and be fast doing so."
msgstr "压缩速度要快"
# 65c1fd4a55404e008c4a06f0666ab9a8
#: ../../recipes.rst:197
msgid "Do not compress for browsers that don't support it."
msgstr "如果浏览器不支持,则不压缩"
# 73e6653b779e443f9edfc0ec0bfffece
#: ../../recipes.rst:198
msgid "Do not compress files that are compressed already (images, videos)."
msgstr "不压缩那些已经充分压缩的文件(图像,视频)"
# b4c5eaedfa1843deb7bed64b690da0df
#: ../../recipes.rst:199
msgid "Do not compress dynamic files."
msgstr "不压缩动态文件"
# dcf512d9530e4c0a9f82b8b6acef1d99
#: ../../recipes.rst:200
msgid "Support two differed compression algorithms (gzip and deflate)."
msgstr "支持两种压缩算法(gzip和deflate)"
# 8f7b2d1ea78c4c54ad76f0c6e45c4b2c
#: ../../recipes.rst:201
msgid "Cache compressed files that don't change often."
msgstr "缓存那些不经常变化的压缩文件"
# 6a123a9ffb9d404c97b6fe7148082cc8
#: ../../recipes.rst:202
msgid "De-validate the cache if one of the files changed anyway."
msgstr ""
"不验证缓存中那些已经变化的文件(De-validate the cache if one of the files "
"changed anyway)"
# 31ba480ff2e64ac8809f2b5a8ba4d84f
#: ../../recipes.rst:203
msgid "Make sure the cache does not get to big."
msgstr "确保缓存不太大"
# 9cca12e96a2a46d1b0f50d0e191527a4
#: ../../recipes.rst:204
msgid ""
"Do not cache small files because a disk seek would take longer than on-the-"
"fly compression."
msgstr "不缓存小文件,因为寻道时间或许比压缩时间还长"
# fd7d6ff9d37f43a48ccaf1153bb6abbf
#: ../../recipes.rst:206
msgid ""
"Because of these requirements, it is the recommendation of the Bottle "
"project that Gzip compression is best handled by the WSGI server Bottle runs "
"on top of. WSGI servers such as cherrypy_ provide a GzipFilter_ middleware "
"that can be used to accomplish this."
msgstr ""
"因为有上述种种限制,建议由WSGI服务器来处理Gzip压缩而不是Bottle。像 cherrypy_ "
"就提供了一个 GzipFilter_ 中间件来处理Gzip压缩。"
# fa5e82e498e34c77bf4ce53402982640
#: ../../recipes.rst:210
msgid "Using the hooks plugin"
msgstr "使用钩子"
# 69f3eb65c7424b8fa5fafc5bbd19c280
#: ../../recipes.rst:212
msgid ""
"For example, if you want to allow Cross-Origin Resource Sharing for the "
"content returned by all of your URL, you can use the hook decorator and "
"setup a callback function::"
msgstr "例如,你想提供跨域资源共享,可参考下面的例子。"
# 27f25eeca0c140c881b5a82396063aaa
#: ../../recipes.rst:230
msgid ""
"You can also use the ``before_request`` to take an action before every "
"function gets called."
msgstr ""
"你也可以使用 ``before_request`` ,这样在route的回调函数被调用之前,都会调用你"
"的钩子函数。"
# 5882be32dd4040c8a642ff5f40a20229
#: ../../recipes.rst:235
msgid "Using Bottle with Heroku"
msgstr "在Heroku中使用Bottle"
# 2800373fd0754dc4adc7ebbb487dcdc3
#: ../../recipes.rst:237
msgid ""
"Heroku_, a popular cloud application platform now provides support for "
"running Python applications on their infastructure."
msgstr "Heroku_ ,一个流行的云应用平台,提供Python支持。"
# 6aa7d15dbd67437aad2028d56dae34f7
#: ../../recipes.rst:240
msgid ""
"This recipe is based upon the `Heroku Quickstart `_, with Bottle specific code replacing the `Write "
"Your App `_ "
"section of the `Getting Started with Python on Heroku/Cedar `_ guide::"
msgstr ""
"这份教程基于 `Heroku Quickstart `_, 用Bottle特有的代码替换了 `Getting Started with Python on "
"Heroku/Cedar `_ 中的`Write Your "
"App `_ 这部分::"
# 526acffa7fd4482db514db6e6da16ee5
#: ../../recipes.rst:256
msgid ""
"Heroku's app stack passes the port that the application needs to listen on "
"for requests, using the `os.environ` dictionary."
msgstr "Heroku使用 `os.environ` 字典来提供Bottle应用需要监听的端口。"
bottle-0.12.7/docs/_locale/zh_CN/deployment.po 0000644 0001750 0001750 00000044400 12327760172 017542 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-11-09 18:23\n"
"PO-Revision-Date: 2012-11-09 16:46+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# e79a5ecbd44d4b95b285c0c15aa604b5
#: ../../deployment.rst:27
msgid "Deployment"
msgstr "部署"
# 90d5d3c767a840e98624f37fe00e495a
#: ../../deployment.rst:29
msgid ""
"The bottle :func:`run` function, when called without any parameters, starts "
"a local development server on port 8080. You can access and test your "
"application via http://localhost:8080/ if you are on the same host."
msgstr ""
"不添加任何参数,直接运行Bottle的 :func:`run` 函数,会启动一个本地的开发服务"
"器,监听8080端口。你可在同一部主机上访问http://localhost:8080/来测试你的应"
"用。"
# be20533847e944aba27d3501a407c78b
#: ../../deployment.rst:31
msgid ""
"To get your application available to the outside world, specify the IP of "
"the interface the server should listen to (e.g. ``run(host='192.168.0.1')``) "
"or let the server listen to all interfaces at once (e.g. ``run"
"(host='0.0.0.0')``). The listening port can be changed in a similar way, but "
"you need root or admin rights to choose a port below 1024. Port 80 is the "
"standard for HTTP servers::"
msgstr ""
"可更改服务器监听的IP地址(例如: ``run(host='192.168.0.1')`` ),来让应用对其可"
"访问,或者让服务器接受所有地址的请求(例如: ``run(host='0.0.0.0')`` )。可通过"
"类似的方法改变服务器监听的端口,但如果你选择了一个小于1024的端口,则需要root"
"权限。HTTP服务器的标准端口是80端口::"
# 69e830c825454c2fbf350c56a6576300
#: ../../deployment.rst:36
msgid "Server Options"
msgstr "可选服务器"
# ef9d03fa6f634c1d858b1ba8e82f0bf8
#: ../../deployment.rst:38
msgid ""
"The built-in default server is based on `wsgiref WSGIServer `_. 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:"
msgstr ""
"内置的服务器基于 `wsgiref WSGIServer `_ 。这个单线程的HTTP服务器很适合用于开发,"
"但当服务器的负载上升的时候,会成为一个性能瓶颈。有三种方法可消除这一瓶颈:"
# ed2cadfab77a43b58b41257af4e1d365
#: ../../deployment.rst:40
msgid "Use a different server that is either multi-threaded or asynchronous."
msgstr "使用多线程或异步的服务器"
# 45dbb890ad694ccab24ebebe15d0272e
#: ../../deployment.rst:41
msgid ""
"Start multiple server processes and spread the load with a load-balancer."
msgstr "运行多个服务器,使用负载均衡"
# 6d7e312467b649c39d095bce6eec1751
#: ../../deployment.rst:42
msgid "Do both."
msgstr "同时使用上面两种方法"
# 1fa254c00fa4404a8ad6a599375d0b8c
#: ../../deployment.rst:44
msgid ""
"**Multi-threaded** servers are the 'classic' way to do it. They are very "
"robust, reasonably fast and easy to manage. As a drawback, they can only "
"handle a limited number of connections at the same time and utilize only one "
"CPU core due to the \"Global Interpreter Lock\" (GIL). This does not hurt "
"most applications, they are waiting for network IO most of the time anyway, "
"but may slow down CPU intensive tasks (e.g. image processing)."
msgstr ""
"**多线程** 服务器是经典的解决方法。它们非常鲁棒(稳定),快速和易于管理。但它们"
"也有缺点,同时只能处理固定数量的请求,因为全局解释器锁(GIL)的存在,所有只能利"
"用一个CPU核心。对于大部分的应用而言,这无伤大雅,也许它们大部分时间都在等待网"
"络IO。但对于一些比较耗CPU的应用(例如图像处理),就要考虑性能问题了。"
# 41ca69b13f1c4182905d274e18a5b298
#: ../../deployment.rst:46
msgid ""
"**Asynchronous** servers are very fast, can handle a virtually unlimited "
"number of concurrent connections and are easy to manage, but can get a bit "
"tricky. To take full advantage of their potential, you need to design your "
"application accordingly and understand the concepts of the specific server."
msgstr ""
"**异步** 服务器非常快,同时处理的请求数无上限,也方便管理。为了充分利用它们的"
"潜力,你需要根据异步的原理来设计你的应用,了解它们的工作机制。"
# 6b274d7997da4dbab0ad352a0b6af597
#: ../../deployment.rst:48
msgid ""
"**Multi-processing** (forking) servers are not limited by the GIL and "
"utilize more than one CPU core, but make communication between server "
"instances more expensive. You need a database or external message query to "
"share state between processes, or design your application so that it does "
"not need any shared state. The setup is also a bit more complicated, but "
"there are good tutorials available."
msgstr ""
"**多进程** (forking) 服务器就没有受到GIL的限制,能利用多个CPU核心,但服务器实"
"例之间的交流代价比较高昂。你需要一个数据库或消息队列来在进程之间共享状态,或"
"将你的应用设计成根本不需要共享状态。多进程服务器的安装也比较负责,但已经有很"
"多好的教程了。"
# 7950fbc4dbe849af9b6e8fcbc7fbad8c
#: ../../deployment.rst:51
msgid "Switching the Server Backend"
msgstr "更改服务器后端"
# 5e77521d11344f92a28053e59281eff6
#: ../../deployment.rst:53
msgid ""
"The easiest way to increase performance is to install a multi-threaded "
"server library like paste_ or cherrypy_ and tell Bottle to use that instead "
"of the single-threaded server::"
msgstr ""
"提高性能最简单的办法,是安装一个多线程的服务器库,例如 paste_ 和 cherrypy_ ,"
"然后告诉Bottle使用它们。"
# 06a336e02f474466b2ced7bc0d1f7847
#: ../../deployment.rst:57
msgid ""
"Bottle ships with a lot of ready-to-use adapters for the most common WSGI "
"servers and automates the setup process. Here is an incomplete list:"
msgstr ""
"Bottle为很多常见的WSGI服务器都编写了适配器,能自动化安装过程。下面是一个不完"
"整的清单:"
# 1aa1ab9777c84fa3b40112b866976d2c
#: ../../deployment.rst:60
msgid "Name"
msgstr "名称"
# a9840552bf3248acb79506092785a343
#: ../../deployment.rst:60
msgid "Homepage"
msgstr "主页"
# 2b35d4918e0f4386aa7ad7b857486c67
#: ../../deployment.rst:60
msgid "Description"
msgstr "描述"
# d5996a4c22e448af81100e2762b8e852
#: ../../deployment.rst:62
msgid "cgi"
msgstr ""
# da5c8bd6130b4a2ab82cc8ed2c66a17c
#: ../../deployment.rst:62
msgid "Run as CGI script"
msgstr ""
# 611871b28f1349a7811638c538fc3eb1
#: ../../deployment.rst:63
msgid "flup"
msgstr ""
# b6ca7e7cc7d84786b66f3a66b1dac28c
#: ../../deployment.rst:63
msgid "flup_"
msgstr ""
# 8730e1384f3c4ca5bd4ae22a205254b9
#: ../../deployment.rst:63
msgid "Run as FastCGI process"
msgstr ""
# 0618b584d4cc49909da1ba31777c181b
#: ../../deployment.rst:64
msgid "gae"
msgstr ""
# 747662cc00794894970a3ac8ce7e04d3
#: ../../deployment.rst:64
msgid "gae_"
msgstr ""
# 9dc8135f97ba416187e21da3265bf6a6
#: ../../deployment.rst:64
msgid "Helper for Google App Engine deployments"
msgstr "用于Google App Engine"
# 1cfd09034d7e4d7780ec0ada01cc1bc6
#: ../../deployment.rst:65
msgid "wsgiref"
msgstr ""
# f1227078c6fc487bb5ac4b6f0ec36468
#: ../../deployment.rst:65
msgid "wsgiref_"
msgstr ""
# f250f65fdf9b4f9bbc9d6a5955590ed5
#: ../../deployment.rst:65
msgid "Single-threaded default server"
msgstr "默认的单线程服务器"
# 01d364e912d04e3c8e293f5a2e8961b3
#: ../../deployment.rst:66
msgid "cherrypy"
msgstr ""
# fa5d69dde84a42cf835a41d99b6956fb
#: ../../deployment.rst:66
msgid "cherrypy_"
msgstr ""
# 0f31f5406dd342adbfe7fce1412bda34
#: ../../deployment.rst:66
msgid "Multi-threaded and very stable"
msgstr "多线程,稳定"
# 1e7de22115ad4ae69df9b6a8324ab8cd
#: ../../deployment.rst:67
msgid "paste"
msgstr ""
# 2663f8370e1548e48310eda696f6b7a1
#: ../../deployment.rst:67
msgid "paste_"
msgstr ""
# 7799c8e33cc4411fb9c8b3cf5f5cb011
#: ../../deployment.rst:67
msgid "Multi-threaded, stable, tried and tested"
msgstr "多线程,稳定,久经考验,充分测试"
# 1ec1f0afa1944692af933626c83e1e59
#: ../../deployment.rst:68
msgid "rocket"
msgstr ""
# 021f3f12795f4be688799b34b6f56e9d
#: ../../deployment.rst:68
msgid "rocket_"
msgstr ""
# 51b02f23b9a14accbba41e59aacd4bf4
#: ../../deployment.rst:68
msgid "Multi-threaded"
msgstr "多线程"
# e10f6b047c6144c0bfd0543b1e9a8d26
#: ../../deployment.rst:69
msgid "waitress"
msgstr ""
# eaa5c14173e642568041d89317456cda
#: ../../deployment.rst:69
msgid "waitress_"
msgstr ""
# 52a0ea00e1314e85a34af85cc67dc611
#: ../../deployment.rst:69
msgid "Multi-threaded, poweres Pyramid"
msgstr "多线程,源于Pyramid"
# a40591f82b0b4586b8deb5e1cb8958f7
#: ../../deployment.rst:70
msgid "gunicorn"
msgstr ""
# 54bda396687149e38384c16f7e1602cd
#: ../../deployment.rst:70
msgid "gunicorn_"
msgstr ""
# be07f75ddcfa46b39c1c4a012091ed4a
#: ../../deployment.rst:70
msgid "Pre-forked, partly written in C"
msgstr ""
# ccab55aeedef4b9a8b27724b90e9147e
#: ../../deployment.rst:71
msgid "eventlet"
msgstr ""
# c75912557c7443e39686a53a0d50f310
#: ../../deployment.rst:71
msgid "eventlet_"
msgstr ""
# dcd1301f85fc4f508edfb145936a8981
#: ../../deployment.rst:71
msgid "Asynchronous framework with WSGI support."
msgstr "支持WSGI的异步框架"
# e74b58a9d7d54b1b94bbc7a1ffa40195
#: ../../deployment.rst:72
msgid "gevent"
msgstr ""
# 2beea95f00d144f7921a885d8c27539d
#: ../../deployment.rst:72
msgid "gevent_"
msgstr ""
# a80c773e08fa4a8999e1b880e595cdfc
# a2c352eaf5234afea0a8dbbd39c8d95c
#: ../../deployment.rst:72 ../../deployment.rst:73
msgid "Asynchronous (greenlets)"
msgstr "异步 (greenlets)"
# e4239c25b7c243a8a65c3376b6324657
#: ../../deployment.rst:73
msgid "diesel"
msgstr ""
# f1f4d6225de948728236ff63a6061b8b
#: ../../deployment.rst:73
msgid "diesel_"
msgstr ""
# 47bf711ccf4c4bc3a27294ffac85012b
#: ../../deployment.rst:74
msgid "fapws3"
msgstr ""
# 6c2749281ce54842b60dfdd8102f0760
#: ../../deployment.rst:74
msgid "fapws3_"
msgstr ""
# bbd374f295eb4cd5837e348023187fa1
#: ../../deployment.rst:74
msgid "Asynchronous (network side only), written in C"
msgstr "异步 (network side only), written in C"
# 38e55f3ef23b453ca4be59de80a86a58
#: ../../deployment.rst:75
msgid "tornado"
msgstr ""
# b68f024f752143fea2d3551f06535724
#: ../../deployment.rst:75
msgid "tornado_"
msgstr ""
# 127ad8b4a945499b8e03e3eac662e96e
#: ../../deployment.rst:75
msgid "Asynchronous, powers some parts of Facebook"
msgstr "异步,支撑Facebook的部分应用"
# c319318ff0e747249048d1492ff9d468
#: ../../deployment.rst:76
msgid "twisted"
msgstr ""
# 474bfbaf4c4b471ca12ff95d43b72fc5
#: ../../deployment.rst:76
msgid "twisted_"
msgstr ""
# fded1b2c80334bf7b8d62fef6a3cc106
#: ../../deployment.rst:76
msgid "Asynchronous, well tested but... twisted"
msgstr "异步, well tested but... twisted"
# a51d20d8c07a4d6593dd44141d90df6a
#: ../../deployment.rst:77
msgid "meinheld"
msgstr ""
# a5d7d4a87937454c817bd6b4954c780b
#: ../../deployment.rst:77
msgid "meinheld_"
msgstr ""
# 1c4d989fa3aa4dbbbd435c88308f85c3
#: ../../deployment.rst:77
msgid "Asynchronous, partly written in C"
msgstr "异步,部分用C语言编写"
# 9accb12067ce403e958cb544323edc95
#: ../../deployment.rst:78
msgid "bjoern"
msgstr ""
# bef5c69cc89647d19caa34443bf05be2
#: ../../deployment.rst:78
msgid "bjoern_"
msgstr ""
# b3658d3992e94bee930a3c902f320b7c
#: ../../deployment.rst:78
msgid "Asynchronous, very fast and written in C"
msgstr "异步,用C语言编写,非常快"
# 6d5ee7b287ce47199e1eb806df41da12
#: ../../deployment.rst:79
msgid "auto"
msgstr ""
# 06a3e02e1e4449fba32bbc704e180011
#: ../../deployment.rst:79
msgid "Automatically selects an available server adapter"
msgstr "自动选择一个可用的服务器"
# 584162cdf6474670a29f2fcadd147b13
#: ../../deployment.rst:82
msgid "The full list is available through :data:`server_names`."
msgstr "完整的列表在 :data:`server_names` 。"
# cc5a1335e0c64f6399dd070a1f6ef5bd
#: ../../deployment.rst:84
msgid ""
"If there is no adapter for your favorite server or if you need more control "
"over the server setup, you may want to start the server manually. Refer to "
"the server documentation on how to run WSGI applications. Here is an example "
"for paste_::"
msgstr ""
"如果没有适合你的服务器的适配器,或者你需要更多地控制服务器的安装,你也许需要"
"手动启动服务器。可参考你的服务器的文档,看看是如何运行一个WSGI应用。下面是一"
"个使用 paste_ 的例子。"
# 8c6a91e237a24498b5c3223a616e1254
#: ../../deployment.rst:93
msgid "Apache mod_wsgi"
msgstr ""
# a72769ad7e8a42bfa796f3b995a70e4b
#: ../../deployment.rst:95
msgid ""
"Instead of running your own HTTP server from within Bottle, you can attach "
"Bottle applications to an `Apache server `_ using mod_wsgi_."
msgstr ""
"除了直接在Bottle里面运行HTTP服务器,你也可以将你的应用部署到一个Apache服务器"
"上,使用 mod_wsgi_ 来运行。"
# 935849b733614fc58e5463e5c6ba69bf
#: ../../deployment.rst:97
msgid ""
"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-compatible Python callable."
msgstr ""
"你需要的只是提供一个 ``application`` 对象的 ``app.wsgi`` 文件。mod_wsgi会使用"
"这个对象来启动你的应用,这个对象必须是兼容WSGI的 callable对象。"
# 28f009fc7c0f42a39d30b818126dc74d
#: ../../deployment.rst:99
msgid "File ``/var/www/yourapp/app.wsgi``::"
msgstr " ``/var/www/yourapp/app.wsgi`` 文件 "
# a76a11ae64834882baa0ee1d0e2c723d
#: ../../deployment.rst:109
msgid "The Apache configuration may look like this::"
msgstr "Apache的配置"
# 7620c70255014ffe8840ca0709d76c7a
#: ../../deployment.rst:128
msgid "Google AppEngine"
msgstr ""
# d4ace9ef663f42bb9357a450ce95320b
#: ../../deployment.rst:132
msgid ""
"The ``gae`` server adapter is used to run applications on Google App Engine. "
"It works similar to the ``cgi`` adapter in that it does not start a new HTTP "
"server, but prepares and optimizes your application for Google App Engine "
"and makes sure it conforms to their API::"
msgstr ""
"``gae`` 这个服务器适配器可在Google App Engine上运行你的应用。它的工作方式和 "
"``cgi`` 适配器类似,并没有启动一个HTTP服务器,只是针对做了一下准备和优化工"
"作。确保你的应用遵守Google App Engine的API。"
# 7c4fa384b251470eb198fc0f0b1816fe
#: ../../deployment.rst:136
msgid ""
"It is always a good idea to let GAE serve static files directly. Here is "
"example for a working ``app.yaml``::"
msgstr ""
"直接让GAE来提供静态文件服务总是一个好主意。类似的可工作的 ``app.yaml`` 文件如"
"下。"
# 98b002b7a9b542a19a83b81fe317239d
#: ../../deployment.rst:152
msgid "Load Balancer (Manual Setup)"
msgstr "负载均衡 (手动安装)"
# 442149987ce2410b9d03f1a48248af9c
#: ../../deployment.rst:154
msgid ""
"A single Python process can utilize only 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."
msgstr ""
"单一的Python进程一次只能使用一个CPU内核,即使CPU是多核的。我们的方法就是在多"
"核CPU的机器上,使用多线程来实现负载均衡。"
# 10fef6601a4048f3a0604fc672fb8fb6
#: ../../deployment.rst:156
msgid ""
"Instead of a single Bottle application server, you start one instance for "
"each CPU core available using different local port (localhost:8080, 8081, "
"8082, ...). You can choose any server adapter you want, even asynchronous "
"ones. Then a high performance load balancer acts as a reverse proxy and "
"forwards each new requests to a random port, spreading the load between all "
"available back-ends. This way you can use all of your CPU cores and even "
"spread out the load between different physical servers."
msgstr ""
"不只是启动一个应用服务器,你需要同时启动多个应用服务器,监听不同的端口"
"(localhost:8080, 8081, 8082, ...)。你可选择任何服务器,甚至那些异步服务器。然"
"后一个高性能的负载均衡器,像一个反向代理那样工作,将新的请求发送到一个随机端"
"口,在多个服务器之间分散压力。这样你就可以利用所有的CPU核心,甚至在多个机器上"
"实现负载均衡。"
# d77aec94ad8a4986bb0ae2761ebcffa4
#: ../../deployment.rst:158
msgid ""
"One of the fastest load balancers available is Pound_ but most common web "
"servers have a proxy-module that can do the work just fine."
msgstr ""
" Pound_ 是最快的负载均衡器之一,但是只要有代理模块的Web服务器,也可以充当这一"
"角色。"
# fcbb45ba206244d893de7e13415b56d7
#: ../../deployment.rst:160
msgid "Pound example::"
msgstr "Pound的例子::"
# fab06de93eed468ebdfa731b5407a43e
#: ../../deployment.rst:178
msgid "Apache example::"
msgstr "Apache的例子::"
# 3cdac45e435942a09076cf399934985e
#: ../../deployment.rst:186
msgid "Lighttpd example::"
msgstr "Lighttpd的例子::"
# e4f5617ee96b4550b47db6fd041c819c
#: ../../deployment.rst:198
msgid "Good old CGI"
msgstr "CGI这个老好人"
# a62b689e2ad0402a9d9acba6458e4781
#: ../../deployment.rst:200
msgid ""
"A CGI server starts a new process for each request. This adds a lot of "
"overhead but is sometimes the only option, especially on cheap hosting "
"packages. The `cgi` server adapter does not actually start a CGI server, but "
"transforms your bottle application into a valid CGI application::"
msgstr ""
"CGI服务器会为每个请求启动一个进程。虽然这样代价高昂,但有时这是唯一的选择。 "
"`cgi` 这个适配器实际上并没有启动一个CGI服务器,只是将你的Bottle应用转换成了一"
"个有效的CGI应用。"
bottle-0.12.7/docs/_locale/zh_CN/index.po 0000644 0001750 0001750 00000014066 12327760172 016476 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-09 18:12\n"
"PO-Revision-Date: 2013-08-09 17:25+0800\n"
"Last-Translator: \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.7\n"
# 982a9ff09f57469ea201f9681c77d2c3
#: ../../index.rst:20
msgid "Bottle: Python Web Framework"
msgstr "Bottle: Python Web框架"
# 4c5d800e46c2412a9f777bdcf45828bc
#: ../../index.rst:22
msgid ""
"Bottle is a fast, simple and lightweight WSGI_ micro web-framework for "
"Python_. It is distributed as a single file module and has no dependencies "
"other than the `Python Standard Library `_."
msgstr ""
"Bottle是一个快速,简单,轻量级的 Python_ WSGI_ Web框架。单一文件,只依赖 "
"`Python标准库 `_ 。"
# 87fb9bd30b3b41448aa966e6f47b3495
#: ../../index.rst:25
msgid ""
"**Routing:** Requests to function-call mapping with support for clean and "
"dynamic URLs."
msgstr ""
"**URL映射(Routing):** 将URL请求映射到Python函数,支持动态URL,且URL更简洁。"
# 3d7f52b05cb741c99ec48b8ff29f9b73
#: ../../index.rst:26
msgid ""
"**Templates:** Fast and pythonic :ref:`built-in template engine ` and support for mako_, jinja2_ and cheetah_ templates."
msgstr ""
"**模板(Templates):** 快速且pythonic的 :ref:`内置模板引擎 ` ,同时支持 mako_ , jinja2_ 和 cheetah_ 等模板。"
# 1ef9c634d3b148dbb49d21228a9cddaf
#: ../../index.rst:27
msgid ""
"**Utilities:** Convenient access to form data, file uploads, cookies, "
"headers and other HTTP-related metadata."
msgstr ""
"**基础功能(Utilities):** 方便地访问表单数据,上传文件,使用cookie,查看HTTP元"
"数据。"
# a9afd6291c9745d48c909e1cfa96b62c
#: ../../index.rst:28
msgid ""
"**Server:** Built-in HTTP development server and support for paste_, "
"fapws3_, bjoern_, `Google App Engine `_, cherrypy_ or any other WSGI_ capable HTTP server."
msgstr ""
"**开发服务器(Server):** 内置了开发服务器,且支持 paste_, fapws3_ , bjoern_, "
"`Google App Engine `_, "
"cherrypy_ 等符合 WSGI_ 标准的HTTP服务器。"
# 17ee65d0e5434da2971dad90262f8998
#: ../../index.rst:31
msgid "Example: \"Hello World\" in a bottle"
msgstr "示例: \"Hello World\""
# 576fbd7f466749fea3553b0c70cded4a
#: ../../index.rst:42
msgid ""
"Run this script or paste it into a Python console, then point your browser "
"to ``_. That's it."
msgstr ""
"将其保存为py文件并执行,用浏览器访问 ``_ "
"即可看到效果。就这么简单!"
# 2e1347a5473444f7b5c95be5ece49b80
#: ../../index.rst:45
msgid "Download and Install"
msgstr "下载和安装"
# da4edbc4bf894ed09f69ff20784f656c
#: ../../index.rst:50
msgid ""
"Install the latest stable release via PyPI_ (``easy_install -U bottle``) or "
"download `bottle.py`__ (unstable) into your project directory. There are no "
"hard [1]_ dependencies other than the Python standard library. Bottle runs "
"with **Python 2.5+ and 3.x**."
msgstr ""
"通过 PyPI_ (``easy_install -U bottle``)安装最新的稳定版,或下载 `bottle."
"py`__ (开发版)到你的项目文件夹。 Bottle除了Python标准库无任何依赖 [1]_ ,同时"
"支持 **Python 2.5+ and 3.x** 。"
# e4e0c283078a4bc7b60281c8c96116f3
#: ../../index.rst:53
msgid "User's Guide"
msgstr "用户指南"
# 0fb51b23ecd3442599753dde04753b38
#: ../../index.rst:54
msgid ""
"Start here if you want to learn how to use the bottle framework for web "
"development. If you have any questions not answered here, feel free to ask "
"the `mailing list `_."
msgstr ""
"如果你有将Bottle用于Web开发的打算,请继续看下去。如果这份文档没有解决你遇到的"
"问题,尽管在 `邮件列表 `_ 中吼出来吧(译者"
"注:用英文哦)。"
# cfb536e857dc41b0bf43f0e185d47e98
#: ../../index.rst:68
msgid "Knowledge Base"
msgstr "知识库"
# baeb4c393ec246b690500089c6647096
#: ../../index.rst:69
msgid "A collection of articles, guides and HOWTOs."
msgstr "收集文章,使用指南和HOWTO"
# 7c0f6a746c0f4a5da9fb8da7dec405da
#: ../../index.rst:81
msgid "Development and Contribution"
msgstr "开发和贡献"
# 8c7445707fd945a4a8e0fdf6e5055edd
#: ../../index.rst:83
msgid ""
"These chapters are intended for developers interested in the bottle "
"development and release workflow."
msgstr "这些章节是为那些对Bottle的开发和发布流程感兴趣的开发者准备的。"
# 5dc3afd489cb4053a42ab582b40e2985
#: ../../index.rst:99
msgid "License"
msgstr "许可证"
# 04840f1a47654598a640bc3fd44bdb10
#: ../../index.rst:101
msgid "Code and documentation are available according to the MIT License:"
msgstr "代码和文件皆使用MIT许可证:"
# 4eaa7176213e47189636c52b21aa9d0d
#: ../../index.rst:106
msgid ""
"The Bottle logo however is *NOT* covered by that license. It is allowed to "
"use the logo as a link to the bottle homepage or in direct context with the "
"unmodified library. In all other cases please ask first."
msgstr ""
"然而,许可证 *不包含* Bottle的logo。logo用作指向Bottle主页的连接,或未修改过"
"的类库。如要用于其它用途,请先请求许可。"
# 9ede3f752bd74e2280f3b15cdbbe0796
#: ../../index.rst:111
msgid "Footnotes"
msgstr "脚注"
# a8762741595242a89d72fa712bcf95dc
#: ../../index.rst:112
msgid ""
"Usage of the template or server adapter classes of course requires the "
"corresponding template or server modules."
msgstr "如果使用了第三方的模板或HTTP服务器,则需要安装相应的第三方模块。"
bottle-0.12.7/docs/_locale/zh_CN/api.po 0000644 0001750 0001750 00000136116 12327760172 016141 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-09 17:22\n"
"PO-Revision-Date: 2012-11-09 16:39+0800\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
# fbe35ab019974025ade6c7afb67ec0e9
#: ../../api.rst:3
msgid "API Reference"
msgstr "API参考"
# 07f8bab761f04aea8b9c9ecd467acdff
#: ../../api.rst:10
msgid ""
"This is a mostly auto-generated API. If you are new to bottle, you might "
"find the narrative :doc:`tutorial` more helpful."
msgstr ""
"这份文档几乎是全自动生成的。如果你刚接触bottle,也许 :doc:`tutorial` 会更有帮"
"助。"
# 60b4c8f092624c28907f8e014404266e
#: ../../api.rst:17
msgid "Module Contents"
msgstr ""
# 623845929cb84fb3922263ab0e1cf6d6
#: ../../api.rst:19
msgid "The module defines several functions, constants, and an exception."
msgstr ""
# 0360779739fe41d19735b61aa7654001
#: ../../../bottle.py:docstring of bottle.debug:1
msgid ""
"Change the debug level. There is only one debug level supported at the "
"moment."
msgstr ""
# 644c0a8eb325483696b60bed16c2df4a
#: ../../../bottle.py:docstring of bottle.run:1
msgid ""
"Start a server instance. This method blocks until the server terminates."
msgstr ""
# ba4e497a63924813b2ab8457a1916492
#: ../../../bottle.py:docstring of bottle.load:1
msgid "Import a module or fetch an object from a module."
msgstr ""
# 4d283ca03c2b4fdf8cfcd08dc8ade89f
#: ../../../bottle.py:docstring of bottle.load:3
msgid "``package.module`` returns `module` as a module object."
msgstr ""
# a4770e87e7f64c6e8ea511221fdda6d6
#: ../../../bottle.py:docstring of bottle.load:4
msgid "``pack.mod:name`` returns the module variable `name` from `pack.mod`."
msgstr ""
# 8de14751c87f4652902fa858c868c1e2
#: ../../../bottle.py:docstring of bottle.load:5
msgid "``pack.mod:func()`` calls `pack.mod.func()` and returns the result."
msgstr ""
# 0f4be93ee77340c89bd64e958f9522dd
#: ../../../bottle.py:docstring of bottle.load:7
msgid ""
"The last form accepts not only function calls, but any type of expression. "
"Keyword arguments passed to this function are available as local variables. "
"Example: ``import_string('re:compile(x)', x='[a-z]')``"
msgstr ""
# 8a6e30706f344350b925379e177df002
#: ../../../bottle.py:docstring of bottle.load_app:1
msgid ""
"Load a bottle application from a module and make sure that the import does "
"not affect the current default application, but returns a separate "
"application object. See :func:`load` for the target parameter."
msgstr ""
# e0839bf597c5432d98d9ff1364b794c6
#: ../../../bottle.py:docstring of bottle.request:1
msgid ""
"A thread-safe instance of :class:`LocalRequest`. If accessed from within a "
"request callback, this instance always refers to the *current* request (even "
"on a multithreaded server)."
msgstr ""
# 301be6b4c0db45d9828169e666cb4a87
#: ../../../bottle.py:docstring of bottle.response:1
msgid ""
"A thread-safe instance of :class:`LocalResponse`. It is used to change the "
"HTTP response for the *current* request."
msgstr ""
# 2182bbf9e89a407aa0fd3505735347c4
#: ../../../bottle.py:docstring of bottle.HTTP_CODES:1
msgid ""
"A dict to map HTTP status codes (e.g. 404) to phrases (e.g. 'Not Found')"
msgstr ""
# 4e6bc011ddb0490c8f82636be99ccb9a
#: ../../api.rst:38
msgid ""
"Return the current :ref:`default-app`. Actually, these are callable "
"instances of :class:`AppStack` and implement a stack-like API."
msgstr ""
# 993cefb361da4f4f8d2888d9eb460653
#: ../../api.rst:42
msgid "Routing"
msgstr ""
# b5505727f5cf4beea9f751b5f60e64c4
#: ../../api.rst:44
msgid ""
"Bottle maintains a stack of :class:`Bottle` instances (see :func:`app` and :"
"class:`AppStack`) and uses the top of the stack as a *default application* "
"for some of the module-level functions and decorators."
msgstr ""
# 825650775f864ee19fa78603d427bdba
#: ../../api.rst:53
msgid ""
"Decorator to install a route to the current default application. See :meth:"
"`Bottle.route` for details."
msgstr ""
# e714829c069d4e138db734ab96085e8a
#: ../../api.rst:58
msgid ""
"Decorator to install an error handler to the current default application. "
"See :meth:`Bottle.error` for details."
msgstr ""
# 8f769dab5b9442e6ad49d3cb9f4754ef
#: ../../api.rst:62
msgid "WSGI and HTTP Utilities"
msgstr ""
# 34b4f8fb4f8e442aa28d8477a30d99a4
#: ../../../bottle.py:docstring of bottle.parse_date:1
msgid "Parse rfc1123, rfc850 and asctime timestamps and return UTC epoch."
msgstr ""
# 001de5f591de4f378d902641f9a03e90
#: ../../../bottle.py:docstring of bottle.parse_auth:1
msgid ""
"Parse rfc2617 HTTP authentication header string (basic) and return (user,"
"pass) tuple or None"
msgstr ""
# 2675c3c439fc45818d55c0fdbb191683
#: ../../../bottle.py:docstring of bottle.cookie_encode:1
msgid "Encode and sign a pickle-able object. Return a (byte) string"
msgstr ""
# 9eb5a61979b54811805b6fe53e3d3ee3
#: ../../../bottle.py:docstring of bottle.cookie_decode:1
msgid "Verify and decode an encoded string. Return an object or None."
msgstr ""
# 13f13118209b4b67b7894b428db9bde8
#: ../../../bottle.py:docstring of bottle.cookie_is_encoded:1
msgid "Return True if the argument looks like a encoded cookie."
msgstr ""
# 7d33d97d4fdb41398aef0d56d4a49250
#: ../../../bottle.py:docstring of bottle.yieldroutes:1
msgid ""
"Return a generator for routes that match the signature (name, args) of the "
"func parameter. This may yield more than one route if the function takes "
"optional keyword arguments. The output is best described by example::"
msgstr ""
# 1f2dbbce55f942beb1a0000a82f29c06
#: ../../../bottle.py:docstring of bottle.path_shift:1
msgid "Shift path fragments from PATH_INFO to SCRIPT_NAME and vice versa."
msgstr ""
# cbffed2b48824bb0b4fe9f26b454a260
#: ../../api.rst:80
msgid "Data Structures"
msgstr ""
# 7585a471a000456eb2970b4039f17ff6
#: ../../../bottle.py:docstring of bottle.MultiDict:1
msgid ""
"This dict stores multiple values per key, but behaves exactly like a normal "
"dict in that it returns only the newest value for any given key. There are "
"special methods available to access the full list of values."
msgstr ""
# 48ce9646c309413192f0cded0189750f
#: ../../../bottle.py:docstring of bottle.MultiDict.get:1
msgid "Return the most recent value for a key."
msgstr ""
# 6bc19fc65e4f475083fd1eb47c28bd51
#: ../../../bottle.py:docstring of bottle.MultiDict.append:1
msgid "Add a new value to the list of values for this key."
msgstr ""
# 76d54d9bb2fa476a9ba3e1fb47c48f75
#: ../../../bottle.py:docstring of bottle.MultiDict.replace:1
msgid "Replace the list of values with a single value."
msgstr ""
# 6b739bda1f2d47dead2c240ce156a52c
# 408d04186344473197fdfda230a11a43
#: ../../../bottle.py:docstring of bottle.MultiDict.getall:1
#: bottle.MultiDict.getlist:1
msgid "Return a (possibly empty) list of values for a key."
msgstr ""
# 096a32b3920840ae81aeb1b74df13937
#: ../../../bottle.py:docstring of bottle.MultiDict.getone:1
msgid "Aliases for WTForms to mimic other multi-dict APIs (Django)"
msgstr ""
# 568f7d1aa3de48b3b585c2ce4f507364
#: ../../../bottle.py:docstring of bottle.HeaderDict:1
msgid ""
"A case-insensitive version of :class:`MultiDict` that defaults to replace "
"the old value instead of appending it."
msgstr ""
# 33192248b67945f6ab3bdfaae1022853
#: ../../../bottle.py:docstring of bottle.FormsDict:1
msgid ""
"This :class:`MultiDict` subclass is used to store request form data. "
"Additionally to the normal dict-like item access methods (which return "
"unmodified data as native strings), this container also supports attribute-"
"like access to its values. Attributes are automatically de- or recoded to "
"match :attr:`input_encoding` (default: 'utf8'). Missing attributes default "
"to an empty string."
msgstr ""
# 5767896f774f4c0cbc60b12de9ebe4b4
#: ../../../bottle.py:docstring of bottle.FormsDict.input_encoding:1
msgid "Encoding used for attribute values."
msgstr ""
# 0f6a6fd12b4e432b85a28dc0cb33e6f5
#: ../../../bottle.py:docstring of bottle.FormsDict.recode_unicode:1
msgid ""
"If true (default), unicode strings are first encoded with `latin1` and then "
"decoded to match :attr:`input_encoding`."
msgstr ""
# bfe4e448783b491a90d44d940c065e06
#: ../../../bottle.py:docstring of bottle.FormsDict.decode:1
msgid ""
"Returns a copy with all keys and values de- or recoded to match :attr:"
"`input_encoding`. Some libraries (e.g. WTForms) want a unicode dictionary."
msgstr ""
# 7fc82cc9c0834b7da08e3b3860e1a9d6
#: ../../../bottle.py:docstring of bottle.FormsDict.getunicode:1
msgid "Return the value as a unicode string, or the default."
msgstr ""
# 19ac58e686224a19b67845c5061582f2
#: ../../../bottle.py:docstring of bottle.WSGIHeaderDict:1
msgid ""
"This dict-like class wraps a WSGI environ dict and provides convenient "
"access to HTTP_* fields. Keys and values are native strings (2.x bytes or 3."
"x unicode) and keys are case-insensitive. If the WSGI environment contains "
"non-native string values, these are de- or encoded using a lossless 'latin1' "
"character set."
msgstr ""
# eec339b8e4ac4faca373130a77190a85
#: ../../../bottle.py:docstring of bottle.WSGIHeaderDict:7
msgid ""
"The API will remain stable even on changes to the relevant PEPs. Currently "
"PEP 333, 444 and 3333 are supported. (PEP 444 is the only one that uses non-"
"native strings.)"
msgstr ""
# 693b370f02d74df0b1e7851290f831ed
#: ../../../bottle.py:docstring of bottle.WSGIHeaderDict.cgikeys:1
msgid "List of keys that do not have a ``HTTP_`` prefix."
msgstr ""
# 0c70f44ff2a543bc92035a4a1578505b
#: ../../../bottle.py:docstring of bottle.WSGIHeaderDict.raw:1
msgid "Return the header value as is (may be bytes or unicode)."
msgstr ""
# bd725bbc2a0c4b508fe46abf350a0661
#: ../../../bottle.py:docstring of bottle.AppStack:1
msgid "A stack-like list. Calling it returns the head of the stack."
msgstr ""
# 379355eb37684a51837275ae5bcf062c
#: ../../api.rst:99
msgid "Return the current default application and remove it from the stack."
msgstr ""
# 1650474558c047ae8ce151129af31a3e
#: ../../../bottle.py:docstring of bottle.AppStack.push:1
msgid "Add a new :class:`Bottle` instance to the stack"
msgstr ""
# 19a9f2b2e67a4983a1c300631f14ad2c
#: ../../../bottle.py:docstring of bottle.ResourceManager:1
msgid ""
"This class manages a list of search paths and helps to find and open "
"application-bound resources (files)."
msgstr ""
# 2196cd941c6646f586f7c4990cc9e99d
#: ../../../bottle.py:docstring of bottle.ResourceManager.path:1
msgid "A list of search paths. See :meth:`add_path` for details."
msgstr ""
# 25c2e942f3174e4080e1051805eef350
#: ../../../bottle.py:docstring of bottle.ResourceManager.cache:1
msgid "A cache for resolved paths. ``res.cache.clear()`` clears the cache."
msgstr ""
# 84f7c5ef07074d959c37d62815af0f71
#: ../../../bottle.py:docstring of bottle.ResourceManager.add_path:1
msgid ""
"Add a new path to the list of search paths. Return False if the path does "
"not exist."
msgstr ""
# d5787be650274ae99b6d45a61dbeb300
#: ../../../bottle.py:docstring of bottle.ResourceManager.add_path:12
msgid ""
"The `base` parameter makes it easy to reference files installed along with a "
"python module or package::"
msgstr ""
# 6aaae04bb6304323bed63f45614eb041
#: ../../../bottle.py:docstring of bottle.ResourceManager.lookup:1
msgid "Search for a resource and return an absolute file path, or `None`."
msgstr ""
# 88d250b10df24f0aa72ae15640d2f274
#: ../../../bottle.py:docstring of bottle.ResourceManager.lookup:3
msgid ""
"The :attr:`path` list is searched in order. The first match is returend. "
"Symlinks are followed. The result is cached to speed up future lookups."
msgstr ""
# ffc785d1770d40aa872ea22d52233c02
#: ../../../bottle.py:docstring of bottle.ResourceManager.open:1
msgid "Find a resource and return a file object, or raise IOError."
msgstr ""
# fcec5a93e13a48b68e251a6a8f94d74f
#: ../../../bottle.py:docstring of bottle.FileUpload.file:1
msgid "Open file(-like) object (BytesIO buffer or temporary file)"
msgstr ""
# 48ffa5c976f245d0becc21a9e2c62bb6
#: ../../../bottle.py:docstring of bottle.FileUpload.name:1
msgid "Name of the upload form field"
msgstr ""
# 2a94d248a0804134b8b2950ee6872a16
#: ../../../bottle.py:docstring of bottle.FileUpload.raw_filename:1
msgid "Raw filename as sent by the client (may contain unsafe characters)"
msgstr ""
# e6845621bb9d42ccba141441bc8a5bc5
#: ../../../bottle.py:docstring of bottle.FileUpload.headers:1
msgid "A :class:`HeaderDict` with additional headers (e.g. content-type)"
msgstr ""
# ec33f9a869df439ab4ca59a460350271
#: ../../../bottle.py:docstring of bottle.FileUpload.content_type:1
#: bottle.BaseResponse.content_type:1
msgid "Current value of the 'Content-Type' header."
msgstr ""
# 001c6d13b2db4841b81f6b23b55a4fcb
#: ../../../bottle.py:docstring of bottle.FileUpload.content_length:1
#: bottle.BaseResponse.content_length:1
msgid "Current value of the 'Content-Length' header."
msgstr ""
# 44d2df642fd545b08b622a73a84bd9e6
#: ../../../bottle.py:docstring of bottle.FileUpload.filename:1
msgid ""
"Name of the file on the client file system, but normalized to ensure file "
"system compatibility (lowercase, no whitespace, no path separators, no "
"unsafe characters, ASCII only). An empty filename is returned as 'empty'."
msgstr ""
# ba76ee38fe954b458ba7e961b3caad15
#: ../../../bottle.py:docstring of bottle.FileUpload.save:1
msgid ""
"Save file to disk or copy its content to an open file(-like) object. If "
"*destination* is a directory, :attr:`filename` is added to the path. "
"Existing files are not overwritten by default (IOError)."
msgstr ""
# 841c0e821e284d91b7b014ab046f0b29
#: ../../api.rst:108
msgid "Exceptions"
msgstr ""
# 2fd091069448414fa46126c820382bb2
#: ../../../bottle.py:docstring of bottle.BottleException:1
msgid "A base class for exceptions used by bottle."
msgstr ""
# acafc1e6403e44b4bd5821201cdb82fa
#: ../../api.rst:116
msgid "The :class:`Bottle` Class"
msgstr ""
# a3d6dd8f70bf4874a14cea66590f4096
#: ../../../bottle.py:docstring of bottle.Bottle:1
msgid ""
"Each Bottle object represents a single, distinct web application and "
"consists of routes, callbacks, plugins, resources and configuration. "
"Instances are callable WSGI applications."
msgstr ""
# e316cd279454454186fd767fe6663083
#: ../../../bottle.py:docstring of bottle.Bottle.config:1
msgid "A :class:`ConfigDict` for app specific configuration."
msgstr ""
# a54618bbe184416ea06fe641e3bc581f
#: ../../../bottle.py:docstring of bottle.Bottle.resources:1
msgid "A :class:`ResourceManager` for application files"
msgstr ""
# c85fb189289d4452994f37a93d29aa04
#: ../../../bottle.py:docstring of bottle.Bottle.catchall:1
msgid "If true, most exceptions are caught and returned as :exc:`HTTPError`"
msgstr ""
# a153859ed6604e65ba9a9681e700a76f
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:1
msgid "Attach a callback to a hook. Three hooks are currently implemented:"
msgstr ""
# 6dc152c60013420abdb297caa28a3813
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:4
msgid "before_request"
msgstr ""
# 70abd3193e50425e82f98b3f68d4e4dc
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:4
msgid ""
"Executed once before each request. The request context is available, but no "
"routing has happened yet."
msgstr ""
# b8d91a10af2343399eaa8574f904e5d9
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:6
msgid "after_request"
msgstr ""
# 0e85cfc0a3bb4d9b97b68ae264a44ee3
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:7
msgid "Executed once after each request regardless of its outcome."
msgstr ""
# b580af375d614432bd1ac5e0f35f18fd
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:8
msgid "app_reset"
msgstr ""
# 9ce7e89d4e41419e85f0d9c338117c8c
#: ../../../bottle.py:docstring of bottle.Bottle.add_hook:9
msgid "Called whenever :meth:`Bottle.reset` is called."
msgstr ""
# 145ccba16d8f47729e885aa264b33a8f
#: ../../../bottle.py:docstring of bottle.Bottle.remove_hook:1
msgid "Remove a callback from a hook."
msgstr ""
# 55678852dd1541bda6a38d2d4f7902c0
#: ../../../bottle.py:docstring of bottle.Bottle.trigger_hook:1
msgid "Trigger a hook and return a list of results."
msgstr ""
# ec7d6127e3f44524bf25ce39f47a1fc8
#: ../../../bottle.py:docstring of bottle.Bottle.hook:1
msgid ""
"Return a decorator that attaches a callback to a hook. See :meth:`add_hook` "
"for details."
msgstr ""
# c071e835d9914cd1a24b606e57fc6e12
#: ../../../bottle.py:docstring of bottle.Bottle.mount:1
msgid ""
"Mount an application (:class:`Bottle` or plain WSGI) to a specific URL "
"prefix. Example::"
msgstr ""
# 9cc033bb984f4703867893d82058b6b5
#: ../../../bottle.py:docstring of bottle.Bottle.mount:10
msgid "All other parameters are passed to the underlying :meth:`route` call."
msgstr ""
# ee990c4498394cb0acea5c9be5e7923f
#: ../../../bottle.py:docstring of bottle.Bottle.merge:1
msgid ""
"Merge the routes of another :class:`Bottle` application or a list of :class:"
"`Route` objects into this application. The routes keep their 'owner', "
"meaning that the :data:`Route.app` attribute is not changed."
msgstr ""
# 522ef1b9d92149f99b4eb66e81700835
#: ../../../bottle.py:docstring of bottle.Bottle.install:1
msgid ""
"Add a plugin to the list of plugins and prepare it for being applied to all "
"routes of this application. A plugin may be a simple decorator or an object "
"that implements the :class:`Plugin` API."
msgstr ""
# 1f920e670f1f42bdb182fa5ee6892b9d
#: ../../../bottle.py:docstring of bottle.Bottle.uninstall:1
msgid ""
"Uninstall plugins. Pass an instance to remove a specific plugin, a type "
"object to remove all plugins that match that type, a string to remove all "
"plugins with a matching ``name`` attribute or ``True`` to remove all "
"plugins. Return the list of removed plugins."
msgstr ""
# b0f6b824b5bb48f5a73ce8df7cf1ecd2
#: ../../../bottle.py:docstring of bottle.Bottle.reset:1
msgid ""
"Reset all routes (force plugins to be re-applied) and clear all caches. If "
"an ID or route object is given, only that specific route is affected."
msgstr ""
# ea0b9e9a1cd845499900b9ae0650c1c9
#: ../../../bottle.py:docstring of bottle.Bottle.close:1
msgid "Close the application and all installed plugins."
msgstr ""
# 9d904857add44dacbd2351fa34a9416d
#: ../../../bottle.py:docstring of bottle.Bottle.run:1
msgid "Calls :func:`run` with the same parameters."
msgstr ""
# 579b86a9a0e74698b0bfa8685ae73562
#: ../../../bottle.py:docstring of bottle.Bottle.match:1
msgid ""
"Search for a matching route and return a (:class:`Route` , urlargs) tuple. "
"The second value is a dictionary with parameters extracted from the URL. "
"Raise :exc:`HTTPError` (404/405) on a non-match."
msgstr ""
# 8c65d88c42384c8fbe1461b738be7328
#: ../../../bottle.py:docstring of bottle.Bottle.get_url:1
msgid "Return a string that matches a named route"
msgstr ""
# f53b92832d0e44f38c78840aa20acd93
#: ../../../bottle.py:docstring of bottle.Bottle.add_route:1
msgid "Add a route object, but do not change the :data:`Route.app` attribute."
msgstr ""
# 5855345f15e54935b5961c491f4df1c8
#: ../../../bottle.py:docstring of bottle.Bottle.route:1
msgid "A decorator to bind a function to a request URL. Example::"
msgstr ""
# a6a690e885a849a1b6784d0271d763a0
#: ../../../bottle.py:docstring of bottle.Bottle.route:7
msgid ""
"The ``:name`` part is a wildcard. See :class:`Router` for syntax details."
msgstr ""
# bf69fcb9e82e4aba84d8b46bb8f44c10
#: ../../../bottle.py:docstring of bottle.Bottle.route:23
msgid ""
"Any additional keyword arguments are stored as route-specific configuration "
"and passed to plugins (see :meth:`Plugin.apply`)."
msgstr ""
# aaa09cd9b5654107b3550272d034b590
#: ../../../bottle.py:docstring of bottle.Bottle.get:1
msgid "Equals :meth:`route`."
msgstr ""
# c3b3f1634a874a0791c7bc2e3e15d45a
#: ../../../bottle.py:docstring of bottle.Bottle.post:1
msgid "Equals :meth:`route` with a ``POST`` method parameter."
msgstr ""
# 2178c890ba6445439171493fef9e111f
#: ../../../bottle.py:docstring of bottle.Bottle.put:1
msgid "Equals :meth:`route` with a ``PUT`` method parameter."
msgstr ""
# da82d3802c7944eb99c426e6a86596a7
#: ../../../bottle.py:docstring of bottle.Bottle.delete:1
msgid "Equals :meth:`route` with a ``DELETE`` method parameter."
msgstr ""
# be193cc1118748e588bda1eb93dc0b18
#: ../../../bottle.py:docstring of bottle.Bottle.error:1
msgid "Decorator: Register an output handler for a HTTP error code"
msgstr ""
# ae4266c2a37f43f1b1fd10db27745ebf
#: ../../../bottle.py:docstring of bottle.Bottle.handle:1
msgid ""
"(deprecated) Execute the first matching route callback and return the "
"result. :exc:`HTTPResponse` exceptions are caught and returned. If :attr:"
"`Bottle.catchall` is true, other exceptions are caught as well and returned "
"as :exc:`HTTPError` instances (500)."
msgstr ""
# 505b97c9c9f74ed8a9cfdbfc5d39e9fe
#: ../../../bottle.py:docstring of bottle.Bottle.wsgi:1
msgid "The bottle WSGI-interface."
msgstr ""
# 6dbe117230bb473fafbf45d5a7c1a6bb
#: ../../../bottle.py:docstring of bottle.Route:1
msgid ""
"This class wraps a route callback along with route specific metadata and "
"configuration and applies Plugins on demand. It is also responsible for "
"turing an URL path rule into a regular expression usable by the Router."
msgstr ""
# a4b55c71f2544e7ea88dec1b381f5bd1
#: ../../../bottle.py:docstring of bottle.Route.app:1
msgid "The application this route is installed to."
msgstr ""
# 96261d8a5d9845afa58ce6187e958ee9
#: ../../../bottle.py:docstring of bottle.Route.rule:1
msgid "The path-rule string (e.g. ``/wiki/:page``)."
msgstr ""
# 524c69435594465b9c01e66ec6e366e4
#: ../../../bottle.py:docstring of bottle.Route.method:1
msgid "The HTTP method as a string (e.g. ``GET``)."
msgstr ""
# bf67f447b9c84beca14f9a581bbee99b
#: ../../../bottle.py:docstring of bottle.Route.callback:1
msgid ""
"The original callback with no plugins applied. Useful for introspection."
msgstr ""
# ced088a30a0c4bfabc944af22e2f5d30
#: ../../../bottle.py:docstring of bottle.Route.name:1
msgid "The name of the route (if specified) or ``None``."
msgstr ""
# f949e89c75fe47229c191f89c17196d0
#: ../../../bottle.py:docstring of bottle.Route.plugins:1
msgid "A list of route-specific plugins (see :meth:`Bottle.route`)."
msgstr ""
# c0cb7ea593dc4db5b0e279da0fe5ef42
#: ../../../bottle.py:docstring of bottle.Route.skiplist:1
msgid ""
"A list of plugins to not apply to this route (see :meth:`Bottle.route`)."
msgstr ""
# 8bb3cca930af481f8ca44da2c39ceefc
#: ../../../bottle.py:docstring of bottle.Route.config:1
msgid ""
"Additional keyword arguments passed to the :meth:`Bottle.route` decorator "
"are stored in this dictionary. Used for route-specific plugin configuration "
"and meta-data."
msgstr ""
# 0943215c952f4b53b91d4630599c798c
#: ../../../bottle.py:docstring of bottle.Route.call:1
msgid ""
"The route callback with all plugins applied. This property is created on "
"demand and then cached to speed up subsequent requests."
msgstr ""
# 498d6f0a85a541eba29a8f48855750f7
#: ../../../bottle.py:docstring of bottle.Route.reset:1
msgid ""
"Forget any cached values. The next time :attr:`call` is accessed, all "
"plugins are re-applied."
msgstr ""
# f873381927a84bceaf58eee4ff90c5d6
#: ../../../bottle.py:docstring of bottle.Route.prepare:1
msgid "Do all on-demand work immediately (useful for debugging)."
msgstr ""
# d63a0238d0634d47b8e5aec45248be7c
#: ../../../bottle.py:docstring of bottle.Route.all_plugins:1
msgid "Yield all Plugins affecting this route."
msgstr ""
# 1ec3c38fbcb849b1b43263e370ffd136
#: ../../../bottle.py:docstring of bottle.Route.get_undecorated_callback:1
msgid ""
"Return the callback. If the callback is a decorated function, try to recover "
"the original function."
msgstr ""
# d3c5328a4cab44989c52d2127b3544b4
#: ../../../bottle.py:docstring of bottle.Route.get_callback_args:1
msgid ""
"Return a list of argument names the callback (most likely) accepts as "
"keyword arguments. If the callback is a decorated function, try to recover "
"the original function before inspection."
msgstr ""
# 96aa046ca3da4f6e8ee873d30bba2a36
#: ../../../bottle.py:docstring of bottle.Route.get_config:1
msgid ""
"Lookup a config field and return its value, first checking the route.config, "
"then route.app.config."
msgstr ""
# 62603aa4019e4732a6caa0083f27ceee
#: ../../api.rst:126
msgid "The :class:`Request` Object"
msgstr ""
# 39128b7c74ed400e9a103a6b37e84b43
#: ../../api.rst:128
msgid ""
"The :class:`Request` class wraps a WSGI environment and provides helpful "
"methods to parse and access form data, cookies, file uploads and other "
"metadata. Most of the attributes are read-only."
msgstr ""
# da1e3ca7fd8143bd99c098bd62ce6f1b
#: ../../../bottle.py:docstring of bottle.BaseRequest:1
msgid ""
"A wrapper for WSGI environment dictionaries that adds a lot of convenient "
"access methods and properties. Most of them are read-only."
msgstr ""
# 145f7050a42a494f9dbc28a25c402150
#: ../../../bottle.py:docstring of bottle.BaseRequest:4
msgid ""
"Adding new attributes to a request actually adds them to the environ "
"dictionary (as 'bottle.request.ext.'). This is the recommended way to "
"store and access request-specific data."
msgstr ""
# 199355247ef144f4ba61954e5936825d
#: ../../../bottle.py:docstring of bottle.BaseRequest.MEMFILE_MAX:1
msgid "Maximum size of memory buffer for :attr:`body` in bytes."
msgstr ""
# e0bbf2db8195408a977035a5a884d0da
#: ../../../bottle.py:docstring of bottle.BaseRequest.MAX_PARAMS:1
msgid "Maximum number pr GET or POST parameters per request"
msgstr ""
# ef1ff6ae9a0541e8b9d7e7f747f57b3d
#: ../../../bottle.py:docstring of bottle.BaseRequest.environ:1
msgid ""
"The wrapped WSGI environ dictionary. This is the only real attribute. All "
"other attributes actually are read-only properties."
msgstr ""
# af4ebeade1b94633be302638a1c5d543
#: ../../../bottle.py:docstring of bottle.BaseRequest.app:1
msgid "Bottle application handling this request."
msgstr ""
# c41f7380550042b4ac7111a188a88f77
#: ../../../bottle.py:docstring of bottle.BaseRequest.route:1
msgid "The bottle :class:`Route` object that matches this request."
msgstr ""
# 0aeb079900744334aebdf19893cc043c
#: ../../../bottle.py:docstring of bottle.BaseRequest.url_args:1
msgid "The arguments extracted from the URL."
msgstr ""
# 037aee056fb248628a52cf2447ab4c82
#: ../../../bottle.py:docstring of bottle.BaseRequest.path:1
msgid ""
"The value of ``PATH_INFO`` with exactly one prefixed slash (to fix broken "
"clients and avoid the \"empty path\" edge case)."
msgstr ""
# e40998f41ff342d09e6699927a460971
#: ../../../bottle.py:docstring of bottle.BaseRequest.method:1
msgid "The ``REQUEST_METHOD`` value as an uppercase string."
msgstr ""
# e6845621bb9d42ccba141441bc8a5bc5
#: ../../../bottle.py:docstring of bottle.BaseRequest.headers:1
msgid ""
"A :class:`WSGIHeaderDict` that provides case-insensitive access to HTTP "
"request headers."
msgstr ""
# 7fc82cc9c0834b7da08e3b3860e1a9d6
#: ../../../bottle.py:docstring of bottle.BaseRequest.get_header:1
msgid "Return the value of a request header, or a given default value."
msgstr ""
# a4b6f975aa094fbdb49980bca6a4740c
#: ../../../bottle.py:docstring of bottle.BaseRequest.cookies:1
msgid ""
"Cookies parsed into a :class:`FormsDict`. Signed cookies are NOT decoded. "
"Use :meth:`get_cookie` if you expect signed cookies."
msgstr ""
# c715b1e442094837a714589e3798186f
#: ../../../bottle.py:docstring of bottle.BaseRequest.get_cookie:1
msgid ""
"Return the content of a cookie. To read a `Signed Cookie`, the `secret` must "
"match the one used to create the cookie (see :meth:`BaseResponse."
"set_cookie`). If anything goes wrong (missing cookie or wrong signature), "
"return a default value."
msgstr ""
# 92a7554d93d54dd4a8bba31a0067114b
#: ../../../bottle.py:docstring of bottle.BaseRequest.query:1
msgid ""
"The :attr:`query_string` parsed into a :class:`FormsDict`. These values are "
"sometimes called \"URL arguments\" or \"GET parameters\", but not to be "
"confused with \"URL wildcards\" as they are provided by the :class:`Router`."
msgstr ""
# 6e38df25852449a29bd683f33364b48f
#: ../../../bottle.py:docstring of bottle.BaseRequest.forms:1
msgid ""
"Form values parsed from an `url-encoded` or `multipart/form-data` encoded "
"POST or PUT request body. The result is returned as a :class:`FormsDict`. "
"All keys and values are strings. File uploads are stored separately in :attr:"
"`files`."
msgstr ""
# 521472a4de8345f98bc3c787393ad395
#: ../../../bottle.py:docstring of bottle.BaseRequest.params:1
msgid ""
"A :class:`FormsDict` with the combined values of :attr:`query` and :attr:"
"`forms`. File uploads are stored in :attr:`files`."
msgstr ""
# 7e4b95b0b3054f54a33b518c161f0f86
#: ../../../bottle.py:docstring of bottle.BaseRequest.files:1
msgid ""
"File uploads parsed from `multipart/form-data` encoded POST or PUT request "
"body. The values are instances of :class:`FileUpload`."
msgstr ""
# 0d0624fb0853462aab441d63adc1a3be
#: ../../../bottle.py:docstring of bottle.BaseRequest.json:1
msgid ""
"If the ``Content-Type`` header is ``application/json``, this property holds "
"the parsed content of the request body. Only requests smaller than :attr:"
"`MEMFILE_MAX` are processed to avoid memory exhaustion."
msgstr ""
# e365ed3beb1d44c4af25f40b7f4a8226
#: ../../../bottle.py:docstring of bottle.BaseRequest.body:1
msgid ""
"The HTTP request body as a seek-able file-like object. Depending on :attr:"
"`MEMFILE_MAX`, this is either a temporary file or a :class:`io.BytesIO` "
"instance. Accessing this property for the first time reads and replaces the "
"``wsgi.input`` environ variable. Subsequent accesses just do a `seek(0)` on "
"the file object."
msgstr ""
# 0f818e4e9be54445a5d849f282fbb91a
#: ../../../bottle.py:docstring of bottle.BaseRequest.GET:1
msgid "An alias for :attr:`query`."
msgstr ""
# 1cb7905e16964d0781a080367f6c4355
#: ../../../bottle.py:docstring of bottle.BaseRequest.POST:1
msgid ""
"The values of :attr:`forms` and :attr:`files` combined into a single :class:"
"`FormsDict`. Values are either strings (form values) or instances of :class:"
"`cgi.FieldStorage` (file uploads)."
msgstr ""
# 19474bb856ea4df983d033e944c07d91
#: ../../../bottle.py:docstring of bottle.BaseRequest.COOKIES:1
msgid "Alias for :attr:`cookies` (deprecated)."
msgstr ""
# 7a59ab7b57544482a2b7d0207c28b2cb
#: ../../../bottle.py:docstring of bottle.BaseRequest.url:1
msgid ""
"The full request URI including hostname and scheme. If your app lives behind "
"a reverse proxy or load balancer and you get confusing results, make sure "
"that the ``X-Forwarded-Host`` header is set correctly."
msgstr ""
# 6abcd81bc21d439a895207e630f97c52
#: ../../../bottle.py:docstring of bottle.BaseRequest.urlparts:1
msgid ""
"The :attr:`url` string as an :class:`urlparse.SplitResult` tuple. The tuple "
"contains (scheme, host, path, query_string and fragment), but the fragment "
"is always empty because it is not visible to the server."
msgstr ""
# f392bad831ff4fa88c9ea744d8bc950c
#: ../../../bottle.py:docstring of bottle.BaseRequest.fullpath:1
msgid "Request path including :attr:`script_name` (if present)."
msgstr ""
# aab6198ddcfc4e65bc1ab4b782683370
#: ../../../bottle.py:docstring of bottle.BaseRequest.query_string:1
msgid ""
"The raw :attr:`query` part of the URL (everything in between ``?`` and "
"``#``) as a string."
msgstr ""
# 946709194f5344eb842770c997f68202
#: ../../../bottle.py:docstring of bottle.BaseRequest.script_name:1
msgid ""
"The initial portion of the URL's `path` that was removed by a higher level "
"(server or routing middleware) before the application was called. This "
"script path is returned with leading and tailing slashes."
msgstr ""
# 42adec892f1849f18d69527e9fe788b7
#: ../../../bottle.py:docstring of bottle.BaseRequest.path_shift:1
msgid ""
"Shift path segments from :attr:`path` to :attr:`script_name` and vice versa."
msgstr ""
# 76e85971464548518acd9810d924f387
#: ../../../bottle.py:docstring of bottle.BaseRequest.content_length:1
msgid ""
"The request body length as an integer. The client is responsible to set this "
"header. Otherwise, the real length of the body is unknown and -1 is "
"returned. In this case, :attr:`body` will be empty."
msgstr ""
# 8dc2def91405473fbfd3e904686be740
#: ../../../bottle.py:docstring of bottle.BaseRequest.content_type:1
msgid "The Content-Type header as a lowercase-string (default: empty)."
msgstr ""
# 4d564e1fd934434181981c12030c784f
#: ../../../bottle.py:docstring of bottle.BaseRequest.is_xhr:1
msgid ""
"True if the request was triggered by a XMLHttpRequest. This only works with "
"JavaScript libraries that support the `X-Requested-With` header (most of the "
"popular libraries do)."
msgstr ""
# f42ba086381c4735b07013b78beabbe0
#: ../../../bottle.py:docstring of bottle.BaseRequest.is_ajax:1
msgid "Alias for :attr:`is_xhr`. \"Ajax\" is not the right term."
msgstr ""
# deb53a1c59ed428688d2ff4250cac9b2
#: ../../../bottle.py:docstring of bottle.BaseRequest.auth:1
msgid ""
"HTTP authentication data as a (user, password) tuple. This implementation "
"currently supports basic (not digest) authentication only. If the "
"authentication happened at a higher level (e.g. in the front web-server or a "
"middleware), the password field is None, but the user field is looked up "
"from the ``REMOTE_USER`` environ variable. On any errors, None is returned."
msgstr ""
# a6336e9837814b37a483c52185795a82
#: ../../../bottle.py:docstring of bottle.BaseRequest.remote_route:1
msgid ""
"A list of all IPs that were involved in this request, starting with the "
"client IP and followed by zero or more proxies. This does only work if all "
"proxies support the ```X-Forwarded-For`` header. Note that this information "
"can be forged by malicious clients."
msgstr ""
# 38ce3f106a16450e943f25ff7a586069
#: ../../../bottle.py:docstring of bottle.BaseRequest.remote_addr:1
msgid ""
"The client IP as a string. Note that this information can be forged by "
"malicious clients."
msgstr ""
# 259ef70a0d7b421ca8e468d9f1b71899
#: ../../../bottle.py:docstring of bottle.BaseRequest.copy:1
msgid "Return a new :class:`Request` with a shallow :attr:`environ` copy."
msgstr ""
# 21846efc4aa7410cbe609eaf42910736
#: ../../api.rst:136
msgid ""
"The module-level :data:`bottle.request` is a proxy object (implemented in :"
"class:`LocalRequest`) and always refers to the `current` request, or in "
"other words, the request that is currently processed by the request handler "
"in the current thread. This `thread locality` ensures that you can safely "
"use a global instance in a multi-threaded environment."
msgstr ""
# 10dd41c5686147648141a87cc6e82f77
#: ../../../bottle.py:docstring of bottle.LocalRequest:1
msgid ""
"A thread-local subclass of :class:`BaseRequest` with a different set of "
"attribues for each thread. There is usually only one global instance of this "
"class (:data:`request`). If accessed during a request/response cycle, this "
"instance always refers to the *current* request (even on a multithreaded "
"server)."
msgstr ""
# f7b6c6f51a9f412985f867be926b555d
#: ../../../bottle.py:docstring of bottle.LocalRequest.bind:1
msgid "Wrap a WSGI environ dictionary."
msgstr ""
# 3b6cc79779f144989921ddb4d71d4cb0
#: ../../../bottle.py:docstring of bottle.LocalRequest.environ:1
msgid "Thread-local property stored in :data:`_lctx.request_environ`"
msgstr ""
# 106092478f51479997b74ebeccd2ea06
#: ../../api.rst:145
msgid "The :class:`Response` Object"
msgstr ""
# bde46b3aad08469aa59a263616041959
#: ../../api.rst:147
msgid ""
"The :class:`Response` class stores the HTTP status code as well as headers "
"and cookies that are to be sent to the client. Similar to :data:`bottle."
"request` there is a thread-local :data:`bottle.response` instance that can "
"be used to adjust the `current` response. Moreover, you can instantiate :"
"class:`Response` and return it from your request handler. In this case, the "
"custom instance overrules the headers and cookies defined in the global one."
msgstr ""
# bc428c10813347058ee3eaefb7889f2b
#: ../../../bottle.py:docstring of bottle.BaseResponse:1
msgid "Storage class for a response body as well as headers and cookies."
msgstr ""
# 442a16db61924e0aa362afa4a37cefcd
#: ../../../bottle.py:docstring of bottle.BaseResponse:3
msgid ""
"This class does support dict-like case-insensitive item-access to headers, "
"but is NOT a dict. Most notably, iterating over a response yields parts of "
"the body and not the headers."
msgstr ""
# 83d9a04c39784dba9c1c644d8aa82ccd
#: ../../../bottle.py:docstring of bottle.BaseResponse:12
msgid ""
"Additional keyword arguments are added to the list of headers. Underscores "
"in the header name are replaced with dashes."
msgstr ""
# 4b9d3e8a27d24baeb19851f986eb9053
#: ../../../bottle.py:docstring of bottle.BaseResponse.copy:1
msgid "Returns a copy of self."
msgstr ""
# 20dd731104a14134b1cb816272da6bff
#: ../../../bottle.py:docstring of bottle.BaseResponse.status_line:1
msgid "The HTTP status line as a string (e.g. ``404 Not Found``)."
msgstr ""
# 24f7622dd04d43ca8cffb16b093785a1
#: ../../../bottle.py:docstring of bottle.BaseResponse.status_code:1
msgid "The HTTP status code as an integer (e.g. 404)."
msgstr ""
# e4b4d153add948bfa41eafc92be7b5b0
#: ../../../bottle.py:docstring of bottle.BaseResponse.status:1
msgid ""
"A writeable property to change the HTTP response status. It accepts either a "
"numeric code (100-999) or a string with a custom reason phrase (e.g. \"404 "
"Brain not found\"). Both :data:`status_line` and :data:`status_code` are "
"updated accordingly. The return value is always a status string."
msgstr ""
# 1c0fa51fff2f46b3ab5dbc423cd5b1ad
#: ../../../bottle.py:docstring of bottle.BaseResponse.headers:1
msgid ""
"An instance of :class:`HeaderDict`, a case-insensitive dict-like view on the "
"response headers."
msgstr ""
# 69dbca79c72646da9d204b40422bc2d9
#: ../../../bottle.py:docstring of bottle.BaseResponse.get_header:1
msgid ""
"Return the value of a previously defined header. If there is no header with "
"that name, return a default value."
msgstr ""
# c75d39ca206a4355ba6573abe3ccca7c
#: ../../../bottle.py:docstring of bottle.BaseResponse.set_header:1
msgid ""
"Create a new response header, replacing any previously defined headers with "
"the same name."
msgstr ""
# 800ed6de5292405980d7f0b42a2241b6
#: ../../../bottle.py:docstring of bottle.BaseResponse.add_header:1
msgid "Add an additional response header, not removing duplicates."
msgstr ""
# ea08ec78e270408ebd927b40ed16e915
#: ../../../bottle.py:docstring of bottle.BaseResponse.iter_headers:1
msgid ""
"Yield (header, value) tuples, skipping headers that are not allowed with the "
"current response status code."
msgstr ""
# 91f79c216555439f871d6ef43f6bda9f
#: ../../../bottle.py:docstring of bottle.BaseResponse.headerlist:1
msgid "WSGI conform list of (header, value) tuples."
msgstr ""
# 899832cd9ab0434481ab7dfa4a482d79
#: ../../../bottle.py:docstring of bottle.BaseResponse.expires:1
msgid "Current value of the 'Expires' header."
msgstr ""
# c9a8f8c5c29c4dfdbd5c77e910133ed9
#: ../../../bottle.py:docstring of bottle.BaseResponse.charset:1
msgid ""
"Return the charset specified in the content-type header (default: utf8)."
msgstr ""
# 3741634227334c49bc1c44bde23035ab
#: ../../../bottle.py:docstring of bottle.BaseResponse.COOKIES:1
msgid ""
"A dict-like SimpleCookie instance. This should not be used directly. See :"
"meth:`set_cookie`."
msgstr ""
# faf6b57b146a42399bbfada0234bf0b8
#: ../../../bottle.py:docstring of bottle.BaseResponse.set_cookie:1
msgid ""
"Create a new cookie or replace an old one. If the `secret` parameter is set, "
"create a `Signed Cookie` (described below)."
msgstr ""
# f24ed8fe5dc64069af63525064bfc57f
#: ../../../bottle.py:docstring of bottle.BaseResponse.set_cookie:8
msgid ""
"Additionally, this method accepts all RFC 2109 attributes that are supported "
"by :class:`cookie.Morsel`, including:"
msgstr ""
# 16e1167be236401f91bfc40593afdd71
#: ../../../bottle.py:docstring of bottle.BaseResponse.set_cookie:20
msgid ""
"If neither `expires` nor `max_age` is set (default), the cookie will expire "
"at the end of the browser session (as soon as the browser window is closed)."
msgstr ""
# 13a85a16b98a4e00b6567058431481ea
#: ../../../bottle.py:docstring of bottle.BaseResponse.set_cookie:24
msgid ""
"Signed cookies may store any pickle-able object and are cryptographically "
"signed to prevent manipulation. Keep in mind that cookies are limited to 4kb "
"in most browsers."
msgstr ""
# fd074f58f7a446bcb51b788462b67465
#: ../../../bottle.py:docstring of bottle.BaseResponse.set_cookie:28
msgid ""
"Warning: Signed cookies are not encrypted (the client can still see the "
"content) and not copy-protected (the client can restore an old cookie). The "
"main intention is to make pickling and unpickling save, not to store secret "
"information at client side."
msgstr ""
# 5ad4fdb60e0146d7bdecb10b8f3e05cb
#: ../../../bottle.py:docstring of bottle.BaseResponse.delete_cookie:1
msgid ""
"Delete a cookie. Be sure to use the same `domain` and `path` settings as "
"used to create the cookie."
msgstr ""
# ae8c905c87694bf3a2ea42d09cfea02c
#: ../../../bottle.py:docstring of bottle.LocalResponse:1
msgid ""
"A thread-local subclass of :class:`BaseResponse` with a different set of "
"attribues for each thread. There is usually only one global instance of this "
"class (:data:`response`). Its attributes are used to build the HTTP response "
"at the end of the request/response cycle."
msgstr ""
# f6ace90a9670484d8a866dea8cd8b38a
#: ../../../bottle.py:docstring of bottle.LocalResponse.body:1
msgid "Thread-local property stored in :data:`_lctx.response_body`"
msgstr ""
# 8ca709f8313b482da65c7268859ae250
#: ../../api.rst:159
msgid ""
"The following two classes can be raised as an exception. The most noticeable "
"difference is that bottle invokes error handlers for :class:`HTTPError`, but "
"not for :class:`HTTPResponse` or other response types."
msgstr ""
# d3a8f15c0c9c4c8697fdb8ae365c3b21
#: ../../../bottle.py:docstring of bottle.HTTPResponse.output:1
msgid "Alias for .body"
msgstr ""
# 50180b5649a744c987ed84c266b7a9bd
#: ../../api.rst:171
msgid "Templates"
msgstr ""
# b4f775e4de0b4249b8e33108e33a7a49
#: ../../api.rst:173
msgid ""
"All template engines supported by :mod:`bottle` implement the :class:"
"`BaseTemplate` API. This way it is possible to switch and mix template "
"engines without changing the application code at all."
msgstr ""
# 975585fd7dca4b0a8572be0fafcda6be
#: ../../../bottle.py:docstring of bottle.BaseTemplate:1
msgid "Base class and minimal API for template adapters"
msgstr ""
# a89e857e507644bdaf8d55dc717c5d68
#: ../../../bottle.py:docstring of bottle.BaseTemplate.__init__:1
msgid ""
"Create a new template. If the source parameter (str or buffer) is missing, "
"the name argument is used to guess a template filename. Subclasses can "
"assume that self.source and/or self.filename are set. Both are strings. The "
"lookup, encoding and settings parameters are stored as instance variables. "
"The lookup parameter stores a list containing directory paths. The encoding "
"parameter should be used to decode byte strings or files. The settings "
"parameter contains a dict for engine-specific settings."
msgstr ""
# 2490a05b3cfe487a9cd697defe07282d
#: ../../../bottle.py:docstring of bottle.BaseTemplate.search:1
msgid ""
"Search name in all directories specified in lookup. First without, then with "
"common extensions. Return first hit."
msgstr ""
# 680a8fe096e741d9bfa6fe53086209dd
#: ../../../bottle.py:docstring of bottle.BaseTemplate.global_config:1
msgid "This reads or sets the global settings stored in class.settings."
msgstr ""
# 55ecc208fadd4c089c872170477a9f0c
#: ../../../bottle.py:docstring of bottle.BaseTemplate.prepare:1
msgid ""
"Run preparations (parsing, caching, ...). It should be possible to call this "
"again to refresh a template or to update settings."
msgstr ""
# 0ab4a6d80b044ddf87397b0f587d9fe0
#: ../../../bottle.py:docstring of bottle.BaseTemplate.render:1
msgid ""
"Render the template with the specified local variables and return a single "
"byte or unicode string. If it is a byte string, the encoding must match self."
"encoding. This method must be thread-safe! Local variables may be provided "
"in dictionaries (args) or directly, as keywords (kwargs)."
msgstr ""
# 6b1c141cf449499b9ae972b7975d2a3b
#: ../../../bottle.py:docstring of bottle.view:1
msgid ""
"Decorator: renders a template for a handler. The handler can control its "
"behavior like that:"
msgstr ""
# 89e057215ad24a5f97966f920f26ff3c
#: ../../../bottle.py:docstring of bottle.view:4
msgid "return a dict of template vars to fill out the template"
msgstr ""
# 688fd6bb93f348a287e476ec16da2180
#: ../../../bottle.py:docstring of bottle.view:5
msgid ""
"return something other than a dict and the view decorator will not process "
"the template, but return the handler result as is. This includes returning a "
"HTTPResponse(dict) to get, for instance, JSON with autojson or other "
"castfilters."
msgstr ""
# c30940ff52eb4578a46ebaa485189c2f
#: ../../../bottle.py:docstring of bottle.template:1
msgid ""
"Get a rendered template as a string iterator. You can use a name, a filename "
"or a template string as first parameter. Template rendering arguments can be "
"passed as dictionaries or directly (as keyword arguments)."
msgstr ""
# 24d18841c1104f21bc1e523a11d37f9b
#: ../../api.rst:184
msgid ""
"You can write your own adapter for your favourite template engine or use one "
"of the predefined adapters. Currently there are four fully supported "
"template engines:"
msgstr ""
# 0b18f89b92bd47cea75484f063b4a305
#: ../../api.rst:187
msgid "Class"
msgstr ""
# e61c4e15bcac42e4b82f9dca7f257058
#: ../../api.rst:187
msgid "URL"
msgstr ""
# 1d62c00724264840af5a38445a2f2046
#: ../../api.rst:187
msgid "Decorator"
msgstr ""
# f358c8038cb54d25a612ce662ac57e66
#: ../../api.rst:187
msgid "Render function"
msgstr ""
# b53044adf2c64defa1fc407003b81f86
#: ../../api.rst:189
msgid ":class:`SimpleTemplate`"
msgstr ""
# a1a04a507e14417ab3539197b18afa4b
#: ../../api.rst:189
msgid ":doc:`stpl`"
msgstr ""
# 33dca0a76e23412abee840c3dbd6dcf6
#: ../../api.rst:189
msgid ":func:`view`"
msgstr ""
# 1e86243291384e2d92ed890830d4d338
#: ../../api.rst:189
msgid ":func:`template`"
msgstr ""
# 4d3a8eb5e32d40fda44342622bba81b8
#: ../../api.rst:190
msgid ":class:`MakoTemplate`"
msgstr ""
# 6c423025f4cb4d4a801b605bafecb026
#: ../../api.rst:190
msgid "http://www.makotemplates.org"
msgstr ""
# bc162e8800634503978fee1cfc325f3c
#: ../../api.rst:190
msgid ":func:`mako_view`"
msgstr ""
# e777be7d76044134b1b534e5612a397f
#: ../../api.rst:190
msgid ":func:`mako_template`"
msgstr ""
# 1169be7e540d4b028108f0437d1fb791
#: ../../api.rst:191
msgid ":class:`CheetahTemplate`"
msgstr ""
# 81026d25ce3948468a6e4f7ff2eb49ac
#: ../../api.rst:191
msgid "http://www.cheetahtemplate.org/"
msgstr ""
# a5003711086e4b729b97068f1d5e3d93
#: ../../api.rst:191
msgid ":func:`cheetah_view`"
msgstr ""
# 41355d3738e145589e85992557dd818e
#: ../../api.rst:191
msgid ":func:`cheetah_template`"
msgstr ""
# 4cecefe7caf84f7bbbf14deba520fd62
#: ../../api.rst:192
msgid ":class:`Jinja2Template`"
msgstr ""
# a2dc200da35848f5b9b36d8d0cea1f33
#: ../../api.rst:192
msgid "http://jinja.pocoo.org/"
msgstr ""
# 19500baf956c445fac89420ee8b30d57
#: ../../api.rst:192
msgid ":func:`jinja2_view`"
msgstr ""
# 1a5f61a4b9aa4aa0a2933ef65e5cb88f
#: ../../api.rst:192
msgid ":func:`jinja2_template`"
msgstr ""
# a113494ab5c348cdbb1d5c7b9533f062
#: ../../api.rst:195
msgid ""
"To use :class:`MakoTemplate` as your default template engine, just import "
"its specialised decorator and render function::"
msgstr ""
bottle-0.12.7/docs/_locale/zh_CN/tutorial.po 0000644 0001750 0001750 00000264633 12327760172 017241 0 ustar fede fede # SOME DESCRIPTIVE TITLE.
# Copyright (C) 2009-2012, Marcel Hellkamp
# This file is distributed under the same license as the Bottle package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Bottle 0.12-dev\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-09 18:12\n"
"PO-Revision-Date: 2013-08-09 17:27+0800\n"
"Last-Translator: \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.7\n"
# 2cfce930fec043468539792502c72326
#: ../../tutorial.rst:24
msgid "Tutorial"
msgstr "教程"
# 0c236f89c90b4a3a9a21281e710524c0
#: ../../tutorial.rst:26
msgid ""
"This tutorial introduces you to the concepts and features of the Bottle web "
"framework and covers basic and advanced topics alike. You can read it from "
"start to end, or use it as a reference later on. The automatically "
"generated :doc:`api` may be interesting for you, too. It covers more "
"details, but explains less than this tutorial. Solutions for the most common "
"questions can be found in our :doc:`recipes` collection or on the :doc:`faq` "
"page. If you need any help, join our `mailing list `_ or visit us in our `IRC channel `_."
msgstr ""
"这份教程将向你介绍Bottle的开发理念和功能特性。既介绍Bottle的基本用法,也包含"
"了进阶用法。你可以从头到尾通读一遍,也可当做开发时的参考。你也许对自动生成"
"的 :doc:`api` 感兴趣。它包含了更多的细节,但解释没有这份教程详细。在 :doc:"
"`recipes` 或 :doc:`faq` 可找到常见问题的解决办法。如果需要任何帮助,可加入我"
"们的 `邮件列表 `_ 或在 `IRC频道 `_ 和我们交流。"
# 0ec6fe51620140ad9382936c9de05314
#: ../../tutorial.rst:31
msgid "Installation"
msgstr "安装"
# 568892e9dee44a7e9037426bf4d0aee0
#: ../../tutorial.rst:33
msgid ""
"Bottle does not depend on any external libraries. You can just download "
"`bottle.py `_ into your project directory and start coding:"
msgstr ""
"Bottle不依赖其他库,你需要做的仅是下载 `bottle.py `_ (开发版)到你"
"的项目文件夹,然后开始写代码。"
# 00ba13db53314514a6c6f6af77210c46
#: ../../tutorial.rst:39
msgid ""
"This will get you the latest development snapshot that includes all the new "
"features. If you prefer a more stable environment, you should stick with the "
"stable releases. These are available on `PyPI `_ and can be installed via :command:`pip` (recommended), :command:"
"`easy_install` or your package manager:"
msgstr ""
"在终端运行以上命令,即可下载到Bottle的最新开发版,包含了所有新功能特性。如果"
"更需要稳定性,你应该坚持使用Bottle的稳定版本。可在 `PyPI `_ 下载稳定版本,然后通过 :command:`pip` (推荐), :command:"
"`easy_install` 或你的包管理软件安装。"
# b99a73f45a24406dbde64204f2ceb385
#: ../../tutorial.rst:47
msgid ""
"Either way, you'll need Python 2.5 or newer (including 3.x) to run bottle "
"applications. If you do not have permissions to install packages system-wide "
"or simply don't want to, create a `virtualenv `_ first:"
msgstr ""
"你需要Python 2.5或以上版本(包括3.x)来运行bottle应用。如果你没有管理员权限或"
"你不想将Bottle安装为整个系统范围内可用,可先创建一个 `virtualenv `_ :"
# 36a9cfdae7c3425ea112e9b4f4340db3
#: ../../tutorial.rst:55
msgid "Or, if virtualenv is not installed on your system:"
msgstr "如果还未安装virtualenv:"
# 28ef5dd33f0f42da9dcbb4b808ff8ef6
#: ../../tutorial.rst:67
msgid "Quickstart: \"Hello World\""
msgstr ""
# 63ae84f2a3ec45ae994f1ad1fd3dca8b
#: ../../tutorial.rst:69
msgid ""
"This tutorial assumes you have Bottle either :ref:`installed ` "
"or copied into your project directory. Let's start with a very basic \"Hello "
"World\" example::"
msgstr ""
"到目前为止,我假设你已经 :ref:`安装 ` 好了bottle或已将bottle.py"
"拷贝到你的项目文件夹。接下来我们就可以写一个非常简单的\"Hello World\"了::"
# 56a3e1b859df44d8838a1f879dc6edef
#: ../../tutorial.rst:79
msgid ""
"This is it. Run this script, visit http://localhost:8080/hello and you will "
"see \"Hello World!\" in your browser. Here is how it works:"
msgstr ""
"就这么简单!保存为py文件并执行,用浏览器访问 http://localhost:8080/hello 就可"
"以看到\"Hello World!\"。它的执行流程大致如下:"
# 9de9930646be4df7ab8a12f9759574db
#: ../../tutorial.rst:81
msgid ""
"The :func:`route` decorator binds a piece of code to an URL path. In this "
"case, we link the ``/hello`` path to the ``hello()`` function. This is "
"called a `route` (hence the decorator name) and is the most important "
"concept of this framework. You can define as many routes as you want. "
"Whenever a browser requests an URL, the associated function is called and "
"the return value is sent back to the browser. Its as simple as that."
msgstr ""
":func:`route` 函数将一段代码绑定到一个URL,在这个例子中, 我们将 ``hello()`` "
"函数绑定给了 ``/hello`` 。我们称之为 `route` (也是该修饰器的函数名) ,这是"
"Bottle框架最重要的开发理念。你可以根据需要定义任意多的 `route` 。在浏览器请求"
"一个URL的时候,框架自动调用与之相应的函数,接着将函数的返回值发送给浏览器。就"
"这么简单!"
# 66de45a278fd457e9f68b2847b841118
#: ../../tutorial.rst:83
msgid ""
"The :func:`run` call in the last line starts a built-in development server. "
"It runs on ``localhost`` port ``8080`` and serves requests until you hit :"
"kbd:`Control-c`. You can switch the server backend later, but for now a "
"development server is all we need. It requires no setup at all and is an "
"incredibly painless way to get your application up and running for local "
"tests."
msgstr ""
"最后一行调用的 :func:`run` 函数启动了内置的开发服务器。它监听 `localhost` 的"
"8080端口并响应请求, :kbd:`Control-c` 可将其关闭。到目前为止,这个内置的开发"
"服务器已经足够用于日常的开发测试了。它根本不需要安装,就可以让你的应用跑起"
"来。在教程的后面,你将学会如何让你的应用跑在其他服务器上面(译者注:内置服务"
"器不能满足生产环境的要求)"
# 58b30c8abcee451e80f9fc3d0b79d180
#: ../../tutorial.rst:85
msgid ""
"The :ref:`tutorial-debugging` is very helpful during early development, but "
"should be switched off for public applications. Keep that in mind."
msgstr ""
":ref:`tutorial-debugging` 在早期开发的时候非常有用,但请务必记得,在生产环境"
"中将其关闭。"
# 717a9032a00a46b8b4845025571cafb4
#: ../../tutorial.rst:87
msgid ""
"Of course this is a very simple example, but it shows the basic concept of "
"how applications are built with Bottle. Continue reading and you'll see what "
"else is possible."
msgstr ""
"毫无疑问,这是一个十分简单例子,但它展示了用Bottle做应用开发的基本理念。接下"
"来你将了解到其他开发方式。"
# 7c5ad76ca2ab4a3fbf06a891d59fc47b
#: ../../tutorial.rst:92
msgid "The Default Application"
msgstr "`默认应用`"
# ec04f7c314a04d51a1f5a5d7fa1585d0
#: ../../tutorial.rst:94
msgid ""
"For the sake of simplicity, most examples in this tutorial use a module-"
"level :func:`route` decorator to define routes. This adds routes to a global "
"\"default application\", an instance of :class:`Bottle` that is "
"automatically created the first time you call :func:`route`. Several other "
"module-level decorators and functions relate to this default application, "
"but if you prefer a more object oriented approach and don't mind the extra "
"typing, you can create a separate application object and use that instead of "
"the global one::"
msgstr ""
"基于简单性考虑,这份教程中的大部分例子都使用一个模块层面的 :func:`route` 修饰"
"器函数来定义route。这样的话,所有route都添加到了一个全局的“默认应用”里面,即"
"是在第一次调用 :func:`route` 函数时,创建的一个 :class:`Bottle` 类的实例。其"
"他几个模块层面的修饰器函数都与这个“默认应用”有关,如果你偏向于面向对象的做法"
"且不介意多打点字,你可以创建一个独立的应用对象,这样就可避免使用全局范围的“默"
"认应用”。"
# b3de36e15f504e4099b98ad3421a8a3d
#: ../../tutorial.rst:106
msgid ""
"The object-oriented approach is further described in the :ref:`default-app` "
"section. Just keep in mind that you have a choice."
msgstr ""
"接下来的 :ref:`default-app` 章节中将更详细地介绍这种做法。现在,你只需知道不"
"止有一种选择就好了。"
# 3c4ef0c7652d427db62949755a6c40b3
#: ../../tutorial.rst:114
msgid "Request Routing"
msgstr "URL映射"
# def96408b0aa4043965308a19be3984c
#: ../../tutorial.rst:116
msgid ""
"In the last chapter we built a very simple web application with only a "
"single route. Here is the routing part of the \"Hello World\" example again::"
msgstr ""
"在上一章中,我们实现了一个十分简单的web应用,只有一个URL映射(route)。让我们再"
"来看一下“Hello World”中与routing有关的部分::"
# 349b072faacd4906b20c28de17c17b2c
#: ../../tutorial.rst:122
msgid ""
"The :func:`route` decorator links an URL path to a callback function, and "
"adds a new route to the :ref:`default application `. An "
"application with just one route is kind of boring, though. Let's add some "
"more::"
msgstr ""
":func:`route` 函数将一个URL路径与一个回调函数关联了起来,然后在 :ref:"
"`default application ` 中添加了一个URL映射(route)。但只有一"
"个route的应用未免太无聊了,让我们试着再添加几个route吧。::"
# e0fcfc8632d74f1c829909f7ec493047
#: ../../tutorial.rst:129
msgid ""
"This example demonstrates two things: You can bind more than one route to a "
"single callback, and you can add wildcards to URLs and access them via "
"keyword arguments."
msgstr ""
"这个例子说明了两件事情,一个回调函数可绑定多个route,你也可以在URL中添加通配"
"符,然后在回调函数中使用它们。"
# dabaff12e29b40abbd26c784abd18696
#: ../../tutorial.rst:136
msgid "Dynamic Routes"
msgstr "动态URL映射"
# 988f03163d7b4112863628e580d3ec24
#: ../../tutorial.rst:138
msgid ""
"Routes that contain wildcards are called `dynamic routes` (as opposed to "
"`static routes`) and match more than one URL at the same time. A simple "
"wildcard consists of a name enclosed in angle brackets (e.g. ````) and "
"accepts one or more characters up to the next slash (``/``). For example, "
"the route ``/hello/`` accepts requests for ``/hello/alice`` as well as "
"``/hello/bob``, but not for ``/hello``, ``/hello/`` or ``/hello/mr/smith``."
msgstr ""
"包含通配符的route,我们称之为动态route(与之对应的是静态route),它能匹配多个"
"URL地址。一个通配符包含在一对尖括号里面(像这样 ```` ),通配符之间用\"/"
"\"分隔开来。如果我们将URL定义为 ``/hello/`` 这样,那么它就能匹配 ``/"
"hello/alice`` 和 ``/hello/bob`` 这样的浏览器请求,但不能匹配 ``/hello`` , ``/"
"hello/`` 和 ``/hello/mr/smith`` 。"
# 3d1bccff797843218d755217b1a64025
#: ../../tutorial.rst:140
msgid ""
"Each wildcard passes the covered part of the URL as a keyword argument to "
"the request callback. You can use them right away and implement RESTful, "
"nice-looking and meaningful URLs with ease. Here are some other examples "
"along with the URLs they'd match::"
msgstr ""
"URL中的通配符都会当作参数传给回调函数,直接在回调函数中使用。这样可以漂亮地实"
"现RESTful形式的URL。例子如下::"
# 39b80f89f2e24b88a48f4fde1f066d5f
#: ../../tutorial.rst:152
msgid ""
"Filters are used to define more specific wildcards, and/or transform the "
"covered part of the URL before it is passed to the callback. A filtered "
"wildcard is declared as ```` or ````. The "
"syntax for the optional config part depends on the filter used."
msgstr ""
"过滤器(Filter)可被用来定义特殊类型的通配符,在传通配符给回调函数之前,先自动"
"转换通配符类型。包含过滤器的通配符定义一般像 ```` 或 ```` 这样。config部分是可选的,其语法由你使用的过滤器决定。"
# f0f981dd9d6c485c88ceffbb7145caab
#: ../../tutorial.rst:154
msgid "The following filters are implemented by default and more may be added:"
msgstr "已实现下面几种形式的过滤器,后续可能会继续添加:"
# ea5726150090430fb51657407ba183c3
#: ../../tutorial.rst:156
msgid ""
"**:int** matches (signed) digits only and converts the value to integer."
msgstr "**:int** 匹配一个数字,自动将其转换为int类型。"
# d6b0d5f1a9c241a6b29dec4e65e890d6
#: ../../tutorial.rst:157
msgid "**:float** similar to :int but for decimal numbers."
msgstr "**:float** 与:int类似,用于浮点数。"
# b6a7efae1777408299795041cd226806
#: ../../tutorial.rst:158
msgid ""
"**:path** matches all characters including the slash character in a non-"
"greedy way and can be used to match more than one path segment."
msgstr "**:path** 匹配一个路径(包含\"/\")"
# e84964d6d43f4fe1afae7ba6bc7032a0
#: ../../tutorial.rst:159
msgid ""
"**:re** allows you to specify a custom regular expression in the config "
"field. The matched value is not modified."
msgstr "**:re** 匹配config部分的一个正则表达式,不更改被匹配到的值"
# 69650355e34d4716a450d9f712b88fd8
#: ../../tutorial.rst:161
msgid "Let's have a look at some practical examples::"
msgstr "让我们来看看具体的使用例子::"
# f2d03c373c8a4ada93e344985fb6cee7
#: ../../tutorial.rst:175
msgid "You can add your own filters as well. See :doc:`Routing` for details."
msgstr "你可以添加自己的过滤器。详见 :doc:`routing` 。"
# ce116c2df52344fc8ef6ab0dc85198fd
#: ../../tutorial.rst:179
msgid ""
"The new rule syntax was introduced in **Bottle 0.10** to simplify some "
"common use cases, but the old syntax still works and you can find a lot of "
"code examples still using it. The differences are best described by example:"
msgstr ""
"从 **Bottle 0.10** 版本开始,可以用新的语法来在URL中定义通配符,更简单了。新"
"旧语法之间的对比如下:"
# 4f170d5d120f4cb0a5576bcc352b6e81
#: ../../tutorial.rst:182
msgid "Old Syntax"
msgstr "旧语法"
# d98e5579e3c7481aacf83ee066cfa826
#: ../../tutorial.rst:182
msgid "New Syntax"
msgstr "新语法"
# 3ef58345079544b8a954099b097d5583
#: ../../tutorial.rst:184
msgid "``:name``"
msgstr ""
# ca2dfc00260445eba77bacd64e89f4e2
#: ../../tutorial.rst:184
msgid "````"
msgstr ""
# 24034e67d3194c6ea694d522ff118743
#: ../../tutorial.rst:185
msgid "``:name#regexp#``"
msgstr ""
# 9b40ae713f9a4c2182ab7666bd77e4fe
#: ../../tutorial.rst:185
msgid "````"
msgstr ""
# 47f26059d42b48ae8372c47a9c1cff3c
#: ../../tutorial.rst:186
msgid "``:#regexp#``"
msgstr ""
# 831629c77fb5421e8857371ed9b28751
#: ../../tutorial.rst:186
msgid "``<:re:regexp>``"
msgstr ""
# 2c0f1748c68a42829971f32f109f95a9
#: ../../tutorial.rst:187
msgid "``:##``"
msgstr ""
# 1191242878fd4759988a1717eeaa8d4f
#: ../../tutorial.rst:187
msgid "``<:re>``"
msgstr ""
# d866a2106ce5412795d39e31231da875
#: ../../tutorial.rst:190
msgid ""
"Try to avoid the old syntax in future projects if you can. It is not "
"currently deprecated, but will be eventually."
msgstr ""
"请尽可能在新项目中使用新的语法。虽然现在依然兼容旧语法,但终究会将其废弃的。"
# facb8eac8d394a2595b3745e4c2a67b4
#: ../../tutorial.rst:194
msgid "HTTP Request Methods"
msgstr "HTTP请求方法"
# 5cdb148bc56047629b19cac6c211ccba
#: ../../tutorial.rst:198
msgid ""
"The HTTP protocol defines several `request methods`__ (sometimes referred to "
"as \"verbs\") for different tasks. GET is the default for all routes with no "
"other method specified. These routes will match GET requests only. To handle "
"other methods such as POST, PUT or DELETE, add a ``method`` keyword argument "
"to the :func:`route` decorator or use one of the four alternative "
"decorators: :func:`get`, :func:`post`, :func:`put` or :func:`delete`."
msgstr ""
"HTTP协议定义了多个 `request methods`__ (请求方法)来满足不同的需求。所有"
"route默认使用GET方法,只响应GET请求。可给 :func:`route` 函数指定 ``method`` "
"参数。或用 :func:`get` , :func:`post` , :func:`put` 或 :func:`delete` 等"
"函数来代替 :func:`route` 函数。"
# 7278fe2bf62a4b3fb8abc0d391fd50e5
#: ../../tutorial.rst:200
msgid ""
"The POST method is commonly used for HTML form submission. This example "
"shows how to handle a login form using POST::"
msgstr ""
"POST方法一般用于HTML表单的提交。下面是一个使用POST来实现用户登录的例子::"
# d24dc377bdd6407eb5caaa912bf71dcb
#: ../../tutorial.rst:223
msgid ""
"In this example the ``/login`` URL is linked to two distinct callbacks, one "
"for GET requests and another for POST requests. The first one displays a "
"HTML form to the user. The second callback is invoked on a form submission "
"and checks the login credentials the user entered into the form. The use of :"
"attr:`Request.forms` is further described in the :ref:`tutorial-request` "
"section."
msgstr ""
"在这个例子中, ``/login`` 绑定了两个回调函数,一个回调函数响应GET请求,一个回"
"调函数响应POST请求。如果浏览器使用GET请求访问 ``/login`` ,则调用login_form()"
"函数来返回登录页面,浏览器使用POST方法提交表单后,调用login_submit()函数来检"
"查用户有效性,并返回登录结果。接下来的 :ref:`tutorial-request` 章节中,会详细"
"介绍 :attr:`Request.forms` 的用法。"
# 9a3d93e1646a48779d3cc9bef9713c21
#: ../../tutorial.rst:226
msgid "Special Methods: HEAD and ANY"
msgstr "特殊请求方法: HEAD 和 ANY"
# 78e1a7741c96447f912f8dd10cbc3aa4
#: ../../tutorial.rst:227
msgid ""
"The HEAD method is used to ask for the response identical to the one that "
"would correspond to a GET request, but without the response body. This is "
"useful for retrieving meta-information about a resource without having to "
"download the entire document. Bottle handles these requests automatically by "
"falling back to the corresponding GET route and cutting off the request "
"body, if present. You don't have to specify any HEAD routes yourself."
msgstr ""
"HEAD方法类似于GET方法,但服务器不会返回HTTP响应正文,一般用于获取HTTP原数据而"
"不用下载整个页面。Bottle像处理GET请求那样处理HEAD请求,但是会自动去掉HTTP响应"
"正文。你无需亲自处理HEAD请求。"
# 3628c8206bcb4b229d4e875e41a44e6b
#: ../../tutorial.rst:229
msgid ""
"Additionally, the non-standard ANY method works as a low priority fallback: "
"Routes that listen to ANY will match requests regardless of their HTTP "
"method but only if no other more specific route is defined. This is helpful "
"for *proxy-routes* that redirect requests to more specific sub-applications."
msgstr ""
"另外,非标准的ANY方法做为一个低优先级的fallback:在没有其它route的时候,监听"
"ANY方法的route会匹配所有请求,而不管请求的方法是什么。这对于用做代理的route很"
"有用,可将所有请求都重定向给子应用。"
# 1f0764c8a13a457bb5673ab0bfae1bf8
#: ../../tutorial.rst:231
msgid ""
"To sum it up: HEAD requests fall back to GET routes and all requests fall "
"back to ANY routes, but only if there is no matching route for the original "
"request method. It's as simple as that."
msgstr ""
"总而言之:HEAD请求被响应GET请求的route来处理,响应ANY请求的route处理所有请"
"求,但仅限于没有其它route来匹配原先的请求的情况。就这么简单。"
# 680955ebae544b4189d61a3ec93b13de
#: ../../tutorial.rst:236
msgid "Routing Static Files"
msgstr "静态文件映射"
# be9beea7a5c54379ae3b73c2f21b16e2
#: ../../tutorial.rst:238
msgid ""
"Static files such as images or CSS files are not served automatically. You "
"have to add a route and a callback to control which files get served and "
"where to find them::"
msgstr ""
"Bottle不会处理像图片或CSS文件的静态文件请求。你需要给静态文件提供一个route,"
"一个回调函数(用于查找和控制静态文件的访问)。"
# e174df21a55d4aaf9f92b14124f03538
#: ../../tutorial.rst:245
msgid ""
"The :func:`static_file` function is a helper to serve files in a safe and "
"convenient way (see :ref:`tutorial-static-files`). This example is limited "
"to files directly within the ``/path/to/your/static/files`` directory "
"because the ```` wildcard won't match a path with a slash in it. "
"To serve files in subdirectories, change the wildcard to use the `path` "
"filter::"
msgstr ""
":func:`static_file` 函数用于响应静态文件的请求。 (详见 :ref:`tutorial-static-"
"files` )这个例子只能响应在 ``/path/to/your/static/files`` 目录下的文件请求,"
"因为 ```` 这样的通配符定义不能匹配一个路径(路径中包含\"/\")。 为了"
"响应子目录下的文件请求,我们需要更改 `path` 过滤器的定义::"
# a42ae34a52d64603ad51dd2ac3e65ad1
#: ../../tutorial.rst:251
msgid ""
"Be careful when specifying a relative root-path such as ``root='./static/"
"files'``. The working directory (``./``) and the project directory are not "
"always the same."
msgstr ""
"使用 ``root='./static/files'`` 这样的相对路径的时候,请注意当前工作目录 (``./"
"``) 不一定是项目文件夹。"
# 22950a221ee24d8bb93f2202e7f5a843
#: ../../tutorial.rst:259
msgid "Error Pages"
msgstr "错误页面"
# e84b29f5921f42c487cd7409490d5026
#: ../../tutorial.rst:261
msgid ""
"If anything goes wrong, Bottle displays an informative but fairly plain "
"error page. You can override the default for a specific HTTP status code "
"with the :func:`error` decorator::"
msgstr ""
"如果出错了,Bottle会显示一个默认的错误页面,提供足够的debug信息。你也可以使"
"用 :func:`error` 函数来自定义你的错误页面::"
# 4bf4e85c95bd4b56b431ca5191f8f08d
#: ../../tutorial.rst:268
msgid ""
"From now on, `404 File not Found` errors will display a custom error page to "
"the user. The only parameter passed to the error-handler is an instance of :"
"exc:`HTTPError`. Apart from that, an error-handler is quite similar to a "
"regular request callback. You can read from :data:`request`, write to :data:"
"`response` and return any supported data-type except for :exc:`HTTPError` "
"instances."
msgstr ""
"从现在开始,在遇到404错误的时候,将会返回你在上面自定义的页面。传给error404函"
"数的唯一参数,是一个 :exc:`HTTPError` 对象的实例。除此之外,这个回调函数与我"
"们用来响应普通请求的回调函数没有任何不同。你可以从 :data:`request` 中读取数"
"据, 往 :data:`response` 中写入数据和返回所有支持的数据类型,除了 :exc:"
"`HTTPError` 的实例。"
# f3020bad30b147e9a86f81a825a379e9
#: ../../tutorial.rst:270
msgid ""
"Error handlers are used only if your application returns or raises an :exc:"
"`HTTPError` exception (:func:`abort` does just that). Changing :attr:"
"`Request.status` or returning :exc:`HTTPResponse` won't trigger the error "
"handler."
msgstr ""
"只有在你的应用返回或raise一个 :exc:`HTTPError` 异常的时候(就像 :func:`abort` "
"函数那样),处理Error的函数才会被调用。更改 :attr:`Request.status` 或返回 :"
"exc:`HTTPResponse` 不会触发错误处理函数。"
# 9112d2478be94ef8a880cea1dabce53a
#: ../../tutorial.rst:280
msgid "Generating content"
msgstr "生成内容"
# 8415bb3259f54aceab2160438457d486
#: ../../tutorial.rst:282
msgid ""
"In pure WSGI, the range of types you may return from your application is "
"very limited. Applications must return an iterable yielding byte strings. "
"You may return a string (because strings are iterable) but this causes most "
"servers to transmit your content char by char. Unicode strings are not "
"allowed at all. This is not very practical."
msgstr ""
"在纯WSGI环境里,你的应用能返回的内容类型相当有限。应用必须返回一个iterable的"
"字节型字符串。你可以返回一个字符串(因为字符串是iterable的),但这会导致服务器"
"按字符来传输你的内容。Unicode字符串根本不允许。这不是很实用。"
# 0c5e8549b2c14b10b64c1030888a9f11
#: ../../tutorial.rst:284
msgid ""
"Bottle is much more flexible and supports a wide range of types. It even "
"adds a ``Content-Length`` header if possible and encodes unicode "
"automatically, so you don't have to. What follows is a list of data types "
"you may return from your application callbacks and a short description of "
"how these are handled by the framework:"
msgstr ""
"Bottle支持返回更多的内容类型,更具弹性。它甚至能在合适的情况下,在HTTP头中添"
"加 `Content-Length` 字段和自动转换unicode编码。下面列出了所有你能返回的内容类"
"型,以及框架处理方式的一个简述。"
# cd50167d8d094ecf947bb272905d75b7
#: ../../tutorial.rst:287
msgid "Dictionaries"
msgstr ""
# 05aa98461f2e434f81e050cbcc756f6a
#: ../../tutorial.rst:287
msgid ""
"As mentioned above, Python dictionaries (or subclasses thereof) are "
"automatically transformed into JSON strings and returned to the browser with "
"the ``Content-Type`` header set to ``application/json``. This makes it easy "
"to implement json-based APIs. Data formats other than json are supported "
"too. See the :ref:`tutorial-output-filter` to learn more."
msgstr ""
"上面已经提及,Python中的字典类型(或其子类)会被自动转换为JSON字符串。返回给浏"
"览器的时候,HTTP头的 ``Content-Type`` 字段被自动设置为 `` application/"
"json`` 。可十分简单地实现基于JSON的API。Bottle同时支持json之外的数据类型,详"
"见 :ref:`tutorial-output-filter` 。"
# fef9f9cdcf174200a8c9d34fe40ec6a8
#: ../../tutorial.rst:290
msgid "Empty Strings, ``False``, ``None`` or other non-true values:"
msgstr ""
# 947fe77a24c4436f92b3de6ac018bfb8
#: ../../tutorial.rst:290
msgid ""
"These produce an empty output with the ``Content-Length`` header set to 0."
msgstr "输出为空, ``Content-Length`` 设为0。"
# 53831a3d134a4bcc8b1553ff0e8ef190
#: ../../tutorial.rst:293
msgid "Unicode strings"
msgstr "Unicode的问题"
# 6b454d4e4ee04af1809c42870727aeab
#: ../../tutorial.rst:293
msgid ""
"Unicode strings (or iterables yielding unicode strings) are automatically "
"encoded with the codec specified in the ``Content-Type`` header (utf8 by "
"default) and then treated as normal byte strings (see below)."
msgstr ""
"Unicode字符串 (or iterables yielding unicode strings) 被自动转码, ``Content-"
"Type`` 被默认设置为utf8,接着视之为普通字符串(见下文)。"
# e8ae5fa61f0942cd9fe48e03fa9351e9
#: ../../tutorial.rst:296
msgid "Byte strings"
msgstr ""
# e20b8cfb4e7a434c9a95dc125561a7f0
#: ../../tutorial.rst:296
msgid ""
"Bottle returns strings as a whole (instead of iterating over each char) and "
"adds a ``Content-Length`` header based on the string length. Lists of byte "
"strings are joined first. Other iterables yielding byte strings are not "
"joined because they may grow too big to fit into memory. The ``Content-"
"Length`` header is not set in this case."
msgstr ""
"Bottle将字符串当作一个整体来返回(而不是按字符来遍历),并根据字符串长度添加 "
"``Content-Length`` 字段。包含字节型字符串的列表先被合并。其它iterable的字节型"
"字符串不会被合并,因为它们也许太大来,耗内存。在这种情况下, ``Content-"
"Length`` 字段不会被设置。"
# c0b5bc13bd1f456ea06c9ec8c0ae332e
#: ../../tutorial.rst:299
msgid "Instances of :exc:`HTTPError` or :exc:`HTTPResponse`"
msgstr ""
# 4b231556398548d6804429d660fe8f90
#: ../../tutorial.rst:299
msgid ""
"Returning these has the same effect as when raising them as an exception. In "
"case of an :exc:`HTTPError`, the error handler is applied. See :ref:"
"`tutorial-errorhandling` for details."
msgstr ""
"返回它们和直接raise出来有一样的效果。对于 :exc:`HTTPError` 来说,会调用错误处"
"理程序。详见 :ref:`tutorial-errorhandling` 。"
# 8ec78edc24634cb19d9d3fe68fff214f
#: ../../tutorial.rst:302
msgid "File objects"
msgstr ""
# 84bf9373fcf148a0b17af9a22e9473d7
#: ../../tutorial.rst:302
msgid ""
"Everything that has a ``.read()`` method is treated as a file or file-like "
"object and passed to the ``wsgi.file_wrapper`` callable defined by the WSGI "
"server framework. Some WSGI server implementations can make use of optimized "
"system calls (sendfile) to transmit files more efficiently. In other cases "
"this just iterates over chunks that fit into memory. Optional headers such "
"as ``Content-Length`` or ``Content-Type`` are *not* set automatically. Use :"
"func:`send_file` if possible. See :ref:`tutorial-static-files` for details."
msgstr ""
"任何有 ``.read()`` 方法的对象都被当成一个file-like对象来对待,会被传给 WSGI "
"Server 框架定义的 ``wsgi.file_wrapper`` callable对象来处理。一些WSGI Server实"
"现会利用优化过的系统调用(sendfile)来更有效地传输文件,另外就是分块遍历。可选"
"的HTTP头,例如 ``Content-Length`` 和 ``Content-Type`` 不会被自动设置。尽可能"
"使用 :func:`send_file` 。详见 :ref:`tutorial-static-files` 。"
# 5a4011401e1b4adfa5dc9114b1491c26
#: ../../tutorial.rst:305
msgid "Iterables and generators"
msgstr ""
# 134e34ab7165436b8232fe79d85d695e
#: ../../tutorial.rst:305
msgid ""
"You are allowed to use ``yield`` within your callbacks or return an "
"iterable, as long as the iterable yields byte strings, unicode strings, :exc:"
"`HTTPError` or :exc:`HTTPResponse` instances. Nested iterables are not "
"supported, sorry. Please note that the HTTP status code and the headers are "
"sent to the browser as soon as the iterable yields its first non-empty "
"value. Changing these later has no effect."
msgstr ""
"你可以在回调函数中使用 ``yield`` 语句,或返回一个iterable的对象,只要该对象返"
"回的是字节型字符串,unicode字符串, :exc:`HTTPError` 或 :exc:`HTTPResponse` "
"实例。不支持嵌套iterable对象,不好意思。注意,在iterable对象返回第一个非空值"
"的时候,就会把HTTP状态码和HTTP头发送给浏览器。稍后再更改它们就起不到什么作用"
"了。"
# 465e3afd48064a6aa286d3b5428b038b
#: ../../tutorial.rst:307
msgid ""
"The ordering of this list is significant. You may for example return a "
"subclass of :class:`str` with a ``read()`` method. It is still treated as a "
"string instead of a file, because strings are handled first."
msgstr ""
"以上列表的顺序非常重要。在你返回一个 :class:`str` 类的子类的时候,即使它有 "
"``.read()`` 方法,它依然会被当成一个字符串对待,而不是文件,因为字符串先被处"
"理。"
# 2fc6610bcc9f406f8b368ef74e8b26f9
#: ../../tutorial.rst:310
msgid "Changing the Default Encoding"
msgstr "改变默认编码"
# 23b6daa9751f4ba5920edfff5246fbc0
#: ../../tutorial.rst:311
msgid ""
"Bottle uses the `charset` parameter of the ``Content-Type`` header to decide "
"how to encode unicode strings. This header defaults to ``text/html; "
"charset=UTF8`` and can be changed using the :attr:`Response.content_type` "
"attribute or by setting the :attr:`Response.charset` attribute directly. "
"(The :class:`Response` object is described in the section :ref:`tutorial-"
"response`.)"
msgstr ""
"Bottle使用 ``Content-Type`` 的 `charset` 参数来决定编码unicode字符串的方式。"
"默认的 ``Content-Type`` 是 ``text/html;charset=UTF8`` ,可在 :attr:`Response."
"content_type` 属性中修改,或直接设置 :attr:`Response.charset` 的值。关于 :"
"class:`Response` 对象的介绍,详见 :ref:`tutorial-response` 。"
# 2bd0c5aa83bb43b1ad029c4a8f8a19d9
#: ../../tutorial.rst:326
msgid ""
"In some rare cases the Python encoding names differ from the names supported "
"by the HTTP specification. Then, you have to do both: first set the :attr:"
"`Response.content_type` header (which is sent to the client unchanged) and "
"then set the :attr:`Response.charset` attribute (which is used to encode "
"unicode)."
msgstr ""
"在极少情况下,Python中定义的编码名字和HTTP标准中的定义不一样。这样,你就必须"
"同时修改 :attr:`Response.content_type`` (发送给客户端的)和设置 :attr:"
"`Response.charset` 属性 (用于编码unicode)。"
# e3e2fb4d1ee847ca84245ed5a5729071
#: ../../tutorial.rst:331
msgid "Static Files"
msgstr "静态文件"
# 4a4c82922fbf4478886571051b910204
#: ../../tutorial.rst:333
msgid ""
"You can directly return file objects, but :func:`static_file` is the "
"recommended way to serve static files. It automatically guesses a mime-type, "
"adds a ``Last-Modified`` header, restricts paths to a ``root`` directory for "
"security reasons and generates appropriate error responses (401 on "
"permission errors, 404 on missing files). It even supports the ``If-Modified-"
"Since`` header and eventually generates a ``304 Not Modified`` response. You "
"can pass a custom MIME type to disable guessing."
msgstr ""
"你可直接返回文件对象。但我们更建议你使用 :func:`static_file` 来提供静态文件服"
"务。它会自动猜测文件的mime-type,添加 ``Last-Modified`` 头,将文件路径限制在"
"一个root文件夹下面来保证安全,且返回合适的HTTP状态码(由于权限不足导致的401错"
"误,由于文件不存在导致的404错误)。它甚至支持 ``If-Modified-Since`` 头,如果文"
"件未被修改,则直接返回 ``304 Not Modified`` 。你可指定MIME类型来避免其自动猜"
"测。"
# 3d6989c4599c4f9d9fcdd6cba03e29aa
#: ../../tutorial.rst:346
msgid ""
"You can raise the return value of :func:`static_file` as an exception if you "
"really need to."
msgstr "如果确实需要,你可将 :func:`static_file` 的返回值当作异常raise出来。"
# 8d57af8994bd44cd8dd00013b3a71231
#: ../../tutorial.rst:349
msgid "Forced Download"
msgstr "强制下载"
# 23ef7011528a4bf9a2b181d2427f0b21
#: ../../tutorial.rst:350
msgid ""
"Most browsers try to open downloaded files if the MIME type is known and "
"assigned to an application (e.g. PDF files). If this is not what you want, "
"you can force a download dialog and even suggest a filename to the user::"
msgstr ""
"大多数浏览器在知道MIME类型的时候,会尝试直接调用相关程序来打开文件(例如PDF文"
"件)。如果你不想这样,你可强制浏览器只是下载该文件,甚至提供文件名。::"
# 2b57ebda0b8b47c09d4cebcc702835e3
#: ../../tutorial.rst:356
msgid ""
"If the ``download`` parameter is just ``True``, the original filename is "
"used."
msgstr "如果 ``download`` 参数的值为 ``True`` ,会使用原始的文件名。"
# 3abd91e08f5c439481852f8eced8b1de
#: ../../tutorial.rst:361
msgid "HTTP Errors and Redirects"
msgstr "HTTP错误和重定向"
# 4ef454163f78497fa8f0c3b112e02a6c
#: ../../tutorial.rst:363
msgid ""
"The :func:`abort` function is a shortcut for generating HTTP error pages."
msgstr ":func:`abort` 函数是生成HTTP错误页面的一个捷径。"
# 65a2e1ed20634574932f8c39c8ac2d13
#: ../../tutorial.rst:372
msgid ""
"To redirect a client to a different URL, you can send a ``303 See Other`` "
"response with the ``Location`` header set to the new URL. :func:`redirect` "
"does that for you::"
msgstr ""
"为了将用户访问重定向到其他URL,你在 ``Location`` 中设置新的URL,接着返回一个 "
"``303 See Other`` 。 :func:`redirect` 函数可以帮你做这件事情。"
# 50ab2a7b353a41c39c7fdcb9456630e3
#: ../../tutorial.rst:379
msgid "You may provide a different HTTP status code as a second parameter."
msgstr "你可以在第二个参数中提供另外的HTTP状态码。"
# 757d4047c42d4e71a774a63b020fbb42
#: ../../tutorial.rst:382
msgid ""
"Both functions will interrupt your callback code by raising an :exc:"
"`HTTPError` exception."
msgstr "这两个函数都会抛出 :exc:`HTTPError` 异常,终止回调函数的执行。"
# 2ee3e09d1528432294fcead9239e99b6
#: ../../tutorial.rst:385
msgid "Other Exceptions"
msgstr "其他异常"
# 72ce4695e46c40d0a2f4aad019108612
#: ../../tutorial.rst:386
msgid ""
"All exceptions other than :exc:`HTTPResponse` or :exc:`HTTPError` will "
"result in a ``500 Internal Server Error`` response, so they won't crash your "
"WSGI server. You can turn off this behavior to handle exceptions in your "
"middleware by setting ``bottle.app().catchall`` to ``False``."
msgstr ""
"除了 :exc:`HTTPResponse` 或 :exc:`HTTPError` 以外的其他异常,都会导致500错"
"误,所以不会造成WSGI服务器崩溃。你将 ``bottle.app().catchall`` 的值设为 "
"``False`` 来关闭这种行为,以便在你的中间件中处理异常。"
# 49ba8af1eacf4ca6b5eef9f290d09a94
#: ../../tutorial.rst:392
msgid "The :class:`Response` Object"
msgstr ":class:`Response` 对象"
# 8ff2b5057b384d199aa9e15374ca37d4
#: ../../tutorial.rst:394
msgid ""
"Response metadata such as the HTTP status code, response headers and cookies "
"are stored in an object called :data:`response` up to the point where they "
"are transmitted to the browser. You can manipulate these metadata directly "
"or use the predefined helper methods to do so. The full API and feature list "
"is described in the API section (see :class:`Response`), but the most common "
"use cases and features are covered here, too."
msgstr ""
"诸如HTTP状态码,HTTP响应头,用户cookie等元数据都保存在一个名字为 :data:"
"`response` 的对象里面,接着被传输给浏览器。你可直接操作这些元数据或使用一些更"
"方便的函数。在API章节可查到所有相关API(详见 :class:`Response` ),这里主要介绍"
"一些常用方法。"
# a4837fc6a70147fa9abce539af78cda0
#: ../../tutorial.rst:397
msgid "Status Code"
msgstr "状态码"
# 16869c8c17d54323ab7486f66efdc860
#: ../../tutorial.rst:398
msgid ""
"The `HTTP status code `_ controls the behavior of the browser and "
"defaults to ``200 OK``. In most scenarios you won't need to set the :attr:"
"`Response.status` attribute manually, but use the :func:`abort` helper or "
"return an :exc:`HTTPResponse` instance with the appropriate status code. Any "
"integer is allowed, but codes other than the ones defined by the `HTTP "
"specification `_ will only confuse the browser and break "
"standards."
msgstr ""
"`HTTP状态码 `_ 控制着浏览器的行为,默认为 ``200 OK`` 。多数情况"
"下,你不必手动修改 :attr:`Response.status` 的值,可使用 :func:`abort` 函数或"
"return一个 :exc:`HTTPResponse` 实例(带有合适的状态码)。虽然所有整数都可当作状"
"态码返回,但浏览器不知道如何处理 `HTTP标准 `_ 中定义的那些状态码之"
"外的数字,你也破坏了大家约定的标准。"
# fad4d415e6b34d8da4915371819dad0b
#: ../../tutorial.rst:401
msgid "Response Header"
msgstr "响应头"
# 6837d7afd10c499e84b15229465f8a3a
#: ../../tutorial.rst:402
msgid ""
"Response headers such as ``Cache-Control`` or ``Location`` are defined via :"
"meth:`Response.set_header`. This method takes two parameters, a header name "
"and a value. The name part is case-insensitive::"
msgstr ""
"``Cache-Control`` 和 ``Location`` 之类的响应头通过 :meth:`Response."
"set_header` 来定义。这个方法接受两个参数,一个是响应头的名字,一个是它的值,"
"名字是大小写敏感的。"
# 6414dd7a448b45f998147a61ce167933
#: ../../tutorial.rst:409
msgid ""
"Most headers are unique, meaning that only one header per name is send to "
"the client. Some special headers however are allowed to appear more than "
"once in a response. To add an additional header, use :meth:`Response."
"add_header` instead of :meth:`Response.set_header`::"
msgstr ""
"大多数的响应头是唯一的,meaning that only one header per name is send to the "
"client。一些特殊的响应头在一次response中允许出现多次。使用 :meth:`Response."
"add_header` 来添加一个额外的响应头,而不是 :meth:`Response.set_header` ::"
# cc64c4d2b8f541728562d60b69e95246
#: ../../tutorial.rst:414
msgid ""
"Please note that this is just an example. If you want to work with cookies, "
"read :ref:`ahead `."
msgstr ""
"请注意,这只是一个例子。如果你想使用cookie,详见 :ref:`ahead ` 。"
# 1ffb76e4eada4039b6633e13cdb49c6a
# 35303652d16f422bacde561fb6912852
#: ../../tutorial.rst:420 ../../tutorial.rst:549
msgid "Cookies"
msgstr ""
# 6b9e5c6de2f0499b9483fc1f2e666aa4
#: ../../tutorial.rst:422
msgid ""
"A cookie is a named piece of text stored in the user's browser profile. You "
"can access previously defined cookies via :meth:`Request.get_cookie` and set "
"new cookies with :meth:`Response.set_cookie`::"
msgstr ""
"Cookie是储存在浏览器配置文件里面的一小段文本。你可通过 :meth:`Request."
"get_cookie` 来访问已存在的Cookie,或通过 :meth:`Response.set_cookie` 来设置新"
"的Cookie。"
# 89a73e9549444c0ba012c873a5f82ad5
#: ../../tutorial.rst:432
msgid ""
"The :meth:`Response.set_cookie` method accepts a number of additional "
"keyword arguments that control the cookies lifetime and behavior. Some of "
"the most common settings are described here:"
msgstr ""
":meth:`Response.set_cookie` 方法接受一系列额外的参数,来控制Cookie的生命周期"
"及行为。一些常用的设置如下:"
# f4b185b380fd44129a1c9e606627d9cd
#: ../../tutorial.rst:434
msgid "**max_age:** Maximum age in seconds. (default: ``None``)"
msgstr "**max_age:** 最大有效时间,以秒为单位 (默认: ``None``)"
# 5f7ec5d053de45c1b7f018e4a77a5100
#: ../../tutorial.rst:435
msgid ""
"**expires:** A datetime object or UNIX timestamp. (default: ``None``)"
msgstr "**expires:** 一个datetime对象或一个UNIX timestamp (默认: ``None``)"
# 93366621f0de4592872fbbd675ccfe9b
#: ../../tutorial.rst:436
msgid ""
"**domain:** The domain that is allowed to read the cookie. (default: "
"current domain)"
msgstr "**domain:** 可访问该Cookie的域名 (默认: 当前域名)"
# 6011fc5e6dfa4c70a3fb228d7632dbe7
#: ../../tutorial.rst:437
msgid "**path:** Limit the cookie to a given path (default: ``/``)"
msgstr "**path:** 限制cookie的访问路径 (默认: ``/``)"
# 54a3f9e2aabb4fcf8f9fe532ed8c5ea4
#: ../../tutorial.rst:438
msgid "**secure:** Limit the cookie to HTTPS connections (default: off)."
msgstr "**secure:** 只允许在HTTPS链接中访问cookie (默认: off)"
# 52488fc9830349e0ad2a586ef39ce369
#: ../../tutorial.rst:439
msgid ""
"**httponly:** Prevent client-side javascript to read this cookie (default: "
"off, requires Python 2.6 or newer)."
msgstr ""
"**httponly:** 防止客户端的javascript读取cookie (默认: off, 要求python 2.6或"
"以上版本)"
# 01244742811543388b079c56b8927022
#: ../../tutorial.rst:441
msgid ""
"If neither `expires` nor `max_age` is set, the cookie expires at the end of "
"the browser session or as soon as the browser window is closed. There are "
"some other gotchas you should consider when using cookies:"
msgstr ""
"如果 `expires` 和 `max_age` 两个值都没设置,cookie会在当前的浏览器session失效"
"或浏览器窗口关闭后失效。在使用cookie的时候,应该注意一下几个陷阱。"
# 6cbd22399dd348bea70e2e80ee49110c
#: ../../tutorial.rst:443
msgid "Cookies are limited to 4 KB of text in most browsers."
msgstr "在大多数浏览器中,cookie的最大容量为4KB。"
# 14572986849c49978df7a87343a71ab3
#: ../../tutorial.rst:444
msgid ""
"Some users configure their browsers to not accept cookies at all. Most "
"search engines ignore cookies too. Make sure that your application still "
"works without cookies."
msgstr ""
"一些用户将浏览器设置为不接受任何cookie。大多数搜索引擎也忽略cookie。确保你的"
"应用在无cookie的时候也能工作。"
# 5dca7f9d829541ddbe8d5e168938dffa
#: ../../tutorial.rst:445
msgid ""
"Cookies are stored at client side and are not encrypted in any way. Whatever "
"you store in a cookie, the user can read it. Worse than that, an attacker "
"might be able to steal a user's cookies through `XSS `_ vulnerabilities "
"on your side. Some viruses are known to read the browser cookies, too. Thus, "
"never store confidential information in cookies."
msgstr ""
"cookie被储存在客户端,也没被加密。你在cookie中储存的任何数据,用户都可以读"
"取。更坏的情况下,cookie会被攻击者通过 `XSS `_ 偷走,一些已知病毒也会读取"
"浏览器的cookie。既然如此,就不要在cookie中储存任何敏感信息。"
# d7e20326f4d8418697a0f9d697149837
#: ../../tutorial.rst:446
msgid "Cookies are easily forged by malicious clients. Do not trust cookies."
msgstr "cookie可以被伪造,不要信任cookie!"
# f9d19c03dc70462badd8b0b5493a9c5c
#: ../../tutorial.rst:451
msgid "Signed Cookies"
msgstr "Cookie签名"
# 269d39ae6e4f413ca3221424985aa0c4
#: ../../tutorial.rst:452
msgid ""
"As mentioned above, cookies are easily forged by malicious clients. Bottle "
"can cryptographically sign your cookies to prevent this kind of "
"manipulation. All you have to do is to provide a signature key via the "
"`secret` keyword argument whenever you read or set a cookie and keep that "
"key a secret. As a result, :meth:`Request.get_cookie` will return ``None`` "
"if the cookie is not signed or the signature keys don't match::"
msgstr ""
"上面提到,cookie容易被客户端伪造。Bottle可通过加密cookie来防止此类攻击。你只"
"需在读取和设置cookie的时候,通过 `secret` 参数来提供一个密钥。如果cookie未签"
"名或密钥不匹配, :meth:`Request.get_cookie` 方法返回 ``None`` "
# 99cbc28ea5f240cba38b5f2cd2fc7518
#: ../../tutorial.rst:472
msgid ""
"In addition, Bottle automatically pickles and unpickles any data stored to "
"signed cookies. This allows you to store any pickle-able object (not only "
"strings) to cookies, as long as the pickled data does not exceed the 4 KB "
"limit."
msgstr ""
"例外,Bottle自动序列化储存在签名cookie里面的数据。你可在cookie中储存任何可序"
"列化的对象(不仅仅是字符串),只要对象大小不超过4KB。"
# a3e875cbc84a440488152c627190d081
#: ../../tutorial.rst:474
msgid ""
"Signed cookies are not encrypted (the client can still see the content) and "
"not copy-protected (the client can restore an old cookie). The main "
"intention is to make pickling and unpickling safe and prevent manipulation, "
"not to store secret information at client side."
msgstr ""
"签名cookie在客户端不加密(译者注:即在客户端没有经过二次加密),也没有写保护(客"
"户端可使用之前的cookie)。给cookie签名的主要意义在于在cookie中存储序列化对象和"
"防止伪造cookie,依然不要在cookie中存储敏感信息。"
# 4655322431dd449193c8c18eeb8cdf95
#: ../../tutorial.rst:487
msgid "Request Data"
msgstr "请求数据 (Request Data)"
# 5bf5d62b2bae4266b7c48345f157eda7
#: ../../tutorial.rst:489
msgid ""
"Cookies, HTTP header, HTML ``