带环境变量的argparse

envargparse的Python项目详细描述


带环境变量的argparse。这个模块都是派生的argparse 类支持环境变量和一个框架或一组建议的 扩展argparse的增强功能。

示例

以下内容摘自本模块末尾的条件:

parser = EnvArgParser\
        ( prog="Test Program"
        , formatter_class=EnvArgDefaultsHelpFormatter
        )

parser.add_argument\
        ( '--bar'
        , required=True
        , env_var="BAR"
        , type=int
        , nargs="+"
        , default=22
        , help="Help message for bar."
        )

parser.add_argument\
        ( 'baz'
        , type=int
        )

args = parser.parse_args()
print(args)

示例输出:

$ BAR="1 2 3 '45  ' 6 7" ./envargparse.py 123
Namespace(bar=[1, 2, 3, 45, 6, 7], baz=123)
$ ./envargparse.py -h
usage: Test Program [-h] --bar BAR [BAR ...] baz

positional arguments:
  baz

optional arguments:
  -h, --help           show this help message and exit
  --bar BAR [BAR ...]  Help message for bar. (default: 22) (env_var: BAR)

工作原理

这个模块试图变得非常简单:它可能看起来更长,因为它有很好的注释。没有代码重复。实际上,版本0.1(标记)更简单:通过parse_args()的命名空间参数跟踪操作,保持优先级:

cmd args > env var > preexisting namespace > defaults
<>基本上,它存储在命名空间内,如果环境变量存在,每个动作都有一个环境变量密钥的唯一实例。在argparse完成解析之后,它将执行与每个剩余的唯一实例相关联的操作。想法是这样的:如果操作是通过命令行提供的,那么它将从命名空间中被覆盖。

如果需要,您仍然可以使用该版本,但它不处理未能在命名空间上设置dest属性的操作。公平地说,这样的行动是极不可能的。有一段时间,我为每个动作考虑了沙空拳空洞命名空间,只将 Dist属性复制回主命名空间,但这将是人为的限制。相反…

版本0.2(标记)是围绕跟踪操作构建的。是否已将操作视为命令行参数,以及调用操作的频率。信不信由你,有些边缘的情况下,一个行动可以看到,但没有调用。有关详细信息,请参见注释。

envargparser类维护所看到的操作集,而每个操作(不管是否环境变量键)都嵌入在跟踪对象中。最初是解析函数中的函数局部变量,看到的操作集被提升到实例命名空间中,并在每次新的解析过程之前重置。幸运的是,在看到一个操作和调用\u get_values之间有一个1:1的调用对应关系,它现在更新看到的操作集。每次调用时,每个跟踪对象都会增加一个计数器,否则其行为与包含的操作完全相同,转发(几乎)所有属性访问。

一个环境变量记录, EnValgEngs,附加到每个有效的环境变量操作,不管该环境变量是否实际存在——用于帮助格式化原因。只有当环境变量可用且尚未看到或调用该操作时,才会执行此类操作。

至于实际解析环境变量,在0.1到0.2之间没有太大的变化。由于每个操作都可以重写解析函数,因此默认的env var_parse是一个静态方法;第一个参数始终是解析器。默认值通过依赖内部的ArgumentParser方法模拟对ArgParse的解析(计算、转换和检查值),而不需要代码复制。其实很简单-只需要两个方法调用。参数是使用shlex拆分的,但是您的自定义解析器可以使用yaml、json或您喜欢的任何其他方法。不管是什么情况,解析函数都必须返回一个元组:结果值和一个额外值列表。由于额外的值通常会引发异常,您可以考虑将其保留为空。

基本上就是这样,除了值检查模板。从python 3.7开始,新引入的混合解析方法执行两步解析,强制envargparser跟踪解析“深度”。所看到的操作集仅在此两个过程之前被清除,环境变量仅在之后被解析-bo在最深处。

有一个将环境变量键添加到参数帮助的帮助格式化程序,以及一个将环境变量键和参数默认值都添加到类中的示例mix withargparse.argumentDefaultShelpFormatter。自定义帮助格式化程序只需从适当的基类继承即可创建。

