针对多个配置源的python项目的类型化、可扩展、无依赖关系的配置读取器,并在ide中运行良好,可获得良好的自动完成性能。

typed-config的Python项目详细描述


构建状态codecoov

键入配置

用于多个配置源的python项目的类型化、可扩展、无依赖关系的配置读取器,在ide中运行良好,可获得良好的自动完成性能。

pip安装类型配置

需要Python3.6或更高版本。

基本用法

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
# my_app/main.pyfrommy_app.configimportconfigprint(config.host)

在pycharm和其他ide中,它将识别配置的数据类型并允许您自动完成。再也不记得用绳子把正确的东西拿出来了!

工作原理

配置总是以两级结构提供的,因此源配置可以有多个部分,每个部分包含多个键/值配置对。例如:

[database]host=127.0.0.1port=2000[algorithm]max_value=10min_value=20

然后,您可以在代码中创建配置层次结构(可以是平面的,也可以是多层的),并在配置源和配置类的属性中提供字符串之间的匹配。

您可以提供一个或多个configsources,从中可以读取应用程序的配置。例如,您可以提供一个environmentconfigsource和两个inifileconfigsource在返回到第二个ini文件(可能是所有用户共享的默认配置)之前。如果仍然找不到参数,并且该参数是必需的参数,则会引发错误。

这里强调的是所有内容都可以使用类型信息,以便IDE在尝试跨应用程序使用配置时自动完成。

多个数据源

fromtypedconfigimportConfig,key,section,group_keyfromtypedconfig.sourceimportEnvironmentConfigSource,IniFileConfigSource@section('database')classDatabaseConfig(Config):host=key(cast=str)port=key(cast=int)username=key(cast=str)password=key(cast=str)config=DatabaseConfig()config.add_source(EnvironmentConfigSource(prefix="EXAMPLE"))config.add_source(IniFileConfigSource("config.cfg"))# OR provide sources directly to the constructorconfig=DatabaseConfig(sources=[EnvironmentConfigSource(prefix="EXAMPLE"),IniFileConfigSource("config.cfg")])

因为您不想硬编码您的机密凭据,所以可以通过环境提供它们。 因此,对于上述配置,环境可能如下所示:

exportEXAMPLE_DATABASE_USERNAME=my_username
exportEXAMPLE_DATABASE_PASSWORD=my_very_secret_password
exportEXAMPLE_DATABASE_PORT=2001

那些在环境中找不到的值将从ini文件中读取,该文件可能如下所示:

[database]HOST=db1.mydomain.comPORT=2000

注意在此之后,config.port将等于2001因为环境中的值优先于ini文件中的值。

缓存

第一次使用配置值时,将读取这些值。默认情况下,这是惰性求值,因此如果不需要,不会读取所有内容。

首次使用后,它们会被缓存在内存中,以便在再次使用配置值时不再有I/O。

对于Fail Fast行为,以及在应用程序中途读取配置值时停止意外延迟(例如,您的配置可能通过网络),该选项可用于在开始时读取所有配置值。只要打电话

config.read()

如果找不到任何必需的配置值,这将引发异常,并且还将在下次使用时将所有读取的配置值保留在内存中。如果不使用read则只有在首次尝试使用有问题的配置键时才会出现异常。

分层配置

使用组键来表示配置的"子配置"。按照上面的说明设置"sub configs",然后创建一个父配置,将它们组合到一个位置。

fromtypedconfigimportConfig,key,section,group_keyfromtypedconfig.sourceimportEnvironmentConfigSource,IniFileConfigSource@section('database')classDatabaseConfig(Config):host=key(cast=str)port=key(cast=int)@section('algorithm')classAlgorithmConfig(Config):max_value=key(cast=float)min_value=key(cast=float)classParentConfig(Config):database=group_key(DatabaseConfig)algorithm=group_key(AlgorithmConfig)description=key(cast=str,section_name="general")config=ParentConfig()config.add_source(EnvironmentConfigSource(prefix="EXAMPLE"))config.add_source(IniFileConfigSource("config.cfg"))config.read()

第一次访问config.databaseconfig.algorithm时(在上述情况下,当调用read()时),将实例化一个实例。请注意,它是类定义,而不是类的实例,传递给组键函数。

自定义节/键名称、可选参数、默认值

让我们看看这个:

fromtypedconfigimportConfig,key,section@section('database')classAppConfig(Config):host1=key()host2=key(section_name='database',key_name='HOST2',required=True,cast=str,default=None)

host1和host2都是合法的配置键定义。

  • 节名称-配置源中应该从中读取此参数的节的名称。这可以按键提供,但如果省略了,则使用@section装饰程序提供的节名称。如果所有键都提供一个节名,则不需要类装饰器。如果同时提供了section\u name和decorator,则优先使用section\u name参数。
  • key_name-从中读取此参数的配置源中的此密钥的名称。如果没有提供,某些魔术会使用对象属性名作为密钥名。
  • 必需-默认为true。如果为false,并且找不到配置值,则不会抛出错误,并且将使用默认值(如果提供)。如果未提供默认值,则将使用none
  • cast-可能是最重要的输入选项。如果需要自动完成键入支持,则必须指定此项。它只是一个函数,它接受一个字符串作为输入并返回一个已解析的值。有关更多信息,请参见"铸造"部分。如果未提供,则该值将保持为字符串。
  • 默认值-仅当必需值为false时才适用。当required为false时,如果找不到值,则使用此值。

类型

fromtypedconfigimportConfig,key,sectionfromtypingimportListdefsplit_str(s:str)->List[str]:return[x.strip()forxins.split(",")]@section('database')classAppConfig(Config):host=key()port=key(cast=int)users=key(cast=split_str)zero_based_index=key(cast=lambdax:int(x)-1)config=AppConfig(sources=[...])

