使用setuptools打包并使用pip安装后,Python代码无法读取数据文件

3
我用setuptools打包了一些Python代码。这些代码使用了一个数据文件,但是在使用pip安装包之后,代码无法找到数据文件。我做错了什么? 以下是文件结构和文件内容。可以在这里找到这些文件。Python代码setup.py试图使用mesa/a.txt数据文件。如果不打包+pip,代码可以正常工作。
|
|- tm/
|  |- __init__.py
|  |- test2.py
|- mesa/
|  |- __init__.py
|  |- a.txt
|- MANIFEST.in
|- setup.py

MANIFEST.in:

include mesa/a.txt

setup.py:

from setuptools import setup
setup(name='bobab',
      version='0.1',
      py_modules=['tm.test2'],
      author_email='x@gmail.com',
      package_data = {
        'tm': ['mesa/a.txt']
        },
    )

'mesa/a.txt:

hello world!

tm/test2.py:

import os

def main():
    print 'hi' 
    print open(os.path.join('..', 'mesa', 'a.txt'), 'r').read() # print file content

if __name__ == "__main__":
    main()

我使用命令python setup.py sdist创建软件包。我使用以下命令安装软件包:

unzip bobab-0.1.zip
cd bobab-0.1
python setup.py install

如下的错误信息所示,该包没有找到数据文件mesa/a.txt

