使用ConfigParser读取没有节名的文件

发布于 2024-09-02 21:07:11 字数 307 浏览 7 评论 0原文

我正在使用 ConfigParser 来读取脚本的运行时配置。

我希望具有不提供部分名称的灵活性(有些脚本足够简单;它们不需要“部分”)。 ConfigParser 将抛出 NoSectionError 异常,并且不会接受该文件。

如何使 ConfigParser 简单地检索配置文件的 (key, value) 元组而无需部分名称?

例如:

key1=val1
key2:val2

我宁愿不写入配置文件。

I am using ConfigParser to read the runtime configuration of a script.

I would like to have the flexibility of not providing a section name (there are scripts which are simple enough; they don't need a 'section'). ConfigParser will throw a NoSectionError exception, and will not accept the file.

How can I make ConfigParser simply retrieve the (key, value) tuples of a config file without section names?

For instance:

key1=val1
key2:val2

I would rather not write to the config file.

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

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

发布评论

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

评论(8

め可乐爱微笑 2024-09-09 21:07:11

您可以在一行代码中完成此操作。

(但 tomllib 可能是更好的选择。请参阅我答案的底部。)

在 python 3 中,在您的配置文件数据中添加一个假节头,并将其传递给 read_string()< /a>.

from configparser import ConfigParser

parser = ConfigParser()
with open("foo.conf") as stream:
    parser.read_string("[top]\n" + stream.read())  # This line does the trick.

您还可以使用 itertools.chain()< /a> 模拟 read_file() 的节标题。这可能比上述方法更节省内存,如果您在受限的运行时环境中有大型配置文件,这可能会有所帮助。

from configparser import ConfigParser
from itertools import chain

parser = ConfigParser()
with open("foo.conf") as lines:
    lines = chain(("[top]",), lines)  # This line does the trick.
    parser.read_file(lines)

在 python 2 中,在配置文件数据前面添加一个假节标头,将结果包装在 < code>StringIO 对象,并将其传递给 readfp()

from ConfigParser import ConfigParser
from StringIO import StringIO

parser = ConfigParser()
with open("foo.conf") as stream:
    stream = StringIO("[top]\n" + stream.read())  # This line does the trick.
    parser.readfp(stream)

使用任何这些方法,您的配置设置都将在 parser.items('top') 中可用。

您也可以在 python 3 中使用 StringIO,也许是为了与新旧 python 解释器兼容,但请注意,它现在位于 io 包中,并且 readfp() 是现在已弃用。

或者,您可以考虑使用 TOML 解析器而不是 ConfigParser。 Python 3.11 在标准库中添加了解析器: tomllib

You can do this in a single line of code.

(But tomllib is probably a better choice. See the bottom of my answer.)

In python 3, prepend a fake section header to your config file data, and pass it to read_string().

from configparser import ConfigParser

parser = ConfigParser()
with open("foo.conf") as stream:
    parser.read_string("[top]\n" + stream.read())  # This line does the trick.

You could also use itertools.chain() to simulate a section header for read_file(). This might be more memory-efficient than the above approach, which might be helpful if you have large config files in a constrained runtime environment.

from configparser import ConfigParser
from itertools import chain

parser = ConfigParser()
with open("foo.conf") as lines:
    lines = chain(("[top]",), lines)  # This line does the trick.
    parser.read_file(lines)

In python 2, prepend a fake section header to your config file data, wrap the result in a StringIO object, and pass it to readfp().

from ConfigParser import ConfigParser
from StringIO import StringIO

parser = ConfigParser()
with open("foo.conf") as stream:
    stream = StringIO("[top]\n" + stream.read())  # This line does the trick.
    parser.readfp(stream)

With any of these approaches, your config settings will be available in parser.items('top').

You could use StringIO in python 3 as well, perhaps for compatibility with both old and new python interpreters, but note that it now lives in the io package and readfp() is now deprecated.

Alternatively, you might consider using a TOML parser instead of ConfigParser. Python 3.11 added a parser to the standard library: tomllib

予囚 2024-09-09 21:07:11

Alex Martelli 提供了一个解决方案使用 ConfigParser 解析 .properties 文件(显然是无节配置文件)。

他的解决方案是一个类似文件的包装器,它将自动插入一个虚拟节标题以满足ConfigParser的要求。

Alex Martelli provided a solution for using ConfigParser to parse .properties files (which are apparently section-less config files).

His solution is a file-like wrapper that will automagically insert a dummy section heading to satisfy ConfigParser's requirements.

南风几经秋 2024-09-09 21:07:11

受到 jterrace 的回答的启发,我提出了这个解决方案:

  1. 将整个文件读入字符串
  2. 带有默认部分名称的前缀
  3. 使用 StringIO模仿类似文件的对象
ini_str = '[root]\n' + open(ini_path, 'r').read()
ini_fp = StringIO.StringIO(ini_str)
config = ConfigParser.RawConfigParser()
config.readfp(ini_fp)

为未来的 Google 用户进行编辑:从 Python 3.4+ 开始,readfp 已弃用,并且不再需要 StringIO。相反,我们可以直接使用 read_string

with open('config_file') as f:
    file_content = '[dummy_section]\n' + f.read()

config_parser = ConfigParser.RawConfigParser()
config_parser.read_string(file_content)

Enlightened by this answer by jterrace, I come up with this solution:

  1. Read entire file into a string
  2. Prefix with a default section name
  3. Use StringIO to mimic a file-like object
ini_str = '[root]\n' + open(ini_path, 'r').read()
ini_fp = StringIO.StringIO(ini_str)
config = ConfigParser.RawConfigParser()
config.readfp(ini_fp)

EDIT for future googlers: As of Python 3.4+ readfp is deprecated, and StringIO is not needed anymore. Instead we can use read_string directly:

with open('config_file') as f:
    file_content = '[dummy_section]\n' + f.read()

config_parser = ConfigParser.RawConfigParser()
config_parser.read_string(file_content)
姜生凉生 2024-09-09 21:07:11

您可以使用 ConfigObj 库来简单地做到这一点:http://www.voidspace.org。 uk/python/configobj.html

更新:此处查找最新代码。

如果您使用的是 Debian/Ubuntu,您可以使用包管理器安装此模块:

apt-get install python-configobj

使用示例:

from configobj import ConfigObj

config = ConfigObj('myConfigFile.ini')
config.get('key1') # You will get val1
config.get('key2') # You will get val2

You can use the ConfigObj library to do that simply : http://www.voidspace.org.uk/python/configobj.html

Updated: Find latest code here.

If you are under Debian/Ubuntu, you can install this module using your package manager :

apt-get install python-configobj

An example of use:

from configobj import ConfigObj

config = ConfigObj('myConfigFile.ini')
config.get('key1') # You will get val1
config.get('key2') # You will get val2
无妨# 2024-09-09 21:07:11

在我看来,最简单的方法是使用 python 的 CSV 解析器。这是演示此方法的读/写函数以及测试驱动程序。如果值不允许是多行的话,这应该可以工作。 :)

import csv
import operator

def read_properties(filename):
    """ Reads a given properties file with each line of the format key=value.  Returns a dictionary containing the pairs.

    Keyword arguments:
        filename -- the name of the file to be read
    """
    result={ }
    with open(filename, "rb") as csvfile:
        reader = csv.reader(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
        for row in reader:
            if len(row) != 2:
                raise csv.Error("Too many fields on row with contents: "+str(row))
            result[row[0]] = row[1] 
    return result

def write_properties(filename,dictionary):
    """ Writes the provided dictionary in key-sorted order to a properties file with each line of the format key=value

    Keyword arguments:
        filename -- the name of the file to be written
        dictionary -- a dictionary containing the key/value pairs.
    """
    with open(filename, "wb") as csvfile:
        writer = csv.writer(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
        for key, value in sorted(dictionary.items(), key=operator.itemgetter(0)):
                writer.writerow([ key, value])

def main():
    data={
        "Hello": "5+5=10",
        "World": "Snausage",
        "Awesome": "Possum"
    }

    filename="test.properties"
    write_properties(filename,data)
    newdata=read_properties(filename)

    print "Read in: "
    print newdata
    print

    contents=""
    with open(filename, 'rb') as propfile:
        contents=propfile.read()
    print "File contents:"
    print contents

    print ["Failure!", "Success!"][data == newdata]
    return

if __name__ == '__main__': 
     main() 

The easiest way to do this is to use python's CSV parser, in my opinion. Here's a read/write function demonstrating this approach as well as a test driver. This should work provided the values are not allowed to be multi-line. :)

import csv
import operator

def read_properties(filename):
    """ Reads a given properties file with each line of the format key=value.  Returns a dictionary containing the pairs.

    Keyword arguments:
        filename -- the name of the file to be read
    """
    result={ }
    with open(filename, "rb") as csvfile:
        reader = csv.reader(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
        for row in reader:
            if len(row) != 2:
                raise csv.Error("Too many fields on row with contents: "+str(row))
            result[row[0]] = row[1] 
    return result

def write_properties(filename,dictionary):
    """ Writes the provided dictionary in key-sorted order to a properties file with each line of the format key=value

    Keyword arguments:
        filename -- the name of the file to be written
        dictionary -- a dictionary containing the key/value pairs.
    """
    with open(filename, "wb") as csvfile:
        writer = csv.writer(csvfile, delimiter='=', escapechar='\\', quoting=csv.QUOTE_NONE)
        for key, value in sorted(dictionary.items(), key=operator.itemgetter(0)):
                writer.writerow([ key, value])

def main():
    data={
        "Hello": "5+5=10",
        "World": "Snausage",
        "Awesome": "Possum"
    }

    filename="test.properties"
    write_properties(filename,data)
    newdata=read_properties(filename)

    print "Read in: "
    print newdata
    print

    contents=""
    with open(filename, 'rb') as propfile:
        contents=propfile.read()
    print "File contents:"
    print contents

    print ["Failure!", "Success!"][data == newdata]
    return

if __name__ == '__main__': 
     main() 
裂开嘴轻声笑有多痛 2024-09-09 21:07:11

我自己也遇到了这个问题,我为 ConfigParser (Python 2 中的版本)编写了一个完整的包装器,它可以透明地读取和写入没有节的文件,基于 Alex Martelli 的方法(链接到已接受的答案)。它应该是 ConfigParser 任何用法的直接替代品。发布它以防任何需要的人找到此页面。

import ConfigParser
import StringIO

class SectionlessConfigParser(ConfigParser.RawConfigParser):
    """
    Extends ConfigParser to allow files without sections.

    This is done by wrapping read files and prepending them with a placeholder
    section, which defaults to '__config__'
    """

    def __init__(self, *args, **kwargs):
        default_section = kwargs.pop('default_section', None)
        ConfigParser.RawConfigParser.__init__(self, *args, **kwargs)

        self._default_section = None
        self.set_default_section(default_section or '__config__')

    def get_default_section(self):
        return self._default_section

    def set_default_section(self, section):
        self.add_section(section)

        # move all values from the previous default section to the new one
        try:
            default_section_items = self.items(self._default_section)
            self.remove_section(self._default_section)
        except ConfigParser.NoSectionError:
            pass
        else:
            for (key, value) in default_section_items:
                self.set(section, key, value)

        self._default_section = section

    def read(self, filenames):
        if isinstance(filenames, basestring):
            filenames = [filenames]

        read_ok = []
        for filename in filenames:
            try:
                with open(filename) as fp:
                    self.readfp(fp)
            except IOError:
                continue
            else:
                read_ok.append(filename)

        return read_ok

    def readfp(self, fp, *args, **kwargs):
        stream = StringIO()

        try:
            stream.name = fp.name
        except AttributeError:
            pass

        stream.write('[' + self._default_section + ']\n')
        stream.write(fp.read())
        stream.seek(0, 0)

        return ConfigParser.RawConfigParser.readfp(self, stream, *args,
                                                   **kwargs)

    def write(self, fp):
        # Write the items from the default section manually and then remove them
        # from the data. They'll be re-added later.
        try:
            default_section_items = self.items(self._default_section)
            self.remove_section(self._default_section)

            for (key, value) in default_section_items:
                fp.write("{0} = {1}\n".format(key, value))

            fp.write("\n")
        except ConfigParser.NoSectionError:
            pass

        ConfigParser.RawConfigParser.write(self, fp)

        self.add_section(self._default_section)
        for (key, value) in default_section_items:
            self.set(self._default_section, key, value)

Having ran into this problem myself, I wrote a complete wrapper to ConfigParser (the version in Python 2) that can read and write files without sections transparently, based on Alex Martelli's approach linked on the accepted answer. It should be a drop-in replacement to any usage of ConfigParser. Posting it in case anyone in need of that finds this page.

import ConfigParser
import StringIO

class SectionlessConfigParser(ConfigParser.RawConfigParser):
    """
    Extends ConfigParser to allow files without sections.

    This is done by wrapping read files and prepending them with a placeholder
    section, which defaults to '__config__'
    """

    def __init__(self, *args, **kwargs):
        default_section = kwargs.pop('default_section', None)
        ConfigParser.RawConfigParser.__init__(self, *args, **kwargs)

        self._default_section = None
        self.set_default_section(default_section or '__config__')

    def get_default_section(self):
        return self._default_section

    def set_default_section(self, section):
        self.add_section(section)

        # move all values from the previous default section to the new one
        try:
            default_section_items = self.items(self._default_section)
            self.remove_section(self._default_section)
        except ConfigParser.NoSectionError:
            pass
        else:
            for (key, value) in default_section_items:
                self.set(section, key, value)

        self._default_section = section

    def read(self, filenames):
        if isinstance(filenames, basestring):
            filenames = [filenames]

        read_ok = []
        for filename in filenames:
            try:
                with open(filename) as fp:
                    self.readfp(fp)
            except IOError:
                continue
            else:
                read_ok.append(filename)

        return read_ok

    def readfp(self, fp, *args, **kwargs):
        stream = StringIO()

        try:
            stream.name = fp.name
        except AttributeError:
            pass

        stream.write('[' + self._default_section + ']\n')
        stream.write(fp.read())
        stream.seek(0, 0)

        return ConfigParser.RawConfigParser.readfp(self, stream, *args,
                                                   **kwargs)

    def write(self, fp):
        # Write the items from the default section manually and then remove them
        # from the data. They'll be re-added later.
        try:
            default_section_items = self.items(self._default_section)
            self.remove_section(self._default_section)

            for (key, value) in default_section_items:
                fp.write("{0} = {1}\n".format(key, value))

            fp.write("\n")
        except ConfigParser.NoSectionError:
            pass

        ConfigParser.RawConfigParser.write(self, fp)

        self.add_section(self._default_section)
        for (key, value) in default_section_items:
            self.set(self._default_section, key, value)
缺⑴份安定 2024-09-09 21:07:11

Blueicefield的答案提到了configobj,但原始lib仅支持Python 2。它现在有Python 3+兼容端口:

https: //github.com/DiffSK/configobj

API 没有改变,看它是 文档

Blueicefield's answer mentioned configobj, but the original lib only supports Python 2. It now has a Python 3+ compatible port:

https://github.com/DiffSK/configobj

APIs haven't changed, see it's doc.

〃温暖了心ぐ 2024-09-09 21:07:11

Python 的开发版本(3.13)终于支持不带节的文件。

https://docs.python.org/3.13/library/configparser。 html#unnamed-sections

The development version of Python (3.13) finally support files without sections.

https://docs.python.org/3.13/library/configparser.html#unnamed-sections

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文