为什么导入在 setuptools entry_point 脚本中失败,但在 python 解释器中却没有?
Why do imports fail in setuptools entry_point scripts, but not in python interpreter?
我有以下项目结构:
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
文档并没有说明如何在分发后导入包(setuptools
和 distutils
的区别不少于神秘 - 无法知道 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
你的项目结构似乎是 b0rken。发行版的标准布局是 setup.py
在 top-level 上。您的项目将有 1 (top-level) 个包,即 project
,sub-package 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
确实不能很好地同时处理 top-level + sub-package。在那之后 pip remove project
这么多次,你可以确定你没有在 site-packages 中安装任何有缺陷的版本,然后 运行 python setup.py develop
到 link 来源变成site-packages
.
在那之后,问题是您使用的是 Python 2 及其损坏的导入系统,该系统假定相对导入。在 project.py
中,您的 import project.lib
默认采用 relative 导入,并尝试实际导入 project.project.lib
。因为这不是你想要的,你应该添加
from __future__ import absolute_import
在该文件的顶部。我强烈建议您添加这个(如果您在任何地方都使用 /
运算符,为什么不也添加 division
导入),以避免这些陷阱并保持 Python 3 兼容。
我有以下项目结构:
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
文档并没有说明如何在分发后导入包(setuptools
和 distutils
的区别不少于神秘 - 无法知道 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
你的项目结构似乎是 b0rken。发行版的标准布局是 setup.py
在 top-level 上。您的项目将有 1 (top-level) 个包,即 project
,sub-package 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
确实不能很好地同时处理 top-level + sub-package。在那之后 pip remove project
这么多次,你可以确定你没有在 site-packages 中安装任何有缺陷的版本,然后 运行 python setup.py develop
到 link 来源变成site-packages
.
在那之后,问题是您使用的是 Python 2 及其损坏的导入系统,该系统假定相对导入。在 project.py
中,您的 import project.lib
默认采用 relative 导入,并尝试实际导入 project.project.lib
。因为这不是你想要的,你应该添加
from __future__ import absolute_import
在该文件的顶部。我强烈建议您添加这个(如果您在任何地方都使用 /
运算符,为什么不也添加 division
导入),以避免这些陷阱并保持 Python 3 兼容。