Skip to content

Commit

Permalink
Added chapter about config
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed May 27, 2010
1 parent 78fc994 commit 182ee31
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 8 deletions.
1 change: 1 addition & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,4 @@ Configuration
-------------

.. autoclass:: Config
:members:
120 changes: 120 additions & 0 deletions docs/config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
Configuration Handling
======================

.. versionadded:: 0.5

Applications need some kind of configuration. There are different things
you might want to change. Like toggling debug mode, the secret key and a
lot of very similar things.

The way Flask is designed usually requires the configuration to be
available when the application starts up. You can either hardcode the
configuration in the code which for many small applications is not
actually that bad, but there are better ways.

Independent of how you load your config, there is a config object
available which holds the loaded configuration values:
The :attr:`~flask.Flask.config` attribute of the :class:`~flask.Flask`
object. This is the place where Flask itself puts certain configuration
values and also where extensions can put their configuration values. But
this is also where you can have your own configuration.

Configuration Basics
--------------------

The :attr:`~flask.Flask.config` is actually a subclass of a dictionary and
can be modified just like any dictionary::

app = Flask(__name__)
app.config['DEBUG'] = True

Certain configuration values are also forwarded to the
:attr:`~flask.Flask` object so that you can read and write them from
there::

app.debug = True

To update multiple keys at once you can use the :meth:`dict.update`
method::

app.config.update(
DEBUG=True,
SECRET_KEY='...'
)

Builtin Configuration Values
----------------------------

The following configuration values are used internally by Flask:

=============================== =========================================
``DEBUG`` enable/disable debug mode
``SECRET_KEY`` the secret key
``SESSION_COOKIE_NAME`` the name of the session cookie
``PERMANENT_SESSION_LIFETIME`` the lifetime of a permanent session as
:class:`datetime.timedelta` object.
``USE_X_SENDFILE`` enable/disable x-sendfile
=============================== =========================================

Configuring from Files
----------------------

Configuration becomes more useful if you can configure from a file. And
ideally that file would be outside of the actual application package that
you can install the package with distribute (:ref:`distribute-deployment`)
and still modify that file afterwards.

So a common pattern is this::

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

What this does is first loading the configuration from the
`yourapplication.default_settings` module and then overrides the values
with the contents of the file the :envvar:`YOURAPPLICATION_SETTINGS`
environment variable points to. This environment variable can be set on
Linux or OS X with the export command in the shell before starting the
server::

$ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg
$ python run-app.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader...

On Windows systems use the `set` builtin instead::

>set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg

The configuration files themselves are actual Python files. Only values
in uppercase are actually stored in the config object later on. So make
sure to use uppercase letters for your config keys.

Here an example configuration file::

DEBUG = False
SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83'

Make sure to load the configuration very early on so that extensions have
the ability to access the configuration when starting up. There are other
methods on the config object as well to load from individual files. For a
complete reference, read the :class:`~flask.Config` object's
documentation.


Configuration Best Practices
----------------------------

The downside with the approach mentioned earlier is that it makes testing
a little harder. There is no one 100% solution for this problem in
general, but there are a couple of things you can do to improve that
experience:

1. create your application in a function and register modules on it.
That way you can create multiple instances of your application with
different configurations attached which makes unittesting a lot
easier. You can use this to pass in configuration as needed.

2. Do not write code that needs the configuration at import time. If you
limit yourself to request-only accesses to the configuration you can
reconfigure the object later on as needed.
1 change: 1 addition & 0 deletions docs/contents.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ web development.
tutorial/index
testing
errorhandling
config
shell
patterns/index
deploying/index
Expand Down
2 changes: 2 additions & 0 deletions docs/patterns/distribute.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _distribute-deployment:

Deploying with Distribute
=========================

