使用 ConfigParser 将注释写入文件

发布于 2024-11-19 04:42:08 字数 729 浏览 8 评论 0原文

如何在节内向给定文件写入注释?

如果我有:

import ConfigParser
with open('./config.ini', 'w') as f:
    conf = ConfigParser.ConfigParser()
    conf.set('DEFAULT', 'test', 1)
    conf.write(f)

我将获取文件:

[DEFAULT]
test = 1

但是如何获取 [DEFAULT] 部分中包含注释的文件,例如:

[DEFAULT]
; test comment
test = 1

我知道我可以通过以下方式将代码写入文件:

import ConfigParser
with open('./config.ini', 'w') as f:
    conf = ConfigParser.ConfigParser()
    conf.set('DEFAULT', 'test', 1)
    conf.write(f)
    f.write('; test comment') # but this gets printed after the section key-value pairs

这是否有可能配置解析器?我不想尝试另一个模块,因为我需要尽可能保持我的程序为“库存”。

How can one write comments to a given file within sections?

If I have:

import ConfigParser
with open('./config.ini', 'w') as f:
    conf = ConfigParser.ConfigParser()
    conf.set('DEFAULT', 'test', 1)
    conf.write(f)

I will get the file:

[DEFAULT]
test = 1

But how can I get a file with comments inside [DEFAULT] section, like:

[DEFAULT]
; test comment
test = 1

I know I can write codes to files by doing:

import ConfigParser
with open('./config.ini', 'w') as f:
    conf = ConfigParser.ConfigParser()
    conf.set('DEFAULT', 'test', 1)
    conf.write(f)
    f.write('; test comment') # but this gets printed after the section key-value pairs

Is this a possibility with ConfigParser? And I don't want to try another module because I need to keep my program as "stock" as possible.

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

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

发布评论

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

