console_scripts 执行时出现 ModuleNotFoundError
ModuleNotFoundError on console_scripts execution
发生了什么
我有一个用 Python 3(Python 3.6.0 解释器)编写的简单 CLI 项目,我可以 运行 直接从命令行使用包和模块名称,但在使用 setuptools
:
安装时失败
# success
❯ python -m myProject.cli --version
0.0.1.dev0
# failure
❯ mycli --version
Traceback (most recent call last):
File "/path/myProject/venv/bin/mycli", line 11, in <module>
load_entry_point('myProject==0.0.1.dev0', 'console_scripts', 'mycli')()
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 560, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2648, in load_entry_point
return ep.load()
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2302, in load
return self.resolve()
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2308, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'myProject'
项目设置
项目结构如下:
.
├── myProject
│ └── cli.py
└── setup.py
我希望稍后将脚本安装为 mycli
,因此我的 setup.py
看起来像这样:
from setuptools import setup, find_packages
from myProject.cli import __version__
setup(
# Package info
name = 'myProject',
version = __version__,
packages = find_packages(),
# Dependencies
install_requires = [
'docopt>=0.6.2'
],
# Script info
entry_points = {
'console_scripts': [
'mycli = myProject.cli:main'
]
}
)
安装
安装完成且没有错误:
❯ python setup.py install
running install
running bdist_egg
running egg_info
writing myProject.egg-info/PKG-INFO
writing dependency_links to myProject.egg-info/dependency_links.txt
writing entry points to myProject.egg-info/entry_points.txt
writing requirements to myProject.egg-info/requires.txt
writing top-level names to myProject.egg-info/top_level.txt
reading manifest file 'myProject.egg-info/SOURCES.txt'
writing manifest file 'myProject.egg-info/SOURCES.txt'
installing library code to build/bdist.macosx-10.12-x86_64/egg
running install_lib
warning: install_lib: 'build/lib' does not exist -- no Python modules to install
creating build/bdist.macosx-10.12-x86_64/egg
creating build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/PKG-INFO -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/SOURCES.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/dependency_links.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/entry_points.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/requires.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/top_level.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating 'dist/myProject-0.0.1.dev0-py3.6.egg' and adding 'build/bdist.macosx-10.12-x86_64/egg' to it
removing 'build/bdist.macosx-10.12-x86_64/egg' (and everything under it)
Processing myProject-0.0.1.dev0-py3.6.egg
Removing /path/myProject/venv/lib/python3.6/site-packages/myProject-0.0.1.dev0-py3.6.egg
Copying myProject-0.0.1.dev0-py3.6.egg to /path/myProject/venv/lib/python3.6/site-packages
myProject 0.0.1.dev0 is already the active version in easy-install.pth
Installing mycli script to /path/myProject/venv/bin
Installed /path/myProject/venv/lib/python3.6/site-packages/myProject-0.0.1.dev0-py3.6.egg
Processing dependencies for myProject==0.0.1.dev0
Searching for docopt==0.6.2
Best match: docopt 0.6.2
Adding docopt 0.6.2 to easy-install.pth file
Using /path/myProject/venv/lib/python3.6/site-packages
Finished processing dependencies for myProject==0.0.1.dev0
pip show
也显示了预期的结果:
❯ pip show myProject
Name: myProject
Version: 0.0.1.dev0
Location: /path/myProject/venv/lib/python3.6/site-packages/myProject-0.0.1.dev0-py3.6.egg
Requires: docopt
尽管如此,当我执行mycli
.
时,总是弹出ModuleNotFoundError: No module named 'myProject'
错误
如有指点,我将不胜感激。
我找到了我的问题的解决方案,我认为这是对 PEP 420 -- Implicit Namespace Packages 的误解。
此页面指出,自 Python 3.3:
While looking for a module or package named "foo", for each directory in the parent path:
- If <directory>/foo/__init__.py is found, a regular package is imported and returned.
- If not, but <directory>/foo is found and is a directory, it is recorded and the scan continues with the next directory in the parent path.
If the scan completes without returning a module or package, and at least one directory was recorded, then a namespace package is created. The new namespace package:
- Has a __path__ attribute set to an iterable of the path strings that were found and recorded during the scan.
- Does not have a __file__ attribute.
定义在pkg_resources
documentation:
A namespace package is a package that only contains other packages and modules, with no direct contents of its own.
正如我所描述的那样,我的包裹属于该类别,这不是预期的。
在 myProject/
目录下添加一个空的 __init.py__
后,我在 install
步骤中看到了这种情况:
❯ python setup.py build
running build
running build_py
creating build/lib
creating build/lib/myProject
copying myProject/__init__.py -> build/lib/myProject
copying myProject/cli.py -> build/lib/myProject
之前:
>>> myProject.__path__
_NamespacePath(['/path/myProject'])
>>> myProject.__file__
AttributeError: module 'myProject' has no attribute '__file__'
之后:
>>> myProject.__path__
['/path/myProject']
>>> myProject.__file__
'/path/myProject/__init__.py'
发生了什么
我有一个用 Python 3(Python 3.6.0 解释器)编写的简单 CLI 项目,我可以 运行 直接从命令行使用包和模块名称,但在使用 setuptools
:
# success
❯ python -m myProject.cli --version
0.0.1.dev0
# failure
❯ mycli --version
Traceback (most recent call last):
File "/path/myProject/venv/bin/mycli", line 11, in <module>
load_entry_point('myProject==0.0.1.dev0', 'console_scripts', 'mycli')()
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 560, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2648, in load_entry_point
return ep.load()
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2302, in load
return self.resolve()
File "/path/myProject/venv/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2308, in resolve
module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'myProject'
项目设置
项目结构如下:
.
├── myProject
│ └── cli.py
└── setup.py
我希望稍后将脚本安装为 mycli
,因此我的 setup.py
看起来像这样:
from setuptools import setup, find_packages
from myProject.cli import __version__
setup(
# Package info
name = 'myProject',
version = __version__,
packages = find_packages(),
# Dependencies
install_requires = [
'docopt>=0.6.2'
],
# Script info
entry_points = {
'console_scripts': [
'mycli = myProject.cli:main'
]
}
)
安装
安装完成且没有错误:
❯ python setup.py install
running install
running bdist_egg
running egg_info
writing myProject.egg-info/PKG-INFO
writing dependency_links to myProject.egg-info/dependency_links.txt
writing entry points to myProject.egg-info/entry_points.txt
writing requirements to myProject.egg-info/requires.txt
writing top-level names to myProject.egg-info/top_level.txt
reading manifest file 'myProject.egg-info/SOURCES.txt'
writing manifest file 'myProject.egg-info/SOURCES.txt'
installing library code to build/bdist.macosx-10.12-x86_64/egg
running install_lib
warning: install_lib: 'build/lib' does not exist -- no Python modules to install
creating build/bdist.macosx-10.12-x86_64/egg
creating build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/PKG-INFO -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/SOURCES.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/dependency_links.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/entry_points.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/requires.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
copying myProject.egg-info/top_level.txt -> build/bdist.macosx-10.12-x86_64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating 'dist/myProject-0.0.1.dev0-py3.6.egg' and adding 'build/bdist.macosx-10.12-x86_64/egg' to it
removing 'build/bdist.macosx-10.12-x86_64/egg' (and everything under it)
Processing myProject-0.0.1.dev0-py3.6.egg
Removing /path/myProject/venv/lib/python3.6/site-packages/myProject-0.0.1.dev0-py3.6.egg
Copying myProject-0.0.1.dev0-py3.6.egg to /path/myProject/venv/lib/python3.6/site-packages
myProject 0.0.1.dev0 is already the active version in easy-install.pth
Installing mycli script to /path/myProject/venv/bin
Installed /path/myProject/venv/lib/python3.6/site-packages/myProject-0.0.1.dev0-py3.6.egg
Processing dependencies for myProject==0.0.1.dev0
Searching for docopt==0.6.2
Best match: docopt 0.6.2
Adding docopt 0.6.2 to easy-install.pth file
Using /path/myProject/venv/lib/python3.6/site-packages
Finished processing dependencies for myProject==0.0.1.dev0
pip show
也显示了预期的结果:
❯ pip show myProject
Name: myProject
Version: 0.0.1.dev0
Location: /path/myProject/venv/lib/python3.6/site-packages/myProject-0.0.1.dev0-py3.6.egg
Requires: docopt
尽管如此,当我执行mycli
.
ModuleNotFoundError: No module named 'myProject'
错误
如有指点,我将不胜感激。
我找到了我的问题的解决方案,我认为这是对 PEP 420 -- Implicit Namespace Packages 的误解。
此页面指出,自 Python 3.3:
While looking for a module or package named "foo", for each directory in the parent path:
- If <directory>/foo/__init__.py is found, a regular package is imported and returned.
- If not, but <directory>/foo is found and is a directory, it is recorded and the scan continues with the next directory in the parent path.
If the scan completes without returning a module or package, and at least one directory was recorded, then a namespace package is created. The new namespace package:
- Has a __path__ attribute set to an iterable of the path strings that were found and recorded during the scan.
- Does not have a __file__ attribute.
定义在pkg_resources
documentation:
A namespace package is a package that only contains other packages and modules, with no direct contents of its own.
正如我所描述的那样,我的包裹属于该类别,这不是预期的。
在 myProject/
目录下添加一个空的 __init.py__
后,我在 install
步骤中看到了这种情况:
❯ python setup.py build
running build
running build_py
creating build/lib
creating build/lib/myProject
copying myProject/__init__.py -> build/lib/myProject
copying myProject/cli.py -> build/lib/myProject
之前:
>>> myProject.__path__
_NamespacePath(['/path/myProject'])
>>> myProject.__file__
AttributeError: module 'myProject' has no attribute '__file__'
之后:
>>> myProject.__path__
['/path/myProject']
>>> myProject.__file__
'/path/myProject/__init__.py'