python - 在 python 包中添加和读取 config.ini 文件

标签 python python-2.7 import config configparser

我正在编写我的第一个 python 包,我想将它上传到 PyPI。我根据这个 blog post 构建了我的代码.

我想将用户设置存储在 config.ini 文件中。在同一包中的单独 python 模块中读取一次(每次运行包时),并将用户设置保存在该模块的全局变量中。稍后将它们导入其他模块。

为了重现错误,我刚刚在博文中描述的模板中编辑了几行代码。 (请引用它,因为在这里重新创建整个问题需要太多的输入。)

唯一的区别是我的 stuff.py 像这样从配置文件中读取:

from ConfigParser import SafeConfigParser

config = SafeConfigParser()
config.read('config.ini')

TEST_KEY = config.get('main', 'test_key')

这是 config.ini 的内容(与 stuff.py 放在同一目录中):

[main]
test_key=value

而我的 bootstrap.py 只是导入并打印 TEST_KEY

from .stuff import TEST_KEY

def main():
    print(TEST_KEY)

但是在执行包时,导入失败给出了这个错误

Traceback (most recent call last):
    File "D:\Coding\bootstrap\bootstrap-runner.py", line 8, in <module>
    from bootstrap.bootstrap import main
    File "D:\Coding\bootstrap\bootstrap\bootstrap.py", line 11, in <module>
    from .stuff import TEST_KEY
    File "D:\Coding\bootstrap\bootstrap\stuff.py", line 14, in <module>
    TEST_KEY = config.get('main', 'test_key')
    File "C:\Python27\Lib\ConfigParser.py", line 607, in get
    raise NoSectionError(section)
ConfigParser.NoSectionError: No section: 'main'

Import 不断给出 ConfigParser.NoSectionError,但是如果你只构建/运行 stuff.py(我使用 sublime3),模块不会给出错误并且打印 TEST_KEY 给出 value 作为输出。

此外,当我只在一个目录中使用 3 个文件(config、stuff、main)并将 main 作为脚本执行时,这种导入方法确实有效。但是我不得不像这样导入它

from stuff import TEST_KEY

我只是使用那篇文章中描述的显式相对导入,但对这些没有足够的理解。我猜错误是由于项目结构和导入引起的,因为作为独立脚本运行 stuff.py 不会引发 ConfigParser.NoSectionError

其他读取配置文件一次然后在其他模块中使用数据的方法也非常有用。

最佳答案

这个问题有两个方面。 首先ConfigParser 的奇怪行为。当ConfigParser 无法找到.ini 文件时;由于某些烦人的原因,它从不给出 IOError 或指示它无法读取文件的错误。

在我的例子中,当 section 明显存在时,它一直给出 ConfigParser.NoSectionError。当我发现 ConfigParser.NoSectionError 错误时,它给出了一个 ImportError!但它从不告诉您它根本无法读取文件。

其次是如何安全地读取包中包含的数据文件。我发现这样做的唯一方法是使用 __file__ 参数。对于 Python27 和 Python3,这就是您安全阅读上述问题中的 config.ini 的方式:

import os

try:
    # >3.2
    from configparser import ConfigParser
except ImportError:
    # python27
    # Refer to the older SafeConfigParser as ConfigParser
    from ConfigParser import SafeConfigParser as ConfigParser

config = ConfigParser()

# get the path to config.ini
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.ini')

# check if the path is to a valid file
if not os.path.isfile(config_path):
    raise BadConfigError # not a standard python exception

config.read(config_path)

TEST_KEY = config.get('main', 'test_key') # value

这依赖于 config.ini 位于我们的包 bootstrap 内,并且预计会随它一起提供。

重要的一点是如何获得 config_path:

config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.ini')

__file__ 指的是当前正在执行的script 的位置。在我的问题中,这意味着 stuff.py 的位置,它位于 bootstrap 文件夹内,config.ini 也是如此。

上面这行代码的意思是;获取 stuff.py 的绝对路径;从该获取路径到包含它的目录;并将其与 config.ini 连接(因为它在同一目录中)以提供 config.ini 的绝对路径。然后您可以继续阅读它并引发 exception 以防万一。

即使您在 pip 上发布您的包并且用户从那里安装它,这也会起作用。

作为一个奖励,稍微偏离问题一点,如果您在pip 上发布您的包并在包中包含数据文件,您必须告诉 setuptools 在构建 sdistbdist 时将它们包含在您的包中。因此,要在上面的包中包含 config.ini,请将以下行添加到 setup.py 中的 setup 类调用中:

include_package_data = True,
package_data = {
    # If any package contains *.ini files, include them
    '': ['*.ini'],
},

但在某些情况下它仍然可能不起作用,例如。构建轮子等。所以你也可以在你的 MANIFEST.IN 文件中做同样的事情:

include LICENSE
include bootstrap/*.ini

关于python - 在 python 包中添加和读取 config.ini 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35236223/

相关文章:

python - 没有名为 _graphviz 的模块

python - 程序执行时pyqtgraph plot不显示

python - Pandas 系列 : compare values all vs. 所有

python - 如果超时则跳过 URL

python - Windows xgboost 错误

python - 从python中的用户指定文件导入变量

python - Docker,如何通过 Django 应用程序的端口公开套接字

python 单路径: path to current file directory (ancestor) outputs nothing

python - 如何将列表作为环境变量传递?

python - 断言整数在范围内