Ошибка Python distutils: "[каталог]... не существует или нет обычного файла"
Возьмем следующий макет проекта:
$ ls -R .
.:
package setup.py
./package:
__init__.py dir file.dat module.py
./package/dir:
tool1.dat tool2.dat
И следующий контент для setup.py
:
$ cat setup.py
from distutils.core import setup
setup(name='pyproj',
version='0.1',
packages=[
'package',
],
package_data={
'package': [
'*',
'dir/*',
],
},
)
Как вы можете видеть, я хочу включить все файлы, отличные от Python, в каталоги package/
и package/dir/
. Однако запуск setup.py install
приведет к следующей ошибке:
$ python setup.py install
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/package
copying package/module.py -> build/lib/package
copying package/__init__.py -> build/lib/package
error: can't copy 'package/dir': doesn't exist or not a regular file
Что дает?
Ответы
Ответ 1
В package_data
ваш твист '*'
будет соответствовать самому package/dir
и попытаться скопировать этот каталог в файл, что приведет к ошибке. Найдите glob, который не будет соответствовать каталогу package/dir
, переписав ваш setup.py
в следующих строках:
from distutils.core import setup
setup(name='pyproj',
version='0.1',
packages=[
'package',
],
package_data={
'package': [
'*.dat',
'dir/*'
],
},
)
Учитывая ваш пример, просто изменив '*'
на '*.dat'
, хотя вам, вероятно, понадобится уточнить ваш glob больше, чем это, просто убедитесь, что он не будет соответствовать 'dir'
Ответ 2
Вы можете использовать Distribute вместо distutils. Он работает в основном одинаково (по большей части вам не придется менять setup.py), и он дает вам опцию exclude_package_data:
from distribute_setup import use_setuptools
use_setuptools()
from setuptools import setup
setup(name='pyproj',
version='0.1',
packages=[
'package',
],
package_data={
'package': [
'*.dat',
'dir/*'
],
},
exclude_package_data={
'package': [
'dir'
],
},
)
Ответ 3
Я создал функцию, которая дает мне все файлы, которые мне нужны
def find_files(directory, strip):
"""
Using glob patterns in ``package_data`` that matches a directory can
result in setuptools trying to install that directory as a file and
the installation to fail.
This function walks over the contents of *directory* and returns a list
of only filenames found. The filenames will be stripped of the *strip*
directory part.
"""
result = []
for root, dirs, files in os.walk(directory):
for filename in files:
filename = os.path.join(root, filename)
result.append(os.path.relpath(filename, strip))
return result
И использовал это как выражение для package_data
Ответ 4
Не совсем понятно, почему, но после некоторого устранения неполадок я понял, что переименование каталогов с точками в их именах решило проблему. Например.
chart.js-2.4.0 => chart_js-2_4_0
Примечание. Я использую Python 2.7.10, SetupTools 12.2