Browse Source

Heavily improved documentation

pull/1638/head
Armin Ronacher 15 years ago
parent
commit
05f36c7f7e
  1. 5
      docs/_templates/sidebarintro.html
  2. 94
      docs/_themes/flasky/static/flasky.css_t
  3. 8
      docs/api.rst
  4. 266
      docs/deploying.rst
  5. 20
      docs/flaskext.py
  6. 9
      docs/foreword.rst
  7. 1
      docs/index.rst
  8. 43
      docs/installation.rst
  9. 11
      docs/quickstart.rst
  10. 73
      flask.py

5
docs/_templates/sidebarintro.html vendored

@ -5,3 +5,8 @@
not stable yet, but if you have some feedback,
<a href="mailto:armin.ronacher@active-4.com">let me know</a>.
</p>
<h3>Useful Links</h3>
<ul>
<li><a href="http://pypi.python.org/pypi/Flask">Flask @ PyPI</a></li>
<li><a href="http://github.com/mitsuhiko/flask">Flask @ github</a></li>
</ul>

94
docs/_themes/flasky/static/flasky.css_t vendored

@ -16,7 +16,7 @@
body {
font-family: 'Georgia', serif;
font-size: 100%;
background-color: #111;
background-color: #555;
color: #555;
margin: 0;
padding: 0;
@ -47,15 +47,13 @@ div.body {
}
div.footer {
color: #555;
width: 100%;
padding: 13px 0;
text-align: center;
font-size: 75%;
color: #ccc;
padding: 10px;
font-size: 0.8em;
}
div.footer a {
color: #444;
color: white;
text-decoration: underline;
}
@ -138,7 +136,7 @@ div.sphinxsidebar input[type=text]{
/* -- body styles ----------------------------------------------------------- */
a {
color: #003B55;
color: #004B6B;
text-decoration: none;
}
@ -159,7 +157,7 @@ div.body h6 {
color: #212224;
margin: 30px 0px 10px 0px;
padding: 8px 0 5px 10px;
text-shadow: 0px 1px 0 white
text-shadow: 0px 1px 0 white;
}
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
@ -170,14 +168,14 @@ div.body h5 { font-size: 100%; background-color: #eee; }
div.body h6 { font-size: 100%; background-color: #eee; }
a.headerlink {
color: #c60f0f;
color: white;
padding: 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
color: #444;
background: #eaeaea;
}
div.body p, div.body dd, div.body li {
@ -218,22 +216,78 @@ p.admonition-title {
p.admonition-title:after {
content: ":";
}
pre, tt {
font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.9em;
}
tt.descname, tt.descclassname {
font-size: 0.95em;
-webkit-box-shadow: none;
-moz-box-shadow: none;
}
tt.descname {
padding-right: 0.08em;
}
table.docutils {
border: 1px solid #888;
-webkit-box-shadow: 2px 2px 1px #d8d8d8;
-moz-box-shadow: 2px 2px 1px #d8d8d8;
}
table.docutils td, table.docutils th {
border: 1px solid #888;
padding: 0.25em 0.7em;
}
table.field-list {
border: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
}
table.field-list th {
padding: 0 0.8em 0 0;
}
table.field-list td {
padding: 0;
}
pre {
background: #FDFDFD;
padding: 10px;
color: #222;
line-height: 1.2em;
border: 1px solid #C6C9CB;
font-size: 1.1em;
margin: 1.5em 0 1.5em 0;
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
line-height: 1.3em;
border: 1px solid #f9f9f9;
margin: 1.5em 3px 1.5em 0;
-webkit-box-shadow: 2px 2px 1px #d8d8d8;
-moz-box-shadow: 2px 2px 1px #d8d8d8;
}
tt {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
font-size: 1.1em;
font-family: monospace;
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
}
tt.xref, a tt {
background-color: #FBFBFB;
}
a:hover tt {
background: #EEE;
}
div.document + div.related {
background: #aaa;
}
div.document + div.related a {
color: white;
}

8
docs/api.rst

@ -163,7 +163,13 @@ Useful Functions and Classes
.. autofunction:: url_for
.. autofunction:: abort
.. function:: abort(code)
Raises an :exc:`~werkzeug.exception.HTTPException` for the given
status code. For example to abort request handling with a page not
found exception, you would call ``abort(404)``.
:param code: the HTTP error code.
.. autofunction:: redirect

266
docs/deploying.rst

@ -0,0 +1,266 @@
Deployment Options
==================
Depending on what you have available there are multiple ways to run Flask
applications. A very common method is to use the builtin server during
development and maybe behind a proxy for simple applications, but there
are more options available.
If you have a different WSGI server look up the server documentation about
how to use a WSGI app with it. Just remember that your application object
is the actual WSGI application.
FastCGI
-------
A very popular deployment setup on servers like `lighttpd`_ and `nginx`_
is FastCGI. To use your WSGI application with any of them you will need
a FastCGI server first.
The most popular one is `flup`_ which we will use for this guide. Make
sure to have it installed.
Creating a `.fcgi` file
```````````````````````
First you need to create the FastCGI server file. Let's call it
`yourapplication.fcgi`::
#!/usr/bin/python
from flup.server.fcgi import WSGIServer
from yourapplication import app
WSGIServer(app).run()
This is enough for Apache to work, however lighttpd and nginx need a
socket to communicate with the FastCGI server. For that to work you
need to pass the path to the socket to the
:class:`~flup.server.fcgi.WSGIServer`::
WSGIServer(application, bindAddress='/path/to/fcgi.sock').run()
The path has to be the exact same path you define in the server
config.
Save the `yourapplication.fcgi` file somewhere you will find it again.
It makes sense to have that in `/var/www/yourapplication` or something
similar.
Make sure to set the executable bit on that file so that the servers
can execute it::
# chmod +x /var/www/yourapplication/yourapplication.fcgi
Configuring lighttpd
````````````````````
A basic FastCGI configuration for lighttpd looks like that::
fastcgi.server = ("/yourapplication" =>
"yourapplication" => (
"socket" => "/tmp/yourapplication-fcgi.sock",
"bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
"check-local" => "disable"
)
)
This configuration binds the application to `/yourapplication`. If you
want the application to work in the URL root you have to work around a
lighttpd bug with the `~werkzeug.contrib.fixers.LighttpdCGIRootFix` middleware.
Make sure to apply it only if you are mounting the application the URL
root.
Configuring nginx
`````````````````
Installing FastCGI applications on nginx is a bit tricky because by default
some FastCGI parameters are not properly forwarded.
A basic FastCGI configuration for nginx looks like this::
location /yourapplication/ {
include fastcgi_params;
if ($uri ~ ^/yourapplication/(.*)?) {
set $path_url $1;
}
fastcgi_param PATH_INFO $path_url;
fastcgi_param SCRIPT_NAME /yourapplication;
fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}
This configuration binds the application to `/yourapplication`. If you want
to have it in the URL root it's a bit easier because you don't have to figure
out how to calculate `PATH_INFO` and `SCRIPT_NAME`::
location /yourapplication/ {
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param SCRIPT_NAME "";
fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}
Since Nginx doesn't load FastCGI apps, you have to do it by yourself. You
can either write an `init.d` script for that or execute it inside a screen
session::
$ screen
$ /var/www/yourapplication/yourapplication.fcgi
Debugging
`````````
FastCGI deployments tend to be hard to debug on most webservers. Very often the
only thing the server log tells you is something along the lines of "premature
end of headers". In order to debug the application the only thing that can
really give you ideas why it breaks is switching to the correct user and
executing the application by hand.
This example assumes your application is called `application.fcgi` and that your
webserver user is `www-data`::
$ su www-data
$ cd /var/www/yourapplication
$ python application.fcgi
Traceback (most recent call last):
File "yourapplication.fcg", line 4, in <module>
ImportError: No module named yourapplication
In this case the error seems to be "yourapplication" not being on the python
path. Common problems are:
- relative paths being used. Don't rely on the current working directory
- the code depending on environment variables that are not set by the
web server.
- different python interpreters being used.
.. _lighttpd: http://www.lighttpd.net/
.. _nginx: http://nginx.net/
.. _flup: http://trac.saddi.com/flup
mod_wsgi (Apache)
-----------------
If you are using the `Apache`_ webserver you should consider using `mod_wsgi`_.
.. _Apache: http://httpd.apache.org/
Installing `mod_wsgi`
`````````````````````
If you don't have `mod_wsgi` installed yet you have to either install it using
a package manager or compile it yourself.
The mod_wsgi `installation instructions`_ cover installation instructions for
source installations on UNIX systems.
If you are using ubuntu / debian you can apt-get it and activate it as follows::
# apt-get install libapache2-mod-wsgi
On FreeBSD install `mod_wsgi` by compiling the `www/mod_wsgi` port or by using
pkg_add::
# pkg_add -r mod_wsgi
If you are using pkgsrc you can install `mod_wsgi` by compiling the
`www/ap2-wsgi` package.
If you encounter segfaulting child processes after the first apache reload you
can safely ignore them. Just restart the server.
Creating a `.wsgi` file
```````````````````````
To run your application you need a `yourapplication.wsgi` file. This file
contains the code `mod_wsgi` is executing on startup to get the application
object. The object called `application` in that file is then used as
application.
For most applications the following file should be sufficient::
from yourapplication import app as application
If you don't have a factory function for application creation but a singleton
instance you can directly import that one as `application`.
Store that file somewhere where you will find it again (eg:
`/var/www/yourapplication`) and make sure that `yourapplication` and all
the libraries that are in use are on the python load path. If you don't
want to install it system wide consider using a `virtual python`_ instance.
Configuring Apache
``````````````````
The last thing you have to do is to create an Apache configuration file for
your application. In this example we are telling `mod_wsgi` to execute the
application under a different user for security reasons:
.. sourcecode:: apache
<VirtualHost *>
ServerName example.com
WSGIDaemonProcess yourapplication user=user1 group=group1 processes=1 threads=5
WSGIScriptAlias / /var/www/yourapplication/yourapplication.wsgi
<Directory /var/www/yourapplication>
WSGIProcessGroup yourapplication
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
For more information consult the `mod_wsgi wiki`_.
.. _mod_wsgi: http://code.google.com/p/modwsgi/
.. _installation instructions: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide
.. _virtual python: http://pypi.python.org/pypi/virtualenv
.. _mod_wsgi wiki: http://code.google.com/p/modwsgi/wiki/
CGI
---
If all other deployment methods do not work, CGI will work for sure. CGI
is supported by all major browsers but usually has a less-than-optimal
performance.
This is also the way you can use a Flask application on Google's
`AppEngine`_, there however the execution does happen in a CGI-like
environment. The application's performance is unaffected because of that.
.. _AppEngine: http://code.google.com/appengine/
Creating a `.cgi` file
``````````````````````
First you need to create the CGI application file. Let's call it
`yourapplication.cgi`::
#!/usr/bin/python
from wsgiref.handlers import CGIHandler
from yourapplication import app
CGIHandler().run(app)
If you're running Python 2.4 you will need the :mod:`wsgiref` package. Python
2.5 and higher ship this as part of the standard library.
Server Setup
````````````
Usually there are two ways to configure the server. Either just copy the
`.cgi` into a `cgi-bin` (and use `mod_rerwite` or something similar to
rewrite the URL) or let the server point to the file directly.
In Apache for example you can put a like like this into the config:
.. sourcecode:: apache
ScriptName /app /path/to/the/application.cgi
For more information consult the documentation of your webserver.

20
docs/flaskext.py

@ -16,10 +16,7 @@ class FlaskyStyle(Style):
Other: "#000000", # class 'x'
Comment: "italic #8f5902", # class: 'c'
Comment.Multiline: "italic #8f5902", # class: 'cm'
Comment.Preproc: "italic #8f5902", # class: 'cp'
Comment.Single: "italic #8f5902", # class: 'c1'
Comment.Special: "italic #8f5902", # class: 'cs'
Comment.Preproc: "noitalic", # class: 'cp'
Keyword: "bold #004461", # class: 'k'
Keyword.Constant: "bold #004461", # class: 'kc'
@ -43,7 +40,7 @@ class FlaskyStyle(Style):
Name.Builtin.Pseudo: "#3465a4", # class: 'bp'
Name.Class: "#000000", # class: 'nc' - to be revised
Name.Constant: "#000000", # class: 'no' - to be revised
Name.Decorator: "#999", # class: 'nd' - to be revised
Name.Decorator: "#888", # class: 'nd' - to be revised
Name.Entity: "#ce5c00", # class: 'ni'
Name.Exception: "bold #cc0000", # class: 'ne'
Name.Function: "#000000", # class: 'nf'
@ -57,14 +54,7 @@ class FlaskyStyle(Style):
Name.Variable.Global: "#000000", # class: 'vg' - to be revised
Name.Variable.Instance: "#000000", # class: 'vi' - to be revised
# since the tango light blue does not show up well in text, we choose
# a pure blue instead.
Number: "bold #0000cf", # class: 'm'
Number.Float: "bold #0000cf", # class: 'mf'
Number.Hex: "bold #0000cf", # class: 'mh'
Number.Integer: "bold #0000cf", # class: 'mi'
Number.Integer.Long: "bold #0000cf", # class: 'il'
Number.Oct: "bold #0000cf", # class: 'mo'
Number: "#990000", # class: 'm'
Literal: "#000000", # class: 'l'
Literal.Date: "#000000", # class: 'ld'
@ -88,8 +78,8 @@ class FlaskyStyle(Style):
Generic.Error: "#ef2929", # class: 'gr'
Generic.Heading: "bold #000080", # class: 'gh'
Generic.Inserted: "#00A000", # class: 'gi'
Generic.Output: "italic #000000", # class: 'go'
Generic.Prompt: "#8f5902", # class: 'gp'
Generic.Output: "#888", # class: 'go'
Generic.Prompt: "#745334", # class: 'gp'
Generic.Strong: "bold #000000", # class: 'gs'
Generic.Subheading: "bold #800080", # class: 'gu'
Generic.Traceback: "bold #a40000", # class: 'gt'

9
docs/foreword.rst

@ -36,6 +36,15 @@ something the framework just cannot do for you without modification.
If you are ever in that situation, check out the :ref:`becomingbig`
chapter.
A Framework and An Example
--------------------------
Flask is not only a microframework, it is also an example. Based on
Flask, there will be a series of blog posts that explain how to create a
framework. Flask itself is just one way to implement a framework on top
of existing libraries. Unlike many other microframeworks Flask does not
try to implement anything on its own, it reuses existing code.
Target Audience
---------------

1
docs/index.rst

@ -20,4 +20,5 @@ you want to dive into all the internal parts of Flask, check out the
quickstart
patterns
api
deploying
becomingbig

43
docs/installation.rst

@ -41,18 +41,19 @@ So let's see how that works!
If you are on OS X or Linux chances are that one of the following two
commands will for for you::
sudo easy_install virtualenv
$ sudo easy_install virtualenv
or even better::
sudo pip install virtualenv
$ sudo pip install virtualenv
Changes are you have virtualenv installed on your system then. Maybe it's
even in your package manager (on ubuntu try ``sudo apt-get install
python-virtualenv``).
On windows, just installed virtualenv from the `Python Package Index
<http://pypi.python.org/pypi/virtualenv>`_.
If you are on Windows and missing the `easy_install` command you have to
install it first. Check the :ref:`windows-easy-install` section for more
information about how to do that.
So now that you have virtualenv running just fire up a shell and create
your own environment. I usually create a folder and a `env` folder
@ -101,3 +102,37 @@ The Drop into Place Version
Now I really don't recommend this way on using Flask, but you can do that
of course as well. Download the `dip` zipfile from the website and unzip
it next to your application.
.. _windows-easy-install:
`easy_install` on Windows
-------------------------
On Windows installation of `easy_install` is a little bit tricker because
on Windows slightly different rules apply, but it's not a biggy. The
easiest way to accomplish that is downloading the `ez_setup.py`_ file and
running it. (Double clicking should do the trick)
Once you have done that it's important to add the `easy_install` command
and other Python scripts to the path. To do that you have to add the
Python installation's Script folder to the `PATH` variable.
To do that, click right on your "Computer" desktop icon and click
"Properties". On Windows Vista and Windows 7 then click on "Advanced System
settings", on Windows XP click on the "Advanced" tab instead. Then click
on the "Environment variables" button and double click on the "Path"
variable in the "System variables" section.
There append the path of your Python interpreter's Script folder to the
end of the last (make sure you delimit it from existing values with a
semicolon). Assuming you are using Python 2.6 on the default path, add
the following value::
;C:\Python26\Scripts
Then you are done. To check if it worked, open the cmd and execute
"easy_install". If you have UAC enabled it should prompt you for admin
privileges.
.. _ez_setup.py: http://peak.telecommunity.com/dist/ez_setup.py

11
docs/quickstart.rst

@ -23,9 +23,14 @@ A minimal Flask application looks something like that::
if __name__ == '__main__':
app.run()
If you now start that application with your Python interpreter and head
over to `http://localhost:5000/ <http://localhost:5000/>`_, you should see
your hello world application.
Just save it as `hello.py` or something similar and run it with your
Python interpreter::
$ python hello.py
* Running on http://localhost:5000/
Head over to `http://localhost:5000/ <http://localhost:5000/>`_, you should
see your hello world greeting.
So what did that code do?

73
flask.py

@ -79,6 +79,8 @@ def flash(message):
"""Flashes a message to the next request. In order to remove the
flashed message from the session and to display it to the user,
the template has to call :func:`get_flashed_messages`.
:param message: the message to be flashed.
"""
session['_flashes'] = (session.get('_flashes', [])) + [message]
@ -98,6 +100,10 @@ def get_flashed_messages():
def render_template(template_name, **context):
"""Renders a template from the template folder with the given
context.
:param template_name: the name of the template to be rendered
:param context: the variables that should be available in the
context of the template.
"""
current_app.update_template_context(context)
return current_app.jinja_env.get_template(template_name).render(context)
@ -106,6 +112,11 @@ def render_template(template_name, **context):
def render_template_string(source, **context):
"""Renders a template from the given template source string
with the given context.
:param template_name: the sourcecode of the template to be
rendered
:param context: the variables that should be available in the
context of the template.
"""
current_app.update_template_context(context)
return current_app.jinja_env.from_string(source).render(context)
@ -222,6 +233,9 @@ class Flask(object):
def update_template_context(self, context):
"""Update the template context with some commonly used variables.
This injects request, session and g into the template context.
:param context: the context as a dictionary that is updated in place
to add extra variables.
"""
reqctx = _request_ctx_stack.top
context['request'] = reqctx.request
@ -232,6 +246,13 @@ class Flask(object):
"""Runs the application on a local development server. If the
:attr:`debug` flag is set the server will automatically reload
for code changes and show a debugger in case an exception happened.
:param host: the hostname to listen on. set this to ``'0.0.0.0'``
to have the server available externally as well.
:param port: the port of the webserver
:param options: the options to be forwarded to the underlying
Werkzeug server. See :func:`werkzeug.run_simple`
for more information.
"""
from werkzeug import run_simple
if 'debug' in options:
@ -268,6 +289,9 @@ class Flask(object):
with app.open_resource('schema.sql') as f:
contents = f.read()
do_something_with(contents)
:param resource: the name of the resource. To access resources within
subfolders use forward slashes as separator.
"""
return pkg_resources.resource_stream(self.package_name, resource)
@ -275,6 +299,8 @@ class Flask(object):
"""Creates or opens a new session. Default implementation stores all
session data in a signed cookie. This requires that the
:attr:`secret_key` is set.
:param request: an instance of :attr:`request_class`.
"""
key = self.secret_key
if key is not None:
@ -284,6 +310,11 @@ class Flask(object):
def save_session(self, session, response):
"""Saves the session if it needs updates. For the default
implementation, check :meth:`open_session`.
:param session: the session to be saved (a
:class:`~werkzeug.contrib.securecookie.SecureCookie`
object)
:param request: an instance of :attr:`response_class`
"""
if session is not None:
session.save_cookie(response, self.session_cookie_name)
@ -304,6 +335,13 @@ class Flask(object):
pass
app.add_url_rule('index', '/')
app.view_functions['index'] = index
:param rule: the URL rule as string
:param endpoint: the endpoint for the registered URL rule. Flask
itself assumes the name of the view function as
endpoint
:param options: the options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object
"""
options['endpoint'] = endpoint
options.setdefault('methods', ('GET',))
@ -363,6 +401,7 @@ class Flask(object):
The :meth:`route` decorator accepts a couple of other arguments
as well:
:param rule: the URL rule as string
:param methods: a list of methods this rule should be limited
to (``GET``, ``POST`` etc.). By default a rule
just listens for ``GET`` (and implicitly ``HEAD``).
@ -370,6 +409,8 @@ class Flask(object):
subdomain matching is in use.
:param strict_slashes: can be used to disable the strict slashes
setting for this rule. See above.
:param options: other options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object.
"""
def decorator(f):
self.add_url_rule(rule, f.__name__, **options)
@ -392,6 +433,8 @@ class Flask(object):
def page_not_found():
return 'This page does not exist', 404
app.error_handlers[404] = page_not_found
:param code: the code as integer for the handler
"""
def decorator(f):
self.error_handlers[code] = f
@ -440,6 +483,22 @@ class Flask(object):
def make_response(self, rv):
"""Converts the return value from a view function to a real
response object that is an instance of :attr:`response_class`.
The following types are allowd for `rv`:
======================= ===========================================
:attr:`response_class` the object is returned unchanged
:class:`str` a response object is created with the
string as body
:class:`unicode` a response object is created with the
string encoded to utf-8 as body
:class:`tuple` the response object is created with the
contents of the tuple as arguments
a WSGI function the function is called as WSGI application
and buffered as response object
======================= ===========================================
:param rv: the return value from the view function
"""
if isinstance(rv, self.response_class):
return rv
@ -464,6 +523,10 @@ class Flask(object):
def process_response(self, response):
"""Can be overridden in order to modify the response object
before it's sent to the WSGI server.
:param response: a :attr:`response_class` object.
:return: a new response object or the same, has to be an
instance of :attr:`response_class`.
"""
session = _request_ctx_stack.top.session
if session is not None:
@ -477,6 +540,11 @@ class Flask(object):
`__call__` so that middlewares can be applied:
app.wsgi_app = MyMiddleware(app.wsgi_app)
:param environ: a WSGI environment
:param start_response: a callable accepting a status code,
a list of headers and an optional
exception context to start the response
"""
with self.request_context(environ):
rv = self.preprocess_request()
@ -497,6 +565,8 @@ class Flask(object):
with app.request_context(environ):
do_something_with(request)
:params environ: a WSGI environment
"""
_request_ctx_stack.push(_RequestContext(self, environ))
try:
@ -506,7 +576,8 @@ class Flask(object):
def test_request_context(self, *args, **kwargs):
"""Creates a WSGI environment from the given values (see
:func:`werkzeug.create_environ` for more information).
:func:`werkzeug.create_environ` for more information, this
function accepts the same arguments).
"""
return self.request_context(create_environ(*args, **kwargs))

Loading…
Cancel
Save