Ported examples over to new config. documented upgrading
This commit is contained in:
parent
02b916d509
commit
dfecc86dd3
17 changed files with 122 additions and 39 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit f87d00eee80e4a555e94ed124a94ffea483dc329
|
Subproject commit 0d8f3d85558168647632c768bdea7d58cf6f8e42
|
||||||
|
|
@ -27,7 +27,6 @@ endpoints.
|
||||||
Here are some suggestions for how Flask can be modified to better
|
Here are some suggestions for how Flask can be modified to better
|
||||||
accommodate large-scale applications:
|
accommodate large-scale applications:
|
||||||
|
|
||||||
- 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
|
||||||
of troubles for applications that have circular dependencies. It
|
of troubles for applications that have circular dependencies. It
|
||||||
also requires that the whole application is imported when the system
|
also requires that the whole application is imported when the system
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _config:
|
||||||
|
|
||||||
Configuration Handling
|
Configuration Handling
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
|
@ -47,6 +49,8 @@ Builtin Configuration Values
|
||||||
|
|
||||||
The following configuration values are used internally by Flask:
|
The following configuration values are used internally by Flask:
|
||||||
|
|
||||||
|
.. tabularcolumns:: |p{6.5cm}|p{8.5cm}|
|
||||||
|
|
||||||
=============================== =========================================
|
=============================== =========================================
|
||||||
``DEBUG`` enable/disable debug mode
|
``DEBUG`` enable/disable debug mode
|
||||||
``SECRET_KEY`` the secret key
|
``SECRET_KEY`` the secret key
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,5 @@ Design notes, legal information and changelog are here for the interested.
|
||||||
|
|
||||||
design
|
design
|
||||||
license
|
license
|
||||||
|
upgrading
|
||||||
changelog
|
changelog
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,6 @@ widespread usage. Recent versions of Flask scale nicely within reasonable
|
||||||
bounds and if you grow larger, you won't have any troubles adjusting Flask
|
bounds and if you grow larger, you won't have any troubles adjusting Flask
|
||||||
for your new application size.
|
for your new application size.
|
||||||
|
|
||||||
Flask serves two purposes: it's an example of how to create a minimal and
|
|
||||||
opinionated framework on top of Werkzeug to show how this can be done, and
|
|
||||||
to provide people with a simple tool to prototype larger applications or
|
|
||||||
to implement small and medium sized applications.
|
|
||||||
|
|
||||||
If you suddenly discover that your application grows larger than
|
If you suddenly discover that your application grows larger than
|
||||||
originally intended, head over to the :ref:`becomingbig` section to see
|
originally intended, head over to the :ref:`becomingbig` section to see
|
||||||
some possible solutions for larger applications.
|
some possible solutions for larger applications.
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _app-factories:
|
||||||
|
|
||||||
Application Factories
|
Application Factories
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ inside a `script` block here where different rules apply.
|
||||||
will not be parsed. Everything until ``</script>`` is handled as script.
|
will not be parsed. Everything until ``</script>`` is handled as script.
|
||||||
This also means that there must never be any ``</`` between the script
|
This also means that there must never be any ``</`` between the script
|
||||||
tags. ``|tojson`` is kindly enough to do the right thing here and
|
tags. ``|tojson`` is kindly enough to do the right thing here and
|
||||||
escape slashes for you (``{{ "</script>"|tojson|safe }`` is rendered as
|
escape slashes for you (``{{ "</script>"|tojson|safe }}`` is rendered as
|
||||||
``"<\/script>"``).
|
``"<\/script>"``).
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ this::
|
||||||
class FlaskrTestCase(unittest.TestCase):
|
class FlaskrTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.db_fd, flaskr.DATABASE = tempfile.mkstemp()
|
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
|
||||||
self.app = flaskr.app.test_client()
|
self.app = flaskr.app.test_client()
|
||||||
flaskr.init_db()
|
flaskr.init_db()
|
||||||
|
|
||||||
|
|
@ -151,13 +151,13 @@ Now we can easily test if logging in and out works and that it fails with
|
||||||
invalid credentials. Add this 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('admin', 'default')
|
||||||
assert 'You were logged in' in rv.data
|
assert 'You were logged in' in rv.data
|
||||||
rv = self.logout()
|
rv = self.logout()
|
||||||
assert 'You were logged out' in rv.data
|
assert 'You were logged out' in rv.data
|
||||||
rv = self.login(flaskr.USERNAME + 'x', flaskr.PASSWORD)
|
rv = self.login('adminx', 'default')
|
||||||
assert 'Invalid username' in rv.data
|
assert 'Invalid username' in rv.data
|
||||||
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD + 'x')
|
rv = self.login('admin', 'defaultx')
|
||||||
assert 'Invalid password' in rv.data
|
assert 'Invalid password' in rv.data
|
||||||
|
|
||||||
Test Adding Messages
|
Test Adding Messages
|
||||||
|
|
@ -167,7 +167,7 @@ Now we can also test that adding messages works. Add a new test method
|
||||||
like this::
|
like this::
|
||||||
|
|
||||||
def test_messages(self):
|
def test_messages(self):
|
||||||
self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
self.login('admin', 'default')
|
||||||
rv = self.app.post('/add', data=dict(
|
rv = self.app.post('/add', data=dict(
|
||||||
title='<Hello>',
|
title='<Hello>',
|
||||||
text='<strong>HTML</strong> allowed here'
|
text='<strong>HTML</strong> allowed here'
|
||||||
|
|
@ -214,3 +214,7 @@ functions. Here a full example that showcases this::
|
||||||
assert flask.request.args['name'] == 'Peter'
|
assert flask.request.args['name'] == 'Peter'
|
||||||
|
|
||||||
All the other objects that are context bound can be used the same.
|
All the other objects that are context bound can be used the same.
|
||||||
|
|
||||||
|
If you want to test your application with different configurations and
|
||||||
|
there does not seem to be a good way to do that, consider switching to
|
||||||
|
application factories (see :ref:`app-factories`).
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,27 @@ the values from there.
|
||||||
PASSWORD = 'default'
|
PASSWORD = 'default'
|
||||||
|
|
||||||
Next we can create our actual application and initialize it with the
|
Next we can create our actual application and initialize it with the
|
||||||
config::
|
config from the same file::
|
||||||
|
|
||||||
# create our little application :)
|
# create our little application :)
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = SECRET_KEY
|
app.config.from_object(__name__)
|
||||||
app.debug = DEBUG
|
|
||||||
|
:meth:`~flask.Config.from_object` will look at the given object (if it's a
|
||||||
|
string it will import it) and then look for all uppercase variables
|
||||||
|
defined there. In our case, the configuration we just wrote a few lines
|
||||||
|
of code above. You can also move that into a separate file.
|
||||||
|
|
||||||
|
It is also a good idea to be able to load a configuration from a
|
||||||
|
configurable file. This is what :meth:`~flask.Config.from_envvar` can
|
||||||
|
do::
|
||||||
|
|
||||||
|
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
||||||
|
|
||||||
|
That way someone can set an environment variable called
|
||||||
|
:envvar:`FLASKR_SETTINGS` to specify a config file to be loaded which will
|
||||||
|
then override the default values. The silent switch just tells Flask to
|
||||||
|
not complain if no such environment key is set.
|
||||||
|
|
||||||
The `secret_key` is needed to keep the client-side sessions secure.
|
The `secret_key` is needed to keep the client-side sessions secure.
|
||||||
Choose that key wisely and as hard to guess and complex as possible. The
|
Choose that key wisely and as hard to guess and complex as possible. The
|
||||||
|
|
@ -46,7 +61,7 @@ Python shell or a script. This will come in handy later
|
||||||
::
|
::
|
||||||
|
|
||||||
def connect_db():
|
def connect_db():
|
||||||
return sqlite3.connect(DATABASE)
|
return sqlite3.connect(app.config['DATABASE'])
|
||||||
|
|
||||||
Finally we just add a line to the bottom of the file that fires up the
|
Finally we just add a line to the bottom of the file that fires up the
|
||||||
server if we run that file as standalone application::
|
server if we run that file as standalone application::
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,9 @@ notified about that and the user asked again::
|
||||||
def login():
|
def login():
|
||||||
error = None
|
error = None
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if request.form['username'] != USERNAME:
|
if request.form['username'] != app.config['USERNAME']:
|
||||||
error = 'Invalid username'
|
error = 'Invalid username'
|
||||||
elif request.form['password'] != PASSWORD:
|
elif request.form['password'] != app.config['PASSWORD']:
|
||||||
error = 'Invalid password'
|
error = 'Invalid password'
|
||||||
else:
|
else:
|
||||||
session['logged_in'] = True
|
session['logged_in'] = True
|
||||||
|
|
|
||||||
56
docs/upgrading.rst
Normal file
56
docs/upgrading.rst
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
Upgrading to Newer Releases
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Flask itself is changing like any software is changing over time. Most of
|
||||||
|
the changes are the nice kind, the kind where you don't have th change
|
||||||
|
anything in your code to profit from a new release.
|
||||||
|
|
||||||
|
However every once in a while there are changes that do require some
|
||||||
|
changes in your code or there are changes that make it possible for you to
|
||||||
|
improve your own code quality by taking advantage of new features in
|
||||||
|
Flask.
|
||||||
|
|
||||||
|
This section of the documentation enumerates all the changes in Flask from
|
||||||
|
release to release and how you can change your code to have a painless
|
||||||
|
updating experience.
|
||||||
|
|
||||||
|
Version 0.5
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Flask 0.5 introduces configuration support and logging as well as
|
||||||
|
categories for flashing messages. All these are features that are 100%
|
||||||
|
backwards compatible but you might want to take advantage of them.
|
||||||
|
|
||||||
|
Configuration Support
|
||||||
|
`````````````````````
|
||||||
|
|
||||||
|
The configuration support makes it easier to write any kind of application
|
||||||
|
that requires some sort of configuration. (Which most likely is the case
|
||||||
|
for any application out there).
|
||||||
|
|
||||||
|
If you previously had code like this::
|
||||||
|
|
||||||
|
app.debug = DEBUG
|
||||||
|
app.secret_key = SECRET_KEY
|
||||||
|
|
||||||
|
You no longer have to do that, instead you can just load a configuration
|
||||||
|
into the config object. How this works is outlined in :ref:`config`.
|
||||||
|
|
||||||
|
Logging Integration
|
||||||
|
```````````````````
|
||||||
|
|
||||||
|
Flask now configures a logger for you with some basic and useful defaults.
|
||||||
|
If you run your application in production and want to profit from
|
||||||
|
automatic error logging, you might be interested in attaching a proper log
|
||||||
|
handler. Also you can start logging warnings and errors into the logger
|
||||||
|
when appropriately. For more information on that, read
|
||||||
|
:ref:`application-errors`.
|
||||||
|
|
||||||
|
Categories for Flash Messages
|
||||||
|
`````````````````````````````
|
||||||
|
|
||||||
|
Flash messages can now have categories attached. This makes it possible
|
||||||
|
to render errors, warnings or regular messages differently for example.
|
||||||
|
This is an opt-in feature because it requires some rethinking in the code.
|
||||||
|
|
||||||
|
Read all about that in the :ref:`message-flashing-pattern` pattern.
|
||||||
|
|
@ -10,7 +10,9 @@
|
||||||
|
|
||||||
~ How do I use it?
|
~ How do I use it?
|
||||||
|
|
||||||
1. edit the configuration in the flaskr.py file
|
1. edit the configuration in the flaskr.py file or
|
||||||
|
export an FLASKR_SETTINGS environment variable
|
||||||
|
pointing to a configuration file.
|
||||||
|
|
||||||
2. fire up a python shell and run this:
|
2. fire up a python shell and run this:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,13 @@ PASSWORD = 'default'
|
||||||
|
|
||||||
# create our little application :)
|
# create our little application :)
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = SECRET_KEY
|
app.config.from_object(__name__)
|
||||||
app.debug = DEBUG
|
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
|
||||||
|
|
||||||
|
|
||||||
def connect_db():
|
def connect_db():
|
||||||
"""Returns a new connection to the database."""
|
"""Returns a new connection to the database."""
|
||||||
return sqlite3.connect(DATABASE)
|
return sqlite3.connect(app.config['DATABASE'])
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
|
|
@ -76,9 +76,9 @@ def add_entry():
|
||||||
def login():
|
def login():
|
||||||
error = None
|
error = None
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if request.form['username'] != USERNAME:
|
if request.form['username'] != app.config['USERNAME']:
|
||||||
error = 'Invalid username'
|
error = 'Invalid username'
|
||||||
elif request.form['password'] != PASSWORD:
|
elif request.form['password'] != app.config['PASSWORD']:
|
||||||
error = 'Invalid password'
|
error = 'Invalid password'
|
||||||
else:
|
else:
|
||||||
session['logged_in'] = True
|
session['logged_in'] = True
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ class FlaskrTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Before each test, set up a blank database"""
|
"""Before each test, set up a blank database"""
|
||||||
self.db_fd, flaskr.DATABASE = tempfile.mkstemp()
|
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
|
||||||
self.app = flaskr.app.test_client()
|
self.app = flaskr.app.test_client()
|
||||||
flaskr.init_db()
|
flaskr.init_db()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Get rid of the database again after each test."""
|
"""Get rid of the database again after each test."""
|
||||||
os.close(self.db_fd)
|
os.close(self.db_fd)
|
||||||
os.unlink(flaskr.DATABASE)
|
os.unlink(flaskr.app.config['DATABASE'])
|
||||||
|
|
||||||
def login(self, username, password):
|
def login(self, username, password):
|
||||||
return self.app.post('/login', data=dict(
|
return self.app.post('/login', data=dict(
|
||||||
|
|
@ -45,18 +45,22 @@ class FlaskrTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_login_logout(self):
|
def test_login_logout(self):
|
||||||
"""Make sure login and logout works"""
|
"""Make sure login and logout works"""
|
||||||
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
rv = self.login(flaskr.app.config['USERNAME'],
|
||||||
|
flaskr.app.config['PASSWORD'])
|
||||||
assert 'You were logged in' in rv.data
|
assert 'You were logged in' in rv.data
|
||||||
rv = self.logout()
|
rv = self.logout()
|
||||||
assert 'You were logged out' in rv.data
|
assert 'You were logged out' in rv.data
|
||||||
rv = self.login(flaskr.USERNAME + 'x', flaskr.PASSWORD)
|
rv = self.login(flaskr.app.config['USERNAME'] + 'x',
|
||||||
|
flaskr.app.config['PASSWORD'])
|
||||||
assert 'Invalid username' in rv.data
|
assert 'Invalid username' in rv.data
|
||||||
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD + 'x')
|
rv = self.login(flaskr.app.config['USERNAME'],
|
||||||
|
flaskr.app.config['PASSWORD'] + 'x')
|
||||||
assert 'Invalid password' in rv.data
|
assert 'Invalid password' in rv.data
|
||||||
|
|
||||||
def test_messages(self):
|
def test_messages(self):
|
||||||
"""Test that messages work"""
|
"""Test that messages work"""
|
||||||
self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
self.login(flaskr.app.config['USERNAME'],
|
||||||
|
flaskr.app.config['PASSWORD'])
|
||||||
rv = self.app.post('/add', data=dict(
|
rv = self.app.post('/add', data=dict(
|
||||||
title='<Hello>',
|
title='<Hello>',
|
||||||
text='<strong>HTML</strong> allowed here'
|
text='<strong>HTML</strong> allowed here'
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@
|
||||||
|
|
||||||
~ How do I use it?
|
~ How do I use it?
|
||||||
|
|
||||||
1. edit the configuration in the minitwit.py file
|
1. edit the configuration in the minitwit.py file or
|
||||||
|
export an MINITWIT_SETTINGS environment variable
|
||||||
|
pointing to a configuration file.
|
||||||
|
|
||||||
2. fire up a python shell and run this:
|
2. fire up a python shell and run this:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,13 @@ SECRET_KEY = 'development key'
|
||||||
|
|
||||||
# create our little application :)
|
# create our little application :)
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(__name__)
|
||||||
|
app.config.from_envvar('MINITWIT_SETTINGS', silent=True)
|
||||||
|
|
||||||
|
|
||||||
def connect_db():
|
def connect_db():
|
||||||
"""Returns a new connection to the database."""
|
"""Returns a new connection to the database."""
|
||||||
return sqlite3.connect(DATABASE)
|
return sqlite3.connect(app.config['DATABASE'])
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
|
|
@ -237,12 +239,9 @@ def logout():
|
||||||
return redirect(url_for('public_timeline'))
|
return redirect(url_for('public_timeline'))
|
||||||
|
|
||||||
|
|
||||||
# add some filters to jinja and set the secret key and debug mode
|
# add some filters to jinja
|
||||||
# from the configuration.
|
|
||||||
app.jinja_env.filters['datetimeformat'] = format_datetime
|
app.jinja_env.filters['datetimeformat'] = format_datetime
|
||||||
app.jinja_env.filters['gravatar'] = gravatar_url
|
app.jinja_env.filters['gravatar'] = gravatar_url
|
||||||
app.secret_key = SECRET_KEY
|
|
||||||
app.debug = DEBUG
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ class MiniTwitTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Before each test, set up a blank database"""
|
"""Before each test, set up a blank database"""
|
||||||
self.db_fd, minitwit.DATABASE = tempfile.mkstemp()
|
self.db_fd, minitwit.app.config['DATABASE'] = tempfile.mkstemp()
|
||||||
self.app = minitwit.app.test_client()
|
self.app = minitwit.app.test_client()
|
||||||
minitwit.init_db()
|
minitwit.init_db()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Get rid of the database again after each test."""
|
"""Get rid of the database again after each test."""
|
||||||
os.close(self.db_fd)
|
os.close(self.db_fd)
|
||||||
os.unlink(minitwit.DATABASE)
|
os.unlink(minitwit.app.config['DATABASE'])
|
||||||
|
|
||||||
# helper functions
|
# helper functions
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue