Pythonic方法将命令行输出解析为容器对象

时间:2015-08-10 17:21:39

标签: python parsing object dictionary properties

请在回答之前阅读整个问题,因为它不是您的想法......我正在考虑创建代表系统上硬件设备的python对象包装器(下面的修剪示例)。

class TPM(object):

    @property
    def attr1(self):
        """
        Protects value from being accidentally modified after 
        constructor is called.
        """
        return self._attr1

    def __init__(self, attr1, ...):
        self._attr1 = attr1
        ...

    @classmethod
    def scan(cls):
        """Calls Popen, parses to dict, and passes **dict to constructor"""

大多数构造函数输入涉及在subprocess.Popen中运行命令行输出,然后解析输出以填充对象属性。我已经提出了几种方法来处理这些问题,但我对我刚刚放在一起并试图找到更好的解决方案感到不满意。以下是我发现的常见捕获量。 (快速注意:工具版本受到严格控制,因此解析后的输出不会意外更改。)

  1. 许多工具产生变体输出,有时包括字段,有时不包括字段。这意味着如果你组装一个dict来包装在一个容器对象中,那么构造函数或多或少地被迫接受** kwargs并且没有真正定义的字段。我不喜欢这样,因为它通过pylint等进行静态分析并不是很有用。我更喜欢定义的界面,以便狮身人面像文档更清晰,并且可以更可靠地检测错误。

  2. 除了** kwargs之外,我还尝试将许多字段的默认args设置为None,最终结果非常难看。我不喜欢这个选项的一件事是可选字段总是不在命令行工具输出的末尾。这使得查看构造函数并将其与工具输出相匹配有点令人费解。

  3. 我非常希望避免首先构建字典,但使用setattr创建属性会使pylint无法检测_attr1等等并创建警告。欢迎任何想法......

  4. 基本上,我正在寻找合适的Pythonic方法来做到这一点。我的要求,重新总结如下:

    1. 解析为容器对象的命令行工具输出。
    2. Container对象通过构造后的属性保护属性。
    3. 构造函数的输入数量不同,在运行期间对缺少的必填字段进行静态分析和错误检测。
    4. 在Python中有没有一种很好的方法(希望没有大量的样板代码)?如果是这样,它是什么?

      编辑:

      根据一些澄清请求,我们可以看一下tpm_version命令。这是我的笔记本电脑的输出,但对于这个TPM,它并没有包含所有可能的属性。有时,该命令将返回我还想捕获的额外属性。这使得解析容器对象上的已知属性名称相当困难。

      TPM 1.2 Version Info:
      Chip Version:        1.2.4.40
      Spec Level:          2
      Errata Revision:     3
      TPM Vendor ID:       IFX
      Vendor Specific data: 04280077 0074706d 3631ffff ff
      TPM Version:         01010000
      Manufacturer Info:   49465800
      

      示例代码(请忽略缺乏完整性检查,为简洁而修剪):

      def __init__(self, chip_version, spec_level, errata_revision,
                   tpm_vendor_id, vendor_specific_data, tpm_version,
                   manufacturer_info):
          self._chip_version = chip_version
          ...
      
      @classmethod
      def scan(cls):
          tpm_proc = Popen("/usr/sbin/tpm_version")
          stdout, stderr = Popen.communicate()
      
          tpm_dict = dict()
          for line in tpm_proc.stdout.splitlines():
              if "Version Info:" in line:
                  pass
              else:
                  split_line = line.split(":")
                  attribute_name = (
                      split_line[0].strip().replace(' ', '_').lower())
                  tpm_dict[attribute_name] = split_line[1].strip()
          return cls(**tpm_dict)
      

      这里的问题是这个(或者我可能无法查看获取每个可能字段的来源的另一个)可能会添加额外的东西,导致我的解析器工作,但我的对象是不捕获字段。这就是我真正想要以优雅的方式解决的问题。

1 个答案:

答案 0 :(得分:0)

在过去的几个月里,我一直在为这个问题做出更加坚实的答案,因为我基本上在硬件支持库上工作,并且最终得到了一个令人满意的(虽然非常详细)答案。

  1. 将工具输出(无论它们看起来如何)解析为与工具查看设备的方式相匹配的对象结构。这些可以具有非常通用的字典结构,但应尽可能地分解。
  2. 在其上创建另一个容器类,该容器类使用属性来访问工具容器对象中的项目。这会强制执行A​​PI,并且可以跨工具的多个版本以及不同的工具输出返回合理的错误!