Proofreading the documentation

This commit is contained in:
Chris Edgemon 2010-04-19 23:25:51 -05:00
parent 4ff9493e57
commit a7ff9dbddd
8 changed files with 58 additions and 58 deletions

View file

@ -8,11 +8,11 @@ designed for large scale applications and does not attempt to do so, but
that does not mean you picked the wrong tool in the first place. that does not mean you picked the wrong tool in the first place.
Flask is powered by Werkzeug and Jinja2, two libraries that are in use at Flask is powered by Werkzeug and Jinja2, two libraries that are in use at
a number of large websites out there and all Flask does is bringing those a number of large websites out there and all Flask does is bring those
two together. Being a microframework, Flask is literally a single file. two together. Being a microframework, Flask is literally a single file.
What that means for large applications is that it's probably a good idea What that means for large applications is that it's probably a good idea
to take the code from Flask and put it into a new module within the to take the code from Flask and put it into a new module within the
applications and expanding on that. applications and expand on that.
What Could Be Improved? What Could Be Improved?
----------------------- -----------------------
@ -20,12 +20,12 @@ What Could Be Improved?
For instance it makes a lot of sense to change the way endpoints (the For instance it makes a lot of sense to change the way endpoints (the
names of the functions / URL rules) are handled to also take the module names of the functions / URL rules) are handled to also take the module
name into account. Right now the function name is the URL name, but name into account. Right now the function name is the URL name, but
imagine you have a large applications consisting of multiple components. imagine you have a large application consisting of multiple components.
In that case, it makes a lot of sense to use dotted names for the URL In that case, it makes a lot of sense to use dotted names for the URL
endpoints. endpoints.
Here some suggestions how Flask can be modified to better accomodate large Here are some suggestions for how Flask can be modified to better
scale applications: accomodate large-scale applications:
- implement dotted names for URL endpoints - implement dotted names for URL endpoints
- get rid of the decorator function registering which causes a lot - get rid of the decorator function registering which causes a lot
@ -35,7 +35,7 @@ scale applications:
better solution would be to have one module with all URLs in there and better solution would be to have one module with all URLs in there and
specifing the target functions explicitly or by name and importing specifing the target functions explicitly or by name and importing
them when needed. them when needed.
- switch to explicit request object passing. This makes it more to type - switch to explicit request object passing. This requires more typing
(because you now have something to pass around) but it makes it a (because you now have something to pass around) but it makes it a
whole lot easier to debug hairy situations and to test the code. whole lot easier to debug hairy situations and to test the code.
- integrate the `Babel`_ i18n package or `SQLAlchemy`_ directly into the - integrate the `Babel`_ i18n package or `SQLAlchemy`_ directly into the
@ -44,14 +44,14 @@ scale applications:
.. _Babel: http://babel.edgewall.org/ .. _Babel: http://babel.edgewall.org/
.. _SQLAlchemy: http://www.sqlalchemy.org/ .. _SQLAlchemy: http://www.sqlalchemy.org/
Why does not Flask do all that by Default? Why does Flask not do all that by Default?
------------------------------------------ ------------------------------------------
There is a huge difference between a small application that only has to There is a huge difference between a small application that only has to
handle a couple of requests per second and with an overall code complexity handle a couple of requests per second and with an overall code complexity
of less than 4000 lines of code or something of larger scale. At one of less than 4000 lines of code and something of larger scale. At some
point it becomes important to integrate external systems, different point it becomes important to integrate external systems, different
storage backends and more. storage backends and more.
If Flask was designed with all these contingencies in mind, it would be a If Flask was designed with all these contingencies in mind, it would be a
much more complex framework and less easy to get started with. much more complex framework and harder to get started with.

View file

