首页 > 解决方案 > 如何在 pipenv 环境中处理 `pip install`(不反映在 Pipfile 中,仅反映在 `pipenv graph` 中)?

问题描述

如果有人不小心使用pip install而不是pipenv install在 pipenv 环境中使用,则该包不会反映在 Pipfile 上的包列表中,也不会反映在 Pipfile.lock 中。

问题是您可能会使用此 Pipfile.lock 进行部署,以为您拥有所需的一切,而实际上您缺少包。

我正在查看文档https://pipenv.pypa.io/以找出当您运行pip install而不是pipenv install(即使是错误地)时实际发生的情况,但我找不到对此的解释。

如果你运行pipenv graph它,它实际上会显示通过 pip 安装的包!所以我知道 pipenv 不知何故知道这些包。但是我需要做什么才能使这些反映在 Pipfile 中?

标签: pythonpippipenv

解决方案


首先,让我们澄清一下该pipenv install命令只是pip. 如果您使用 安装--verbose,您会看到它也只是在使用pip install包并将其放置在同一个已激活的虚拟环境中。所以答案

我正在查看文档https://pipenv.pypa.io/以了解当您运行pip install而不是pipenv install(即使是错误地)时实际发生的情况

只是pipenv- 特定的操作不会被执行。这包括更新PipfilePipfile.lock(这是首先使用的主要原因之一pipenv)以获得确定性构建。Pipfile您可以手动更新自己,但对于Pipfile.lock ...您不能。

如果你运行 pipenv graph 它实际上会显示通过 pip 安装的包!

是的,因为正如我所说,他们都只使用pip. 这两种方法都会将软件包安装在同一个虚拟环境中,并且pipenv graph只是检查一个环境。这些包将被存储在一个文件夹中lib/pythonX.Y/site-packages,无论是 withpipenv还是 plain pip

现在谈谈你的实际问题:

但是我需要做什么才能使这些反映在 Pipfile 中?

D Malan 对 using 的评论pipenv clean是一个很好的方法。从文档:

$ pipenv clean --help
Usage: pipenv clean [OPTIONS]

  Uninstalls all packages not specified in Pipfile.lock.

Options:
  --bare           Minimal output.
  --dry-run        Just output unneeded packages.
  ...

如前所述,您只需要运行该命令来检查不一致之处。添加--dry-run命令,使其仅报告,而不是实际卸载它们。

然后,您可以为此制作一个脚本,例如这个 Bash 脚本:

#!/usr/local/bin/bash

echo "Checking if there are packages in venv not in Pipfile.lock"

# Get packages pipenv did not find in Pipfile.lock
# NOTE:
#   Here, mapfile requires Bash 4.x syntax
#   For alternatives: https://stackoverflow.com/a/32931403/2745495
mapfile -t packages < <(pipenv clean --dry-run)

if [ ${#packages[@]} -eq 0 ]; then
    echo "All good!"
else
    echo "Found ${#packages[@]} not in Pipfile.lock!"
    for pkg in "${packages[@]}"; do
        echo "  ${pkg}"
    done
    echo ""
    echo "Check if they need to be 'pipenv install'-ed or deleted with 'pipenv clean'"

    # Make sure script exits with a non-zero code here
    exit 1
fi

在带有pip install-ed 包(例如 mypy)和pipenv install-ed 包(例如 flake8)的测试环境上运行它:

(my-test-repo) $ pipenv graph
flake8==3.8.4
  - mccabe [required: >=0.6.0,<0.7.0, installed: 0.6.1]
  - pycodestyle [required: >=2.6.0a1,<2.7.0, installed: 2.6.0]
  - pyflakes [required: >=2.2.0,<2.3.0, installed: 2.2.0]
mypy==0.790
  - mypy-extensions [required: >=0.4.3,<0.5.0, installed: 0.4.3]
  - typed-ast [required: >=1.4.0,<1.5.0, installed: 1.4.1]
  - typing-extensions [required: >=3.7.4, installed: 3.7.4.3]

(my-test-repo) $ cat Pipfile.lock | grep mypy

(my-test-repo) $ ./check.sh 
Checking if there are packages in venv not in Pipfile.lock
Found 4 not in Pipfile.lock!
  typing-extensions
  typed-ast
  mypy
  mypy-extensions

Check if they need to be 'pipenv install'-ed or deleted with 'pipenv clean'

(my-test-repo) $ pipenv install mypy
...
✔ Success! 
Updated Pipfile.lock (e60379)!
Installing dependencies from Pipfile.lock (e60379)...
     ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:

(my-test-repo) $ ./check.sh 
Checking if there are packages in venv not in Pipfile.lock
All good!

为了解决问题

您可能会使用此 Pipfile.lock 进行部署,以为您拥有所需的一切,而实际上您缺少包。

如果您使用的是 Git,请将脚本作为您的git pre-commit hook的一部分。

预提交挂钩首先运行,甚至在您输入提交消息之前。它用于检查即将提交的快照、查看您是否忘记了某些内容、确保测试运行或检查您需要在代码中检查的任何内容。从此钩子中退出非零值会中止提交,尽管您可以使用git commit --no-verify.

(my-test-repo) $ cp check.sh .git/hooks/pre-commit
(my-test-repo) $ chmod +x .git/hooks/pre-commit

(my-test-repo) $ git add .
(my-test-repo) $ git commit
Checking if there are packages in venv not in Pipfile.lock
Found 4 not in Pipfile.lock!
  typing-extensions
  mypy
  mypy-extensions
  typed-ast

Check if they need to be 'pipenv install'-ed or deleted with 'pipenv clean'
(my-test-repo) $

发现不一致时会中止提交,从而防止您提交可能不完整的 Pipfile.lock。


推荐阅读