To build a extendable config server.
Project description
引言
定义
系统名称:配置标准化开发工具包(以下简称“本系统”)。
编写目的
本手册较详细地介绍了本系统的应用程序接口与使用方法,用户通过查看本手册,可以了解如何使用本系统。
系统介绍
系统简介
在程序设计的功能中,随着版本的迭代,程序的功能会逐渐累计;功能越多的程序,一般越需要用户自行选择启用哪些功能,并在一定程度上可以决定程序执行的流程等,这样的过程可以称为对程序进行“配置”。
不同的程序面向不同的使用人群,不同的使用人群也会有不同的配置方式。例如,没有程序设计基础的普通用户更偏向于使用携带用户操作界面的配置页面,部分具有程序设计基础的用户更偏向于使用命令行参数输入、载入配置文件等配置方式,部分开发者更偏向于使用软件开发工具包来按照需求定制程序配置方案。
另一方面,随着程序功能增多,配置参数之间极可能出现耦合和约束关系。由于目前行业内尚未有公开的、成熟的、针对携带复杂参数的程序的软件开发工具,因此开发本系统以填补行业空缺,为复杂配置参数的场景提供解决方案。
由于 python 语言有着“胶水语言”的特性,能很好地与其他编程语言(如 C,Java,Fortran 等)编写的程序进行交互,并且它的学习门槛低,应用范围广, 本系统形成了一套 python 语言的软件开发工具包。
本系统将复杂参数的关系以树状图进行整理,以 yaml 格式的配置文件为标准,开发者可以通过该系统定制包含复杂约束关系的参数配置系统,可以生成网页端的配置页面、命令行操作接口、配置文件接口、网站后台接口等多种接入方案,可满足不同用户的使用习惯。
系统流程图
%%{
init: {
'theme': 'base',
'themeVariables': {
'fontSize': '24px',
'fontFamily': "SimSun, serif",
'background': '#efefef',
'primaryColor': '#fff',
'primaryTextColor': '#000',
'primaryBorderColor': '#000',
'lineColor': '#000',
'secondaryColor': '#000',
'tertiaryColor': '#000'
}
}
}%%
flowchart TB
a(开始)
b[通过思维导图整理参数结构]
c[配置python环境]
d[载入本系统]
e[定义参数结点]
f[运行程序]
g(结束)
a-->b-->c-->d-->e-->f-->g
系统快速入门
设计概念
通过思维导图的整理后的参数结构是树状的,而树状的数据可分为根节点、子节点、叶子节点,如下图所示:
mindmap
root((根节点))
))叶子节点((
[子节点]
))叶子节点((
))叶子节点((
[子节点]
))叶子节点((
))叶子节点((
[子节点]
))叶子节点((
))叶子节点((
在配置文件中,"根节点"对应配置文件本身,"子节点"对应若干个参数所在的分组,"叶子节点"对应某个参数,如下图所示:
mindmap
root((配置文件))
))一级参数((
[一级分组]
))二级参数((
))二级参数((
[二级分组]
))三级参数((
))三级参数((
[一级分组]
))二级参数((
))二级参数((
在参数说明文档应以章节号的形式体现参数的分组结果,在参数说明文档的每小节对应某个分组或参数。
例如,以下是参数说明文档目录的示例:
1. 一级参数
2. 一级分组
2.1 二级参数
2.2 二级参数
2.3 二级分组
2.3.1 三级参数
2.3.2 三级参数
3. 一级分组
3.1 二级参数
3.2 二级参数
案例说明
mindmap
root((配置文件))
))用户名((
[登录方式(三选一)]
[微信]
))微信号((
))密码((
[邮箱]
))邮箱地址((
))密码((
[手机号]
))手机号码((
))密码((
在本案例中,我们主要关注一个典型的用户身份验证系统,其中提供了三种不同的登录方式,以满足不同用户的需求和习惯。
用户名
用户名是用户在系统中的唯一标识符,用于在登录后显示及与其他用户进行区分。通常,用户名是一个自选项,可以是用户的真实姓名、昵称或其他有意义的组合字符。
性别
可选“男”、“女”或“保密”,默认值为“保密”。
注册信息
为了方便和安全考虑,系统提供了三种不同的登录方式供用户选择:
微信登录: 通过微信登录,用户可以使用他们的微信凭证进行身份验证。这种方法便捷且安全,因为它与微信的身份验证系统直接相连,若使用该方式,用户需要填写:① 微信号: 用户的唯一微信识别码,② 密码: 与微信号对应的密码。
邮箱登录: 邮箱登录允许用户使用其电子邮箱地址和密码登录。许多用户可能更倾向于使用邮箱登录,因为它是常用的身份验证方法。若使用该方式,用户需要填写:① 邮箱地址: 用户的有效电子邮箱地址,② 密码: 与邮箱地址关联的密码。
手机号登录: 手机号登录提供了一种通过用户手机号码进行身份验证的方式。对于没有微信或不常使用电子邮件的用户,这可能是一个方便的选择,若使用该方式,用户需要填写:① 手机号码: 用户的有效手机号码,② 密码: 与手机号码关联的密码。
程序定义
from typing import Literal
from config_server import (
set_title,
set_doc,
add_multi_type_field,
ConfigLeaf,
ConfigNode,
)
@set_title("用户名") # Tips 1: 通过装饰器设置标题
@set_doc("用户名是用户在系统中的唯一标识符。") # Tips 2: 通过装饰器设置字段的详细说明
class UserName(ConfigLeaf):
root: str # Tips 3: 只是做了类型标注,但没有赋值,表示该字段为必填字段
@set_title("性别")
class Gender(ConfigLeaf):
root: Literal["男", "女", "保密"] = "保密" # Tips 3: 直接赋值,表示默认值为“保密”
# Tips 4: 在全局作用域中定义(叶)子节点
@set_title("密码")
class Password(ConfigLeaf):
root: str
# Tips 5:
# 通过重写`verify_constraints`方法来实现自定义的约束,
# 本方法会在实例化时自动调用;若验证不通过,请抛出异常;
# 如果需要表示跨节点的约束条件,请在其最近的共同父节点中定义。
def verify_constraints(self) -> None:
if len(self.root) < 8:
raise ValueError("密码长度不能小于8位")
@set_title("微信")
class WeChat(ConfigNode):
# Tips 4: 也可以通过内部类来定义(叶)子节点
@set_title("微信号")
class WeChatId(ConfigLeaf):
root: str
wechat_id: WeChatId
wechat_password: Password
@set_title("邮箱")
class Email(ConfigNode):
@set_title("邮箱地址")
class EmailAddress(ConfigLeaf):
root: str
email_address: EmailAddress
email_password: Password
@set_title("手机号")
class Phone(ConfigNode):
@set_title("手机号码")
class PhoneNumber(ConfigLeaf):
root: str
phone_number: PhoneNumber
phone_password: Password
@set_title("注册信息")
@set_doc(
"""
提供了三种不同的登录方式供用户选择:
| 登录方式 | 说明 |
| :---: | :----------------: |
| 微信 | 用户可以使用微信号登录 |
| 邮箱 | 用户可以使用邮箱登录 |
| 手机 | 用户可以使用手机号登录 |
"""
) # Tips 6: 详细说明支持markdown语法
@add_multi_type_field( # Tips 7: 通过装饰器添加多类型字段
field_name="root", # Tips 7: `field_name`为该字段在添加后的字段名
field_title="注册信息",
field_doc="用户在网站上注册时所填写的信息",
types=[WeChat, Email, Phone], # Tips 7: `types`为该字段可以接受的类型,此处为三种不同的登录方式
discriminator="login_method", # Tips 7: 在子节点中,通过discriminator字段来区分不同的类型
)
class AuthInfo(ConfigLeaf): # tips 8: 当节点只有一个字段时,可以直接使用ConfigLeaf,并将唯一字段名设置为`root`
pass # tips 9: 在python中,pass是一个空语句,一般用做占位语句
@set_title("用户系统")
class UserSystem(ConfigNode):
username: UserName
auth_info: AuthInfo
命令行生成配置文件
当程序完成定义时,可以通过调用 mock_cli
和 model_dump_yaml
方法,能在命令行中操作后生成配置文件:
UserSystem.mock_cli().model_dump_yaml(comment=True)
命令行执行效果,如下图所示:
程序拓展接口
当程序完成定义时,可以通过调用 get_api_router
方法来启动后端服务开启标准化的应用程序接口,以下是一个简单的案例:
import uvicorn
import fastapi
from fastapi.middleware.cors import CORSMiddleware
app = fastapi.FastAPI()
app.include_router(UserSystem.get_api_router("/"))
app.add_middleware( # 添加跨域中间件,用于解决跨域问题
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
uvicorn.run(app, host="127.0.0.1", port=8000, log_level="info")
用户界面
本系统包含一个配套的网页端用户界面,以上案例对应的页面如下图所示:
当点击表单字段前方的 ?
标识时,会出现该字段的详细说明,如下图所示:
当选择多类型字段的值后,其子节点的内容也会随之发生变化,如下图所示:
当必填字段没有填写时,网页会给出提示:
在验证通过时,可以生成 yaml 格式的配置文件,如下图所示:
程序接口
本系统的核心部分就是其配置节点(ConfigNode)和配置叶子节点(ConfigLeaf),它们共同构成了配置的树形结构。
节点类(ConfigNode)
节点类作为配置系统的核心,用于构建、验证、转换、序列化配置树的结构。
验证YAML文件
使用model_validate_yaml
方法,开发人员可以通过传递YAML文件的路径进行验证。如果验证成功,将返回一个有效的ConfigNode实例。
模拟方法
ConfigNode类还提供了多个模拟方法,如mock
,mock_with_default
,mock_with_blank
和mock_cli
。这些方法可以根据字段类型和默认值生成模拟实例。
YAML序列化
使用model_dump_yaml
方法,可以将ConfigNode实例转储为YAML字符串。model_dump_mock_yaml
方法提供了模拟实例的转储功能。
生成后端接口路由
get_api_router
方法可用于获取API路由。
约束验证
verify_constraints
方法用于验证约束条件,可以根据需要覆盖。
叶节点类(ConfigLeaf)
叶节点类继承自根模型和节点类,用于构建配置树的末端节点。
装饰器
设置标题(set_title)
通过传递标题字符串,可以设置模型的标题。
@set_title("标题")
class ExampleModel(BaseModel):
...
设置说明(set_doc)
该装饰器用于设置模型的详细说明。
@set_doc("这是一个示例模型")
class ExampleModel(BaseModel):
...
设置鉴别字段(set_discriminator)
此装饰器可以设置模型的区分器字段名。
@set_discriminator("type")
class ExampleModel(BaseModel):
...
添加复合类型字段(add_multi_type_field)
此装饰器可以将具有多种类型的字段添加到模型中,还可以通过可选参数设置字段标题和文档。
@add_multi_type_field("field_name", [Type1, Type2])
class ExampleModel(BaseModel):
...
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Hashes for config_server-0.3.0-cp310-cp310-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a281298979da6129dbcd1f02e1255925882a89b7e0270000e8c1c314ea365e7d |
|
MD5 | c927c3c9b15e3ab13305928412dad00d |
|
BLAKE2b-256 | 9d48d14ed4fe50e3fe1e44568faf51b00c44d9cf4f01b602776e1e803a72220a |
Hashes for config_server-0.3.0-cp39-cp39-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4df76ea2c6108d200e228e2540d4f52cfcf45a92da639e1d99cc6167adeeff6f |
|
MD5 | 5c31e85db2ece417d025e919baede4a9 |
|
BLAKE2b-256 | 1ce4d255d7680b16d54dc1945a08189d73a5544c8415267cf005c2073ee39c40 |
Hashes for config_server-0.3.0-cp38-cp38-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1c4d4a723547755caf671b3ba52b25166a1c9d991d890788c40689601f19dbf2 |
|
MD5 | fc857f956e9444c479a3cf6ae1f3573e |
|
BLAKE2b-256 | db3ccce8aaf006a71ef766196c6ec2d430cdeb38978bd84da9459f8671f1d5ce |