cxfreeze отсутствует модуль distutils внутри virtualenv

При запуске двоичного файла cxfreeze из проекта python3.2 я получаю следующую ошибку во время выполнения:

/project/dist/project/distutils/__init__.py:13: UserWarning: The virtualenv distutils package at %s appears to be in the same location as the system distutils?
Traceback (most recent call last):
  File "/home/chrish/.virtualenvs/project/lib/python3.2/distutils/__init__.py", line 19, in <module>
    import dist
ImportError: No module named dist

Соответственно есть несколько distutils записи в разделе отсутствующих модулей вывода cxfreeze:

? dist imported from distutils
? distutils.ccompiler imported from numpy.distutils.ccompiler
? distutils.cmd imported from setuptools.dist
? distutils.command.build_ext imported from distutils
? distutils.core imported from numpy.distutils.core
...

Я попытался принудительно включить distutils как модуль, импортировав его в мой основной файл python и добавив его в cxfreeze setup.py как:

options = {"build_exe": {"packages" : ["distutils"]} },

Ни один из подходов не сработал. Кажется вероятным, что я каким-то образом сломал virtualenv [поскольку distutils кажется основополагающим, а предупреждение о местонахождении distutils], повторяя с чистым virtualenv, повторил проблему.

Может быть стоит отметить, что я установил cx-freeze, запустив $VIRTUAL_ENV/build/cx-freeze/setup.py install поскольку он не устанавливается чисто в пипсах.

5 ответов

Решение

Обобщая мои комментарии:

Копия distutils в virtualenv делает некоторые странные вещи, которые сбивают с толку cx_Freeze. Простой обходной путь - заморозить виртуальную среду, чтобы она использовала системную копию distutils.

В Ubuntu Python 2 и 3 счастливо сосуществуют: просто используйте python3 сделать что-нибудь с Python 3. Например, чтобы установить cx_Freeze под Python 3: python3 setup.py install,

Найден другой обходной путь, который позволяет вам все еще использовать virtualenv при замораживании.

Обходной путь - исключить distutils и вручную добавить пакет из исходного интерпретатора (не из virtualenv).

# contents of setup.py
from cx_Freeze import setup, Executable

import distutils
import opcode
import os

# opcode is not a virtualenv module, so we can use it to find the stdlib; this is the same
# trick used by distutils itself it installs itself into the virtualenv
distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
build_exe_options = {'include_files': [(distutils_path, 'distutils')], "excludes": ["distutils"]}

setup(
    name="foo",
    version="0.1",
    description="My app",
    options={"build_exe": build_exe_options},
    executables=[Executable("foo_main.py", base=None)],
)

Благодарю Бруно Оливейру за ответ на github
Полный ответ в гисте: https://gist.github.com/nicoddemus/ca0acd93a20acbc42d1d

Я нашел обходной путь о distutils проблема при замерзании изнутри virtualenv это может помочь другим.

Сначала убедитесь, что исключили distutils из вашей сборки:

build_exe_options = {'excludes': ['distutils']}

Во-вторых, объявите эту функцию в вашем setup.py файл:

def copy_distutils_to_build_dir(build_dir):
    # the code below was obtained from the distutils.py file created by
    # virtualenv
    import opcode
    dirname = os.path.dirname
    distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
    target_dir = os.path.join(build_dir, 'distutils')
    if os.path.isdir(target_dir):
        shutil.rmtree(target_dir)
    shutil.copytree(distutils_path, target_dir)

Наконец, вызовите функцию после вызова setup() в вашем setup.py:

setup(...)
copy_distutils_to_build_dir(join('build', 'exe.win32-3.4'))

Это скопирует весь distutils пакет из исходного интерпретатора в каталог, содержащий ваш замороженный исполняемый файл.

Хакки и некрасиво, но это работает. Я хотел бы услышать идеи для улучшения хотя.

Это было давно, но я столкнулся с той же проблемой. Я смог решить эту проблему, скопировав пакет distutils из локальной библиотеки Python в библиотеку virtualenv. Я еще не знаю о побочных эффектах. Кажется, все работает хорошо.

Одна из проблем заключается в том, что distutils/__init__.py в вашем venv пытается выполнить неявный относительный импорт (импорт dist вместо правильного import из distutils import dist), так что это будет первое, что нужно исправить. Как был создан venv? Откуда берется distutils/__init__.py?

Другие вопросы по тегам