<p>由于这个问题已经非常流行,下面是在安装后丢失文件时要执行的诊断步骤。假设有一个具有以下结构的示例项目:</p>
<pre><code>root
├── spam
│ ├── __init__.py
│ ├── data.txt
│ ├── eggs.py
│ └── fizz
│ ├── __init__.py
│ └── buzz.py
├── bacon.py
└── setup.py
</code></pre>
<p>现在我运行<code>pip install .</code>,检查包是否已安装:</p>
<pre><code>$ pip list
Package Version
---------- -------
mypkg 0.1
pip 19.0.1
setuptools 40.6.3
wheel 0.32.3
</code></pre>
<p>但在属于已安装包的文件列表中,既看不到<code>spam</code>,也看不到<code>spam/eggs.py</code>,也看不到<code>bacon.py</code>,也看不到<code>spam/fizz/buzz.py</code>:</p>
<pre><code>$ pip show -f mypkg
Name: mypkg
Version: 0.1
...
Files:
mypkg-0.1.dist-info/DESCRIPTION.rst
mypkg-0.1.dist-info/INSTALLER
mypkg-0.1.dist-info/METADATA
mypkg-0.1.dist-info/RECORD
mypkg-0.1.dist-info/WHEEL
mypkg-0.1.dist-info/metadata.json
mypkg-0.1.dist-info/top_level.txt
</code></pre>
<p>那现在该怎么办?</p>
<h3>通过检查车轮制造日志进行诊断</h3>
<p>除非被告知不要这样做,<code>pip</code>将始终尝试构建一个wheel文件并从中安装您的包。如果以详细模式重新安装,我们可以检查日志中的车轮生成过程。第一步是卸载包:</p>
<pre><code>$ pip uninstall -y mypkg
...
</code></pre>
<p>然后再安装一次,但现在需要一个附加参数:</p>
<pre><code>$ pip install . -vvv
...
</code></pre>
<p>现在如果我检查日志:</p>
<pre><code>$ pip install . -vvv | grep 'adding'
adding 'mypkg-0.1.dist-info/METADATA'
adding 'mypkg-0.1.dist-info/WHEEL'
adding 'mypkg-0.1.dist-info/top_level.txt'
adding 'mypkg-0.1.dist-info/RECORD'
</code></pre>
<p>我注意到<code>spam</code>目录或<code>bacon.py</code>目录中的任何文件都没有提到。这意味着它们不包含在wheel文件中,因此不由<code>pip</code>安装。最常见的错误源是:</p>
<h3>缺少包:检查<code>packages</code>参数</h3>
<p>验证是否已将<code>packages</code>参数传递给安装函数。检查您是否提到了应该安装的所有软件包。如果只提到父包,则不会自动收集子包!例如,在安装脚本中</p>
<pre><code>from setuptools import setup
setup(
name='mypkg',
version='0.1',
packages=['spam']
)
</code></pre>
<p>将安装<code>spam</code>,但不会安装<code>spam.fizz</code>,因为它本身是一个包,必须显式提及。修复:</p>
<pre><code>from setuptools import setup
setup(
name='mypkg',
version='0.1',
packages=['spam', 'spam.fizz']
)
</code></pre>
<p>如果您有很多包,请使用<code>setuptools.find_packages</code>来自动执行此过程:</p>
<pre><code>from setuptools import find_packages, setup
setup(
name='mypkg',
version='0.1',
packages=find_packages() # will return a list ['spam', 'spam.fizz']
)
</code></pre>
<p>如果缺少模块:</p>
<h3>缺少模块:检查<code>py_modules</code>参数</h3>
<p>在上面的例子中,我将在安装后丢失<code>bacon.py</code>,因为它不属于任何包。我必须在单独的参数<code>py_modules</code>中提供它的模块名:</p>
<pre><code>from setuptools import find_packages, setup
setup(
name='mypkg',
version='0.1',
packages=find_packages(),
py_modules=['bacon']
)
</code></pre>
<h3>缺少数据文件:检查<code>package_data</code>参数</h3>
<p>我已经准备好了所有的源代码文件,但是<code>data.txt</code>文件仍然没有安装。位于包目录下的数据文件应该通过<code>package_data</code>参数添加。修复上述设置脚本:</p>
<pre><code>from setuptools import find_packages, setup
setup(
name='mypkg',
version='0.1',
packages=find_packages(),
package_data={'spam': ['data.txt']},
py_modules=['bacon']
)
</code></pre>
<p>不要试图使用<code>data_files</code>参数。将数据文件放在包下,然后配置<code>package_data</code>。</p>
<h3>修复安装脚本后,请在安装后验证包文件是否已就位</h3>
<p>如果现在重新安装程序包,我会注意到所有文件都已添加到控制盘:</p>
<pre><code>$ pip install . -vvv | grep 'adding'
adding 'bacon.py'
adding 'spam/__init__.py'
adding 'spam/data.txt'
adding 'spam/eggs.py'
adding 'spam/fizz/__init__.py'
adding 'spam/fizz/buzz.py'
adding 'mypkg-0.1.dist-info/METADATA'
adding 'mypkg-0.1.dist-info/WHEEL'
adding 'mypkg-0.1.dist-info/top_level.txt'
adding 'mypkg-0.1.dist-info/RECORD'
</code></pre>
<p>它们也将在属于<code>mypkg</code>的文件列表中可见:</p>
<pre><code>$ pip show -f mypkg
Name: mypkg
Version: 0.1
...
Files:
__pycache__/bacon.cpython-36.pyc
bacon.py
mypkg-0.1.dist-info/INSTALLER
mypkg-0.1.dist-info/METADATA
mypkg-0.1.dist-info/RECORD
mypkg-0.1.dist-info/WHEEL
mypkg-0.1.dist-info/top_level.txt
spam/__init__.py
spam/__pycache__/__init__.cpython-36.pyc
spam/__pycache__/eggs.cpython-36.pyc
spam/data.txt
spam/eggs.py
spam/fizz/__init__.py
spam/fizz/__pycache__/__init__.cpython-36.pyc
spam/fizz/__pycache__/buzz.cpython-36.pyc
spam/fizz/buzz.py
</code></pre>