【问题标题】:Why do imports fail in setuptools entry_point scripts, but not in python interpreter?为什么在 setuptools entry_point 脚本中导入失败,但在 python 解释器中却没有?
【发布时间】:2016-04-20 14:08:09
【问题描述】:

我的项目结构如下:

project
|-project.py
|-__init__.py
|-setup.py
|-lib
  |-__init__.py
  |-project
    |-__init__.py
    |-tools.py

project.py:

from project.lib import *

def main():
    print("main")
    tool()

if __name__ == "__main__":
    main()

setup.py:

from setuptools import setup

setup(
    name = "project",
    version="1.0",
    packages = ["project", "project.lib"],
    package_dir = {"project": ".", "project.lib": 'lib/project'},
    entry_points={
        'console_scripts': [
            'project = project.project:main',
        ],
    },
)

tools.py:

def tool():
    print("tool")

如果我跑了

import project.lib.tools
project.lib.tools.tool()

它按预期工作,但运行命令 project 失败

Traceback (most recent call last):
  File "/usr/local/bin/project", line 9, in <module>
    load_entry_point('project==1.0', 'console_scripts', 'project')()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 568, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2720, in load_entry_point
    return ep.load()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2380, in load
    return self.resolve()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2386, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "build/bdist.linux-x86_64/egg/project/project.py", line 3, in <module>
ImportError: No module named lib

我不明白为什么两个解释器没有相同的默认导入路径。

这个设置的原因是我希望能够import project.lib.tools,但保持lib/project的目录结构。

完整的 distutils 文档严重地没有说明如何在分发包后导入包(setuptoolsdistutils 的区别同样神秘 - 无法知道是否distutils 的行为是否在此处扩展)。

我在 Ubuntu 15.10 上使用 setuptools 18.4-1 和 python 2.7。

如果我按照@AnttiHaapala 的回答中的建议更改项目结构和setup.py,我会得到

$ project
Traceback (most recent call last):
  File "/usr/local/bin/project", line 9, in <module>
    load_entry_point('project==1.0', 'console_scripts', 'project')()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 568, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2720, in load_entry_point
    return ep.load()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2380, in load
    return self.resolve()
  File "/usr/local/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2386, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "build/bdist.linux-x86_64/egg/project/project.py", line 3, in <module>
ImportError: No module named lib

【问题讨论】:

    标签: python python-2.7 import setuptools


    【解决方案1】:

    您的项目结构似乎是 b0rken。分发的标准布局是 setup.py 在顶层。然后,您的项目将有 1 个(顶级)包,即project,以及子包project.lib。因此我们得到以下目录布局:

    Project-0.42/
     +- project/
     |    +- __init__.py
     |    +- lib/
     |    |   +- __init__.py
     |    |   +- tools.py
     |    +- project.py
     +- setup.py
    

    然后在你的setup.py 你可以简单地做

    from setuptools import find_packages
    
    setup(
        ...
        # remove package_dir, it is unnecessary
        packages=find_packages(),
        ...
    )
    

    package_dir 确实不能很好地同时处理顶级 + 子包。之后pip remove project 多次,您可以确定您没有在站点包中安装任何错误版本,然后运行python setup.py develop 将源链接到site-packages


    在那之后,问题是您使用的 Python 2 的导入系统已损坏,该系统假定相对导入。在project.py 中,您的import project.lib 默认假定为relative 导入,并尝试实际导入project.project.lib。由于这不是您想要的,您应该添加

    from __future__ import absolute_import
    

    在该文件的顶部。我强烈建议您添加这个(如果您在任何地方都使用 / 运算符,为什么不添加 division 导入),以避免这些陷阱并保持 Python 3 兼容。

    【讨论】:

    • 知道如何使setuptools'package_data 工作吗?问题是(基本相同)pkg_resources.resource_string("project", "data/file")python 中有效,但在entry_point 脚本中无效。
    • 此解决方案不再适用,原因是人类平均寿命无法检测到 - 或两个。对于理智的人来说,python 包装似乎是不可能的,现在它带走了我的理智,我想说它不适合任何人。真可惜……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 2015-06-15
    • 1970-01-01
    • 2023-03-05
    • 2017-03-30
    • 2018-03-17
    相关资源
    最近更新 更多