cx_freeze 在 virtualenv 中缺少 distutils 模块
Posted
技术标签:
【中文标题】cx_freeze 在 virtualenv 中缺少 distutils 模块【英文标题】:cxfreeze missing distutils module inside virtualenv 【发布时间】:2013-01-09 21:49:24 【问题描述】:从 python3.2 项目运行 cxfreeze 二进制文件时,出现以下运行时错误:
/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
相应地,在 cxfreeze 输出的缺失模块部分中有几个 distutils
条目:
? 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 复制了问题。
值得注意的是,我通过运行$VIRTUAL_ENV/build/cx-freeze/setup.py install
安装了 cx-freeze,因为它没有在 pip 中干净地安装。
【问题讨论】:
virtualenv 中的 distutils 不是常规的 distutils,它正在做一些奇怪的事情来使 virtualenv 工作。如果你在 virtualenv 之外冻结它会起作用吗? 为此我需要 python 3。有没有办法以 3 为目标释放而不改变 python 的替代品(我相信这会破坏 ubuntu 中不为人知的事情)。 在 Ubuntu 中,Python 3 是python3
。无需更改任何内容,您可以将它与 Python 2 一起使用。
但我需要安装 cx_freeze 的 python3 版本(如果我希望冻结的二进制文件与 python3 兼容)。而且我无法安装它,因为貌似python3 cx_freeze 需要系统python(即env python
是python3)。
如果你为 cx_Freeze 执行python3 setup.py install
,它应该为 Python 3 安装它。
【参考方案1】:
找到另一种解决方法,使您在冻结时仍能使用 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)],
)
感谢 Bruno Oliveira 在 github 上提供的答案 完整答案:https://gist.github.com/nicoddemus/ca0acd93a20acbc42d1d
【讨论】:
我需要为 lib/distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'lib/distutils') 加上前缀【参考方案2】:总结我的cmets:
virtualenv 中distutils
的副本正在做一些奇怪的事情,让 cx_Freeze 感到困惑。简单的解决方法是在 virtualenv 之外冻结,以便它使用 distutils 的系统副本。
在 Ubuntu 上,Python 2 和 3 愉快地共存:只需使用 python3
对 Python 3 做任何事情。例如在 Python 3 下安装 cx_Freeze:python3 setup.py install
。
【讨论】:
您没有其他解决方案吗?我正在使用 Python 2.7.5 运行 OSX 和 venv,并且真的不想污染我的系统 python。 您可以尝试使用 conda envs 代替 virtualenvs。无论 distutils 做些什么来支持 virtualenvs,我敢打赌它不涉及 conda envs。 找到了解决问题的要点:gist.github.com/nicoddemus/ca0acd93a20acbc42d1d【参考方案3】:我找到了一种解决方法,解决了从virtualenv
冻结时出现的distutils
问题,这可能对其他人有所帮助。
首先确保从您的构建中排除 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.py
中调用setup()
之后调用函数:
setup(...)
copy_distutils_to_build_dir(join('build', 'exe.win32-3.4'))
这会将整个 distutils
包从原始解释器复制到包含冻结的可执行文件的目录。
Hackish 和丑陋,但它的工作原理。不过,我很想听听改进的想法。
【讨论】:
【参考方案4】:一个问题是你的 venv 中的 distutils/__init__.py 试图做一个隐式的相对导入(import dist 而不是正确的 from distutils import dist),所以这是首先要解决的问题。 venv 是如何创建的? distutils/__init__.py 来自哪里?
【讨论】:
venv 是用mkvirtualenv -p python3.2 name
创建的。
将 import distutils
更改为 from distutils import dist
在该导入行上仍然失败。 distutils/__init__.py
来自$VIRTUAL_ENV/lib/python3.2/distutils/__init__.py
。【参考方案5】:
现在已经有一段时间了,但我遇到了同样的问题。我能够通过将 distutils 包从本地 Python 库复制到 virtualenv 库来解决它。我还不知道副作用。一切似乎都运行良好。
【讨论】:
以上是关于cx_freeze 在 virtualenv 中缺少 distutils 模块的主要内容,如果未能解决你的问题,请参考以下文章
从 crontab 在 virtualenv 中运行 python 方法
未使用 pip 在 virtualenv 中安装 Python 包
pip install mod_wsgi 在 virtualenv 中失败