Python 配置解析器(重复键支持)

发布于 2024-10-25 00:06:44 字数 802 浏览 7 评论 0原文

所以我最近开始为我正在开发的一个 Python 项目编写一个配置解析器。我最初避免使用 configparser 和 configobj,因为我想支持这样的配置文件:

key=value
key2=anothervalue

food=burger
food=hotdog
food=cake icecream

简而言之,这个配置文件将经常通过 SSH 的命令行进行编辑。因此,我不想对空格进行制表符或挑剔(如 YAML),但我也希望避免在 vi 中换行具有多个值(很容易是 10 个或更多)的键。这就是为什么我想支持重复键。

在我的理想世界中,当我向 Python 配置对象请求食物时,它会给我一个包含 ['burger', 'hotdog', 'cake', 'icecream'] 的列表。如果没有定义食物值,它会在默认配置文件中查找并给我那个/那些值。

我已经实现了上述内容

但是,当我意识到我想支持保留内联注释等时,我的麻烦就开始了。我处理读取和写入配置文件的方式是将文件解码为内存中的字典,从字典中读取值,或将值写入字典,然后将该字典转储回文件中。这对于保留行顺序和评论等来说并不是很好,而且它让我烦恼不已。

A) ConfigObj 看起来除了支持重复键之外它拥有我需要的一切。相反,它希望我制作一个列表,由于换行,在 vi 中通过 ssh 手动编辑会很痛苦。我可以让 configobj 对 ssh/vi 更加友好吗?

B)我的自制解决方案是否错误?有没有更好的方法来读取/写入/存储我的配置值?是否有任何简单的方法可以通过修改该行并从内存中重写整个配置文件来处理更改配置文件中的键值?

So I recently started writing a config parser for a Python project I'm working on. I initially avoided configparser and configobj, because I wanted to support a config file like so:

key=value
key2=anothervalue

food=burger
food=hotdog
food=cake icecream

In short, this config file is going to be edited via the command line over SSH often. So I don't want to tab or finicky about spacing (like YAML), but I also want avoid keys with multiple values (easily 10 or more) being line wrapped in vi. This is why I would like to support duplicate keys.

An my ideal world, when I ask the Python config object for food, it would give me a list back with ['burger', 'hotdog', 'cake', 'icecream']. If there wasn't a food value defined, it would look in a defaults config file and give me that/those values.

I have already implemented the above

However, my troubles started when I realized I wanted to support preserving inline comments and such. The way I handle reading and writing to the config files, is decoding the file into a dict in memory, read the values from the dict, or write values to the dict, and then dump that dict back out into a file. This isn't really nice for preserving line order and commenting and such and it's bugging the crap out of me.

A) ConfigObj looks like it has everything I need except support duplicate keys. Instead it wants me to make a list is going to be a pain to edit manually in vi over ssh due to line wrapping. Can I make configobj more ssh/vi friendly?

B) Is my homebrew solution wrong? Is there a better way of reading/writing/storing my config values? Is there any easy way to handle changing a key value in a config file by just modifying that line and rewriting the entire config file from memory?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

转瞬即逝 2024-11-01 00:06:44

如果可以的话,我当然会尝试利用标准库中的内容。

配置解析器类的签名如下所示:

class ConfigParser.SafeConfigParser([defaults[, dict_type[, allowed_no_value]]])

请注意 dict_type 参数。如果提供,它将用于构造节列表、节内选项以及默认值的字典对象。它默认为collections.OrderedDict。也许您可以在其中传递一些内容来获得所需的多键行为,然后获得 ConfigParser 的所有优势。您可能必须编写自己的类才能执行此操作,或者您可能会在 PyPi 或 ActiveState 配方中找到为您编写的类。尝试寻找包包或多组课程。

我要么走那条路,要么就忍气吞声,列个清单:

foo = value1, value2, value3

Well I would certainly try to leverage what is in the standard library if I could.

The signature for the config parser classes look like this:

class ConfigParser.SafeConfigParser([defaults[, dict_type[, allow_no_value]]])

Notice the dict_type argument. When provided, this will be used to construct the dictionary objects for the list of sections, for the options within a section, and for the default values. It defaults to collections.OrderedDict. Perhaps you could pass something in there to get your desired multiple-key behavior, and then reap all the advantages of ConfigParser. You might have to write your own class to do this, or you could possibly find one written for you on PyPi or in the ActiveState recipes. Try looking for a bag or multiset class.

I'd either go that route or just suck it up and make a list:

foo = value1, value2, value3
海拔太高太耀眼 2024-11-01 00:06:44

疯狂的想法:将你的字典值设置为包含行号、列号和值本身的三元组列表,并添加特殊键进行注释。

CommentSymbol = ';'
def readConfig(filename):
    f = open(filename, 'r')
    if not f:
        return
    def addValue(dict, key, lineIdx, colIdx, value):
        if key in dict:
            dict[key].append((lineIdx, colIdx, value))
        else:
            dict[key] = [(lineIdx, colIdx, value)]
    res = {}
    i = 0
    for line in f.readlines():
        idx = line.find(CommentSymbol)
        if idx != -1:
            comment = line[idx + 1:]
            addValue(res, CommentSymbol, i, idx, comment)
            line = line[:idx]
        pair = [x.strip() for x in line.split('=')][:2]
        if len(pair) == 2:
            addValue(res, pair[0], i, 0, pair[1])
        i += 1
    return res

def writeConfig(dict, filename):
    f = open(filename, 'w')
    if not f:
        return
    index = sorted(dict.iteritems(), cmp = lambda x, y: cmp(x[1][:2], y[1][:2]))
    i = 0
    for k, V in index:
        for v in V:
            if v[0] > i:
                f.write('\n' * (v[0] - i - 1))
            if k == CommentSymbol:
                f.write('{0}{1}'.format(CommentSymbol, str(v[2])))
            else:
                f.write('{0} = {1}'.format(str(k), str(v[2])))
            i = v[0]
    f.close() 

Crazy idea: make your dictionary values as a list of 3-tuples with line number, col number and value itself and add special key for comment.

CommentSymbol = ';'
def readConfig(filename):
    f = open(filename, 'r')
    if not f:
        return
    def addValue(dict, key, lineIdx, colIdx, value):
        if key in dict:
            dict[key].append((lineIdx, colIdx, value))
        else:
            dict[key] = [(lineIdx, colIdx, value)]
    res = {}
    i = 0
    for line in f.readlines():
        idx = line.find(CommentSymbol)
        if idx != -1:
            comment = line[idx + 1:]
            addValue(res, CommentSymbol, i, idx, comment)
            line = line[:idx]
        pair = [x.strip() for x in line.split('=')][:2]
        if len(pair) == 2:
            addValue(res, pair[0], i, 0, pair[1])
        i += 1
    return res

def writeConfig(dict, filename):
    f = open(filename, 'w')
    if not f:
        return
    index = sorted(dict.iteritems(), cmp = lambda x, y: cmp(x[1][:2], y[1][:2]))
    i = 0
    for k, V in index:
        for v in V:
            if v[0] > i:
                f.write('\n' * (v[0] - i - 1))
            if k == CommentSymbol:
                f.write('{0}{1}'.format(CommentSymbol, str(v[2])))
            else:
                f.write('{0} = {1}'.format(str(k), str(v[2])))
            i = v[0]
    f.close() 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文