Settings

Introduction

A typical application has some settings: if an application logs, a setting is the path to the log file. If an application sends email, there are settings to control how email is sent, such as the email address of the sender.

Applications that serve as frameworks for other applications may have settings as well: the transaction_app defined by more.transaction for instance has settings controlling transactional behavior.

Morepath has a powerful settings system that lets you define what settings are available in your application and framework. It allows an app that extends another app to override settings. This lets an app that defines a framework can also define default settings that can be overridden by the extending application if needed.

Defining a setting

You can define a setting using the App.setting() directive:

@App.setting(section="logging", name="logfile")
def get_logfile():
    return "/path/to/logfile.log"

You can also use this directive to override a setting in another app:

class Sub(App):
    pass

@Sub.setting(section="logging", name="logfile")
def get_logfile_too():
   return "/a/different/logfile.log"

Settings are grouped logically: a setting is in a section and has a name. This way you can organize all settings that deal with logging under the logging section.

Accessing a setting

During runtime, you can access the settings of the current application using the morepath.App.settings property:

app.settings.logging.logfile

Remember that the current application is also accessible from the request object:

request.app.settings.logging.logfile

Defining multiple settings

It can be convenient to define multiple settings in a section at once. You can do this using the App.setting_section() directive:

@App.setting_section(section="logging")
def get_setting_section():
    return {
       'logfile': "/path/to/logfile.log",
       'loglevel': logging.WARNING
    }

You can mix setting and setting_section freely, but you cannot define a setting multiple times in the same app, as this will result in a configuration conflict.

Loading settings from a config file

For loading settings from a config file just load the file into a python dictionary and pre-fill the settings with morepath.App.init_settings() before committing the app.

A example config file with YAML syntax could look like:

# Config file for Morepath in YAML format

chameleon:
  debug: true

jinja2:
  auto_reload: false
  autoescape: true
  extensions:
    - jinja2.ext.autoescape
    - jinja2.ext.i18n

jwtauth:
  algorithm: ES256
  leeway: 20
  public_key:
    "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBWcJwPEAnS/k4kFgUhxNF7J0SQQhZG+nNgy\
    +/mXwhQ5PZIUmId1a1TjkNXiKzv6DpttBqduHbz/V0EtH+QfWy0B4BhZ5MnTyDGjcz1DQqK\
    dexebhzobbhSIZjpYd5aU48o9rXp/OnAnrajddpGsJ0bNf4rtMLBqFYJN6LOslAB7xTBRg="

sqlalchemy:
  url: 'sqlite:///morepath.db'

transaction:
  attempts: 2

You can load it with:

import yaml

with open('settings.yml') as config:
     settings_dict = yaml.load(config)

Remember to install pyyaml before importing yaml. For example with:

$ pip install pyyaml

The same config file with JSON syntax would look like:

{
    "chameleon": {
        "debug": true
    },
    "jinja2": {
        "auto_reload": false,
        "autoescape": true,
        "extensions": [
            "jinja2.ext.autoescape",
            "jinja2.ext.i18n"
        ]
    },
    "jwtauth": {
        "algorithm": "ES256",
        "leeway": 20,
        "public_key": "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBWcJwPEAnS/k4kFgUhxNF7J0SQQhZG+nNgy+/mXwhQ5PZIUmId1a1TjkNXiKzv6DpttBqduHbz/V0EtH+QfWy0B4BhZ5MnTyDGjcz1DQqKdexebhzobbhSIZjpYd5aU48o9rXp/OnAnrajddpGsJ0bNf4rtMLBqFYJN6LOslAB7xTBRg="
    },
    "sqlalchemy": {
        "url": "sqlite:///morepath.db"
    },
    "transaction": {
        "attempts": 2
    }
}

To load it use:

import json

with open('settings.json') as config:
     settings_dict = json.load(config)

Now register the settings dictionary in the App settings before starting the App:

App.init_settings(settings_dict)
morepath.commit(App)

app = App()

You can access the settings as before:

>>> app.settings.jinja2.extensions
['jinja2.ext.autoescape', 'jinja2.ext.i18n']

>>> app.settings.jwtauth.algorithm
'ES256'

>>> app.settings.sqlalchemy.url
'sqlite:///morepath.db'

You can also override and extend the settings by loading a config file in an extending app as usual.