接下来要做的只是锦上添花。虽然这个模块并没有实际使用它,也没有更改默认行为,但它是一个很好的展示,展示了什么是可能的,也许对用户定义的派生类是有用的。

原始的argumentparser是相对单一的,而envargparser则使用action和parser之间的协作oop来允许parser方法的每个action重写。虽然解析器通常会调用自己的方法,但现在它会调用到操作中。默认情况下,该操作从解析器的基类调用匹配方法,因此开箱即用没有行为更改。作为概念证明,这只适用于\u get_valuesget_values但如果有用,可以通过自定义的\u getattribute_uu扩展到所有方法。同时,可以添加其他方法,或者通过从envargparserenvargaction派生来重写默认行为。

建议

让我们退后一点。为什么不能使用参数默认值:

import argparse
import os

parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--foo", default=os.environ.get("FOO","bar"), help="FOO!")
parser.parse_args()

在默认值和环境之间创建一个人工依赖项。换句话说,这不是用户所期望的。注意默认值是如何保持不变的:

$ ./test.py -h
usage: test.py [-h] [--foo FOO]

optional arguments:
  -h, --help  show this help message and exit
  --foo FOO   FOO! (default: bar)
$ FOO=456 ./test.py -h
usage: test.py [-h] [--foo FOO]

optional arguments:
  -h, --help  show this help message and exit
  --foo FOO   FOO! (default: 456)

不幸的是,argparse太黑了,无法对其进行干净的修改,因此该模块充当了建议改进的工作路线图。要点:

  • 对解析更加透明。

    在实例名称空间中维护解析状态,例如所看到的操作集,而不是作为不可访问的方法变量。在多级解析期间跟踪解析深度。让基础动作类跟踪它被调用的频率。将核心解析方法标记为公共api的一部分。

  • 使解析更加模块化。

    为以下对象创建可重用的入口点(方法):

    • 正在分析单个可选参数。
    • 正在分析单个位置参数。
    • 基于参数值检查冲突。
    • 处理异常(作为装饰器)。

    现在代码太单一了。

  • 不要强制每个参数使用相同的解析链。

    允许操作重载重要的解析器方法,如\u get\u values\u get\u values.u match\u参数。

更重要的是:

  • 切换到新样式({})字符串格式。

    旧样式(%)字符串格式无法访问对象属性。\u get\u help\u string方法应返回一个格式字符串,该字符串将无法访问envargrecord的属性。

模块

代码注释很好,下面是提供的类的简短列表:

  • 环境记录
  • envargparser
  • 环境作用
  • 环境帮助格式化程序
  • envargdefaultshelpformatter
  • 容器

要求

  • Python 3.7+
  • module: decorator (@PyPI)

许可证

GPLv3+; see LICENSE.txt

作者

Yclept Nemo <pscjtwjdjtAhnbjm/dpn>

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

推荐PyPI第三方库


热门话题
java列排序不会忽略大写字母   JFrame中的JavaFX菜单   java My Freemarker无法将对象传递给模板   java SOAP API客户端请求创建问题addChildElement(org.w3c.dom.domeException:NAMESPACE\u ERR)   java双精度值不能转换为布尔值   java如何在JBOSS EAP 6.3中在一个安全域中配置多个登录模块?   datetime如何使用Java ZoneId。systemDefault()如果我的计算机未连接到Internet,是否知道时区?   java PlayFramework应用ClassLoader的演变   java正在向JPanel添加元素,但它们没有显示   java如何使异步侦听器执行阻塞?   json如何让JAXRS将Java8LocalDateTime属性作为JavaScriptstyle日期字符串返回?   java我可以构建一个ApacheAnt任务并在同一步中执行它吗?   java如何使用用户输入的字符串编码到程序中,并确保其中包含小数?   使用ArrayList的java ArrayAdapter   java Hibernate 5。x迁移建议脚本   使用wait()和notify()的java控制线程   SpringMVC在Java中通过jsp显示列表的问题   java如何设置Jsoup读取的数据编码?   java 安卓 AlertDialog显示两次