配置

Bottle 应用可以将它们的配置存储在 Bottle.config 中,这是一个类似字典的对象,也是应用程序特定设置的中心位置。这个字典控制着框架的许多方面,告诉(更新的)插件该做什么,也可以用来存储您自己的配置。

配置基础

这个 Bottle.config 对象在很多方面都像一个普通字典。所有常用的字典方法都可以正常工作。让我们从一些例子开始

import bottle
app = bottle.default_app()             # or bottle.Bottle() if you prefer

app.config['autojson']    = False      # Turns off the "autojson" feature
app.config['sqlite.db']   = ':memory:' # Tells the sqlite plugin which db to use
app.config['myapp.param'] = 'value'    # Example for a custom config value.

# Change many values at once
app.config.update({
    'autojson': False,
    'sqlite.db': ':memory:',
    'myapp.param': 'value'
})

# Add default values
app.config.setdefault('myapp.param2', 'some default')

# Receive values
param  = app.config['myapp.param']
param2 = app.config.get('myapp.param2', 'fallback value')

# An example route using configuration values
@app.route('/about', view='about.rst')
def about():
    email = app.config.get('my.email', 'nomail@example.com')
    return {'email': email}

助手函数可以依赖 Request.app 来获取与当前请求关联的应用程序和配置

from bottle import request
def is_admin(user):
    return user == request.app.config['myapp.admin_user']

命名约定

为了让事情变得更容易,插件和应用程序在配置参数命名方面应该遵循一些简单的规则

  • 所有键都应该是小写字符串,并遵循 Python 标识符的规则(除了下划线,没有特殊字符)。

  • 命名空间用点分隔(例如 namespace.fieldnamespace.subnamespace.field)。

  • Bottle 为其自身的配置使用根命名空间。插件应该将所有变量存储在自己的命名空间中(例如 sqlite.dbwerkzeug.use_debugger)。

  • 您自己的应用程序应该使用一个单独的命名空间(例如 myapp.*)。

从文件加载配置

如果您想让非程序员配置您的应用程序,或者只是不想仅仅为了更改数据库端口而去修改 Python 模块文件,那么配置文件会很有用。此处显示了配置文件的一种非常常见的语法

[sqlite]
db = /tmp/test.db
commit = auto

[myapp]
admin_user = defnull

使用 ConfigDict.load_config(),您可以从磁盘加载这些 *.ini 风格的配置文件,并将它们的值导入到您现有的配置中

app.config.load_config('/etc/myapp.conf')

从 Python 模块加载配置

从 Python 模块加载配置是 Python 程序和框架的一种常见模式。ConfigDict.load_module() 按名称导入 Python 模块,并将所有大写模块级变量添加到配置中。

DEBUG = True
SQLITE = {"db": ":memory:"}
>>> c = ConfigDict()
>>> c.load_module('config')
{'debug': True, 'sqlite.db': 'memory'}
>>> c.load_module("config", squash=False)
{'debug': True, 'sqlite': {'db': 'memory'}}

默认情况下,配置是展平的,类似于 ConfigDict.load_dict() 的行为。您可以通过传递参数 squash=False 来阻止这种情况。

dict 加载配置

另一个有用的方法是 ConfigDict.load_dict()。此方法接受一个由嵌套字典组成的完整结构,并将其转换为带有命名空间键的展平键值列表

# Load an entire dict structure
app.config.load_dict({
    'autojson': False,
    'sqlite': { 'db': ':memory:' },
    'myapp': {
        'param': 'value',
        'param2': 'value2'
    }
})

assert app.config['myapp.param'] == 'value'

# Load configuration from a json file
with open('/etc/myapp.json') as fp:
    app.config.load_dict(json.load(fp))

监听配置更改

每当 Bottle.config 中的值即将更改时,Bottle 都会触发 config 应用程序钩子。一旦运行时配置发生更改,此钩子可用于动态重新配置插件或应用程序的某些部分。例如

  • 启用或禁用维护模式或调试模式。

  • 重新连接到新的数据库。

  • 更改插件或后台服务的设置。

  • 调整工作线程池的大小。

钩子回调接收两个参数 (key, new_value),并在实际更改字典中的值之前调用。从此回调中引发异常将阻止更改并保留旧值。

@app.hook('config')
def on_config_change(key, value):
  if key == 'debug':
      switch_own_debug_mode_to(value)

钩子回调不能更改将要存储到字典中的值。这就是过滤器的作用。

过滤器和其他元数据

ConfigDict 允许您与配置键一起存储元数据。当前定义了两个元字段

help

帮助或描述字符串。可用于调试、内省或管理工具,以帮助站点维护者配置其应用程序。

filter

一个可调用对象,接受并返回单个值。如果为某个键定义了过滤器,则存储到该键的任何新值首先会通过过滤器回调。过滤器可用于将值转换为不同的类型、检查无效值(抛出 ValueError)或触发副作用。

此功能对于插件最有用。它们可以使用过滤器验证其配置参数或触发副作用,并通过 help 字段文档化其配置

class SomePlugin(object):
    def setup(app):
        app.config.meta_set('some.int', 'filter', int)
        app.config.meta_set('some.list', 'filter',
            lambda val: str(val).split(';'))
        app.config.meta_set('some.list', 'help',
            'A semicolon separated list.')

    def apply(self, callback, route):
        ...

import bottle
app = bottle.default_app()
app.install(SomePlugin())

app.config['some.list'] = 'a;b;c'     # Actually stores ['a', 'b', 'c']
app.config['some.int'] = 'not an int' # raises ValueError

API 文档

class ConfigDict[source]

一个类似字典的配置存储,额外支持命名空间、验证器、元数据和覆盖层。

这个类似字典的类针对读取访问进行了大量优化。只读方法和项目访问应该像原生字典一样快速。

__init__()[source]
load_module(name, squash=True)[source]

从 Python 模块加载值。

按名称导入 Python 模块,并将所有大写模块级变量添加到此配置字典中。

参数:
  • name – 要导入和加载的模块名称。

  • squash – 如果为 True(默认值),嵌套字典将被视为命名空间并展平(参见 load_dict())。

load_config(filename, **options)[source]

使用 configparser 从 *.ini 风格的配置文件加载值。

INI 风格的节(例如 [section])用作该节内所有键的命名空间。节名和键名都可以包含点作为命名空间分隔符,并会转换为小写。

特殊节 [bottle][ROOT] 指的是根命名空间,而 [DEFAULT] 节为所有其他节定义默认值。

参数:
  • filename – 配置文件的路径,或路径列表。

  • options – 所有关键字参数都传递给底层的 configparser.ConfigParser 构造函数调用。

load_dict(source, namespace='')[source]

从字典结构加载值。可以使用嵌套来表示命名空间。

>>> c = ConfigDict()
>>> c.load_dict({'some': {'namespace': {'key': 'value'} } })
{'some.namespace.key': 'value'}
update(*a, **ka)[source]

如果第一个参数是字符串,则所有键都将带有此前缀命名空间。除此之外,它的工作方式与常规的 dict.update() 完全相同。

>>> c = ConfigDict()
>>> c.update('some.namespace', key='value')
setdefault(key, value=None)[source]

如果 key 不在字典中,则插入 key,值为 default。

如果 key 在字典中,则返回 key 的值,否则返回 default。

meta_get(key, metafield, default=None)[source]

返回键的元字段值。

meta_set(key, metafield, value)[source]

将键的元字段设置为新值。

元字段在覆盖树的所有成员之间共享。

meta_list(key)[source]

返回为键定义的元字段名称的可迭代对象。