[英]Why do imports fail in setuptools entry_point scripts, but not in python interpreter?
I have the following project structure: 我有以下项目结构:
project
|-project.py
|-__init__.py
|-setup.py
|-lib
|-__init__.py
|-project
|-__init__.py
|-tools.py
with project.py
: 使用
project.py
:
from project.lib import *
def main():
print("main")
tool()
if __name__ == "__main__":
main()
setup.py
: 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
: tools.py
:
def tool():
print("tool")
If I run 如果我跑
import project.lib.tools
project.lib.tools.tool()
it works as expected, but running the command project
fails with 它按预期工作,但运行命令
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
I don't understand why the two interpreters don't have the same default import pathes. 我不明白为什么这两个解释器没有相同的默认导入路径。
The reason for this setup is that I want to be able to import project.lib.tools
, but keep the directory structure with lib/project
. 这个设置的原因是我希望能够
import project.lib.tools
,但保留目录结构与lib/project
。
The complete distutils
documentation seriously doesn't say a word on how one can import packages after they have been distributed (the difference of setuptools
and distutils
isn't less misterious - no way of knowing whether the behavior of distutils
is extended here or not). 完整的
distutils
文档严肃地说没有说明如何在分发包之后导入包( setuptools
和distutils
的区别并不是那么神秘 - 无法知道distutils
的行为是否在这里扩展) 。
I'm using setuptools
18.4-1 with python
2.7 on Ubuntu 15.10. 我在Ubuntu 15.10上使用了
setuptools
18.4-1和python
2.7。
If I change the project structure and setup.py
as suggested in @AnttiHaapala's answer I'm getting 如果我按照@ 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
Your project structure seems to be b0rken. 您的项目结构似乎是b0rken。 The standard layout for a distribution is that the
setup.py
is on the top-level. 分发的标准布局是
setup.py
位于顶层。 Your project would then have 1 (top-level) package, namely project
, with sub-package project.lib
. 然后,您的项目将包含1个(顶级)包,即
project
,包含子包project.lib
。 Thus we get the following directory layout: 因此,我们得到以下目录布局:
Project-0.42/
+- project/
| +- __init__.py
| +- lib/
| | +- __init__.py
| | +- tools.py
| +- project.py
+- setup.py
Then in your setup.py
you can simply do 然后在你的
setup.py
你可以做到
from setuptools import find_packages
setup(
...
# remove package_dir, it is unnecessary
packages=find_packages(),
...
)
The package_dir
really does not handle top-level + sub-packages simultaneously very well. package_dir
确实不能同时处理顶级+子包。 After that pip remove project
so many times that you can be certain you do not have any buggy versions of it installed in the site-packages, and then run python setup.py develop
to link the source into site-packages
. 在那个
pip remove project
之后,你可以确定你没有在site-packages中安装任何bug的版本,然后运行python setup.py develop
来将源链接到site-packages
。
After that, the problem is that you're using Python 2 with its broken import system which assumes relative imports. 在那之后,问题是你使用Python 2及其破坏的导入系统,该系统假定相对导入。 In
project.py
, your import project.lib
assumes a relative import by default, and it tries to actually import project.project.lib
. 在
project.py
, import project.lib
默认采用相对导入,并尝试实际导入project.project.lib
。 As this is not what you want, you should add 因为这不是你想要的,你应该添加
from __future__ import absolute_import
at the top of that file. 在该文件的顶部。 I seriously suggest that you add this (and why not also the
division
import if you're using /
operator anywhere at all), to avoid these pitfalls and to stay Python 3 compatible. 我认真地建议你添加这个(如果你在任何地方使用
/
运算符,为什么不进行division
导入),以避免这些陷阱并保持Python 3兼容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.