从 PyPI 安装我的 sdist 会将文件放在意想不到的地方

Posted

技术标签:

【中文标题】从 PyPI 安装我的 sdist 会将文件放在意想不到的地方【英文标题】:Installing my sdist from PyPI puts the files in unexpected places 【发布时间】:2011-07-08 17:19:36 【问题描述】:

我的问题是,当我将我的 Python 包上传到 PyPI,然后使用 pip 从那里安装它时,我的应用程序会中断,因为它将我的文件安装到完全不同的位置,而不是我从本地 sdist 安装完全相同的包时.

从本地 sdist 安装会将文件放在我的系统上,如下所示:

/Python27/
  Lib/
    site-packages/
      gloopy-0.1.alpha-py2.7.egg/ (egg and install info files)
        data/ (images and shader source)
        doc/ (html)
        examples/ (.py scripts that use the library)
        gloopy/ (source)

这与我预期的差不多,并且工作正常(例如,我的源可以找到我的数据目录,因为它们彼此相邻,就像它们在开发中一样。)

如果我将相同的 sdist 上传到 PyPI,然后使用 pip 从那里安装它,那么事情看起来就大不相同了:

/Python27/
  data/ (images and shader source)
  doc/ (html)
  Lib/
    site-packages/
      gloopy-0.1.alpha-py2.7.egg/ (egg and install info files)
      gloopy/ (source files)
  examples/ (.py scripts that use the library)

这根本行不通——我的应用找不到它的数据文件,而且很明显这是一团糟,我所有的垃圾都污染了*** /python27 目录。

我做错了什么?如何使 pip 安装的行为类似于本地 sdist 安装?这甚至是我应该努力实现的目标吗?

详情

我已经安装了 setuptools,也进行了分发,我正在调用distribute_setup.use_setuptools()

WindowsXP、Python2.7。

我的开发目录是这样的:

/gloopy
  /data (image files and GLSL shader souce read at runtime)
  /doc (html files)
  /examples (some scripts to show off the library)
  /gloopy (the library itself)

我的 MANIFEST.in 提到了我想要包含在 sdist 中的所有文件,包括 data、examples 和 doc 目录中的所有内容:

recursive-include data *.*
recursive-include examples *.py
recursive-include doc/html *.html *.css *.js *.png
include LICENSE.txt
include TODO.txt

我的 setup.py 相当冗长,但我想最好的办法是把它包括在这里,对吧?我还包括对 MANIFEST.in 中提到的相同 data/doc/examples 目录的重复引用,因为我知道这是在安装期间将这些文件从 sdist 复制到系统所必需的。

NAME = 'gloopy'
VERSION= __import__(NAME).VERSION
RELEASE = __import__(NAME).RELEASE
SCRIPT = None
CONSOLE = False

def main():
    import sys
    from pprint import pprint

    from setup_utils import distribute_setup
    from setup_utils.sdist_setup import get_sdist_config
    distribute_setup.use_setuptools()
    from setuptools import setup

    description, long_description = read_description()
    config = dict(
        name=name,
        version=version,
        description=description,
        long_description=long_description,
        keywords='',
        packages=find_packages(),
        data_files=[
            ('examples', glob('examples/*.py')),
            ('data/shaders', glob('data/shaders/*.*')),
            ('doc', glob('doc/html/*.*')),
            ('doc/_images', glob('doc/html/_images/*.*')),
            ('doc/_modules', glob('doc/html/_modules/*.*')),
            ('doc/_modules/gloopy', glob('doc/html/_modules/gloopy/*.*')),
            ('doc/_modules/gloopy/geom', glob('doc/html/_modules/gloopy/geom/*.*')),
            ('doc/_modules/gloopy/move', glob('doc/html/_modules/gloopy/move/*.*')),
            ('doc/_modules/gloopy/shapes', glob('doc/html/_modules/gloopy/shapes/*.*')),
            ('doc/_modules/gloopy/util', glob('doc/html/_modules/gloopy/util/*.*')),
            ('doc/_modules/gloopy/view', glob('doc/html/_modules/gloopy/view/*.*')),
            ('doc/_static', glob('doc/html/_static/*.*')),
            ('doc/_api', glob('doc/html/_api/*.*')),
        ],
        classifiers=[
            'Development Status :: 1 - Planning',
            'Intended Audience :: Developers',
            'License :: OSI Approved :: BSD License',
            'Operating System :: Microsoft :: Windows',
            'Programming Language :: Python :: 2.7',
        ],    
        # see classifiers http://pypi.python.org/pypi?:action=list_classifiers
    ) 

    config.update(dict(
        author='Jonathan Hartley',
        author_email='tartley@tartley.com',
        url='http://bitbucket.org/tartley/gloopy',
        license='New BSD',
    ) )

    if '--verbose' in sys.argv:
        pprint(config)

    setup(**config)


if __name__ == '__main__':
    main()

【问题讨论】:

【参考方案1】:

data_files 参数适用于不属于包的数据文件。你应该改用package_data

见https://docs.python.org/3/distutils/setupscript.html#installing-package-data

这不会在 site-packages/data 中安装数据,但在我看来,无论如何都不应该安装它。你不会知道它是哪个包的一部分。它应该安装在site-packages//gloopy-0.1.alpha-py2.7.egg/[data|doc|examples]IMO。

如果您确实认为数据不是包数据,那么您应该使用data_files,在这种情况下 pip 会正确安装它,而我会声称 setup.py install 将其安装在错误的位置。但在我看来,在这个例子中,它是package_data,因为它与包相关,并没有被其他软件使用。

【讨论】:

我完全同意你的观点,data|doc|examples 应该安装在 site-packages/gloopy-0.1.alpha-py2.7.egg 中。您暗示“data_files”只能用于其他软件使用的数据,这对我很有启发性。谢谢。 糟糕,您的回答提醒我,我为本地 sdist 安装错误绘制了目录布局。 “数据”等没有进入站点包,而是进入站点包/gloopy-0.1.alpha-py2.7.egg,就像你建议的那样。现已修复。 @Tartley:啊。好的。我确实想知道为什么会有差异。我们真的需要直接在 Python 中获得安装故事。 (希望 distutils2 会这样做)。 您的主链接已失效。【参考方案2】:

您可以使用pkgutil.get_data() 加载包数据,它会找到包数据的确切安装位置。

这是一篇关于在包中包含数据文件的精彩博文:Including data files into Python packages

【讨论】:

你好。太棒了-感谢您的回答。查看链接,我认为您没有明确提及的重要问题是我应该始终在 setup.py 中使用“package_data”,而不是“data_files”。因此,是否一致认为永远不应使用“data_files”?这让我感到困惑,因为它与我对如何在 Python 项目中布置目录的理解相矛盾,因为它意味着您的“数据”目录位于您的包源目录中,而不是在它旁边。

以上是关于从 PyPI 安装我的 sdist 会将文件放在意想不到的地方的主要内容,如果未能解决你的问题,请参考以下文章

Python 包管理

Artifactory PyPi repo 布局与构建提升

用于存储 .whl 以进行 pip 安装的目录?

pip和requests模块的安装

从 PyPI 安装软件包时出现问题:未安装根文件

PyPI 安装和压缩包中缺少我的包的 requirements.txt 文件