配置¶
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.field
或namespace.subnamespace.field
)。Bottle 为其自身的配置使用根命名空间。插件应该将所有变量存储在自己的命名空间中(例如
sqlite.db
或werkzeug.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]
返回为键定义的元字段名称的可迭代对象。