Permalink
Browse files

Proofreading the documentation

  • Loading branch information...
1 parent 4ff9493 commit a7ff9dbddd5f861463051601177442e98aae84bf Chris Edgemon committed Apr 20, 2010
View
@@ -8,24 +8,24 @@ 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.
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.
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
-applications and expanding on that.
+applications and expand on that.
What Could Be Improved?
-----------------------
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
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
endpoints.
-Here some suggestions how Flask can be modified to better accomodate large
-scale applications:
+Here are some suggestions for how Flask can be modified to better
+accomodate large-scale applications:
- implement dotted names for URL endpoints
- 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
specifing the target functions explicitly or by name and importing
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
whole lot easier to debug hairy situations and to test the code.
- integrate the `Babel`_ i18n package or `SQLAlchemy`_ directly into the
@@ -44,14 +44,14 @@ scale applications:
.. _Babel: http://babel.edgewall.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
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
storage backends and more.
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.
@@ -11,8 +11,8 @@ 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.
+The mod_wsgi `installation instructions`_ cover source installations on UNIX
+systems.
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
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
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.
View
@@ -2,7 +2,7 @@ Design Decisions in Flask
=========================
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
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
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
(: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.
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.
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
of variables and take the return value as string.
But that's about where similarities end. Jinja2 for example has an
extensive filter system, a certain way to do template inheritance, support
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
hand an engine like Genshi is based on XML stream evaluation, template
inheritance by taking the availability of XPath into account and more.
Mako on the other hand treats templates similar to Python modules.
-When it comes to bridge a template engine with an application or framework
-there is more than just rendering templates. Flask uses Jinja2's
-extensive autoescaping support for instance. Also it provides ways to
-access macros from Jinja2 templates.
+When it comes to connecting a template engine with an application or
+framework there is more than just rendering templates. For instance,
+Flask uses Jinja2's extensive autoescaping support. Also it provides
+ways to access macros from Jinja2 templates.
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
@@ -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
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
-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
-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
in mind: be a good implementation of WSGI for other applications to take
advantage.
View
@@ -9,10 +9,10 @@ way and why there are multiple ways.
Flask depends on two external libraries: `Werkzeug
<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
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
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
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
-that you will be working with different versions of Python itself or a
-library involved. Because let's face it: quite often libraries break
-backwards compatibility and it's unlikely that your application will
-not have any dependencies, that just won't happen. So virtualenv for the
+that you will be working with different versions of Python itself or at
+least an individual library. Because let's face it: quite often libraries
+break backwards compatibility and it's unlikely that your application will
+not have any dependencies, that just won't happen. So virtualenv to the
rescue!
It basically makes it possible to have multiple side-by-side
@@ -47,7 +47,7 @@ or even better::
$ 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
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
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
settings", on Windows XP click on the "Advanced" tab instead. Then click
on the "Environment variables" button and double click on the "Path"
@@ -165,7 +165,7 @@ the following value::
;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
privileges.
@@ -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
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
- `__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`
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.
Here an example `__init__.py`::
@@ -6,7 +6,7 @@ SQLAlchemy in Flask
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
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
of them here:
@@ -52,7 +52,7 @@ automatically remove database sessions at the end of the request for you::
db_session.remove()
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 yourapplication.database import Base
@@ -70,7 +70,7 @@ Here an example model (put that into `models.py` for instance)::
def __repr__(self):
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.models import User
@@ -95,11 +95,11 @@ Manual Object Relational Mapping
Manual object relational mapping has a few upsides and a few downsides
versus the declarative approach from above. The main difference is that
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
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.orm import scoped_session, sessionmaker
@@ -112,7 +112,7 @@ Here the example `database.py` module for your application::
def init_db():
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::
from yourapplication.database import db_session
@@ -122,7 +122,7 @@ each request. Put this into your application module::
db_session.remove()
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.orm import mapper
@@ -172,7 +172,7 @@ connection first so that we can use a transaction:
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()
(1, u'admin', u'admin@localhost')
@@ -183,7 +183,7 @@ These results are also dict-like tuples:
>>> r['name']
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:
>>> engine.execute('select * from users where id = :1', [1]).first()
@@ -3,12 +3,12 @@
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
:meth:`~flask.Flask.before_request` and :meth:`~flask.Flask.after_request`
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
from flask import g
@@ -70,7 +70,7 @@ Initial Schemas
Relational databases need schemas, so applications often ship a
`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::
from contextlib import closing
View
@@ -8,14 +8,14 @@ Testing Flask Applications
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
improve existing code and developers of untested applications tend to
-become pretty paranoid. If an application however has automated tests you
-can savely change things and you will instantly know if your change broke
+become pretty paranoid. If an application however has automated tests, you
+can safely change things and you will instantly know if your change broke
something.
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
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
installation.
@@ -50,13 +50,13 @@ In order to test that, we add a second module (
if __name__ == '__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.
-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
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
keep a reference to the :class:`~tempfile.NamedTemporaryFile` around (we
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
-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.
Logging In and Out
------------------
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
login and logout pages with the required form data (username and
password). Because the login and logout pages redirect, we tell the
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):
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)
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):
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD)
@@ -165,7 +165,7 @@ like this::
assert '&lt;Hello&gt' 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.
Running that should now give us three passing tests::

1 comment on commit a7ff9db

Owner

mitsuhiko commented on a7ff9db Apr 20, 2010

Thanks a lot for that.

Please sign in to comment.