自动配置应用程序对象。
项目描述
tree-config
配置以树状方式嵌套的对象。
更多信息: https://matham.github.io/tree-config/index.html
安装
tree-config 可以通过以下方式安装
pip install tree-config
配置使用
tree-config 可以将所有类的可配置属性导出到yaml文件,然后加载该文件并将值恢复/应用到属性中。例如:
class App:
_config_props_ = ('name', )
_config_children_ = {'app panel': 'panel'}
def __init__(self):
self.name = 'Desk'
self.panel = AppPanel()
class AppPanel:
_config_props_ = ('color', )
color = 'A4FF67'
将自动配置 name 和 color。
以下是一个示例指南,展示了控制配置的多种方法。请参阅 配置API,包括完整的 Configuration 类详情。
请参阅仓库中的示例目录以获取以下示例的完整可运行代码。
基本属性
此示例有一个包含两个可配置面板的应用程序类。 _config_props_ 列出了类的可配置属性,而 _config_children_ 构造了可配置对象的树。
class App:
_config_props_ = ('size', 'name')
_config_children_ = {'app panel': 'panel1', 'home panel': 'panel2'}
def __init__(self):
self.size = 12
self.name = 'Desk'
self.panel1 = AppPanel()
self.panel2 = HomePanel()
class AppPanel:
_config_props_ = ('color', )
color = 'A4FF67'
class HomePanel:
_config_props_ = ('shape', )
shape = 'circle'
然后,运行
from tree_config import dump_config, read_config_from_object
app = App()
dump_config('basic_example.yaml', read_config_from_object(app))
print(f'Shape is: {app.panel2.shape}')
创建一个 basic_example.yaml 文件,内容如下
app panel: {color: A4FF67}
home panel: {shape: circle}
name: Desk
size: 12
并打印 Shape is: circle。如果我们想加载一个之前包含形状为 "square" 的yaml文件并将其应用到实例上,我们执行以下操作
from tree_config import load_config, apply_config
app = App()
apply_config(app, load_config(app, 'basic_example.yaml'))
print(f'Shape is: {app.panel2.shape}')
这会打印出 Shape is: square。
钩子属性发现
`_config_props_` 和 `_config_children_` 是在类上定义的,而不是在实例上定义的。当 `tree-config` 使用它们时,它会遍历整个类层次结构,并从所有超类中累积它们的值,因为子类不会覆盖它们,而是向它们添加。
如果 `_config_props` 和/或 `_config_children` 在类或实例上定义,`tree-config` 将直接使用该值,而不是分别遍历 `_config_props_` 和/或 `_config_children_`。
例如,以下代码
from tree_config import dump_config, read_config_from_object
class App:
_config_children_ = {'app panel': 'panel1', 'home panel': 'panel2'}
def __init__(self):
self.panel1 = AppPanel()
self.panel2 = HomePanel()
class RootPanel:
_config_props_ = ('size', 'name')
size = 12
name = 'Desk'
class AppPanel(RootPanel):
_config_props_ = ('color', )
color = 'A4FF67'
class HomePanel(AppPanel):
_config_props_ = ('shape', )
shape = 'circle'
group = 'window'
_config_props = ('group', 'size')
运行时
app = App()
# now get and save config to yaml file
dump_config('hook_properties.yaml', read_config_from_object(app))
将生成以下 yaml 文件
app panel:
color: A4FF67
name: Desk
size: 12
home panel:
group: window
size: 12
注意,`app panel` 包含了 `RootPanel` 和 `AppPanel` 的属性,而 `home panel` 只包含在 `_config_props` 中列出的属性。《_config_children_》的行为类似。
自定义值钩子
我们可能希望将属性获取/设置过程挂钩以更改值,在它保存之前或再次应用之前。
例如,假设我们有一个存储命名元组的属性,我们需要将其导出为列表(因为 yaml 不理解命名元组),并在恢复时再次创建命名元组。《get_config_property` 和 《apply_config_property` 是所需的钩子方法,如果类中存在,将自动使用它们
from collections import namedtuple
from tree_config import dump_config, load_config, apply_config, \
read_config_from_object
Point = namedtuple('Point', ['x', 'y'])
class App:
_config_props_ = ('point', 'name')
point = Point(11, 34)
name = ''
def get_config_property(self, name):
if name == 'point':
return tuple(self.point)
return getattr(self, name)
def apply_config_property(self, name, value):
if name == 'point':
self.point = Point(*value)
else:
setattr(self, name, value)
然后,运行
from tree_config import dump_config, read_config_from_object
app = App()
dump_config('custom_value_example.yaml', read_config_from_object(app))
print(f'point is: {app.point}')
创建一个包含以下内容的 《custom_value_example.yaml` 文件
name: ''
point: [11, 34]
并打印 `point is: Point(x=11, y=34)`。如果我们想再次加载并应用 yaml 文件,我们做
from tree_config import load_config, apply_config
app = App()
apply_config(app, load_config(app, 'custom_value_example.yaml'))
print(f'point is: {app.point}')
这反过来会再次打印 `point is: Point(x=11, y=34)`。
有关类似挂钩应用子对象的应用,请参阅 `apply_config_child`。默认情况下,如果没有提供,则使用 `apply_config`,因此如果覆盖,这也应该用于基本案例。
应用后分派
在将配置应用于对象及其子对象之后,如果存在,tree-config 将调用对象的 《post_config_applied` 方法。例如。
from tree_config import dump_config, load_config, apply_config, \
read_config_from_object
class App:
_config_props_ = ('size', 'name')
_config_children_ = {'app panel': 'panel'}
size = 12
name = 'Desk'
def __init__(self):
self.panel = Panel()
def apply_config_property(self, name, value):
print('applying', name)
setattr(self, name, value)
def post_config_applied(self):
print('done applying app')
class Panel:
_config_props_ = ('color', )
color = 'A4FF67'
def apply_config_property(self, name, value):
print('applying', name)
setattr(self, name, value)
def post_config_applied(self):
print('done applying panel')
然后,使用
# create app and set properties
app = App()
# now get and save config to yaml file
dump_config('post_apply_dispatch.yaml', read_config_from_object(app))
# load config and apply it
apply_config(app, load_config(app, 'post_apply_dispatch.yaml'))
保存并再次应用 yaml,打印以下内容
applying color done applying panel applying name applying size done applying app
可配置类
上述示例使用了 duck typing 方法来处理这些特殊的配置/钩子方法,并且所有这些方法都是可选的。tree-config 还提供了一个 《Configurable` 超类,它定义了所有这些方法并具有适当的默认值。
从 《Configurable` 继承没有好处,但它确实提供了一个包含所有特殊配置方法的基类。此外,它为每个类缓存属性/配置子对象的列表,因此一旦检索到,就不需要遍历树,这与 duck typing 方法不同,该方法在每次保存/应用时都会重新计算。
自动文档
除了配置之外,tree-config 还可以钩入 Sphinx 文档生成构建步骤,生成列出所有可由应用程序配置的属性的文档,并为每个属性显示文档字符串。这对于想要使用配置 yaml 文件配置这些属性的用户很有帮助。
示例目录有一个完整的文档示例。
给定一个根对象(例如示例中的 App),我们可以在 conf.py 中添加回调,当 Sphinx 遇到在 _config_props_ 中列出的属性时被调用。然后回调将这些属性的文档字符串保存到 yaml 文件中。
随后,在构建完成后,tree-config 可以遍历所有可配置的属性,并从根对象或类开始,从 yaml 文件中提取文档字符串,并创建包含这些文档字符串的 rst 文件。
例如,从下面的代码开始:
class App:
"""The app."""
_config_props_ = ('size', 'name')
_config_children_ = {'app panel': 'panel1', 'home panel': 'panel2'}
size = 55
"""Some filename."""
name = ''
"""Some name."""
panel1: 'AppPanel' = None
"""The app panel."""
panel2: 'HomePanel' = None
"""The home panel."""
def __init__(self, size, name, color, shape):
self.size = size
self.name = name
self.panel1 = AppPanel()
self.panel1.color = color
self.panel2 = HomePanel()
self.panel2.shape = shape
class AppPanel:
"""The app panel."""
_config_props_ = ('color', )
color = ''
"""Color of the app."""
class HomePanel:
"""The home panel."""
_config_props_ = ('shape', )
shape = ''
"""Shape of the home."""
然后,我们在 conf.py 文件的顶部添加以下内容
import os
import sys
from functools import partial
sys.path.insert(0, os.path.abspath('../'))
from config_example import App
from tree_config.doc_gen import create_doc_listener, write_config_props_rst
添加到 sys.path 中的确切路径取决于代码所在的位置,或者如果它是一个不需要安装的 Python 包。
我们还需要将 'sphinx.ext.autodoc' 添加到扩展列表中。最后,在 conf.py 的末尾添加
def setup(app):
# dump all config_example package/subpackages config docstrings to config_prop_docs.yaml
create_doc_listener(app, 'config_example', 'config_prop_docs.yaml')
# then get docstrings from yaml file, walk all config properties from App and
# dump formatted config docs to source/config.rst
app.connect(
'build-finished', partial(
write_config_props_rst, App, 'config_example',
filename='config_prop_docs.yaml', rst_filename='source/config.rst')
)
最后,我们将 config.rst(将在源目录下自动创建的文件名)添加到 Sphinx 生成的 index.rst 中。我们还需要在索引或它引用的文件中添加所有类的自动文档引用,否则我们不会得到相关的文档字符串。我们添加如下:
.. toctree::
:maxdepth: 2
:caption: Contents:
config.rst
API
===
.. automodule:: config_example
:members:
在 index.rst 中。
最后,我们运行
echo $'Config\n===========' > source/config.rst
make html
make html
首先,我们创建了一个几乎为空的 config.rst 文件。否则,Sphinx 在生成时不会包含它。然后我们运行了两次 make html,第一次自动生成以下 config_prop_docs.yaml 文件
config_example.App:
name:
- Some name.
- ''
size:
- Some filename.
- ''
config_example.AppPanel:
color:
- Color of the app.
- ''
config_example.HomePanel:
shape:
- Shape of the home.
- ''
第二次 make html 从这个 yaml 文件中提取文档字符串,并使用以下内容创建 config.rst 文件:
CONFIG_EXAMPLE Config
=====================
The following are the configuration options provided by the app. It can be configured by changing appropriate values in the ``config.yaml`` settings file. The options default to the default value of the classes for each of the options.
`name`:
Default value::
''
Some name.
`size`:
Default value::
55
Some filename.
home panel
----------
`shape`:
Default value::
''
Shape of the home.
app panel
---------
`color`:
Default value::
''
Color of the app.
这个 rst 文件将由 Sphinx 自动渲染为漂亮的 html,并与其他文档一起显示,看起来如下:
CONFIG_EXAMPLE 配置
以下是由应用程序提供的配置选项。可以通过更改 config.yaml 设置文件中相应的值来配置它们。选项的默认值是每个选项的类的默认值。
- name:
默认值
''
一些名称。
- size:
默认值
55
一些文件名。
home panel
- shape:
默认值
''
家的形状。
app panel
- color:
默认值
''
应用程序的颜色。
类与实例
上述配置示例从 App 实例 中保存配置。也可以使用 App 类 来转储 yaml。主要区别在于,对于实例方法(如 apply_config_child、get_config_property、apply_config_property 和 post_config_applied),这些方法是实例方法,将被跳过且不被使用。
此外,与实例不同,如果 _config_children_ 列表中的子属性值为 None,则会失败,对于类,如果定义了属性的类型提示,则将回退到类型提示。
使用 App 类而不是 App() 实例,在文档构建期间非常有帮助,此时可能无法实例化完整的 App(参见上面使用带有类型提示的类实例的文档示例)。
重用其他项目文档
由于我们依赖于 autodoc 来生成 config_prop_docs.yaml,tree-config 提供了一种机制来重用我们依赖的其他项目的文档字符串。
例如,假设我们依赖于定义可配置类的remote1和remote2项目,我们的项目通过继承和扩展它们,进一步增加了可配置属性。此外,假设这些远程项目像示例中那样将它们的可配置docstrings输出到config_prop_docs.yaml,并在它们sphinx生成的文档根目录中提供,例如在github-pages上。
然后,tree-config提供了工具将这些docstrings合并到我们的文档中,从而能够从它们创建config.rst,如下所示
echo $'Config\n===========' > source/config.rst
python -m tree_config.doc_gen download \
-u "https://user.github.io/remote1/config_prop_docs.yaml" -o config_prop_docs.yaml
python -m tree_config.doc_gen download -f config_prop_docs.yaml \
-u "https://matham.github.io/remote2/config_prop_docs.yaml" -o config_prop_docs.yaml
make html
make html
这将从我们的依赖项下载并合并yaml文件,将其添加到我们的文档中,并生成config.rst。
项目详情
下载文件
下载适合您平台的应用程序。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分发
构建分发
tree-config-1.0.2.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 44ac550f25a741a408fbb4379d99ce1d744dc6035089559d5adce8e356dfef2b |
|
MD5 | 8f2797800747e7be133ac80215b16ab7 |
|
BLAKE2b-256 | f4f0540551b439e0efdecf76ab6262aec36f14fa3ce488696a18c481f270d7ea |
tree_config-1.0.2-py2.py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 11e2c7e90aea5ef84d796a64a12e702d0898d9c51e1954fc55e4a8eac15b89c5 |
|
MD5 | 0f5201498c256c45ec9354a83a0671c1 |
|
BLAKE2b-256 | 78428b03ce708c151eb8f3fbaa4fa30b41d43a09182316dee86ca12e670c56c0 |