评论(8

垂暮老矣 2024-11-26 04:42:08

如果版本>= 2.7,则可以使用allow_no_value选项

此代码片段:

import ConfigParser

config = ConfigParser.ConfigParser(allow_no_value=True)
config.add_section('default_settings')
config.set('default_settings', '; comment here')
config.set('default_settings', 'test', 1)
with open('config.ini', 'w') as fp:
    config.write(fp)


config = ConfigParser.ConfigParser(allow_no_value=True)
config.read('config.ini')
print config.items('default_settings')

将创建一个如下所示的ini文件:

[default_settings]
; comment here
test = 1

You can use the allow_no_value option if you have Version >= 2.7

This snippet:

import ConfigParser

config = ConfigParser.ConfigParser(allow_no_value=True)
config.add_section('default_settings')
config.set('default_settings', '; comment here')
config.set('default_settings', 'test', 1)
with open('config.ini', 'w') as fp:
    config.write(fp)


config = ConfigParser.ConfigParser(allow_no_value=True)
config.read('config.ini')
print config.items('default_settings')

will create an ini file like this:

[default_settings]
; comment here
test = 1
从﹋此江山别 2024-11-26 04:42:08

3.7 的更新

我最近一直在处理 configparser 并遇到了这篇文章。我想我会用与 3.7 相关的信息来更新它。

示例 1:

config = configparser.ConfigParser(allow_no_value=True)
config.set('SECTION', '; This is a comment.', None)

示例 2:

config = configparser.ConfigParser(allow_no_value=True)
config['SECTION'] = {'; This is a comment':None, 'Option':'Value')

示例 3: 如果要保持字母大小写不变(默认是将所有选项:值对转换为小写)

config = configparser.ConfigParser(allow_no_value=True)
config.optionxform = str
config.set('SECTION', '; This Comment Will Keep Its Original Case', None)

其中“SECTION”是要添加注释的区分大小写的节名称。使用“None”(无引号)而不是空字符串 ('') 将允许您设置注释,而不会留下尾随“=”。

Update for 3.7

I've been dealing with configparser lately and came across this post. Figured I'd update it with information relevant to 3.7.

Example 1:

config = configparser.ConfigParser(allow_no_value=True)
config.set('SECTION', '; This is a comment.', None)

Example 2:

config = configparser.ConfigParser(allow_no_value=True)
config['SECTION'] = {'; This is a comment':None, 'Option':'Value')

Example 3: If you want to keep your letter case unchanged (default is to convert all option:value pairs to lowercase)

config = configparser.ConfigParser(allow_no_value=True)
config.optionxform = str
config.set('SECTION', '; This Comment Will Keep Its Original Case', None)

Where "SECTION" is the case-sensitive section name you want the comment added to. Using "None" (no quotes) instead of an empty string ('') will allow you to set the comment without leaving a trailing "=".

我爱人 2024-11-26 04:42:08

您还可以使用 ConfigUpdater。它有更多方便的选项以最小侵入的方式更新配置文件。

你基本上会这样做:

from configupdater import ConfigUpdater

updater = ConfigUpdater()
updater.add_section('DEFAULT')
updater.set('DEFAULT', 'test', 1)
updater['DEFAULT']['test'].add_before.comment('test comment', comment_prefix=';')
with open('./config.ini', 'w') as f:
    updater.write(f)

You could also use ConfigUpdater. It has many more convenience options to update configuration files in a minimal invasive way.

You would basically do:

from configupdater import ConfigUpdater

updater = ConfigUpdater()
updater.add_section('DEFAULT')
updater.set('DEFAULT', 'test', 1)
updater['DEFAULT']['test'].add_before.comment('test comment', comment_prefix=';')
with open('./config.ini', 'w') as f:
    updater.write(f)
无法言说的痛 2024-11-26 04:42:08

您可以创建以 # 或 ; 开头的变量字符:

conf.set('default_settings', '; comment here', '')
conf.set('default_settings', 'test', 1)

创建的conf文件是

    [default_settings]
    ; comment here = 
    test = 1

ConfigParser.read函数不会解析

config = ConfigParser.ConfigParser()
config.read('config.ini')
print config.items('default_settings')

给出的第一个值

[('test','1')]

You can create variable that starts by # or ; character:

conf.set('default_settings', '; comment here', '')
conf.set('default_settings', 'test', 1)

created conf file is

    [default_settings]
    ; comment here = 
    test = 1

ConfigParser.read function won't parse first value

config = ConfigParser.ConfigParser()
config.read('config.ini')
print config.items('default_settings')

gives

[('test','1')]
囍孤女 2024-11-26 04:42:08

extended-configparser 包处理在配置文件中写入、读取和调整注释。

from extended_configparser.parser import ExtendedConfigParser

# Load the config
parser = ExtendedConfigParser()
parser.read("myconfig.cfg")

# Use the configuration as usual
...

# Set sections / options together with comments
parser.add_section("Section.New", comment="New Section with a comment")
parser.set("Section.New", "new_option", "new_value", comment="New value with new comment")

# Access and alter the comments of a section or an option
comment = config.get_comment("Section.A")
parser.set_comment("Section.A", comment = "New Section Comment")
parser.set_comment("Section.A", "option1", comment = "New option comment")

# Save the config back to the file
with open("myconfig.cfg", "w") as savefile:
    config.write(savefile)

此代码将产生如下配置:

# New Section Comment
[Section.A]
# Old multiline comment
# of this option
option1 = value1
# New option2 comment
option2 = value2

# New Section with a comment
[Section.New]
# New value with new comment
new_option = new_value

The extended-configparser package handles writing, reading and adjusting comments in a config file.

from extended_configparser.parser import ExtendedConfigParser

# Load the config
parser = ExtendedConfigParser()
parser.read("myconfig.cfg")

# Use the configuration as usual
...

# Set sections / options together with comments
parser.add_section("Section.New", comment="New Section with a comment")
parser.set("Section.New", "new_option", "new_value", comment="New value with new comment")

# Access and alter the comments of a section or an option
comment = config.get_comment("Section.A")
parser.set_comment("Section.A", comment = "New Section Comment")
parser.set_comment("Section.A", "option1", comment = "New option comment")

# Save the config back to the file
with open("myconfig.cfg", "w") as savefile:
    config.write(savefile)

This code will result in a config like that:

# New Section Comment
[Section.A]
# Old multiline comment
# of this option
option1 = value1
# New option2 comment
option2 = value2

# New Section with a comment
[Section.New]
# New value with new comment
new_option = new_value
时光匆匆的小流年 2024-11-26 04:42:08

上述问题的奇怪解决方案:)
注意 有一个 副作用看看这是否适合您

config = configparser.ConfigParser(comment_prefixes='///')
config.set('section', '# cmt', 'comment goes here')

configparse 会将注释视为变量,但是真实的软件不会。
这甚至会保留读取同一个 ini 文件后写入的注释,这是一个真正的游戏规则改变者(消失的注释太可怕了):) 并且您不需要执行 allow_no_value=True允许空值,只是较小的视觉糖果:)

所以ini文件看起来像:

[section]
# cmt = comment goes here

这几乎完成了工作:)
请确保使用永远不会出现在 ini 文件中的字符串初始化 comment_prefixes ,以防万一

这在 3.9 中对我有用。

副作用 对写入已有评论。它们不会消失,这是正常的默认值,但会转换为类似的形式 #first =,其中 first - 评论的第一个单词,剩余 - 注释的剩余部分,这会改变文件的外观,所以要小心...

Freaky solution for the above :)
Note there is a side-effect, see if that suites you

config = configparser.ConfigParser(comment_prefixes='///')
config.set('section', '# cmt', 'comment goes here')

configparse will treat comments as variables, but real software would not.
This would even preserve the comments on writes done after read of the same ini file, which is a real game changer (disappearing comments are just horrible) :) and you don't need to do allow_no_value=True to allow empty value, just minor visual candy :)

so the ini file would look like:

[section]
# cmt = comment goes here

which pretty much gets the job done :)
please make sure to initialize comment_prefixes with a string that would never appear in your ini file just in case

This worked for me in 3.9.

Side effect on writing the already existing comments. They would not disappear which was normal default, but will be converted to a similar form # first = <remaining>, where first - first word of comment, remaining - remaining of the comment, which would change how file looks, so be carefull...

却一份温柔 2024-11-26 04:42:08

