为什么导入在setuptools entry_point脚本中失败,而在python解释器中失败?

Kar*_*ter 5 python import setuptools python-2.7

我有以下项目结构:

project
|-project.py
|-__init__.py
|-setup.py
|-lib
  |-__init__.py
  |-project
    |-__init__.py
    |-tools.py
Run Code Online (Sandbox Code Playgroud)

project.py:

from project.lib import *

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

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

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',
        ],
    },
)
Run Code Online (Sandbox Code Playgroud)

tools.py:

def tool():
    print("tool")
Run Code Online (Sandbox Code Playgroud)

如果我跑

import project.lib.tools
project.lib.tools.tool()
Run Code Online (Sandbox Code Playgroud)

它按预期工作,但运行命令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
Run Code Online (Sandbox Code Playgroud)

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

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

完整的distutils文档严肃地说没有说明如何在分发包之后导入包(差异setuptools并且distutils不是那么神秘 - 无法知道distutils这里的行为是否延伸).

我在Ubuntu 15.10上使用setuptools18.4-1和python2.7.

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

$ 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
Run Code Online (Sandbox Code Playgroud)

Ant*_*ala 11

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

Project-0.42/
 +- project/
 |    +- __init__.py
 |    +- lib/
 |    |   +- __init__.py
 |    |   +- tools.py
 |    +- project.py
 +- setup.py
Run Code Online (Sandbox Code Playgroud)

然后在你的setup.py你可以做到

from setuptools import find_packages

setup(
    ...
    # remove package_dir, it is unnecessary
    packages=find_packages(),
    ...
)
Run Code Online (Sandbox Code Playgroud)

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


在那之后,问题是你使用Python 2及其破坏的导入系统,该系统假定相对导入.在project.py,默认情况下,您import project.lib假定相对导入,并尝试实际导入project.project.lib.因为这不是你想要的,你应该添加

from __future__ import absolute_import
Run Code Online (Sandbox Code Playgroud)

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

  • 该解决方案不再适用于人类平均寿命无法检测到的原因 - 或两个.对于理智的人来说,蟒蛇包装似乎是不可能的,现在它已经剥夺了我的理智,我认为它不适合任何人.太遗憾了... (5认同)