Pip安装升级无法删除临时文件

2024-10-02 16:29:46 发布

您现在位置:Python中文网/ 问答频道 /正文

在维护CLI实用程序的过程中,我想添加一个update操作,该操作将从PyPI获取该包的最新版本并升级现有安装。在

$ cli -V
1.0.23

$ cli update
// many lines of pip spam

$ cli -V
1.0.24  // or etc

这在系统范围内(在C:\Python36中)安装了Python的所有计算机上都能正常工作,但是作为用户(在C:\users\username\AppData\Local\Programs\Python\Python36)安装了Python的计算机在卸载旧版本时会收到以下错误:

^{pr2}$

我假设这是因为当pip试图删除错误文本中调用的cli.exe当前正在运行,但是这里的路径不是指向该exe所在的%LOCALAPPDATA%\Programs\Python\Python36\Scripts,而是%TEMP%。如何允许将文件移到那里,但不在文件到达后将其删除?在

按照错误消息的建议,将--user包含在安装参数中并不能解决问题(与前面编辑的问题相反),但将cli可执行文件移到别处可以解决问题。在

我希望答案是:

  1. 解释无法从临时目录中删除可执行文件的基本问题,以及。。。在
  2. 提供了该问题的解决方案,可以绕过权限错误,也可以查询此包是否以用户身份安装,以便代码可以将--user添加到参数中。在

虽然问题相当普遍,但MCVE如下:

def update(piphost):
    args = ['pip', 'install',
        '--index-url', piphost,
        '-U', 'cli']
    subprocess.check_call(args)

update('https://mypypiserver:8001')

Tags: pip文件用户可执行文件参数cli计算机错误
1条回答
网友
1楼 · 发布于 2024-10-02 16:29:46

正如最初猜测的那样,这里的问题是试图删除正在运行的可执行文件。Windows不喜欢这种胡说八道,当你尝试的时候会抛出PermissionErrors。但奇怪的是,您绝对可以重命名一个正在运行的可执行文件,实际上有几个questionsfromdifferenttags使用这个事实来允许对正在运行的可执行文件进行明显的更改。在

这也解释了为什么可执行文件似乎是从%LOCALAPPDATA%\Programs\Python\Python36\Scripts运行的,但未能从%TEMP%中删除。{pip>在执行过程中试图删除非法的文件夹(pip3)。在

实施过程如下:

  1. 重命名当前可执行文件(Path(sys.argv[0]).with_suffix('.exe')
  2. pip install更新包
  3. 向入口点添加逻辑,删除重命名的可执行文件(如果存在)。在
import click  # I'm using click for my CLI, but YMMV
from pathlib import Path
from sys import argv

def entrypoint():
    # setup.py's console_scripts points cli.exe to here

    tmp_exe_path = Path(argv[0]).with_suffix('.tmp')
    try:
        tmp_exe_path.unlink()
    except FileNotFoundError:
        pass
    return cli_root

@click.group()
def cli_root():
    pass

def update(pip_host):

    exe_path = Path(argv[0])
    tmp_exe_path = exe_path.with_suffix('.tmp')
    handle_renames = False
    if exe_path.with_suffix('.exe').exists():
        # we're running on Windows, so we have to deal with this tomfoolery.
        handle_renames = True
        exe_path.rename(tmp_exe_path)
    args = ['pip', 'install',
        ' index-url', piphost,
        '-U', 'cli']
    try:
        subprocess.check_call(args)
    except Exception:  # in real code you should probably break these out to handle stuff
        if handle_renames:
            tmp_exe_path.rename(exe_path)  # undo the rename if we haven't updated

@cli_root.command('update')
@click.option(" host", default='https://mypypiserver:8001')
def cli_update(host):
    update(host)

相关问题 更多 >