在开发模式下无法从 windows 上的 pypy virtualenv 卸载 python 包

Failure to uninstall a python package from a pypy virtualenv on windows in develop mode

TL;DR: 运行ning python setup.py develop --uninstall 来自使用 tox 创建的 pypy 环境导致异常: error: [Error 32] The process cannot access the file because it is being used by another process: c:\users\shach\code\pydocstyle\.tox\pypy\site-packages\funniest.egg-link.

大家好,

我的 python 包有一组集成测试,它们执行以下操作:

  1. 呼叫python setup.py develop(使用subprocess.check_call
  2. 运行 包的所有测试
  3. 调用 python setup.py develop --uninstall(再次使用 subprocess.check_call

tox 正在 运行 进行测试。在 python 版本 2733343536 上一切正常,但代码在 pypy 上失败.

我不会在此处包含 setup.py 和项目文件,您可以假设它们没问题。我使用显示的最小包复制了这个 here 并且它仍然有效(失败?)。

为了重现,我创建了一个 python 脚本,其中 运行 如下:

import shlex
import subprocess

subprocess.check_call(shlex.split('python setup.py develop'))
print('----------')
subprocess.check_call(shlex.split('python setup.py develop --uninstall'))

运行使用系统上安装的常规 pypy 来处理文件就可以了:

C:\Users\shach\code\bla\funniest>pypy test.py
running develop
running egg_info
writing funniest.egg-info\PKG-INFO
writing dependency_links to funniest.egg-info\dependency_links.txt
writing top-level names to funniest.egg-info\top_level.txt
reading manifest file 'funniest.egg-info\SOURCES.txt'
writing manifest file 'funniest.egg-info\SOURCES.txt'
running build_ext
Creating c:\python\pypy\site-packages\funniest.egg-link (link to .)
Adding funniest 0.1 to easy-install.pth file

Installed c:\users\shach\code\bla\funniest
Processing dependencies for funniest==0.1
Finished processing dependencies for funniest==0.1
----------
running develop
Removing c:\python\pypy\site-packages\funniest.egg-link (link to .)
Removing funniest 0.1 from easy-install.pth file

C:\Users\shach\code\bla\funniest>

但是当我 运行 它来自 pypytox 环境时:

C:\Users\shach\code\bla\funniest>tox
GLOB sdist-make: C:\Users\shach\code\bla\funniest\setup.py
pypy inst-nodeps: C:\Users\shach\code\bla\funniest\.tox\dist\funniest-0.1.zip
pypy installed: cffi==1.10.1,funniest==0.1,greenlet==0.4.12,readline==6.2.4.1
pypy runtests: PYTHONHASHSEED='122'
pypy runtests: commands[0] | python test.py
running develop
running egg_info
writing funniest.egg-info\PKG-INFO
writing dependency_links to funniest.egg-info\dependency_links.txt
writing top-level names to funniest.egg-info\top_level.txt
reading manifest file 'funniest.egg-info\SOURCES.txt'
writing manifest file 'funniest.egg-info\SOURCES.txt'
running build_ext
Creating c:\users\shach\code\bla\funniest\.tox\pypy\site-packages\funniest.egg-link (link to .)
funniest 0.1 is already the active version in easy-install.pth

Installed c:\users\shach\code\bla\funniest
Processing dependencies for funniest==0.1
Finished processing dependencies for funniest==0.1
----------
running develop
Removing c:\users\shach\code\bla\funniest\.tox\pypy\site-packages\funniest.egg-link (link to .)
error: [Error 32] The process cannot access the file because it is being used by another process: c:\users\shach\code\bla\funniest\.tox\pypy\site-packages\funniest.egg-link
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    subprocess.check_call(shlex.split('python setup.py develop --uninstall'))
  File "C:\Python\pypy\lib-python.7\subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
CalledProcessError: Command '['python', 'setup.py', 'develop', '--uninstall']' returned non-zero exit status 1
ERROR: InvocationError: 'C:\Users\shach\code\bla\funniest\.tox\pypy\bin\python.EXE test.py'
___________________________________ summary ___________________________________
ERROR:   pypy: commands failed

C:\Users\shach\code\bla\funniest>

这是我用来复制的tox.ini

[tox]
envlist = pypy
[testenv]
commands=python test.py

我确定我对该目录有 read/write 权限,现在我有点失去理智了。

它在 linux 上工作得很好。可能是因为您可以删除正在使用的文件(inodes,等等):^)

更新 1:

我认为问题可能在于 developdevelop --uninstall 都是来自同一个 python 文件的 运行,并且某些资源没有被清理正确(可能是一个锁定 egg-link 的打开文件),所以我手动 运行 它:

C:\Users\shach\code\bla\funniest>.tox\pypy\bin\activate.bat

(pypy) C:\Users\shach\code\bla\funniest>pypy setup.py develop
running develop
running egg_info
writing funniest.egg-info\PKG-INFO
writing dependency_links to funniest.egg-info\dependency_links.txt
writing top-level names to funniest.egg-info\top_level.txt
reading manifest file 'funniest.egg-info\SOURCES.txt'
writing manifest file 'funniest.egg-info\SOURCES.txt'
running build_ext
Creating c:\users\shach\code\bla\funniest\.tox\pypy\site-packages\funniest.egg-link (link to .)
funniest 0.1 is already the active version in easy-install.pth

Installed c:\users\shach\code\bla\funniest
Processing dependencies for funniest==0.1
Finished processing dependencies for funniest==0.1

(pypy) C:\Users\shach\code\bla\funniest>pypy setup.py develop --uninstall
running develop
Removing c:\users\shach\code\bla\funniest\.tox\pypy\site-packages\funniest.egg-link (link to .)
error: [Error 32] The process cannot access the file because it is being used by another process: c:\users\shach\code\bla\funniest\.tox\pypy\site-packages\funniest.egg-link

(pypy) C:\Users\shach\code\bla\funniest>

仍然失败:(

请指教!

沙查尔。

更新 2:

我尝试使用 Sysinternal 的 Process Explorer 和 nada 检查是否有一个进程持有该文件。我手动 运行 pypy setup.py develop,然后检查 Process Explorer 并确保文件没有在任何进程中打开,然后 运行 pypy setup.py develop --uninstall 和同样的错误是提出。

更新 3:

关闭CMD再打开CMD后仍然出现

更新 4:

重启机器不能解决这个问题!什么-----?

根据描述,似乎在 pypy setup.py develop --uninstall 的 运行 中的某处,一个文件或目录被保持打开状态,这阻止了它在 windows 上被删除。您可以尝试使用“-X track-resources”参数(pypy -X track-resources setup.py develop --uninstall)运行 pypy,如果在资源关闭之前释放持有资源的对象,它应该会通知您。有时扫描像 s - open(path).read() 这样的代码可能足以发现问题,该代码会泄漏文件描述符,直到垃圾收集器 运行 注意到幽灵对象并将其删除。代码应该使用上下文管理器; with open(path) as fid: s = fid.read()

TL;DR: 不要直接使用 setup.py,使用 pip install -e ..

看来问题出在windows上的setuptools。发生的情况是 egg-link 文件在被删除之前仅打开和关闭了几行 - windows 无法处理。

不知何故 pip 确实处理了这种情况,我会在有更多信息时更新。

我在 setuptools 中打开了一个 issue