使用 Nvidia 官方 Docker 镜像折腾 Stable Video Diffusion 的时候,发现 OpenCV 社区有一个古怪的 issue 需要手动解决,所以顺手写了一个能够自动修复的小工具。

以及,聊聊如何快速的发布一个 Python 软件包。

写在前面

如果你在使用 Python 生态的软件时,遇到了 module 'cv2.dnn' has no attribute 'DictValue' 的报错,可以试试看这个小工具。

当然,如果你想进一步确认是因为 OpenCV 引起的问题,可以尝试执行下面的命令:

python -c "import cv2; print(cv2.__version__)"

如果你收获的不是某个版本号,而是下面的报错日志,说明你的 Python 软件包存在需要修复的问题。

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.10/dist-packages/cv2/__init__.py", line 181, in <module>
    bootstrap()
  File "/usr/local/lib/python3.10/dist-packages/cv2/__init__.py", line 175, in bootstrap
    if __load_extra_py_code_for_module("cv2", submodule, DEBUG):
  File "/usr/local/lib/python3.10/dist-packages/cv2/__init__.py", line 28, in __load_extra_py_code_for_module
    py_module = importlib.import_module(module_name)
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/usr/local/lib/python3.10/dist-packages/cv2/typing/__init__.py", line 168, in <module>
    LayerId = cv2.dnn.DictValue
AttributeError: module 'cv2.dnn' has no attribute 'DictValue'

这个问题在社区早些时候有被反馈(opencv/opencv-python #884),主要原因是在安装 numpy 时被带入一起安装的版本过旧 opencv 导致的兼容性问题。比较 Trick 的是我们并不能通过简单执行 pip install 来更新软件包,需要遵从帖子进行一些手动清理安装,才能将问题解决。

所以,我写了一个简单的开源小工具,来自动修正这个问题,项目开源地址在:soulteary/opencv-fixer

下面讲讲如何使用这个小工具。

OpenCV Fixer

工具的使用非常简单,和使用普通的软件包一样,使用 pip install 来完成工具包的下载:

pip install opencv-fixer==0.2.5

软件的修复需要进行 OpenCV 的清理和更新下载,如果你访问 Python 官方的 PyPi 源比较慢,可以顺手更新软件源为国内的镜像:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

然后,执行下面的命令,就能够完成 OpenCV 的自动修复工作了:

python -c "from opencv_fixer import AutoFix; AutoFix()"

如果一切正常,你将看到类似下面的日志输出:

Uninstalling the following OpenCV-related packages: opencv, opencv-fixer

Successfully uninstalled opencv

Successfully uninstalled opencv-fixer

Found opencv-python version is lower than 4.9, version=4.7.0

Begin upgrade your opencv-python version to 4.9+.

The folder /usr/local/lib/python3.10/dist-packages/cv2 has been removed successfully

...

如果我们再次执行之前的测试命令,能够得到 OpenCV 的版本号,那么说明一切都修复正常啦:

# python -c "import cv2; print(cv2.__version__)"
4.9.0

当然,如果我们在 Docker 环境或者使用 root 用户执行,可能会收到下面的 warning 警告日志:

Install opencv-python-headless failed: WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

但其实是没有问题的,如果我们执行 pip show opencv-python-headless,能够看到软件已经被正确安装:

# pip show opencv-python-headless
Name: opencv-python-headless
Version: 4.9.0.80
Summary: Wrapper package for OpenCV python bindings.
Home-page: https://github.com/opencv/opencv-python
Author: 
Author-email: 
License: Apache 2.0
Location: /usr/local/lib/python3.10/dist-packages
Requires: numpy, numpy, numpy, numpy
Required-by: 

其他:快速发布一个 Python 软件包

想要快速发布能够被 pip install 安装的 Python 软件包,其实很简单。

首先,需要注册一个 PyPi 账号,注册完毕后,会要求我们验证邮箱有效性。再完成邮箱验证后,我们需要在账号中配置“二步认证”,从而开启获取 API Token 的权限。

获取的 API Token 页面下方,有可以一键复制的配置文件,内容类似下面这样,我们可以保存起来,稍晚使用:

[pypi]
  username = __token__
  password = pypi-一长串Token

如果你是 macOS 用户,在不配置或者更新本地 Python 环境的情况下,如果想直接发布一个软件包,可能会比较麻烦。但是如果使用 Docker 就会变的简单许多:

cd package-dir

docker run --rm -it -v `pwd`:/app python:3.10 bash

比如,使用上面的命令,可以快速的将软件包里的内容映射到 Python 3.10 容器的 /app 目录,方便我们用一个完备、干净的环境做软件发布。

发布过程中,我们可以配置软件源和完成依赖软件包的下载:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

pip install packaging twine

完成基础依赖后,执行下面的命令,可以将我们之前获得的 API Token 保存为可以通过 PyPi 源认证的配置文件。

cat << EOF > ~/.pypirc
[pypi]
  username = __token__
  password = pypi-一长串Token
EOF

一切就绪之后,我们执行下面的命令,完成 Python 软件包的构建和发布就完事啦:

python setup.py sdist bdist_wheel
twine upload dist/*

最后

好了,这篇文章就先写到这里。

–EOF