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

时间:2016-02-06 01:23:40

标签: python python-2.7 import config configparser

我正在编写我想在PyPI上传的第一个python包。我根据此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'

导入不断提供 ConfigParser.NoSectionError ,但如果你只构建/运行stuff.py(我使用sublime3),模块不会出现错误,打印TEST_KEY会给出{{1}作为输出。

另外,当我在dir中使用3个文件(config,stuff,main)时,这种导入方法确实有效,只需将main作为脚本执行即可。但我必须像这样导入它

value

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

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

2 个答案:

答案 0 :(得分:1)

abhimanyuPathania:问题在于config.inistuff.py的路径。在config.read('config.ini')中将config.read('./bootstrap/config.ini')更改为stuff.py。我尝试了解决方案。它对我有用。

享受Pythoning ......

答案 1 :(得分:0)

这个问题有两个方面。 首先ConfigParser的奇怪行为。 ConfigParser无法找到.ini文件时;出于某些恼人的原因,它永远不会给出IOError或错误,表明它无法读取文件。

就我而言,当ConfigParser.NoSectionError明显存在时,它会继续提供section。当我发现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中添加setup.py类调用,请在上面的包中添加include_package_data = True, package_data = { # If any package contains *.ini files, include them '': ['*.ini'], },

MANIFEST.IN

但在某些情况下它仍然可能无效,例如。建立轮子等。所以你也在include LICENSE include bootstrap/*.ini 文件中做同样的事情:

{{1}}