在本例中,我们有三种铸造方法:

  1. 一点也不选。默认情况下返回str,但您的ide不会知道,因此如果您想要类型提示,请使用cast=str
  2. 强制转换为内置类型,该类型可以接受字符串输入并对其进行解析,例如int
  3. 定义自定义函数。函数应该接受一个字符串输入并返回任何类型的一个输出。要获得类型提示,只需确保函数具有类型批注即可。
  4. 使用lambda表达式。类型推断可能起作用,也可能不起作用,这取决于您的表达式,因此,如果它不只是作为带有类型注释的函数来编写的话。

配置源

配置源是您的mainconfig类知道从哪里获取数据的方式。它们是完全可扩展的,因此您可以从任何您喜欢的地方读取配置—从数据库、从s3、任何您可以为其编写代码的地方。

在实例化配置后,将配置源提供给配置,但在之前,尝试从中读取任何数据:

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
0

或者您可以直接在构造函数中提供源,如下所示:

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
1

下面的做法是错误的,但是如果由于某种原因,您在读取配置源之后添加了其他配置源,或者由于某种原因需要刷新配置,则需要清除任何缓存值,以便强制重新读取配置。您可以通过

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
2

提供的配置源

环境配置源

这只是从环境变量中读取配置。

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
3

它只需要一个可选的输入参数,一个前缀。这有助于避免环境变量中的名称冲突。

  • 如果提供前缀,则环境变量的外观应类似于{prefix}{section}{key},例如export xyz_database\u port=2000
  • 如果没有提供前缀,则环境变量应该像{section}{key},例如导出数据库端口=2000

在文件配置源中

这将使用python内置的configparser从ini文件中读取。有关文件结构的详细信息,请阅读configparser的文档。

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
4
  • 第一个参数是文件名(绝对或相对于当前工作目录)。
  • 编码是文件的文本编码。configparser如果未提供,则使用默认值。
  • 必须存在-默认值true。如果找不到文件,默认情况下将引发错误。设置必须存在允许文件不存在,在这种情况下,此源将只报告它找不到任何配置值,并且您的配置类将继续查找下一个配置源

在字符串配置源中

它从字符串而不是文件中读取数据

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
5

dictconfigsource

最基本的源代码,完全在内存中,在编写测试时也很有用。它不区分大小写。

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
6

它需要数据类型dict[str,dict[str,str],即string\u value=d['section\u name']['key\u name']。所有数据都应以字符串数据的形式提供,以便以与数据来自文件或其他地方时相同的方式对其进行分析。

这是另一种提供默认值的方法,而不是在定义键时使用默认值选项。只需提供一个dictconfigsource作为最低优先级的源,包含您的默认值即可。

编写自己的configsources

提供了一个抽象基类configsource。您应该扩展它并实现方法get_config_value,如下所示,该方法接受一个节名和键名,并返回一个strconfig值,如果找不到该值,则返回none。如果找不到该值,则不应出错;如果在其任何其他可用源中仍找不到该值,则稍后将引发错误。为了方便用户,请尝试使源代码不区分大小写。

例如,这里概述了如何实现从json文件读取配置的源代码。使用\u init\uu方法提供源获取数据所需的任何信息,如文件名、API详细信息等。您可以在\u init\uuu方法中执行健全性检查,如果有问题则抛出错误。

# my_app/config.pyfromtypedconfigimportConfig,key,sectionfromtypedconfig.sourceimportEnvironmentConfigSource@section('database')classAppConfig(Config):host=key(cast=str)port=key(cast=int)timeout=key(cast=float)config=AppConfig()config.add_source(EnvironmentConfigSource())config.read()
7

其他配置源

为了保持键入的配置不依赖,需要附加依赖项的配置源位于单独的包中,这些包还将键入的配置作为依赖项。

以下列出:

<表><广告>PIP安装名称 导入名称说明 < /广告><正文>键入的配置aws源键入配置源使用boto3来配置源,例如从s3或dynamodb获取配置

贡献

欢迎提出新功能和请求。减贫战略必须包括测试。这是用Python3.7开发的,但Travis测试也用V3.6运行。

开发设置

  1. 克隆git存储库
  2. 创建虚拟环境
  3. 激活环境venv/scripts/activate
  4. 安装开发依赖项pip install-r requirements.txt

运行测试

pytest

带着掩护跑

pytest--cov

部署到pypi

如果没有,您需要pip安装绳线

  1. typedconfig/\u version.py中插入版本号
  2. 清除dist目录
  3. python setup.py sdist bdist_wheel
  4. 捆绳检查距离/*
  5. 上传到测试pypitween upload--repository url https://test.pypi.org/legacy/dist/*
  6. 在https://test.pypi.org/project/typed-config" rel="nofollow">https://test.pypi.org/project/typed-config"中检查所有的looks ok
  7. 上传到实时pypi捆绳上传dist/*

以下是关于将包发布到pypi的好教程。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java无法使用JAXB配置Moxy   java如何让我的简单Swing telnet客户端正确显示字符?   java中从可运行线程调用主线程的多线程处理   java数据源。EBJ3会话bean中的getConnection()   使用java和正则表达式从xml文件提取值时出现问题   java定制Jersy胡须Mvc   在Java中,“限制并发”是什么意思?   java有没有更干净的方法可以在这里使用Optional,而不在三个地方返回“NA”?   java Tomcat启动,然后崩溃,除非我打电话   java理解客户机和服务器   java时间戳将在视图对象>实体转换期间丢失   如何在java中返回布尔值(基元)?   java使用spring mvc设置日志记录,希望仅对我的代码进行跟踪/调试   用Jackson解析嵌套对象