Expand Down
67 changes: 59 additions & 8 deletions flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,21 +641,33 @@ class Config(dict):
app.config.from_pyfile('yourconfig.cfg')
Or alternatively you can define the configuration options in the
module that calls :meth:`from_module` or provide an import path to
module that calls :meth:`from_object` or provide an import path to
a module that should be loaded. It is also possible to tell it to
use the same module and with that provide the configuration values
just before the call::
DEBUG = True
SECRET_KEY = 'development key'
app.config.from_module(__name__)
app.config.from_object(__name__)
In both cases (loading from any Python file or loading from modules),
only uppercase keys are added to the config. The actual keys in the
config are however lowercased so they are converted for you. This makes
it possible to use lowercase values in the config file for temporary
values that are not added to the config or to define the config keys in
the same file that implements the application.
only uppercase keys are added to the config. This makes it possible to use
lowercase values in the config file for temporary values that are not added
to the config or to define the config keys in the same file that implements
the application.
Probably the most interesting way to load configurations is from an
environment variable pointing to a file::
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
In this case before launching the application you have to set this
environment variable to the file you want to use. On Linux and OS X
use the export statement::
export YOURAPPLICATION_SETTINGS='/path/to/config/file'
On windows use `set` instead.
:param root_path: path to which files are read relative from. When the
config object is created by the application, this is
Expand All @@ -667,10 +679,33 @@ def __init__(self, root_path, defaults=None):
dict.__init__(self, defaults or {})
self.root_path = root_path

def from_envvar(self, variable_name, silent=False):
"""Loads a configuration from an environment variable pointing to
a configuration file. This basically is just a shortcut with nicer
error messages for this line of code::
app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
:param variable_name: name of the environment variable
:param silent: set to `True` if you want silent failing for missing
files.
:return: bool. `True` if able to load config, `False` otherwise.
"""
rv = os.environ.get(variable_name)
if not rv:
if silent:
return False
raise RuntimeError('The environment variable %r is not set '
'and as such configuration could not be '
'loaded. Set this variable and make it '
'point to a configuration file')
self.from_pyfile(rv)
return True

def from_pyfile(self, filename):
"""Updates the values in the config from a Python file. This function
behaves as if the file was imported as module with the
:meth:`from_module` function.
:meth:`from_object` function.
:param filename: the filename of the config. This can either be an
absolute filename or a filename relative to the
Expand Down Expand Up @@ -752,26 +787,42 @@ class Flask(_PackageBoundObject):
#: application. In debug mode the debugger will kick in when an unhandled
#: exception ocurrs and the integrated server will automatically reload
#: the application if changes in the code are detected.
#:
#: This attribute can also be configured from the config with the `DEBUG`
#: configuration key. Defaults to `False`.
debug = ConfigAttribute('DEBUG')

#: if a secret key is set, cryptographic components can use this to
#: sign cookies and other things. Set this to a complex random value
#: when you want to use the secure cookie for instance.
#:
#: This attribute can also be configured from the config with the
#: `SECRET_KEY` configuration key. Defaults to `None`.
secret_key = ConfigAttribute('SECRET_KEY')

#: The secure cookie uses this for the name of the session cookie
#:
#: This attribute can also be configured from the config with the
#: `SESSION_COOKIE_NAME` configuration key. Defaults to ``'session'``
session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME')

#: A :class:`~datetime.timedelta` which is used to set the expiration
#: date of a permanent session. The default is 31 days which makes a
#: permanent session survive for roughly one month.
#:
#: This attribute can also be configured from the config with the
#: `PERMANENT_SESSION_LIFETIME` configuration key. Defaults to
#: ``timedelta(days=31)``
permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME')

#: Enable this if you want to use the X-Sendfile feature. Keep in
#: mind that the server has to support this. This only affects files
#: sent with the :func:`send_file` method.
#:
#: .. versionadded:: 0.2
#:
#: This attribute can also be configured from the config with the
#: `USE_X_SENDFILE` configuration key. Defaults to `False`.
use_x_sendfile = ConfigAttribute('USE_X_SENDFILE')

#: the logging format used for the debug logger. This is only used when
Expand Down

0 comments on commit 182ee31

Please sign in to comment.