如何恢复旧的Python环境?
我遇到了一点麻烦,因为服务器升级了,之前的一些Python环境不再工作了。我不能直接激活旧环境,但我想创建一个新的环境,尽量让它和旧环境一样。
这意味着我需要在新环境中安装和旧环境相同版本的包。
有没有办法从旧环境中提取这些信息,比如导出到一个requirements.txt文件里?在旧环境中似乎找不到可以用的requirements.txt文件。
补充:谢谢大家的讨论。是我没在升级前做pip freeze,这是我的错,但我没想到事情会这么脆弱。
有些代码比较旧(我知道会有人提到在某些情况下使用了Python 2.7),但是比如说,当我从一个激活的包中运行pip freeze时,我得到了:
# pip freeze
/.../venv/bin/python: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory
我知道机器上安装了Python 2.7,但我在整个服务器上查找了所有文件,还是找不到这个对象文件。
1 个回答
这里有一个 shell 脚本,它大致上能实现 pip freeze
的功能。我在一个我知道结果的环境中测试过它(就是 Charcoal SmokeDetector 项目),结果大致上是对的;不过,有很多 Python 包的名称和文件名并不完全一致。
#!/bin/sh
: ${1?"Syntax: $0 <sdenv>">}
site_packages=""
for d in "$1"/lib/python3.?/site-packages "$1"/lib/python3.??/site-packages; do
test -d "$d" || continue
[ "$site_packages" ] && echo "$0: ignoring $site_packages" >&2
site_packages="$d"
break
done
: ${site_packages?"No lib/python3.*/site_packages found in $1"}
for package_dir in "$site_packages"/*/; do
case $package_dir in
*.dist-info/ | *.egg-info/ | */__pycache__/ ) continue;;
esac
found=""
for metadata in "${package_dir%/}"-*.dist-info/METADATA \
"${package_dir%/}"-*.egg-info/PKG-INFO; do
test -f "$metadata" || continue
awk '/^Name:[ \t]*/ { name=$0; sub(/^Name:[ \t]*/, "", name) }
/^Version:[ \t]*/ {ver=$0; sub(/^Version:[ \t]*/, "", ver) }
name && ver { print name "==" ver; found=1; exit }
END { exit(1-found) }' "$metadata" && found=yes && break
done
test "$found" && continue
package_name=$(basename "$package_dir")
if [ -f "${package_dir}__init__.py" ]; then
if [ "${package_name}" != "${package_name#_}" ] &&
[ -d "$site_packages/${package_name#_}" ]; then
continue
fi
PYTHONPATH="${site_packages%/site-packages}${PYTHONPATH+:}${PYTHONPATH}" \
python3 <<________HERE 2>/dev/null && found="yes"
import $package_name
ver = $package_name.__version__
print(f'$package_name=={ver}')
________HERE
fi
test "$found" && continue
echo "$0: could not extract metadata for $package_name" >&2
echo "$package_name"
done
另外,这个脚本也有 pip freeze
常见的问题;它会列出所有已安装的包,而不仅仅是你明确要求的那些包。所以比如说,如果你想安装 se7en
这个包,而它依赖于 six
,那么 six
也会出现在结果中,即使将来 se7en
的新版本不再需要 six
的情况下,这个包依然会被列出来。
对于 Smokey 的依赖,上面的脚本会对 dns
(实际包名是 dnspython
)、attr
(我 觉得 实际包名是 attrs
,但它奇怪地创建了一个单数形式的目录)、msgpack
(实际包名是 msgpack-python
)和 pkg_resources
(没有提供版本号)发出警告。可以说这个脚本可以改进一下,修复其中的一些问题,但可能还有其他一些特殊情况没有考虑到。总之,可以把这当作一个粗略的草图。