由于您希望使您的应用程序尽可能保持“库存”(不使用外部库),因此您可能希望对 ConfigParser 进行子类化,以允许在保留注释的情况下读取/更新/写入。

例如,就像我在这个要点中所做的那样。它有一个限制。它不支持缩进的节标题、注释和键。它们不应有前导空格。

class CommentConfigParser(configparser.ConfigParser):
"""Comment preserving ConfigParser.

Limitation: No support for indenting section headers,
comments and keys. They should have no leading whitespace.
"""

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # Backup _comment_prefixes
    self._comment_prefixes_backup = self._comment_prefixes
    # Unset _comment_prefixes so comments won't be skipped
    self._comment_prefixes = ()
    # Template to store comments as key value pair
    self._comment_template = "#{0} = {1}"
    # Regex to match the comment id prefix
    self._comment_regex = re.compile(r"^#\d+\s*=\s*")
    # List to store comments above the first section
    self._top_comments = []

def _read(self, fp, fpname):
    lines = fp.readlines()
    above_first_section = True
    # Preprocess config file to preserve comments
    for i, line in enumerate(lines):
        if line.startswith("["):
            above_first_section = False
        elif line.startswith(self._comment_prefixes_backup):
            if above_first_section:
                # Remove this line for now
                lines[i] = ""
                self._top_comments.append(line)
            else:
                # Store comment as value with unique key based on line number
                lines[i] = self._comment_template.format(i, line)

    # Feed the preprocessed file to the original _read method
    return super()._read(io.StringIO("".join(lines)), fpname)

def write(self, fp, space_around_delimiters=True):
    # Write the config to an in-memory file
    with io.StringIO() as sfile:
        super().write(sfile, space_around_delimiters)
        # Start from the beginning of sfile
        sfile.seek(0)
        lines = sfile.readlines()

    for i, line in enumerate(lines):
        # Remove the comment id prefix
        lines[i] = self._comment_regex.sub("", line, 1)

    fp.write("".join(self._top_comments + lines))

您可以像这样使用它来编写带有注释的配置文件:

parser = CommentConfigParser()
parser.read_string("""
[DEFAULT]
; test comment
test = 1
""")

with open('./config.ini', 'w') as f:
    parser.write(f)

Since you want to keep your application as "stock" as possible (not using external library), you may want to subclass the ConfigParser to allow reading/updating/writing with comments preserved.

For example like I did in this Gist. It has one limitation. It does not support indented section headers, comments and keys. They should have no leading whitespace.

class CommentConfigParser(configparser.ConfigParser):
"""Comment preserving ConfigParser.

Limitation: No support for indenting section headers,
comments and keys. They should have no leading whitespace.
"""

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    # Backup _comment_prefixes
    self._comment_prefixes_backup = self._comment_prefixes
    # Unset _comment_prefixes so comments won't be skipped
    self._comment_prefixes = ()
    # Template to store comments as key value pair
    self._comment_template = "#{0} = {1}"
    # Regex to match the comment id prefix
    self._comment_regex = re.compile(r"^#\d+\s*=\s*")
    # List to store comments above the first section
    self._top_comments = []

def _read(self, fp, fpname):
    lines = fp.readlines()
    above_first_section = True
    # Preprocess config file to preserve comments
    for i, line in enumerate(lines):
        if line.startswith("["):
            above_first_section = False
        elif line.startswith(self._comment_prefixes_backup):
            if above_first_section:
                # Remove this line for now
                lines[i] = ""
                self._top_comments.append(line)
            else:
                # Store comment as value with unique key based on line number
                lines[i] = self._comment_template.format(i, line)

    # Feed the preprocessed file to the original _read method
    return super()._read(io.StringIO("".join(lines)), fpname)

def write(self, fp, space_around_delimiters=True):
    # Write the config to an in-memory file
    with io.StringIO() as sfile:
        super().write(sfile, space_around_delimiters)
        # Start from the beginning of sfile
        sfile.seek(0)
        lines = sfile.readlines()

    for i, line in enumerate(lines):
        # Remove the comment id prefix
        lines[i] = self._comment_regex.sub("", line, 1)

    fp.write("".join(self._top_comments + lines))

You'd use it like this to write a config file with comments:

parser = CommentConfigParser()
parser.read_string("""
[DEFAULT]
; test comment
test = 1
""")

with open('./config.ini', 'w') as f:
    parser.write(f)
墨洒年华 2024-11-26 04:42:08

在Python3.11中,您可以使用inline_comment_prefixescomment_prefixes来指定注释和内联commnet以什么开头。

[Section] ; section
; comment
option = 1 ; comment
option2 = 2 # comment
from configparser import ConfigParser

config = ConfigParser(inline_comment_prefixes=('#', ';'))
config.read('pg.ini')
print(config.get('Section', 'option'))

With Python3.11, you can use inline_comment_prefixes and comment_prefixes to specify what comment and inline commnet starts with.

[Section] ; section
; comment
option = 1 ; comment
option2 = 2 # comment
from configparser import ConfigParser

config = ConfigParser(inline_comment_prefixes=('#', ';'))
config.read('pg.ini')
print(config.get('Section', 'option'))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文