Python configparser:获取未使用条目的列表

Python configparser: get list of unused entries

我正在使用 Python 的 configparser 读取 ini 文件。

解析后,我想打印一个未被解析器使用的条目列表,以通知用户他们已将条目添加到他们的 ini 文件中,这些条目将被忽略。

考虑这样的 ini 文件:

[DEFAULT]
param1 = 1
param2 = 2
param3 = 3
param4 = 4

我想要的是:

parser = configparser.ConfigParser()
parser.read(config_path)    
p1 = parser["DEFAULT"]["param1"]
p2 = parser["DEFAULT"]["param2"]
unused = parser["DEFAULT"].get_unused_keys()

最后一行补上了。我希望变量 'unused' 包含

["param3", "param4"]

我没有在手册中找到任何提及此类功能的信息,但我会发现它非常有用。我可以继承自 ConfigParser 并扩展所有访问函数以具有一个标志来跟踪是否访问了特定项目,但我希望有一种更简单的方法。

我写了一个解决方案。它不是太优雅,但它有效。您需要从 RawConfigParser class 创建一个子 class 并在您的 class 中创建一个字典变量并扩展 get, _get 方法。正如您在下面看到的,当您使用 get, getint, getfloat, getboolean 方法获取变量的值时,相关方法会将部分和变量附加到您的字典中。当你调用 get_unused_keys 方法时,它会过滤一个部分中所有可用的选项,其中包含已使用的选项,并给出未使用的选项。

完整代码:

try:
    import ConfigParser as Cp
except ImportError:
    import configparser as Cp


class ConfigParser(Cp.RawConfigParser):
    """
    ConfigParser class contains the all ConfigParser related implementations.
    """

    used_vars = {}

    def get_unused_keys(self, section):
        all_sections = self.options(section)
        unused_options = [x for x in all_sections if x not in self.used_vars[section]]
        return unused_options

    def get(self, section, option, *, raw=False, vars=None, fallback=Cp._UNSET):
        if section not in self.used_vars:
            self.used_vars[section] = [option]
        else:
            self.used_vars[section].append(option)
        return super().get(section, option, raw=raw, vars=vars, fallback=fallback)

    def _get(self, section, conv, option, **kwargs):
        if section not in self.used_vars:
            self.used_vars[section] = [option]
        else:
            self.used_vars[section].append(option)
        return super()._get(section, conv, option, **kwargs)


parser = ConfigParser()
parser.read("test.ini")

p1 = parser.getint(section="TEST", option="param1")
print("TEST section - param1 = {}".format(p1))
p2 = parser.getboolean(section="TEST", option="param2")
print("TEST section - param2 = {}".format(p2))
print("Unused options in 'TEST' section: {}".format(parser.get_unused_keys("TEST")))
print("")
par2 = parser.get(section="TEST_SEC", option="param2")
print("TEST_SEC section - param2 = {}".format(par2))
print("Unused options in 'TEST_SEC' section: {}".format(parser.get_unused_keys("TEST_SEC")))

使用的ini文件:

[TEST]
param1 = 1
param2 = True
param3 = 3
param4 = False

[TEST_SEC]
param1 = 89
param2 = Hello World
param3 = 655

输出:

>>> python3 test.py 
TEST section - param1 = 1
TEST section - param2 = True
Unused options in 'TEST' section: ['param3', 'param4']

TEST_SEC section - param2 = Hello World
Unused options in 'TEST_SEC' section: ['param1', 'param3']

仅供参考:

你不应该使用 DEFAULT 作为部分的名称,因为它是一个特殊的部分,你可能会得到意想不到的行为。我在我的实现中添加了 _get 方法。如果您检查 ConfigParser 的原始实现,您可以看到所有类型特定 getter 使用此方法,因此足以更改。这意味着现在实现也支持 getint, getfloat, getboolean 方法。 希望我的回答对你有帮助!

创建一个 set 允许的密钥。然后创建一个 set 的已用密钥。从使用的键中减去允许的键。

In [1]: import configparser                                                                              

In [2]: config = configparser.ConfigParser()                                                             
Out[2]: <configparser.ConfigParser at 0x80a0624d0>

In [3]: config.read_string("""[DEFAULT] 
   ...: param1 = 1 
   ...: param2 = 2 
   ...: param3 = 3 
   ...: param4 = 4""")                                                                                   

In [4]: allowed_keys = {'param1', 'param2'}                                                              
Out[4]: {'param1', 'param2'}

In [5]: usedkeys = set(config['DEFAULT'].keys())                                                         
Out[5]: {'param1', 'param2', 'param3', 'param4'}

In [6]: illegal_keys = usedkeys - allowed_keys                                                           
Out[6]: {'param3', 'param4'}

使用相同的技术,您可以获得允许的部分名称,以及仅在某些部分中允许的参数。

例如,您可以将 allowed_keys 变成 dictsets:

In [7]: allowed_keys = {'DEFAULT': {'param1', 'param2'}, 'section1': {'param3', 'param4'}}               
Out[7]: {'DEFAULT': {'param1', 'param2'}, 'section1': {'param3', 'param4'}}

所以您可以先查看部分名称,然后查看允许部分的允许参数名称。