Python 2.7.12 (default, Dec  4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
>>> import tm.test2
>>> tm.test2.main()
hi
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tm/test2.py", line 5, in main
    print open(os.path.join('..', 'mesa', 'a.txt'), 'r').read()
IOError: [Errno 2] No such file or directory: '../mesa/a.txt'

我使用的是Python 2.7。


以下是打包和安装日志。有趣的是,打包日志提到数据文件mesa/a.txt被添加到了包中,但安装日志没有提到它的存在。

打包日志:

C:\Users\Franck\Documents\GitHub\misc\src\test>python setu
p.py sdist
running sdist
running egg_info
creating bobab.egg-info
writing bobab.egg-info\PKG-INFO
writing top-level names to bobab.egg-info\top_level.txt
writing dependency_links to bobab.egg-info\dependency_links.txt
writing pbr to bobab.egg-info\pbr.json
writing manifest file 'bobab.egg-info\SOURCES.txt'
reading manifest file 'bobab.egg-info\SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'bobab.egg-info\SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst,
README.txt

running check
warning: check: missing required meta-data: url

warning: check: missing meta-data: either (author and author_email) or (maintain
er and maintainer_email) must be supplied

creating bobab-0.1
creating bobab-0.1\bobab.egg-info
creating bobab-0.1\mesa
creating bobab-0.1\tm
copying files to bobab-0.1...
copying MANIFEST.in -> bobab-0.1
copying setup.py -> bobab-0.1
copying bobab.egg-info\PKG-INFO -> bobab-0.1\bobab.egg-info
copying bobab.egg-info\SOURCES.txt -> bobab-0.1\bobab.egg-info
copying bobab.egg-info\dependency_links.txt -> bobab-0.1\bobab.egg-info
copying bobab.egg-info\pbr.json -> bobab-0.1\bobab.egg-info
copying bobab.egg-info\top_level.txt -> bobab-0.1\bobab.egg-info
copying mesa\a.txt -> bobab-0.1\mesa
copying tm\__init__.py -> bobab-0.1\tm
copying tm\test2.py -> bobab-0.1\tm
Writing bobab-0.1\setup.cfg
creating 'dist\bobab-0.1.zip' and adding 'bobab-0.1' to it
adding 'bobab-0.1\MANIFEST.in'
adding 'bobab-0.1\PKG-INFO'
adding 'bobab-0.1\setup.cfg'
adding 'bobab-0.1\setup.py'
adding 'bobab-0.1\bobab.egg-info\dependency_links.txt'
adding 'bobab-0.1\bobab.egg-info\pbr.json'
adding 'bobab-0.1\bobab.egg-info\PKG-INFO'
adding 'bobab-0.1\bobab.egg-info\SOURCES.txt'
adding 'bobab-0.1\bobab.egg-info\top_level.txt'
adding 'bobab-0.1\mesa\a.txt'
adding 'bobab-0.1\tm\test2.py'
adding 'bobab-0.1\tm\__init__.py'
removing 'bobab-0.1' (and everything under it)

安装日志:

(sedona) dernonco@ilcompn0:/mnt/ilcompn0d1/user/dernonco/temp/bobab-0.1$ python setup.py install
running install
running bdist_egg
running egg_info
writing bobab.egg-info/PKG-INFO
writing top-level names to bobab.egg-info/top_level.txt
writing dependency_links to bobab.egg-info/dependency_links.txt
reading manifest file 'bobab.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'bobab.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
creating build
creating build/lib.linux-x86_64-2.7
creating build/lib.linux-x86_64-2.7/tm
copying tm/__init__.py -> build/lib.linux-x86_64-2.7/tm
copying tm/test2.py -> build/lib.linux-x86_64-2.7/tm
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/tm
copying build/lib.linux-x86_64-2.7/tm/__init__.py -> build/bdist.linux-x86_64/egg/tm
copying build/lib.linux-x86_64-2.7/tm/test2.py -> build/bdist.linux-x86_64/egg/tm
byte-compiling build/bdist.linux-x86_64/egg/tm/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/tm/test2.py to test2.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying bobab.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying bobab.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying bobab.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying bobab.egg-info/pbr.json -> build/bdist.linux-x86_64/egg/EGG-INFO
copying bobab.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist/bobab-0.1-py2.7.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing bobab-0.1-py2.7.egg
Copying bobab-0.1-py2.7.egg to /mnt/ilcompn0d1/user/dernonco/pyenv/sedona/lib/python2.7/site-packages
Adding bobab 0.1 to easy-install.pth file

Installed /mnt/ilcompn0d1/user/dernonco/pyenv/sedona/lib/python2.7/site-packages/bobab-0.1-py2.7.egg
Processing dependencies for bobab==0.1
Finished processing dependencies for bobab==0.1
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

需要进行几项调整:

  1. MANIFEST.in will be used only when you package source dists, so python setup.py sdist will include mesa/a.txt even with your current setup. This is not the case with binary distributions, neither bdist_egg nor bdist_wheel will read the MANIFEST.in.
  2. package_data is usually used for non-python files placed inside the package, but mesa is not placed inside the tm dir, so the relative path is wrong. You can circumvent this by setting the dotted path:

    package_data={'tm': ['../mesa/a.txt']}
    

    However, if mesa is part of tm package, it makes sense to put it where it belongs.

  3. os.path.join('..', 'mesa', 'a.txt') will resolve the path relative to current directory, so this line can find the file only when you're in the tm directory - after installing the package, it will be hardly the case. You need to resolve the path properly, for example against the __file__ attribute:

    os.path.join(os.path.dirname(__file__), '..', 'mesa', 'a.txt')
    

附加说明:

  1. You can safely replace py_modules=['tm.test2'] with packages=['tm'] and don't need to care about updating py_modules when adding further modules to tm package.
  2. setuptools offers a module named pkg_resources that offers useful management functions for non-python files installed via package_data. For example,

    open(os.path.join('..', 'mesa', 'a.txt'), 'r').read()
    

    could be replaced with

    pkg_resources.resource_string('tm', '../mesa/a.txt')
    

    Refer to ResourceManager API section in the setuptools docs if you want to learn more.


1
非常感谢您详细的回答!它解决了我的问题并改善了我对如何使用 setuptools 的理解。 - Franck Dernoncourt
很高兴能够帮助! - hoefling

0
当我在处理不同文件夹中的其他文件时,我会在文件顶部使用这段代码。
from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

然后

from file_name import value 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,