@ -11,8 +11,8 @@ Installing `mod_wsgi`
If you don't have `mod_wsgi` installed yet you have to either install it using If you don't have `mod_wsgi` installed yet you have to either install it using
a package manager or compile it yourself. a package manager or compile it yourself.
The mod_wsgi `installation instructions`_ cover installation instructions for The mod_wsgi `installation instructions`_ cover source installations on UNIX
source installations on UNIX systems. systems.
If you are using ubuntu / debian you can apt-get it and activate it as follows:: If you are using ubuntu / debian you can apt-get it and activate it as follows::
@ -44,7 +44,7 @@ For most applications the following file should be sufficient::
If you don't have a factory function for application creation but a singleton If you don't have a factory function for application creation but a singleton
instance you can directly import that one as `application`. instance you can directly import that one as `application`.
Store that file somewhere where you will find it again (eg: Store that file somewhere that you will find it again (e.g.:
`/var/www/yourapplication`) and make sure that `yourapplication` and all `/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 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. want to install it system wide consider using a `virtual python`_ instance.

View file

@ -2,7 +2,7 @@ Design Decisions in Flask
========================= =========================
If you are curious why Flask does certain things the way it does and not If you are curious why Flask does certain things the way it does and not
different, this section is for you. This should give you an idea about differently, this section is for you. This should give you an idea about
some of the design decisions that may appear arbitrary and surprising at some of the design decisions that may appear arbitrary and surprising at
first, especially in direct comparison with other frameworks. first, especially in direct comparison with other frameworks.
@ -44,10 +44,10 @@ something it can be very helpful to create a minimal application to test
specific behavior. When the application object is deleted everything it specific behavior. When the application object is deleted everything it
allocated will be freed again. allocated will be freed again.
Another thing that becomes possible with having an explicit object laying Another thing that becomes possible when you have an explicit object laying
around in your code is that you can subclass the base class around in your code is that you can subclass the base class
(:class:`~flask.Flask`) to alter specific behaviour. This would not be (:class:`~flask.Flask`) to alter specific behaviour. This would not be
possible without hacks if the object was created ahead of time for you possible without hacks if the object were created ahead of time for you
based on a class that is not exposed to you. based on a class that is not exposed to you.
But there is another very important reason why Flask depends on an But there is another very important reason why Flask depends on an
@ -83,23 +83,23 @@ that limitation that Jinja2 is *always* configured will probably go away,
the decision to bundle one template engine and use that will not. the decision to bundle one template engine and use that will not.
Template engines are like programming languages and each of those engines Template engines are like programming languages and each of those engines
has a certain understandment about how things work. On the surface they has a certain understanding about how things work. On the surface they
all work the same: you tell the engine to evaluate a template with a set all work the same: you tell the engine to evaluate a template with a set
of variables and take the return value as string. of variables and take the return value as string.
But that's about where similarities end. Jinja2 for example has an But that's about where similarities end. Jinja2 for example has an
extensive filter system, a certain way to do template inheritance, support extensive filter system, a certain way to do template inheritance, support
for reusable blocks (macros) that can be used from inside templates and for reusable blocks (macros) that can be used from inside templates and
also from Python code, is using unicode for all operations, supports also from Python code, uses unicode for all operations, supports
iterative template rendering, configurable syntax and more. On the other iterative template rendering, configurable syntax and more. On the other
hand an engine like Genshi is based on XML stream evaluation, template hand an engine like Genshi is based on XML stream evaluation, template
inheritance by taking the availability of XPath into account and more. inheritance by taking the availability of XPath into account and more.
Mako on the other hand treats templates similar to Python modules. Mako on the other hand treats templates similar to Python modules.
When it comes to bridge a template engine with an application or framework When it comes to connecting a template engine with an application or
there is more than just rendering templates. Flask uses Jinja2's framework there is more than just rendering templates. For instance,
extensive autoescaping support for instance. Also it provides ways to Flask uses Jinja2's extensive autoescaping support. Also it provides
access macros from Jinja2 templates. ways to access macros from Jinja2 templates.
A template abstraction layer that would not take the unique features of A template abstraction layer that would not take the unique features of
the template engines away is a science on its own and a too large the template engines away is a science on its own and a too large
@ -115,9 +115,9 @@ over to the Ruby side of web development there we have a protocol very
similar to WSGI. Just that it's called Rack there, but besides that it similar to WSGI. Just that it's called Rack there, but besides that it
looks very much like a WSGI rendition for Ruby. But nearly all looks very much like a WSGI rendition for Ruby. But nearly all
applications in Ruby land do not work with Rack directly, but on top of a applications in Ruby land do not work with Rack directly, but on top of a
lirbary with the same name. This Rack library has two equivalents in library with the same name. This Rack library has two equivalents in
Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but Python: WebOb (formerly Paste) and Werkzeug. Paste is still around but
from my understanding it's sortof deprecated in favour of WebOb. The from my understanding it's sort of deprecated in favour of WebOb. The
development of WebOb and Werkzeug started side by side with similar ideas development of WebOb and Werkzeug started side by side with similar ideas
in mind: be a good implementation of WSGI for other applications to take in mind: be a good implementation of WSGI for other applications to take
advantage. advantage.

View file

@ -9,10 +9,10 @@ way and why there are multiple ways.
Flask depends on two external libraries: `Werkzeug Flask depends on two external libraries: `Werkzeug
<http://werkzeug.pocoo.org/>`_ and `Jinja2 <http://jinja.pocoo.org/2/>`_. <http://werkzeug.pocoo.org/>`_ and `Jinja2 <http://jinja.pocoo.org/2/>`_.
The first on is responsible for interfacing WSGI the latter to render The first one is responsible for interfacing WSGI the latter for rendering
templates. Now you are maybe asking, what is WSGI? WSGI is a standard templates. Now you are maybe asking, what is WSGI? WSGI is a standard
in Python that is basically responsible for ensuring that your application in Python that is basically responsible for ensuring that your application
is behaving in a specific way that you can run it on different is behaving in a specific way so that you can run it on different
environments (for example on a local development server, on an Apache2, on environments (for example on a local development server, on an Apache2, on
lighttpd, on Google's App Engine or whatever you have in mind). lighttpd, on Google's App Engine or whatever you have in mind).
@ -26,10 +26,10 @@ Virtualenv is what you want to use during development and in production if
you have shell access. So first: what does virtualenv do? If you are you have shell access. So first: what does virtualenv do? If you are
like me and you like Python, chances are you want to use it for another like me and you like Python, chances are you want to use it for another
project as well. Now the more projects you have, the more likely it is project as well. Now the more projects you have, the more likely it is
that you will be working with different versions of Python itself or a that you will be working with different versions of Python itself or at
library involved. Because let's face it: quite often libraries break least an individual library. Because let's face it: quite often libraries
backwards compatibility and it's unlikely that your application will break backwards compatibility and it's unlikely that your application will
not have any dependencies, that just won't happen. So virtualenv for the not have any dependencies, that just won't happen. So virtualenv to the
rescue! rescue!
It basically makes it possible to have multiple side-by-side It basically makes it possible to have multiple side-by-side
@ -47,7 +47,7 @@ or even better::
$ sudo pip install virtualenv $ sudo pip install virtualenv
Changes are you have virtualenv installed on your system then. Maybe it's Chances are you have virtualenv installed on your system then. Maybe it's
even in your package manager (on ubuntu try ``sudo apt-get install even in your package manager (on ubuntu try ``sudo apt-get install
python-virtualenv``). python-virtualenv``).
@ -152,7 +152,7 @@ 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 and other Python scripts to the path. To do that you have to add the
Python installation's Script folder to the `PATH` variable. Python installation's Script folder to the `PATH` variable.
To do that, click right on your "Computer" desktop icon and click To do that, right-click on your "Computer" desktop icon and click
"Properties". On Windows Vista and Windows 7 then click on "Advanced System "Properties". On Windows Vista and Windows 7 then click on "Advanced System
settings", on Windows XP click on the "Advanced" tab instead. Then click settings", on Windows XP click on the "Advanced" tab instead. Then click
on the "Environment variables" button and double click on the "Path" on the "Environment variables" button and double click on the "Path"
@ -165,7 +165,7 @@ the following value::
;C:\Python26\Scripts ;C:\Python26\Scripts
Then you are done. To check if it worked, open the cmd and execute Then you are done. To check that it worked, open the cmd and execute
"easy_install". If you have UAC enabled it should prompt you for admin "easy_install". If you have UAC enabled it should prompt you for admin
privileges. privileges.

View file

@ -48,12 +48,12 @@ What did we gain from this? Now we can restructure the application a bit
into multiple modules. The only thing you have to remember is the into multiple modules. The only thing you have to remember is the
following quick checklist: following quick checklist:
1. the `Flask` application object creation have to be in the 1. the `Flask` application object creation has to be in the
`__init__.py` file. That way each module can import it safely and the `__init__.py` file. That way each module can import it safely and the
`__name__` variable will resole to the correct package. `__name__` variable will resolve to the correct package.
2. all the view functions (the ones with a :meth:`~flask.Flask.route` 2. all the view functions (the ones with a :meth:`~flask.Flask.route`
decorator on top) have to be imported when in the `__init__.py` file. decorator on top) have to be imported when in the `__init__.py` file.
Not the objects itself, but the module it is in. Do the importing at Not the object itself, but the module it is in. Do the importing at
the *bottom* of the file. the *bottom* of the file.
Here an example `__init__.py`:: Here an example `__init__.py`::

View file

@ -6,7 +6,7 @@ SQLAlchemy in Flask
Many people prefer `SQLAlchemy`_ for database access. In this case it's Many people prefer `SQLAlchemy`_ for database access. In this case it's
encouraged to use a package instead of a module for your flask application encouraged to use a package instead of a module for your flask application
and drop the models into a separate module (:ref:`larger-applications`). and drop the models into a separate module (:ref:`larger-applications`).
Although that is not necessary but makes a lot of sense. While that is not necessary, it makes a lot of sense.
There are three very common ways to use SQLAlchemy. I will outline each There are three very common ways to use SQLAlchemy. I will outline each
of them here: of them here:
@ -52,7 +52,7 @@ automatically remove database sessions at the end of the request for you::
db_session.remove() db_session.remove()
return response return response
Here an example model (put that into `models.py` for instance):: Here is an example model (put this into `models.py`, e.g.)::
from sqlalchemy import Column, Integer, String from sqlalchemy import Column, Integer, String
from yourapplication.database import Base from yourapplication.database import Base
@ -70,7 +70,7 @@ Here an example model (put that into `models.py` for instance)::
def __repr__(self): def __repr__(self):
return '<User %r>' % (self.name, self.email) return '<User %r>' % (self.name, self.email)
You can insert entries into the database like this then: You can insert entries into the database like this:
>>> from yourapplication.database import db_session >>> from yourapplication.database import db_session
>>> from yourapplication.models import User >>> from yourapplication.models import User
@ -95,11 +95,11 @@ Manual Object Relational Mapping
Manual object relational mapping has a few upsides and a few downsides Manual object relational mapping has a few upsides and a few downsides
versus the declarative approach from above. The main difference is that versus the declarative approach from above. The main difference is that
you define tables and classes separately and map them together. It's more you define tables and classes separately and map them together. It's more
flexible but a little more to type. In general it works similar to the flexible but a little more to type. In general it works like the
declarative approach, so make sure to also split up your application into declarative approach, so make sure to also split up your application into
multiple modules in a package. multiple modules in a package.
Here the example `database.py` module for your application:: Here is an example `database.py` module for your application::
from sqlalchemy import create_engine, MetaData from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.orm import scoped_session, sessionmaker
@ -112,7 +112,7 @@ Here the example `database.py` module for your application::
def init_db(): def init_db():
metadata.create_all(bind=engine) metadata.create_all(bind=engine)
As for the declarative approach you need to close down the session after As for the declarative approach you need to close the session after
each request. Put this into your application module:: each request. Put this into your application module::
from yourapplication.database import db_session from yourapplication.database import db_session
@ -122,7 +122,7 @@ each request. Put this into your application module::
db_session.remove() db_session.remove()
return response return response
Here an example table and model (put that into `models.py` for instance):: Here is an example table and model (put this into `models.py`)::
from sqlalchemy import Table, Column, Integer, String from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper from sqlalchemy.orm import mapper
@ -172,7 +172,7 @@ connection first so that we can use a transaction:
SQLAlchemy will automatically commit for us. SQLAlchemy will automatically commit for us.
To query your database, yu use the engine directly or use a connection: To query your database, you use the engine directly or use a connection:
>>> users.select(users.c.id == 1).execute().first() >>> users.select(users.c.id == 1).execute().first()
(1, u'admin', u'admin@localhost') (1, u'admin', u'admin@localhost')
@ -183,7 +183,7 @@ These results are also dict-like tuples:
>>> r['name'] >>> r['name']
u'admin' u'admin'
You can also pass string of SQL statements to the You can also pass strings of SQL statements to the
:meth:`~sqlalchemy.engine.base.Connection.execute` method: :meth:`~sqlalchemy.engine.base.Connection.execute` method:
>>> engine.execute('select * from users where id = :1', [1]).first() >>> engine.execute('select * from users where id = :1', [1]).first()

View file

@ -3,12 +3,12 @@
Using SQLite 3 with Flask Using SQLite 3 with Flask
========================= =========================
In Flask you can implement opening of dabase connections at the beginning In Flask you can implement opening of database connections at the beginning
of the request and closing at the end with the of the request and closing at the end with the
:meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.after_request` :meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.after_request`
decorators in combination with the special :class:`~flask.g` object. decorators in combination with the special :class:`~flask.g` object.
So here a simple example how you can use SQLite 3 with Flask:: So here a simple example of how you can use SQLite 3 with Flask::
import sqlite3 import sqlite3
from flask import g from flask import g
@ -70,7 +70,7 @@ Initial Schemas
Relational databases need schemas, so applications often ship a Relational databases need schemas, so applications often ship a
`schema.sql` file that creates the database. It's a good idea to provide `schema.sql` file that creates the database. It's a good idea to provide
a function that creates the database bases on that schema. This function a function that creates the database based on that schema. This function
can do that for you:: can do that for you::
from contextlib import closing from contextlib import closing

View file

@ -8,14 +8,14 @@ Testing Flask Applications
Not sure where that is coming from, and it's not entirely correct, but Not sure where that is coming from, and it's not entirely correct, but
also not that far from the truth. Untested applications make it hard to also not that far from the truth. Untested applications make it hard to
improve existing code and developers of untested applications tend to improve existing code and developers of untested applications tend to
become pretty paranoid. If an application however has automated tests you become pretty paranoid. If an application however has automated tests, you
can savely change things and you will instantly know if your change broke can safely change things and you will instantly know if your change broke
something. something.
Flask gives you a couple of ways to test applications. It mainly does Flask gives you a couple of ways to test applications. It mainly does
that by exposing the Werkzeug test :class:`~werkzeug.Client` class to your that by exposing the Werkzeug test :class:`~werkzeug.Client` class to your
code and handling the context locals for you. You can then use that with code and handling the context locals for you. You can then use that with
your favourite testing solution. In this documentation we will us the your favourite testing solution. In this documentation we will use the
:mod:`unittest` package that comes preinstalled with each Python :mod:`unittest` package that comes preinstalled with each Python
installation. installation.
@ -50,13 +50,13 @@ In order to test that, we add a second module (
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
The code in the `setUp` function creates a new test client and initialize The code in the `setUp` function creates a new test client and initializes
a new database. That function is called before each individual test function. a new database. That function is called before each individual test function.
What the test client does for us is giving us a simple interface to the What the test client does is give us a simple interface to the
application. We can trigger test requests to the application and the application. We can trigger test requests to the application and the
client will also keep track of cookies for us. client will also keep track of cookies for us.
Because SQLite3 is filesystem based we can easily use the tempfile module Because SQLite3 is filesystem-based we can easily use the tempfile module
to create a temporary database and initialize it. Just make sure that you to create a temporary database and initialize it. Just make sure that you
keep a reference to the :class:`~tempfile.NamedTemporaryFile` around (we keep a reference to the :class:`~tempfile.NamedTemporaryFile` around (we
store it as `self.db` because of that) so that the garbage collector does store it as `self.db` because of that) so that the garbage collector does
@ -112,20 +112,20 @@ Run it again and you should see one passing test::
OK OK
Of course you can submit forms with the test client as well which we will Of course you can submit forms with the test client as well, which we will
use now to log our user in. use now to log our user in.
Logging In and Out Logging In and Out
------------------ ------------------
The majority of the functionality of our application is only available for The majority of the functionality of our application is only available for
the administration user. So we need a way to log our test client into the the administration user. So we need a way to log our test client in to the
application and out of it again. For that we fire some requests to the application and out of it again. For that we fire some requests to the
login and logout pages with the required form data (username and login and logout pages with the required form data (username and
password). Because the login and logout pages redirect, we tell the password). Because the login and logout pages redirect, we tell the
client to `follow_redirects`. client to `follow_redirects`.
Add the following two methods do your `FlaskrTestCase` class:: Add the following two methods to your `FlaskrTestCase` class::
def login(self, username, password): def login(self, username, password):
return self.app.post('/login', data=dict( return self.app.post('/login', data=dict(
@ -137,7 +137,7 @@ Add the following two methods do your `FlaskrTestCase` class::
return self.app.get('/logout', follow_redirects=True) return self.app.get('/logout', follow_redirects=True)
Now we can easily test if logging in and out works and that it fails with Now we can easily test if logging in and out works and that it fails with
invalid credentials. Add this as new test to the class:: invalid credentials. Add this new test to the class::
def test_login_logout(self): def test_login_logout(self):
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD) rv = self.login(flaskr.USERNAME, flaskr.PASSWORD)
@ -165,7 +165,7 @@ like this::
assert '&lt;Hello&gt' in rv.data assert '&lt;Hello&gt' in rv.data
assert '<strong>HTML</strong> allowed here' in rv.data assert '<strong>HTML</strong> allowed here' in rv.data
Here we also check that HTML is allowed in the text but not in the title Here we check that HTML is allowed in the text but not in the title,
which is the intended behavior. which is the intended behavior.
Running that should now give us three passing tests:: Running that should now give us three passing tests::