Pip: 添加“升级”和“升级所有”命令

创建于 2011-03-15  ·  251评论  ·  资料来源: pypa/pip

(更新以反映 2020 年 4 月的实际情况)

这个问题最初是为了改变pip install --upgrade的行为,通过添加一个新的upgrade命令,在升级包时有不同的行为。 较旧的递归“急切”默认值引起了许多人的悲痛 (#304) 然而,在对此进行了大量讨论之后,所采取的方法是添加--upgrade-strategy标志。 该标志最初的默认值为“eager”,在 #4500 中更改为更好的默认值。

“升级所有包”功能的跟踪问题是#4551。

upgrade auto-locked enhancement

最有用的评论

你会在未来 10 年内实施这个吗?

所有251条评论

“upgrade”是“install --upgrade”的简单别名。 需要多想想
关于“全部升级”; 一方面,我认为它只会升级包
在 sys.prefix 里面? (即,如果您在 virtualenv 中,它不会尝试
升级全局包)。 那将是搬家的理由
UninstallPathSet.can_uninstall() 到更通用命名的函数(或
InstallRequirement 的方法),所以它提供了通用的“我可以触摸这个吗?”
决定。


Original Comment By: Carl Meyer

为了记录,我认为这似乎是个好主意,因为有能力
升级前卸载。 虽然我更喜欢--all选项
upgrade而不是自己的upgrade-all命令。

对于 can_uninstall() 的问题,我同意.. 这可能很方便
无论如何,在全球范围内。


Original Comment By: Jannis Leidel

我并非完全反对将升级作为 install --upgrade 的别名。 但
这似乎有点微不足道。

upgrade-all 要求您弄清楚什么是“可升级”。 大概一个
先决条件是它住在/lib/pythonX.Y/site-packages
(仅仅在 sys.prefix 下是不够的)。

如果我们允许诸如“zip import”之类的东西(从父
环境进入 virtualenv 环境)然后可能打包在那个
不应该升级父环境,但并不是 100% 清楚那是什么
用户会期待。

我尝试用“pip uninstall”卸载一个可编辑的包,它很
合理地提议删除 .egg-link 并更新 easy-install.pth。 但它
无法合理升级包,所以 can_uninstall 有点
与 can_upgrade 不同。


Original Comment By: Ian Bicking

是的,你是对的,can_uninstall 和 can_upgrade 是不同的。

我想如果我们有“pip import”,我们仍然不想升级
进口全球包; 但是(连同可编辑的)它可能值得“不
升级此”警告到控制台。


Original Comment By: Carl Meyer

+1 此错误


Original Comment By: smyrman

问题#167被标记为与此问题重复。


Original Comment By: Carl Meyer

1

(echo pip; pip freeze | awk 'BEGIN{FS="=="}{print $1}') | xargs sudo pip

安装 -U

这应该升级升级所有已安装的软件包(包括 pip 本身)。 如果
您在 virtualenv 中运行它,您可能不需要使用 sudo。

当然,它具有很高的失败风险——如果升级其中一个软件包
失败整个过程将失败(类似于port upgrade outdated
MacPorts)。


Original Comment By: Tomasz Elendt

+1 升级--all

为什么目前所有的 Python 模块管理工具都一团糟? 为什么不
一个提供简单的升级+升级--all命令?


Original Comment By: Anonymous

我不介意尝试一下实现,但首先要问几个问题。

普遍的共识是支持“--all”的新“升级”命令
选项被添加到pip?

运行 pip upgrade 应该只影响它运行的环境。如果
从 virtualenv 运行,那么只会升级该 env 的本地包;
对于非虚拟环境也是如此


Original Comment By: Kelsey Hightower

凯尔西:从我对上述讨论的阅读来看,我没有看到任何真实的
反对它。 我认为这是一个很好的补充。 主要的边缘情况是
可编辑的 VCS 安装 - 正如 Ian 建议的那样,我认为是“升级”命令
不应该碰那些。 在所有上下文中定义“升级”的含义
可编辑的可能性(包括安装了可编辑的本地存储库,没有
起源)几乎是不可能的,我认为,即使有些半途而废
定义可以放在一起,只会增加维护
已经脆弱的 VCS 后端的负担。 但是对于不可编辑的 - 去
它!


Original Comment By: Carl Meyer

卡尔:酷,我将开始并用结果更新这张票。


Original Comment By: Kelsey Hightower

在处理升级命令时,出现了以下问题:

  • pip upgrade支持哪些方法来指定哪些包
    升级? 我们应该支持需求文件吗?
  • pip upgrade如何处理尚未安装的软件包?
    我们应该安装丢失的软件包吗?
pip 升级用例以及如何处理它们:
# pip upgrade some_installed_package

Try and locate a package that satisfies the requirement. If the

要求不满足升级到请求的版本。 这包括
升级到旧版本。

# pip upgrade --all

Locate all installed packages (non-editables) and update them to a new

版本(如果可用)。

# pip upgrade some_other_package

Warning: some_other_package not installed, use pip install

some_other_package。

我的目标是让升级命令非常简单。 你可以升级
特定的不可编辑包到新版本或旧版本; 或者你可以升级
将所有不可编辑的软件包更新为更新版本。

想法?


Original Comment By: Kelsey Hightower

我认为“pip upgrade”应该是“pip install --upgrade”的确切别名,因为
它现在有效。 这意味着是的,如果它们安装请求的包
没有安装,是的,它接受带有 -r 的需求文件。 他的应该
几乎不需要新代码就可以实现。

升级 --all 将需要一些代码来查找当前的列表
安装了可升级的软件包; 那么它应该只是通过该列表进行安装
--upgrade,如上。


Original Comment By: Carl Meyer

卡尔,谢谢你的回复。 我几乎走你的路
描述。 今天晚些时候我应该能够发布一些示例运行。


Original Comment By: Kelsey Hightower

完成了大部分代码,在我发布代码之前只剩下一点点润色
供审查。

去做:

  • 测试
  • 过滤器需求文件; 将不可编辑的内容添加到包列表中
    升级。
使用升级命令运行 pip
# pip upgrade --all

All packages up-to-date


# pip upgrade --all -v

Packages installed at latest version:

  pip: 0.8.2 (latest)

  distribute: 0.6.14 (latest)

  Python: 2.7.1 (latest)

  wsgiref: 0.1.2 (latest)

All packages up-to-date


# pip upgrade PyYAML

Package updates available:

  PyYAML: N/A (installed) 3.09 (latest)

Downloading/unpacking PyYAML

  Downloading PyYAML-3.09.tar.gz (238Kb): 238Kb downloaded

....

Successfully installed PyYAML

Cleaning up...


# pip upgrade --all -v

Packages installed at latest version:

  pip: 0.8.2 (latest)

  distribute: 0.6.14 (latest)

  PyYAML: 3.09 (latest)

  Python: 2.7.1 (latest)

  wsgiref: 0.1.2 (latest)

All packages up-to-date


# pip upgrade PyYAML==3.08

Downloading/unpacking PyYAML==3.08

....

Successfully installed PyYAML

Cleaning up...


# pip upgrade --all -v

Packages installed at latest version:

  pip: 0.8.2 (latest)

  distribute: 0.6.14 (latest)

  Python: 2.7.1 (latest)

  wsgiref: 0.1.2 (latest)

Package updates available:

  PyYAML: 3.08 (installed) 3.09 (latest)

Downloading/unpacking PyYAML

...

Successfully installed PyYAML

Cleaning up...

  Removing temporary dir /root/upgrade_env/build...

Original Comment By: Kelsey Hightower

最后一组问题(我希望):

  • pip upgrade是否应该解析需求文件并过滤掉
    可编辑? 网址要求如何?

对于需求文件中的每个不可编辑的项目,我想检查
以后版本的索引。 为了做到这一点,我需要收集
需求文件中每一行的包信息。

欢迎任何提示(目前正在查看pip.req.parse_requirements

  • pip upgrade是否应该搜索索引以安装更高版本?
    (这就是我现在正在做的)。 如果不是,升级命令应该如何确定
    如果有升级?

现在我只在以下情况下将软件包添加到升级列表中:

  • 包没有安装
  • 可以升级(来自索引的更高版本),并且没有明确的
    版本被要求
  • 请求的版本与安装的版本不同(版本未命中
    比赛)。
  • 我将需求文件推迟到安装命令,直到我过滤
    排除不可编辑的要求。

Original Comment By: Kelsey Hightower

卡尔在重新阅读您的帖子后,似乎我做的不仅仅是
必需的。 我将上传我的分支,以便您可以查看。 我可能去过
通过检查 PyPi 是否有更高版本来过水。


Original Comment By: Kelsey Hightower

卡尔在重新阅读您的帖子后,似乎我做的不仅仅是
必需的。 我将上传我的分支,以便您可以查看。 我可能去过
通过检查 PyPi 是否有更高版本来过水。


Original Comment By: Kelsey Hightower

是的,听起来你做的比需要的多。 点安装
--upgrade 完成您已经讨论过的所有事情(检查更新的
版本等); 所有“点子升级”应该就像一个两行传递
一切都交给 pip install --upgrade。

这里唯一要写的真正代码是“upgrade --all”得到的代码
环境中已安装的可升级包的完整列表。


Original Comment By: Carl Meyer

是的,我知道。 嗯,我确实学到了很多。 即使这不是必需的
任务,我确实喜欢能够显示在此期间已安装和可用的内容
升级过程(参见上面的测试运行)。

我会重新考虑和清理事情。 我的叉子上的当前变化
升级命令分支。

https://bitbucket.org/khightower/pip/changeset/2bdc202b446c


Original Comment By: Kelsey Hightower

我已经按照卡尔的建议删除了升级命令(我走得很远
首先)。 不确定我喜欢结果,但它确实镜像安装--功能

pip 似乎尝试下载并重新安装软件包,即使
包已经安装并且是最新的。 升级更糟--all , pip 重新安装包括 pip 本身在内的所有内容。 这是 pip 的方式吗
升级应该有效吗? 如果是这样,那么我就快完成了:)

运行pip升级命令
# pip upgrade Mako


Downloading/unpacking Mako

  Running setup.py egg_info for package Mako


    warning: no files found matching '*.jpg' under directory 'doc'

    warning: no files found matching '*.sty' under directory 'doc'

    warning: no files found matching 'autohandler' under directory 'doc'

    warning: no files found matching '*.xml' under directory 'examples'

    warning: no files found matching '*.mako' under directory 'examples'

    warning: no files found matching '*.dat' under directory 'test'

    warning: no files found matching 'ez_setup.py'

Downloading/unpacking MarkupSafe>=0.9.2 (from Mako)

  Running setup.py egg_info for package MarkupSafe


Installing collected packages: Mako, MarkupSafe

  Found existing installation: Mako 0.3.6

    Uninstalling Mako:

      Successfully uninstalled Mako

  Running setup.py install for Mako

    changing mode of build/scripts-2.7/mako-render from 644 to 755


    warning: no files found matching '*.jpg' under directory 'doc'

    warning: no files found matching '*.sty' under directory 'doc'

    warning: no files found matching 'autohandler' under directory 'doc'

    warning: no files found matching '*.xml' under directory 'examples'

    warning: no files found matching '*.mako' under directory 'examples'

    warning: no files found matching '*.dat' under directory 'test'

    warning: no files found matching 'ez_setup.py'

    changing mode of /root/upgrade_env/bin/mako-render to 755

  Found existing installation: MarkupSafe 0.11

    Uninstalling MarkupSafe:

      Successfully uninstalled MarkupSafe

  Running setup.py install for MarkupSafe


    building 'markupsafe._speedups' extension

    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall

-Wstrict-prototypes -fPIC -I/opt/OpenPython-2.7.1/include/python2.7 -c
markupsafe/_speedups.c -o build/temp.linux-x86_64-2.7/markupsafe/_speedups.o

    gcc -pthread -shared

build/temp.linux-x86_64-2.7/markupsafe/_speedups.o -o
build/lib.linux-x86_64-2.7/markupsafe/_speedups.so

Successfully installed Mako MarkupSafe

Cleaning up...

Original Comment By: Kelsey Hightower

Kelsey - 是的,安装 --upgrade 有一些错误; 特别是你
确定#13 ,它甚至重新下载并重新安装软件包
已经是最新的。 解决方案不是做一些不同的事情
使用新的升级命令,是为了修复安装 --upgrade 中的错误。

使用 upgrade --all,我认为 pip 会自行升级是合理的
同样,如果有可用的升级。 (我个人永远不会使用升级
--all,所以我不知道使用它的人会想要什么样的行为
这里)。 显然,如果#13被修复,它会表现得更好。


Original Comment By: Carl Meyer

谢谢卡尔,我会结束这个并开始看#13


Original Comment By: Kelsey Hightower

如果有人有时间,请查看我的升级命令分支。 与此同时
我将进行单元测试,尽量不复制现有的单元测试
安装命令。

https://bitbucket.org/khightower/pip/src/fa7b2a6d2bf1/pip/commands/upgrade.py


Original Comment By: Kelsey Hightower

@vababiy :我试过你的升级命令,但它似乎不能正常工作......所以我自己做了一个:

https://github.com/pypa/pip/pull/313
https://github.com/jedie/pip/commit/7a31d70dabe0e809184fe1b5280c5a7ccf420dd5

@jedie我想你是想在@khightower 发表你的评论。 @vbabiy将她的评论迁移到这里,但没有写升级命令。

+1

@kelseyhightower 有任何进展吗?

+1

+1!

+1

+1

请停止仅通过“+1”来评论该问题。 我们知道需要该功能,但向我们的收件箱发送垃圾邮件无济于事。

相反,我会很高兴看到评论“补丁完成!” ;)

+1

任何更新? 有没有计划添加这个,现在已经3岁了..

+1

我以为这已经合并了。 我可以摆脱我的蟒蛇技能,再试一次。

这个特性会包含在 1.5 中吗? 在 1.5 文档中找不到对它的任何引用...

+1

此问题的状态如何?

被#988屏蔽了

如果这对您来说真的很重要,那么有一些解决方法可以升级所有软件包; 我拼凑了一个脚本来并行执行(https://github.com/ariccio/update-pip-packages),并且互联网上的其他地方还有许多其他实现。

这个问题有两个部分。 upgrade-all可能会被 gh-988 屏蔽,但我看不出upgrade是如何被屏蔽的。 pip upgrade可以是pip install -U --no-deps的简单别名。 这将解决在 setup.py 文件中使用install_requires的主要问题之一。 这不能很快完成吗?

pip upgrade 可以是 pip install -U --no-deps 的简单别名

从描述:

pip upgrade就像pip install --upgrade除了默认情况下它是非递归的(并提供--recursive选项)。 它当前的递归默认行为已引起许多人的悲痛(#304)。 至于现在如何做非递归升级,看这里

那不是pip install -U --no-deps

在这种情况下,“非递归”不仅仅意味着–no-deps 。 非递归升级将升级依赖项,但前提是需要满足父级要求。

@qwcode感谢您的澄清。 那这不是我关心的。 为什么你会称之为“非递归”,它仍然是递归的,但只是更聪明/不同?

我从 gh-571 中的讨论中得出的印象是,真正的非递归是所需的默认值。 这当然是有道理的,并且不必总是编写像https://github.com/scipy/scipy/commit/8e7ee0c4b3c16这样的代码

在#571 中,“非递归”不是--no-deps它是您所说的“更智能/不同”的递归。
注意来自该 PR 的test_upgrade_with_needed_recursive_upgrades()测试。

不拘泥于条款,有 3 件事:

  1. “更智能/不同的升级”,即发生在操作系统包装中的那种,也可能意味着升级依赖项(但前提是它们确实_需要_升级)。
  2. pip 现在做什么,即升级所有依赖项,无论需要或解决冲突。
  3. --no-deps

一些可能的方法来区分 #1 和 #2

  1. “非递归”与“递归”
  2. “正常”与“递归”
  3. “仅在需要递归时”与“不考虑递归就做”

我愿意使用最好的术语......只是不确定那些是什么。

我想我喜欢这个“仅当需要递归”的短语。 也许我应该使用这里的文档:

我也喜欢这个。 如果您将这三个选项一起描述为

a. non-recursive
b. only if needed recursive
c. recursive (or "do it regardless recursive")

那就清楚了。

然后你想选择好的默认值。 对于upgradeinstall -U , (a) 或 (b) 都有意义。 我非常喜欢 (a),但 (b) 也很有意义,因为这就是操作系统打包的作用。

(c) 作为默认值没有任何意义,因此请重新考虑您不更改install -U

澄清为什么我强烈喜欢 (a):一个毫无戒心的用户想要 (b) 并获得 (a) 将不得不阅读一条消息说"non-recursive upgrade can't satisfy all dependencies, please use only-if-needed recursive" ,这没什么大不了的。 如果默认值是 (b),那么毫无戒心的用户最终可能会升级,甚至安装一个他真的不想接触的软件包。 这可能需要数小时甚至数天才能恢复。

(c) 作为默认值没有任何意义,因此请重新考虑您不更改 install -U 的决定

单独留下install -U原因只是出于兼容性原因,然后最终弃用它。

如果默认值是 (b),那么毫无戒心的用户最终可能会升级
甚至他真的不想接触的软件包的安装损坏

如果用户希望无法完成必要的依赖项升级,他们应该特别要求使用--no-deps 。 在我看来,不可能成为默认值。 这种行为会造成比您所考虑的更大的损害(这是异常情况)。 一次又一次,用户将无法获得他们需要的依赖项升级。

弃用install -U听起来不错。

我同意 (b) 比 (a) 更常见。 即使它会更常见 100 倍(我认为并非如此),更多的伤害也是不真实的。 在安装开始之前阅读清晰的错误消息比例如中途编译错误要好得多,imho (a) 仍然是更好的默认值。

依赖--no-deps对非常有经验的用户来说可能没问题,但新用户只有在出现问题后才会了解它。

反正我是说服不了你的。 然后回到说明书

try:
   import dependency
except ImportError:
    install_requires.append('dependency')
else:
    if dependency.version < 'x.y.z':
        raise ValueError('Please upgrade dependency to x.y.z')

它是。

@qwcode感谢您的详细解释。 我希望这将在不久的将来向前发展 - 只有在需要递归时才会对当前行为进行巨大改进。

本周又花了很多时间来解决为什么我们不使用install_requires ,我添加了一个 :+1: 以摆脱当前的行为。

是否有关于此问题的更新?

我们现在有 2015 年,我仍然需要从pip freeze --local | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U stackoverflow复制

是的,基本上所有的进展都与这个问题有关。

pip_upgrade_github

GitHub 在交叉引用方面做得很好。 所有这些都是可以点击的! (我确定你知道这个?)

是的,但我不明白为什么这个“简单”的功能有这么大的延迟。

这是什么原因?

上午 16.04.2015 嗯 05:28 schrieb Alexander Riccio通知@github.com:

是的,基本上所有的进展都与这个问题有关。

GitHub 在交叉引用方面做得很好。 所有这些都是可以点击的! (我确定你知道这个?)


直接回复此邮件或在 GitHub 上查看。

至于pip upgrade-all ,共识似乎是等待与 #988 相关的工作,然后再发布任何闪亮的新命令,这些命令最终仍然存在缺陷并且可能对工作环境造成危险。 一个不能正确解决需求的简单版本的upgrade-all很容易破坏现有的包

+1

4年你在做什么?

+1

+1

+1

@muhasturk目前,正在等待... https://github.com/pypa/pip/issues/59#issuecomment -93646462

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1 ...对不起,垃圾邮件,但运行pip freeze --local | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U痛苦!

+1

如果有人对此感兴趣,我认为上面的评论有些令人困惑——AFAICT 的实际状态是pip upgrade-all目前由于需要适当的依赖项解析系统而被阻止,但是pip upgrade可以随时执行。 如果有人想在这部分工作,那将非常棒:-)。

(另请参阅从这里开始的线程和@dstufft在此处回复,此处评论同意上述评估。)

这是一年前 pypa-dev 列表中的另一个讨论(同意pip upgrade FOO现在可以完成) https://groups.google.com/forum/#!searchin/pypa -dev/pip$20升级/pypa-dev/vVLmo1PevTg/oBkHCPBLb9YJ

谢谢@qwcode! 我也刚刚在https://pip.pypa.io/en/latest/user_guide/#only -if-needed-recursive-upgrade 看到了新的描述,这很有帮助。

+1

如果我没错的话:

如果没有安装xxx:

  • pip upgrade xxx等价于pip install xxx
  • pip upgrade xxx --recursive相当于pip install xxx --upgrade

如果安装了xxx:

  • pip upgrade xxx --recursive仍然相当于pip install xxx --upgrade (按设计)
  • 但目前没有pip upgrade xxx等价物,这可能是pip install xxx --upgrade-only-if-needed/--upgrade-lazy

目前尚不清楚新命令的附加价值是向pip install添加新选项吗?

目前尚不清楚新命令的附加价值是向pip install添加新选项吗?

许多项目无法接受默认的pip install -U行为。 请参阅我上面的评论(https://github.com/pypa/pip/issues/59#issuecomment-52434862)。 这是一个更长的解释: http :

如果这是不可接受的,那么我猜您打算将 pip install --upgrade 的用法更改为 pip upgrade ?
为什么您不能将当前的 pip install --upgrade 用法更改为 pip install --upgrade-only-needed ?
新命令提供了哪些新选项不能提供的功能?

都是铺牛道。 他担心的不是@rgommers 的个人使用情况,而是他的用户。 如果人们没有更好的了解,他们将寻求“明显”的答案,而现在明显的答案对于 Python 生态系统的某些主要部分来说是有问题的。

的确。 人们不阅读文档。 事实上,我们会修复我们能找到的所有安装文档,但只要用户看到-U--upgrade ,他就会使用它。 人们在被它严重咬伤之前使用--no-deps--only-as-needed或其他任何东西的可能性很小。

为什么您不能将当前的 pip install --upgrade 用法更改为 pip install --upgrade-only-needed ?

需要明确的是:我们现在避免使用pip install --upgrade _and_ 不使用install_requires因为如此。 那是多么糟糕。

我认为这里有一个小误解——IIUC @xavfernandez同意添加非递归升级功能,他们的问题就是为什么该功能的 UI 必须作为新的顶级命令而不是pip install的新选项

@xavfernandez :请注意,#3194 中目前正在讨论什么是此功能最清晰的 UI。

(并且pip install -U将被弃用然后被删除,这样就回答了用户如何知道不使用它的问题:-)。)

我认为这里有一个小误会

我很确定没有。 是的,我们只是在讨论 UI。 但这很重要。

是的,只讨论 UI,我同意这很重要。 但是我看到的是,一旦 pip upgrade 出来了,就没有理由继续使用 pip install ...
安装任何包的用户界面都会变成“pip upgrade foo”

没有理由继续使用 pip install

这是一个问题,为什么? 将pip install --upgrade更改为正确行为的问题(至少对于上面评论中的pip upgrade是避免中断 _and_ 获得正确默认值的方法。

@rgommers :公平地说,我们_会_得到一些非零数量的困惑问题,关于为什么你告诉我在我什至没有安装foo下运行pip upgrade foo ,它没有'不工作(来回争论直到他们真正尝试运行命令而不是假设它不起作用并假装他们运行了它)

在 #3194 上,我发表了评论,也许正确的前进方式是从pip install删除--upgrade pip install ,使pip install始终对显式命名的项目进行升级,并且默认使用--recursive标志的依赖项的最小升级策略,以获取升级时的当前行为。

我想我同意我觉得 #3194 默认的 UX 将变为pip upgrade foo而不是pip install [-U] foo 。 我唯一的问题是我认为拥有这两个命令有点令人困惑,并且鉴于我认为pip upgrade是人们使用的“正确”命令,我认为拥有明显的命令是糟糕的name 是错误的名字。

我有偏头痛,所以我的想法也可能不完全正确,但我有点想弄清楚如何处理该建议的弃用路径可能是正确的前进方向。

好吧,我不会争辩说向后兼容在这里很重要。 我一直赞成改变pip install --upgrade的行为。 它是最干净的,而且成本似乎很小。 但在我看来,它被@qwcode否决了,所以pip upgrade是下一个最好的东西(并且在一年前已经被 pip 开发人员确认)。

如果我们现在想返回更改pip install默认值/行为,太好了。

@dstufft对我来说完全有意义 - 头痛不可能那么糟糕:)

由于我们同意弃用 --upgrade,我们可以保留它并添加两个选项到 pip install: --upgrade-only-needed 和 --upgrade-eager ,第二个是已弃用的 --upgrade 的别名

@xavfernandez我认为将决定糟糕的做法。 除非我理解相当微妙的问题,否则我不确定我是否真的知道我是否想要--upgrade-only-needed--upgrade-eager

@xavfernandez所以你建议在最后的情况下命令是pip install --upgrade-only-needed ? 看起来很丑

最好有一些映射到等效于语义版本固定的东西,例如npmhexCargo 。 这当然需要在 Python 上下文中进行调整,因为 (a) PEP 440版本没有也不能精确地映射到语义版本控制和 (b) 整个 Python 社区不一定在其版本中甚至在其版本中采用类似语义的版本控制PEP 440。

尽管如此,沿着这些路线的东西会非常有帮助,固定指定版本的概念也是如此。

鉴于这些限制,短期内一个可行的选择可能是做一些类似于自制软件的upgradeupgrade --all命令,后者只是继续升级所有东西(可能第一次发出警告)。

然而,从长远来看,在 Python 打包社区中创建关于版本含义的共享约定将非常有用,并且围绕它构建pip支持可能是其中的重要组成部分。

明显的迁移路径是:

点子版本X:

  • 添加选项pip install --eagerpip install --no-eager ,其中--eager表示对于没有附加版本限制的要求,即使已经安装了某个版本,我们也会尝试安装最新版本,并且--no-eager表示安装任何版本我们都满意
  • 还添加选项pip install --eager-recursive与当前的-U语义
  • --no-eager保持默认
  • 如果没有指定这些选项,并且pip install传递了一个没有附加版本号的要求,并且这个要求已经满足,那么输出一个警告说我们没有升级你的包,但在未来我们会的,所以如果你想保持当前的行为,你应该使用--no-eager
  • pip install -U添加弃用警告,将人们推荐给pip install --eager-recursive

点子版本Y:

  • pip install的默认值切换为--eager

点子版本Z:

  • 删除pip install -U

我制作了 Y 和 Z 不同的版本,因为我渴望--eager所以也许我们可以在更积极的时间表上进行更改,同时保留pip install -U一些,因为很多文档已经参考对它,它不会造成任何伤害。 但显然 Y = Z 是一个选项:-)

@chriskrycho :这一切听起来都很棒,但本次讨论是关于如何处理用户明确尝试请求升级到最新版本的软件包的情况,这种情况在今天已经很常见,并且我们没有很好的答案。 我不知道是否有一个请求固定支持的错误开放,但如果没有,那么也许你应该开始一个?

绝对地; 我的观点(我现在承认我完全没有说清楚!)只是要注意,这里采用的任何解决方案都不应与将来采取这种策略相冲突。

pip 的正常弃用路径是什么? 基于时间/版本? 在删除之前需要弃用多长时间?

顺便说一句,我认为“渴望”是用户不会理解的词。 recursive / only-as-needed recursive / always recursive 更清晰。

我们通常会执行两个版本的弃用周期。

我假设的主要版本? 次要版本非常快(7.0 -> 7.1 是一个月)。 主要版本之间通常是半年,所以 1 年的弃用警告?

是的,对不起。 主要版本。 如果我们弃用 8.x 中的某些内容,那么 8.x 的其余部分将是黄色警告,所有 9.x 都是红色警告,并在 10.x 中删除。

谢谢。

从复制@dstufft的评论https://github.com/pypa/pip/pull/3194#issuecomment -152357835在这里,因为它的情况最好的总结:

我猜 tl; dr 是我完全认为我们需要修复“默认”行为,我们只需要解决修复它的具体实现:

  1. 保持 UX 为 pip install --upgrade 并更改默认值。
  2. 使用“正确”默认值将 UX 移动到 pip upgrade 并添加 --recursive 标志。
  3. 将 UX 移至 pip install,删除 --upgrade,并添加 --recursive 标志。

我的 2c:

(1) 拥有良好的用户体验,现在就可以完成
(2) 有点糟糕的用户体验(同时有installupgrade ),现在可以完成
(3) 次优 UX,现在可以更改pip install ,删除--upgrade将仅在 10.0 中完成(在 8.0 和 9.0 中已弃用)。

我不明白为什么(1)的向后兼容问题(无论哪种方式都应该是次要的)会比(3)更糟糕。 所以(1)似乎是最好的。 如果 bw compat 真的很担心,那么选择 (2)。

无论如何,是时候结束了。

我认为 (3) 和 (1) 之间的区别归结为我们是否认为安装或升级是人们想要的最常见的操作——如果是这样,那么将其作为 (3) 中的简短命令可能是最好的。 不过这也没什么大不了的。

顺便说一句,我认为“渴望”是用户不会理解的词。 recursive / only-as-needed recursive / always recursive 更清晰。

我完全不喜欢“eager”拼写,但是递归作为打开和关闭升级的主要词是没有意义的。 我想我们可以使用--upgrade-non-recursive (未来默认值)、 --upgrade-recursive--upgrade-none左右,但它仍然突出了令人困惑的递归行为(我不知道--upgrade-non-recursive意思是如果我还不熟悉遗留 -U 选项的奇怪递归行为),并且--upgrade-none误导性地听起来好像它会确保即使需要保留自我,也不会升级任何包一致性。

如果我们走这条路,那么我不太在意拼写周期,因为大多数人想要的选项只是默认选项,递归升级和不升级选项都是大多数用户很少使用的特殊选项可以无视。

--upgrade-non-recursive (未来默认)...

这当然令人困惑。 但是您忽略了最简单的选项,即根本不提供此开关。 因为如果它与默认行为相同,你为什么需要它?

我认为(3)和(1)之间的区别归结为我们是否认为安装或升级是人们想要的最常见的操作

我希望“安装”。 至少我知道我只升级我故意大量使用的软件包,但每次我看到一些有趣/有用的东西时,只需pip install pkgname

(虽然我不是典型的用户,所以我的期望可能是错误的)

我想我会赞成:

  • 没有新的pip upgrade作为pip install的别名
  • pip install (没有--upgrade*选项)行为不会改变
  • pip install --some_name只会尝试升级命令行上指定的包,而不是它们的依赖项
  • pip install --some_other_name保持旧的--upgrade行为可用

然后有两个选择:

  • 我们不需要/不想要一个弃用路径,那么--some_name可以是--upgrade并且--some_other_name可以是任何看起来最好的
  • 我们需要一个弃用路径,然后 pip8 中的--upgrade会发出警告说它已弃用,我们应该使用--some_other_name来保持旧的行为,或者切换到更安全的--some_name仅在需要时才升级指定的包及其依赖项。

在第二种情况下, --some_name不能是--upgrade 。 所以我们必须为--some_name--some_other_name找到两个新的选项名​​称

在我看来,明显的“最佳”解决方案是将pip install保留为命令,并更改--upgrade的行为以不升级依赖项。 唯一真正的问题是向后兼容性,但是我们有_任何_用户争辩说他们依赖当前的行为吗?

就我个人而言,我倾向于“全力以赴,向后兼容”的观点。 我可以争辩说当前的行为实际上是一个错误,而这种更改将是一个错误修正。 但我确实认为在某些时候我们需要能够说我们已经达到了一个很好的点,我们将对向后兼容性采取更严格的观点。 我认为我们还没有到那个点,但我们可能需要开始让社区知道我们认为为了达到那个点还需要做些什么。

(IMO) 仍然需要某种pip install --upgrade :all:命令来升级所有已安装的软件包。 但这是新功能,因此与此无关。

当前行为 _is_ 很有用,特别是对于像 Pyramid 这样的项目,它们不是单个项目,而是实际上是项目的集合。 能够执行诸如pip install --upgrade-recursive Pyramid的操作以将 Pyramid 及其所有依赖项升级到最新版本会很有用。 一起删除递归意味着我要么必须手动跟踪所有依赖项并执行pip install --upgrade Pyramid dep1 dep2 dep3 dep4 (使用整个依赖项树),要么我需要执行假设的pip install --upgrade :all:并可能升级更多东西比我实际要升级。 在#3194 中,至少有一位用户提到他们希望通过标志提供当前行为,因为它在某些情况下很有用。

是否有任何理由(除了向后兼容)不让它如此pip install隐式地进行“最小”升级? 我试图弄清楚在什么情况下我实际上只希望它安装而不进行升级(IOW,如果我还没有安装最新版本就可以了,但如果我没有安装它就不行了安装),我在想出一个我想要当前行为的案例时遇到了问题。

我喜欢 #3194 中的 _new_ pip upgrade [--recursive]命令的想法(并弃用install --upgrade

我担心任何会破坏兼容性或具有复杂弃用的选择,或者给已经选择繁重的pip install带来更多变化或复杂性的负担。 此外,我个人对“升级”命令很感兴趣,默认情况下,它只是升级类似于发行版工具的工作方式。 “安装”安装,“升级”升级...

我倾向于“坚持下去,向后兼容”的观点

我不是 :) 至少对于这样的核心逻辑。

使 pip install 隐式进行“最小”升级

对我来说,考虑到这似乎是不可能的,对吧? 考虑可能发生的自动构建损坏的数量。 此外,人们在某个时候会陷入关于pip install是什么的概念模型中……这将迫使重新加载新的心智模型。 人们不喜欢那样。

@qwcode我不知道,我认为这不行。 pip upgrade的主要问题是要么删除人们说“无论是否安装都给我最新版本”的方式,要么你有两个几乎完全相同的命令( pip installpip upgrade )。 短期内可能会有一些破损,但我有点担心pip upgrade的实际心理模型,因为我可以看到人们广泛地将他们的安装说明从pip install foo替换为pip upgrade foo (但为什么我要升级我还没有安装的东西?!)。

呃,我想我的意思是可以的。

广泛地将他们的安装说明pip install foo替换为pip upgrade foo

罗杰,这就是为什么我认为upgrade应该升级。 至于“粪” --fill-in-missing ,我并没有坚持下去,所以不要认为我必须拥有它,但请参见下文。

“给我这个的最新版本,不管它是否安装”

  • 如果我没有FOO ,那么我pip install FOO就会得到最新版本。
  • 如果我有FOO ,那么pip upgrade FOO就会得到最新版本。

我想我们在谈论两种情况:

  1. 不知道我是否有FOO ,我希望 _one_ 命令获取最新的FOO ,无论我有没有。
  2. 我想要 _one_ 命令获取最新的FOOBAR 。 我安装了FOO ,但没有安装BAR

我们欠用户_one_命令吗? 与为人们提供快捷方式相比​​,我更喜欢命令的简单性和清晰性。 但是如果用户需要它,那么--fill-in-missing类的东西就会出现。

此外,我个人对“升级”命令很感兴趣,默认情况下,它只是升级类似于发行版工具的工作方式。 “安装”安装,“升级”升级...

澄清点:我刚刚检查了三个流行的发行版工具是如何工作的,以及 AFAICT(部分是基于手册页 b/c 我自己不使用所有这些):

  • 易于:

    • apt install <pkg>执行“升级”——升级或安装取决于它是否已经安装。

    • apt upgrade升级所有已安装的软件包

    • apt upgrade <pkg>不存在,升级单个包的唯一方法是apt install <pkg> (它也接受各种版本说明符)

  • 嗯:

    • yum install <pkg>执行“upstall”

    • yum upgrade升级所有已安装的软件包

    • yum upgrade <pkg>升级指定的软件包列表。 如果它们尚未安装,我不知道会发生什么。

  • 自制:

    • brew install <pkg>执行“upstall”

    • brew upgrade升级所有包

    • brew upgrade <pkg>升级指定的软件包列表。 如果它们尚未安装,我不知道会发生什么。

因此,使用安装进行升级实际上是发行版工具所做的:-)。 并不意味着我们也必须这样做; 只是一个数据点。

我不知道我是否有 FOO,我想要一个命令来获取最新的 FOO,不管我有没有。

我认为最明显引人注目的用例是文档。 示例:我在另一个线程中链接的 django 文档指示人们运行pip install -U <some package> 。 你不想告诉人们“运行pip install <pkg>除非你已经安装了它运行pip upgrade <pkg> ”因为这对新手来说太混乱了,但是如果install没有' t 升级然后只是告诉人们运行pip install <pkg>也会造成混乱,人们开始在安装了旧版本的情况下完成您的教程,然后不知道为什么事情不能正常工作并因此责怪您。 所以你肯定需要一个“upstall”命令,并且它需要简单而明显地包含在文档中。

跟进 Homebrew 的行为以进行比较:如果您尝试安装未安装的软件包,则brew upgrade失败:

$ brew upgrade git
Error: No such file or directory - /usr/local/Cellar/git

此外,当前的brew upgrade行为正在发生变化(请参阅此处的讨论); 在未来的版本中,它将切换为需要--all来升级所有已安装的软件包。

澄清点

我知道有人会注意到这一点。 :)
我几乎回应了自己。 我专注于升级。

百胜升级[...] 如果它们尚未安装,我不知道会发生什么。

它什么都不做

百胜安装执行“upstall”

是的,但默认行为是提示确认,而 pip 没有。

我在另一个线程中链接的 Django 文档

需要明确的是,它们并不是真正的 Django 文档。 Django 文档说pip install Django (https://docs.djangoproject.com/en/1.8/topics/install/)

考虑到-U目前的工作方式,让人们养成使用install -U的习惯,我认为这实际上是一件坏事。

在您链接的示例中,它用于redis ,我认为它没有任何依赖项,因此在这种情况下没问题。

将在人们开始学习您的教程时造成混乱
使用旧版本 [...] 所以你肯定需要一个“upstall”命令

IDK,对我来说,教程应该告诉人们总体上不那么明显。 如果有人正在为 FOO 做教程,并且他们已经安装了 FOO,那么也许他们不应该盲目地“升级”......也许升级会破坏现有环境。

我认为教程应该告诉人们“升级”(伟大的术语!)因为相当多的教程是由项目本身编写的,当人们去看教程时,他们很少先看看现有的 FOO 版本是什么已安装的是,而是他们倾向于查看最新的文档。

我也同意-U目前的工作方式,让人们养成不分青红皂白地使用它的习惯是一个坏习惯,但我认为关键是建议的行为我不认为这是一个坏习惯,而是一件好事。 如果您需要确保安装了特定版本,那么您应该已经使用了== ,我们可以添加一个标志,将默认的“upstall”转回普通的“安装”,供需要确保当前安装的版本或最新版本已安装(尽管我仍然无法想出一个场景,其中这实际上是任何人想要的)。

我认为教程应该告诉人们“升级”

再说一次,他们所处的环境是什么,显然可以升级? 如果它是一个发行版系统 python 环境,那么肯定不是。 如果是其他环境,它们是为应用程序而设计的,那么 upstall 可能会造成破坏。 如果是他们刚刚为教程制作的环境,那么他们不需要升级。

这里的一个关键点是 PyPI 不是一个“策划”的回购,就像发行版回购一样。 您可以相当确定,默认发行版存储库中的“upstall”是安全的……您不知道 PyPI。 每次升级都是一场赌博。 “安装”实际上是保守的。

请记住,让pip install得像一个没有修复 #988 的“upstall”会破坏事情。

考虑AB的安装位置,而A需要B<2 。 现在我去运行新的pip install B ,它将B升级到 v3 或其他(由于没有考虑安装的约束),现在我的环境被破坏了。

对于需要确保当前安装的版本或最新版本已安装的人(尽管我仍然无法想出一个场景,其中这实际上是任何人想要的)。

想出这样的场景是微不足道的。 示例(不幸未编造):当前statsmodels被最新的pandas (0.17.0) 破坏。 我是两者的用户。 我安装了一堆 Python 版本,并且到处都是 venvs。 所以我知道,对于任何 Python/venv,我只想在pandas尚未安装时安装它。 如果是这样,我可能也会有statsmodels然后“upstall”会破坏它。

@rgommers嗯,所以您绝对确定在任何地方的虚拟环境中都没有pip install pandas!=0.17.0pip install pandas<0.17拼写,但我想依赖您已经安装的内容并非完全不合理。

嗯,所以您绝对确定在任何地方的虚拟环境中都没有 Pandas 0.17.0?

那不是我说的。 我确实有一个 Pandas 0.17.0 的 venv,只有一个我没有 statsmodels。 pip install pandas<0.17将完成这项工作,但我没有想到要使用它(主要是因为我不需要,当前的install命令用于此目的)。

无论如何,我不太喜欢或反对 upstall。 当你说你无法想出一个时,我只是想指出一个现实的场景。

+1

这场讨论似乎停滞不前,没有得出结论。 桌面上的任何选项都是对当前状态的重大改进。 看起来所有相关的利弊都已经考虑过了; 对于向后兼容与最佳 API 的相对重要性,只有不同的意见。 也许 pip 开发人员可以尝试最终确定一个决定?

@rgommers他们可能做了决定? https://pip.pypa.io/en/stable/user_guide/#only -if-needed-recursive-upgrade

@rgommers他们可能做了决定? https://pip.pypa.io/en/stable/user_guide/#only -if-needed-recursive-upgrade

@Liso77谢谢,但不 - 这确实是关于这个线程的讨论需要完成。 您链接到的文档只是指向此处。

@rgommers来自我上面发布的链接,我读到开发人员将执行升级命令。 并且不打算添加“仅在需要时”选项来安装命令,因为他们没有为此选项创建术语并且仅使用引号中的描述。 因此,根据您(或 dstuff)在 10 月 30 日的评论 - 它是:_2。 将 UX 移动到使用“正确”默认值的 pip upgrade..._(顺便说一句,我更喜欢这个)
我相信你对这个话题想得更多,你会看到我所做的更微妙的事情。 所以请写下什么(如果你认为有什么)仍然是开放的。 如果您的意思是开发人员在这里明确写下他们的决定并最终解决这个问题可能会很好 - 我同意。

顺便提一句。 如果我们有类似的东西,情况可能会少得多

pip freeze > checkpoint.txt
pip checkout checkpoint.txt

这可以保证将安装恢复到任何“检查点”。 (此时pip install -r 不好)我想在新问题中添加这个建议,但我相信我必须研究和分析更多才能带来真正有用的建议。 我看到有很多警告,但我真的很想有可能

pip checkout git+https://github.com/somebody_trusted/pip_distro4ubuntu<strong i="12">@bleeding_egde_branch</strong>
#or
pip checkout git+https://github.com/somebody_trusted/pip_distro4ubuntu<strong i="13">@stable</strong>

我的意思是,这可以解决(在someone_trusted(或具有大量单元测试的社区)帮助下)您上面描述的pandas 和statsmodels 之类的问题。

(对于这个主题有用的还有:https://pypi.python.org/pypi/peep)

@Liso77很简单:关于这个问题的讨论还没有结束。 执行了upgrade命令(gh-3194)有一个 PR 正在等待,但是 pip 开发人员(至少是 qwcode 和@dstufft ,可能还有@xavfernandez和 @pfmoore)需要决定这是否是他们想要的,或者他们想要改变pip install的行为。 在此之前,什么都不会改变。

+1

因此,似乎就引入新的升级命令达成了一致,最新的未解决的争论是是否应该有一个“upstall”命令,如果是,哪个主命令(安装或升级)应该把它作为开关或默认值.

发表一下我个人的看法:

我认为有一个故障安全的单一命令来升级是“值得的”,_如果只是_对于您想以编程方式验证环境是否出于任何原因是最新的情况。 为什么“以编程方式”? 因为它不是交互式的,即没有用户对错误、警告或其他将他指向兄弟命令或姐妹命令的消息做出反应,因为包已经存在或不存在。
可选地,可以添加一个提示,询问用户是要升级还是安装,而不是仅仅抱怨。

也就是说,这个“upstall”命令不应该是任何一个命令(安装/升级)的默认值,因此需要调用一个选项。 这增加了语义明确定义的“安装”和“升级”动词的清晰度,在我看来,默认情况下在其中一个上安装的所有包管理器都做错了。 提示采取行动(正如yum所做的那样)是可以的。

这给我们留下了upgrade --install (比--install-missing短)和install --upgrade 。 从语义上讲,“升级到最新 [如果不存在则安装]”和“安装最新 [或升级到最新,如果已经存在]”。 这里没有太大区别imo。 install --upgrade是已经存在的版本,可以识别,但向后不兼容。
这是另一个用于混合的命令:一个名为install-upgrade (或upstall ?)的新命令,其中 install 和 upgrade 都没有获得“也做另一个”的选项,但引入了一个新命令明确语义的一个重要位置:命令名称本身。 这将是我的偏好。

TL;DR :引入upgradeupgrade-install ,弃用install --upgrade 。 所有功能都具有清晰的语义。
如果由于软件包已存在或不存在而导致操作失败,则添加消息或可选提示安装和升级命令。

今天早上又手动做了一次。 有关于此功能请求的任何消息吗?

+1

+1

+1

每个人,请在 OP 上使用竖起大拇指的反应,并停止向每个人的收件箱发送垃圾邮件。

由于 pip 具有与 linux 发行版不同的 QA 模型,我相当肯定,随机升级所有命令只是制作中的一个破损

pypi 没有实际验证和测试的软件包版本和兼容性数据库,
所以不像带有 QA 的发行版,pypi 实际上没有自己的 QA 并且完全依赖上传到它的项目(质量各不相同)

在目前的限制条件下,我相信这与其说是一种祝福,不如说是一种诅咒
如果有人想知道为什么发行版如此过时,QA 需要花费实际的时间和精力 ^^

每个人,请在 OP 上使用竖起大拇指的反应,并停止向每个人的收件箱发送垃圾邮件。

请注意,我们实际上不需要_任何_来自人们的“我想要这个”的回应。 我们知道人们想要这个,缺少的是任何人愿意开发一个解决方案来满足所有已经提出的各种担忧和问题,而这将在 PR 审查期间不可避免地出现。

因此,就我个人而言,如果人们避免 ping 这个问题,我将不胜感激,除非他们有至少为实现提供起点的工作代码 - 并且他们愿意遵循它直到实现。

否则,我们会尽快解决。 我个人经常遇到这个问题,而且我是一个核心 pip 开发人员,所以我可以保证,如果我自己有足够的时间来解决这个问题,我会的。 与此同时,“有什么进展吗?” 评论往往只会让我失去动力,因为他们大多只是觉得人们要求有权决定我如何度过我的业余爱好......

实施的起点

我认为这是https://github.com/pypa/pip/pull/3194的目的https://github.com/pypa/pip/pull/3194只需要刷新?

@sfriesel您错过了“并愿意遵循它”。 看起来制作 PR 的人要么没时间了,要么没兴趣(常见问题)。 下一步可能是 OP 或其他愿意接管 PR 所有权的人,写一份 PEP 风格的当前职位摘要,各种悬而未决的问题是什么,他建议作为这些不同问题的决议,并呼吁评论以重新开始讨论。 如果争论对 github 来说太大了,也许他需要将他的文档带到 distutils-sig 以获得更多输入。 如果他不能就各种问题做出他满意的解决方案,或者无法从辩论中获得共识,那么是的,#3194 可能已经死了(直到其他人再次提出问题,此时我“希望他们将他们所做的所有工作纳入他们的新公关中)。

像这样的提案有超过 50% 的工作是“管理”(记录提案、管理讨论、达成共识)。 它不一定是人们喜欢做的事情,但是对于像 pip 一样广泛使用的代码库,它是必不可少的部分。 (是的,这是一个问题 - 说“我将代码作为一种爱好编写”比“我将项目管理作为一种爱好”要好得多:-))

@pfmoore完全同意。

多年来,分布在许多地方的提案数量和讨论量都与这个问题相关,这使得处理这个问题并在短时间内获得清晰的画面变得极其困难。


@RonnyPfannschmidt

pypi 没有软件包版本数据库

这是真的。 这是包在运行时(setup.py 的)提供的信息,它增加了解决依赖关系的过程的复杂性。 此外,由于当前逻辑的行为方式,某些软件包(甚至像 scipy 这样的突出软件包)在安装时不会列出依赖项(例如 numpy)以避免不必要地重新编译它。

这将由PEP 426等解决,但我不知道该 PEP 的状态如何。

@pfmoore

请注意,我们实际上并不需要人们做出任何“我喜欢这个”的回应

很容易说 +1 或竖起大拇指把它放在那里,你希望看到这种情况发生。 它让人们觉得他们为这个问题添加了一些东西,为它做出了贡献。 我并不是说 pip 开发者需要被激励或被说服,只是每个人都想这么说。 和...

如果人们不要ping这个问题,除非他们有工作代码,我将不胜感激

竖起大拇指不会给任何人(烦人的)通知/电子邮件,我们仍然可以看到表现出兴趣的人数。 我认为没有人应该介意这一点,但我可能是错的。

竖起大拇指不会给任何人(烦人的)通知/电子邮件,我们仍然可以看到表现出兴趣的人数。 我认为没有人应该介意这一点,但我可能是错的。

啊,我没有意识到这样做可以避免通知。 是的,这是个好主意。

下一步可能是 OP 或其他愿意接管 PR 所有权的人,写一份 PEP 风格的当前职位摘要,各种悬而未决的问题是什么,他建议作为这些不同问题的决议,并呼吁评论以重新开始讨论。

对于它的价值,我早些时候写了一篇关于这个和依赖解析,PEP 风格的文章。 我现在要把它拆分并更新,添加过去几个月提出的所有内容。 一旦完成(大约 2 天?) ,我会将升级命令作为 Gist 发布,并从这里链接到它。

我还不愿意接管 PR 的所有权。 我打算帮助重新点燃讨论并得出可以实施的最终设计。 如果我周围的一些东西去计划,我应该能够通过实施遵循这一点,但我不想通过,只是还没有提交给下面这一点。

/cc @qwcode @dstufft @pfmoore @xavfernandez

这是我的文章的链接: https ://gist.github.com/pradyunsg/a5abeac4af90fbdc54bb266c32c0d2d8

我最初只是链接到各个地方(约 30 个链接)供读者参考,并尝试复制然后编辑以适应所有评论线程。 文件很长,我的意见漏了。 我最终从头开始。 虽然现在更短,但并不固执己见。 不过,我仍然将其标记为 WIP。

如果其中有任何问题,请在 Gist 上发表评论。 我会尽快进行更正。

警告:_轻微_ 前面的长评论


我喜欢修复现有的--upgrade行为的想法。 除了向后兼容性之外,是否还有其他问题? 由于安装和升级之间的高度重叠,添加upgrade命令似乎不是一个好主意。

FWIW,git 做了一些类似于我们正在讨论的--upgrade事情,在 2014 年改变了git push的默认行为。链接

如果有兴趣改变pip install --upgrade的行为,这里有一个关于该讨论的种子提案(称为 P1):

  • 从下一个主要版本 (9.0) 开始, pip install --upgrade打印警告:

``
PipDeprecationWarning:pip 将停止将依赖项升级到最新
默认情况下无条件版本从 11.0.0 开始。

要在默认行为更改后保持当前行为,
安装命令传递--upgrade-strategy eager

要立即开始使用新行为,请使用安装命令
通过--upgrade-strategy non-eager

为了消除这个消息,.

欲了解更多详情,请阅读.
``

链接的文档页面将提供更改及其影响的快速概览。 然后它将解决最常见的问题:“我该怎么办?” 和“我应该使用哪种升级策略?” 以最直接合理的方式。

  • 该消息可以使用清理。
  • 该选项甚至可以是 2 个标志, --upgrade-eager--upgrade-non-eager或其他东西。 那是自行车棚,即最后一步。

    • 除非发生剧烈的事情,否则在 11.0 版本中, pip install --upgrade在升级依赖项时会将行为切换为不急切。

编辑:我为更改设置了 3 个主要版本周期,只是为了让人们有更多时间进行切换。 这可能是不必要的。 也许,1 个主要版本打印警告和下一个进行更改就足够了?

@dstufft提出了一个类似(相同?)的想法。


如果升级命令是前进的方向,这里是重新启动该讨论的种子提案(如果您愿意,请将此称为 P2):

  1. pip upgrade复制了pip install大多数选项和行为。
  2. --dry-run标志将被添加到installupgrade命令中,这些命令会打印 pip 实际运行时将尝试的内容。
  3. pip install <out_of_date_pkg>不会改变行为。
  4. pip upgrade <not_installed_pkg>会失败。
  5. pip upgrade <up_to_date_pkg>什么都不做,说明为什么它什么都不做并以零退出代码退出。
  6. pip upgrade <out_of_date_pkg>将执行非紧急递归升级。

    • :white_check_mark: 默认为非急切递归升级

  7. pip upgrade --eager package行为就像今天的pip install --upgrade

    • :white_check_mark: 允许选择加入当前行为

  8. pip install --upgrade将打印RemovedInPip10Warning
    因为它会被删除。

另外,你有什么想法:

  1. 使升级命令具有交互性? (类似于 apt-get 的作用)

    • 使pip install <pkg>表现得像操作系统包管理器的安装 ieupstall?

  2. 在新的升级命令中默认有--only-binary吗?

    • 如果没问题,在升级命令中添加--only-source--no-source怎么样?

  3. 添加一个选项来“保持”包的更新? IMO,这是upgrade-all
  4. 区分这些情况是否有意义,即需要不同的 CLI?

    • 安装:未安装 -> 最新

    • 升级:过时 -> 最新

    • upstall: {not-installed, out-of-date} -> up-to-date

我没有提出任何关于“安装为 upstall”的建议,因为我对此并不强烈。 它与操作系统级别的包管理器一致,但将是一个重大的突破性变化。 我不确定它有多大用处,或者确切的行为和界面是什么样的......

也许睡在这可能会有所帮助。

就我个人而言,我认为保持一致的行为没有多大价值,如果有人对此感到高兴的话。 我想知道有一个用于 Python 2(拥抱稳定性)和另一个用于 Python 3(拥抱变化)是更好还是更糟。

@ekevoo

我想知道有一个用于 Python 2(拥抱稳定性)和另一个用于 Python 3(拥抱变化)是更好还是更糟。

一,题外话。 第二,如果你这样做,最终会出现分歧。 这会疏远目前使用 Python 2 的人,因为它(希望)有一天会达到 EOL,他们将不得不转移到 Python 3,不得不适应一种不同行为的工具。 因此, pip不应该发散(并且不会,IMO)。 那么不妨将它放在一个工具中。

OTOH,我确实看到您对可以接受的向后兼容性有什么看法......

pip 9 中的警告,以及调整pip install --upgrade--eager/non-eager (或其他名称)行为的附加选项对我来说似乎很好。

撞。 给大家的另一个通知。

@pfmoore @dstufft @qwcode我不想多管闲事,但你能在周末或下周抽出一些时间吗?

好的,所以我的评论:

关于两种前进的方式,我没有意见。 选择您认为更好的选择,实施它,我们将看到它如何从那里开始。

回复您的其他问题:

  1. 我对让命令具有交互性的态度是 -1。 除非有一个特定的问题需要用户做出决定,比如“你所要求的结果是你显然没有意识到的,并且可能是一个问题 - 你想继续吗”那么它只是无用的噪音。 我一般反对“你确定吗”的提示。 如果您有一个特定的提示建议,您认为值得添加,请随时再次询问,并提供详细信息。
  2. 我们不应该进行与安装不同的升级,因此默认情况下不对--only-binary进行升级。 对于我个人的使用,我可能总是希望首先使用pip upgrade --only-binary ,但我_希望_它是明确的。
  3. 我不确定你所说的“保持”更新是什么意思。 请澄清。 但作为一般性回应,我会说首先不要打扰,让我们保持初始 PR 不受“可选附加项”的影响——它们可以稍后添加。
  4. 这不是有关此功能的各种讨论的主要辩论主题吗? 首先,它不会影响install --upgrade vs upgrade的基本问题吗? 我不记得这个问题有解决方案,所以我有点惊讶你期望对这个问题有一个“简单”的答案? 我当然没有很好的答案。

(顺便说一句,我无法轻松访问要点,因此,如果您的摘要中没有包含其中的任何内容,我很抱歉错过了)。

我知道写 PR 是一项艰巨的工作,而且让它似乎陷入辩论和问题的泥潭会让人失去动力,但最终,我认为有人将不得不写一个公关,并把它放在那里,因为“这就是解决方案”我提议——有什么意见吗?”

我们不应该使升级与安装不同 [snip] 我可能总是想要pip upgrade --only-binary在第一种情况下,但我希望它是明确的。

如果你可能总是想要一些东西,它应该是默认的1 。 但我认为在install和可能的upgrade命令之间保持一致性是一个好主意。

我不确定你所说的“保持”更新是什么意思。

在我们讨论添加全部升级功能之前,我将暂时搁置这个问题。

自我注意: apt-mark pip 概念

我对让命令具有交互性的态度是 -1。 除非存在用户需要做出决定的特定问题

同上。

这不是有关此功能的各种讨论的主要辩论主题吗?

正是为什么我想知道你们的想法。

我不记得这个问题有解决方案,所以我有点惊讶你期望对这个问题有一个“简单”的答案?

我还不指望一个“简单”的答案。 我希望我们通过讨论达成一个,最好是简单的答案。

顺便说一句,我无法轻松访问要旨,因此如果您的摘要中没有包含任何内容,我很抱歉错过了

不仅仅是一个总结,它是写作的后续行动。 请尽快阅读。

选择您认为更好的选择,实施它,我们将看到它如何从那里开始。
[剪辑]
我认为有人将不得不写一个 [PR],然后将其发布为“这是我提出的解决方案 - 有什么意见吗?”

我的想法是“让我们首先弄清楚我们想要什么”,然后继续实施。


1除非它打破了别人的世界

我们不应该使升级与安装不同 [snip] 我可能总是希望 pip upgrade --only-binary 在第一种情况下,但我希望它是明确的。
如果你可能总是想要一些东西,它应该是默认的。 但我认为在安装和可能的升级命令之间保持一致性是一个好主意。

如果_每个人_可能总是想要某样东西,它(也许)应该是默认的。 但我只是在评论我自己的喜好。 老实说,我不知道--only-binary是否是大多数人想要的(这可能取决于我们谈论的是长期还是短期)。

二进制文件(轮子)、可以在任何地方构建的源代码(通常是纯 Python)和需要编译器或其他外部先决条件的源代码之间存在很大差异。 遗憾的是,pip 无法区分后两者,这使得--only-binary不太有用(特别是作为默认值)。

我更看重命令之间的一致性,而不是“按我的意思做”默认值,这又可能只是我个人的偏好。

不仅仅是一个总结,它是写作的后续行动。 请尽快阅读。

我已经阅读了它,它并没有增加我不知道的太多内容(因为我已经关注了有关此的各种线程),因此我的评论成立。 但这是对比赛状态的一个很好的总结,所以感谢你写下它。

我们不应该使升级与安装不同 [snip] 我可能总是希望 pip upgrade --only-binary 在第一种情况下,但我希望它是明确的。

如果你可能总是想要一些东西,它应该是默认的。 但我认为在安装和可能的升级命令之间保持一致性是一个好主意。

如果_每个人_可能总是想要某样东西,它(也许)应该是默认的。 但我只是在评论我自己的喜好。

澄清:我的评论中的“你”指的是最终用户(复数), @pfmoore在这种特定情况下是其中之一。 我真的应该用其他词。

关于升级策略的一些想法。 个人意见,所有这些,当然:-)

假设我做pip upgrade foo

  1. 如果我当前没有安装foo ,我预计会出现错误。 对我来说,“安装”和“升级”是我不想合并的两个独立活动。
  2. 如果没有比当前安装的版本更新的可用版本(请参阅下面的--only-binary ),那么我希望收到无事可做的通知。
  3. 否则,我希望将foo升级到最新版本。 这就是我所要求的,所以它应该发生。

    • 我不相信添加约束有意义。 如果我安装了 1.1 但 1.2 可用, pip upgrade foo>1.0是什么意思? 如果它在那里留下 1.1 这不是升级,但如果它升级到 1.2,它与pip upgrade foo 。 可能你可以将意义归于pip upgrade foo<2.0但 IMO 将是一个非常不寻常的情况,不值得复杂。 所以让我们假设pip upgrade只需要一个包名列表(而不是要求)。

    • 同样,我不知道如何解释pip upgrade <path_to_archive/wheel> 。 让我们假设它在第一种情况下是不允许的。

  4. 我可能希望也可能不想让 pip 尝试从源代码构建(这必须是用户决定,因为 pip 无法判断从源代码构建是否可行,并且如果源构建失败)。 所以--only-binary必须是一个用户选项,如果指定,意味着 pip 在计算出“可用的内容”时应该忽略源代码分发。 (我们当然可以默认只使用二进制文件,并有一个--allow-source选项,但在这方面,无论哪种方式upgrade都应该匹配install )。

好的,这样就处理了明确指定的包。 我怀疑那里有什么有争议的(除了我说我们应该在以后省略的部分)。 现在到依赖项。

  • 我认为的主要规则是我们永远不应该对依赖项做任何事情,除非我们_实际上_升级用户指定的包。 所以这就是起点。 如果目标没有升级,甚至不要查看依赖项。 曾经。
  • 我的观点是 _all_ 依赖项必须以相同的方式处理 - 无论它们是用户指定包的直接依赖项还是间接依赖项,都是无关紧要的。 我不认为这是有争议的。
  • 这里的一个基本假设应该是用户不知道依赖项列表是什么。 毕竟,具有隐式依赖关系的目的是让用户_不必_管理它们。 因此,在我看来,任何需要用户明确了解依赖项的解决方案都是有缺陷的(除非命令失败并显示有关特定依赖项的消息,在这种情况下,用户可能会使用选项中指定的该依赖项重新运行 - 但我们应该希望在尽可能多的情况下第一次工作,所以这不应被视为常态)。
  • 我会说默认情况下,方法应该是只升级_必须_升级以满足新约束的依赖项。 这里潜伏着一个令人讨厌的问题,因为约束可能会根据升级的内容而改变。 但是,我们是否对该问题进行了完整的解决方案,或者只是尝试一些“尽力而为”的解决方案并不那么重要(我怀疑具有冲突约束的复杂依赖图在现实生活中很常见)。 重要的一点是原则,除非我们必须,否则我们不会升级用户未要求升级的任何内容。
  • 有一个标志说“将所有内容升级到最新版本”可能很有用(至少是为了向后兼容)。 更好的是拥有分析和报告升级选项的工具(可能在 pip 外部)。 然后用户可以自己决定。 但我不知道我自己会看到需要这些选项中的任何一个。
  • 而不是“急切升级”选项,我更可能想要一个upgrade-all命令(或者upgrade --all如果我们想保留一个命令)。 这应该在语义上与upgrade ,每个安装的包都列在命令行上。 一旦我对软件包进行盲目升级(通常我可能不知道或记录了我的软件包的依赖关系树),我可能只想要“一切”。 如果我使用虚拟环境来隔离事物,则更是如此。
  • --only-binary问题再次出现在这里。 当然,如果用户指定--only-binary用于主要升级,则应假定依赖项暗示--only-binary 。 但即使用户在升级主包时允许源安装,引入依赖项的源升级所涉及的失败风险似乎是不合理的。 所以我建议我们应该只考虑二进制文件来升级依赖项,除非用户明确允许源。 这意味着需要一个选项--allow-source dep1,dep2,... 。 我预计这个提议会引起争议,但考虑一个纯 Python 包foo ,它仅以源代码形式分发,依赖于 numpy。 我们有 foo 1.0 取决于 numpy >=1.10,而 foo 2.0 取决于 numpy >=1.11。 用户有 foo 1.0 并且想要升级。 他们没有办法建立 numpy. 他们必须允许 foo 的源代码升级,但他们不想浪费时间尝试构建 numpy 1.11(或者更糟糕的是,构建它可能会工作但给出未优化的构建,这会破坏他们的系统)。 他们当然可以指定--only-binary numpy但他们甚至可能不知道 foo 依赖于 numpy。

就是这样。 对我来说,要求非常明确(老实说,如果我们忽略实施问题,我认为它们不会特别有争议)。 然而,实现是这里的杀手(基本上,上面几乎需要一个完整的 SAT 求解器方法,如前所述)。 由于实施 SAT 求解器太难,我们愿意做出哪些妥协,这可能是争论的焦点。

据我所知,以下将是实施挑战:

  1. 一个完整的 SAT 求解器很难。 我不太了解哪些替代方案更简单,以及它们与 SAT 求解器有何不同。 (嗯,我相信急切升级很简单——这就是我们目前所做的事情)。 具体来说,当我们遇到这样的情况时,我们升级了简单的“不升级任何你不需要的东西”原则所说的不应该升级的东西。
  2. 除了最基本的依赖约束之外,我已经掩盖了任何东西。 一旦我们涉及版本上限或允许版本列表,事情就会变得很糟糕。 但实际上,这种情况可能非常罕见(我希望有人对来自 PyPI 的实际依赖信息进行研究——我可能会尝试这样做,但我怀疑我是否有时间)。
  3. 当我们有多个目标时 - pip upgrade a b c - 我们是否将其视为 3 个单独的操作,“升级 a”,然后“升级 b”,然后“升级 c”,还是我们将这 3 个合并为一个“组合”以某种方式采取行动(请注意,因为我建议处理与目标不同的依赖项,这_不_与pip upgrade dummy相同,其中 dummy 取决于 a、b 和 c,我们假设 dummy 已升级)。

如果有人想对上述任何评论或断言提出异议,那就太好了。 其中大部分只是我的意见,老实说,我不在复杂的环境中工作 - 我的使用可能主要是在 Windows 上维护系统安装和一些虚拟环境(因此,关于二进制安装与源安装的辩论对于我,但复杂的依赖图不是那么多)。 我们可以检查我们的假设的用例越多越好。

所以我们目前有两个操作, pip installpip install --upgrade ,但是我认为这两个操作都做了一些在现实生活中没有人真正想要发生的事情。

对于pip install ,我们会得到这种奇怪的行为,您可能会根据系统中已安装的内容获得最新版本(或者您可能不会!)。 我认为这种奇怪的东西使 pip 更难使用,而且我认为这并没有多大意义(在什么情况下你会关心不升级但你仍然想安装最新的如果你还没有它?)。 我认为,这个命令具有这种奇怪的也许是最新的也许不是行为的事实是我们看到很多人将pip install ---upgrade作为他们的主要命令而不是pip install

但是, pip install --upgrade也好不到哪里去,虽然它为您提供了一致的行为,但它过于急切,它扩展到了 _everything_ 的全面升级,用户甚至可能不知道这会牵涉到他们的pip install --upgrade命令。 我确实看到了这种行为的一些用途,但我不认为它是顶级命令的良好默认值。

我认为我们应该在这里做的是找出一条路径来进行`pip install ... more consistent. In that I mean pip install应该总是最终拥有最新的可接受版本(给定说明符和修饰符标志,如--only-binary ``) 不管之前安装了什么。

我认为给这个命令某种--eager--recursive--upgrade-all-the-things行为会很好。

我不认为pip upgrade接受包列表的命令是我们应该做的事情。 我认为如果我们添加这样一个命令,那么它应该用于简单地将安装的所有内容升级到最新版本(考虑依赖链信息,以及像--only-binary这样的修饰符)。

嗯? 因此,如果安装了 foo, pip install foo并不总是失败? 这对我来说似乎是错误的,我希望它只是说“已经安装”。

我不热衷于pip install是“安装或升级”的想法。 最好是明确的等等。

现在pip install foo永远不会根据是否安装了某些东西而“失败”,它不会做任何事情并说 X 已经安装。 我的断言是行为不是很有用。 “断言某个版本,安装了任何版本”对我来说似乎不是有用的行为。 它也与我习惯于apt-get左右的其他包管理器不匹配。

好的,我可以看到这种行为没有用(尽管我个人认为默默地接受“已经安装”是相当无害的)。 但我更愿意看到安装已安装的软件包失败,而不是升级它。

如果 foo 2.0 已经安装,你希望pip install foo-1.0-none-any.whl做什么? 降级? 默默地什么都不做? 我宁愿看到一个不错的、简单的“已安装”错误,也不愿看到一组我怀疑人们在实践中会记住的复杂规则。

我对 Linux 包管理器没有太多经验,所以我无法评论与 pip 的相似之处(或其他方面)。 但我不认为我会期望apt-get install foo会升级,所以如果你说它会升级,我只能回答说我也觉得这很奇怪。

“断言某个版本,安装了任何版本”对我来说似乎不是有用的行为。

关于此的快速附带问题:“断言已安装此特定版本”怎么样?

没关系,我们今天有这种行为。

@pfmoore

如果 foo 2.0 已经安装,你希望 pip install foo-1.0-none-any.whl 做什么? 降级? 默默地什么都不做? 我宁愿看到一个不错的、简单的“已安装”错误,也不愿看到一组我怀疑人们在实践中会记住的复杂规则。

呵呵,期待是出乎意料的东西。 我会说_显然_在这种情况下 pip 应该降级。 用户已经完全明确地表示他们希望 pip 安装这个特定的轮子,所以 pip 应该安装那个特定的轮子。 这没有什么复杂的。 但是“明确给出分发路径/文件”的情况是#536——也许我们应该让这个讨论更多地集中在如果用户说“pip install foo”时会发生什么,这会转到包索引并找到一个 foo 2.0,当 foo 1.0 已经安装时。

我非常同意唐纳德在这里的立场。 如果我们从“ pip install该做什么?”这个问题开始,那么我可以看到人们可能会争辩说,好吧,它在名称中说“安装”,所以它应该只安装东西,永远不要升级它们(好吧,除非有一些限制)。 但是如果我们从“用户想要什么操作?”这个问题开始,那么一个可能安装最新版本的命令,或者可能给你留下一个旧版本的命令,真的很奇怪和违反直觉。 我断言,在 99% 的用户键入pip install x ,这是因为他们 (a) 要么不确定它是否已安装,要么知道它没有安装,并且 (b) 想要确保他们确实安装了它,因为他们即将开始第一次使用它。 (如果不是第一次,他们会知道它已安装,所以他们不会运行pip install 。)在这种情况下,给他们最新版本是正确的做法。

@nhammas

“断言已安装此特定版本”怎么样? 这对我来说似乎很有用,有一个幂等的安装命令。

对于“特定版本”,有pip install x==<version>

我还可以想象,对于某些类型的脚本/编程使用,使用pip require x命令可能很有用,该命令与使用Dist-Requires: x安装包具有相同的语义,即它确保某些版本已安装,但不保证什么。 但这将是一个不适合最终用户的低级命令。

考虑这些之间的区别的一种方法:如果没有安装x ,那么pip require x安装一些随机的旧版本就可以了。 (哎呀,也许应该这样做,迫使人们对它采取强硬态度。)但是没有人会接受pip install x安装一些随机的旧版本。

(这是一个思想实验,我实际上并不提倡在没有x的环境中使用普通的Dist-Requires: xpip require x x应该随机选择x旧版本

好吧,我想还有另一种情况,用户输入pip install x ,这是他们已经知道它已安装的情况,但他们习惯于具有 Debian 风格行为的系统,其中install总是升级. 显然这些用户也希望它升级:-)。

我宁愿不添加pip upgrade命令。

pip 用户已经对 pip 的行为有了一些期望。
主要的痛点来自pip instal --upgrade默认行为,所以让我们关注一下。

pip 9 中的警告,以及调整pip install --upgrade行为的附加选项,(--eager/non-eager) 在 pip 10 中更改其默认行为似乎很简单,应该消除主要的痛苦起源并且不会破坏 pip 用户的 pip 心理模型。

是的,我绝对试图从“用户想要做什么操作”与“X 命令应该做什么操作”来解决这个问题。 然后我将执行我_认为_用户想要执行的高级操作,并尝试将其映射到单个命名命令(尽管如此明确,pip install-the-latest-version`` 对用户不是很友好) .

这显然非常模糊,但我可以说我所做的 99% 的时间是pip install -U <whatever>因为这最符合我对安装程序的期望,因为当前可用。 我还在各种自动化脚本中看到人们使用pip install -U 。 这也是默认情况下其他流行的语言包管理器(如 npm)所做的。 在我确实看到人们不使用-U ,这是因为它的递归性质,而不是因为他们不想安装最新版本的东西。

pip 用户已经对 pip 的行为有了一些期望。

TBH,不过,作为用户,我对 pip 的主要期望是,在大约 50% 的调用中,它会做一些令人惊讶且明显错误的事情。 而且我不是唯一一个——参见上周 @glyph在 pycon 上的演讲,他观察到 pip 很棒,除了所有默认值都被破坏并且需要 unbreak-me 标志。 这不是对 pip 开发人员的批评,我理解你/我们都在一组复杂的约束下工作,这不是我们应该为了破坏它们而随意破坏事物的论点—— pip 有很多部分,其中很多都很好! 但是考虑到 pop 的默认值的整体状态,我真的不相信“pip 总是做 X,因此 pip 应该总是做 X”形式的参数。 如果您想争论 pip install 拒绝升级,那么这很酷,但我更愿意看到该争论是基于实际优点,而不仅仅是基于惯性。

是的,我当然同意这里的@njsmith@glyph 。 我们有许多不良的默认行为,我认为前进的一部分需要弄清楚我们如何摆脱这些并处理那些重大变化以将事情推向更好的默认值。

这种特殊的变化可能不是其中之一,但我认为它是。

是的,我绝对试图从“用户想要做什么操作”与“X 命令应该做什么操作”来解决这个问题。 然后,我将执行我认为用户想要执行的高级操作,并尝试将其映射到单个命名命令(尽管如此,pip install-the-latest-version 并不是非常用户友好) .

行。 假设我愿意认为自己(在某种程度上)对此深信不疑。 但是,如果我们认为这是正确的做法,那么依赖关系呢? 我 100% 相信“尝试从源代码安装 numpy”几乎总是不是我们想要的。 所以我们只从轮子安装 numpy,除非用户明确提到 numpy。 暂时把它当作给定的,然后假设我们有我之前描述的情况。

  • 用户安装了 foo 1.0 和 numpy 1.10,foo 1.0 依赖于 numpy >= 1.10
  • PyPI 有 foo 2.0 可用,取决于 numpy >= 1.11。 没有 numpy 1.11 轮子。

pip install foo什么作用? 大概将用户留在 1.0,因为它是一个工作安装? 但是它应该成功(因为安装了 foo)还是失败(因为它无法安装最新版本)? 如果是前者,用户如何发现他的系统已过期? 如果是后者,用户如何说“我只是想确保 foo 在那里”? 好的,用户可以执行pip list --outdated ,看到 foo 2.0 存在并执行pip install foo (顺便说一句,这对我来说仍然很奇怪,我有 foo,但我知道有一个新版本,所以我做 pip install??? 没关系...)并获得成功,但 1.0 仍然安装?

我更喜欢两个命令的原因之一是用户的意图是完全明确的,因此可以正确处理这样的边缘情况,因为我们知道用户的期望。

如果您习惯了 apt-get,这可能是显而易见的。 但我可以肯定地说,对于像我这样不了解的人来说,它一点也不清楚。

如果您想争论 pip install 拒绝升级,那么这很酷,但我更愿意看到该争论是基于实际优点,而不仅仅是基于惯性。

我的论点是基于明确的而不是隐含的。 绝对_不_关于“我们一直都是这样做的”。 我对可能 apt 用户习惯于“安装”意味着“可能升级”的想法没有异议。 我真的不太确定其他用户会是。

一个想法 - apt 是否有“包已经存在 - 升级”? 迅速的? 我可以想象如果它是“安装或询问如果我应该升级”的话,安装即升级对我来说就不那么令人惊讶了......当然,pip 目前并没有像那样交互行为,尽管显然,这样做是一种选择。

这是一个有趣的问题——其他包管理器大多通过根本没有二进制包来解决这个问题,所以它_always_按源,或者几乎只处理二进制包所以它_always_二进制。 我们之间有点奇怪,这让它变得更难。

鉴于此,我认为现在默认情况下,我们应该拉下 numpy 1.11 源包并尝试安装它,但如果他们指定了--only-binary ,那么我们假设的解析器(我们迫切需要,SAT或回溯或其他)会看到foo-2.0不是可解析的安装,然后将回退到安装foo-1.0 。 这不是一个很好的默认设置,特别是对于编译困难得多的 Windows 用户,但我认为它反映了当今的现实。

话虽如此,我真正想做的一件事是开始尝试将事情推向一个我们可以再次改变 pip 行为的世界,这样默认情况下我们只能是二进制的,并且需要选择加入源代码版本,但是我不要认为我们已经到了可以做到的地方。

@pfmoore :我认为二进制安装与源安装的问题有点正交? 在我看来,专门的pip upgrade命令会出现完全相同的问题,所以虽然它们是我们需要解决的实际问题,但拆分升级和安装只会移动问题而不是简化它们? 此外,在 numpy 的特殊情况下,我们现在基本上为我们关心支持的所有平台提供轮子:-)。

但这里是我建议如何为pip install foo处理这些问题(特别是这个命令——我不是在谈论pip install foo==whateverpip install ./foo-*.whlpip install bar where barRequires-Dist: foo ):

1) 查询索引,找到foo的最新候选版本; 称之为$LATEST 。 如果不存在候选版本,则出错。

2) 如果已经安装了$LATEST ,则成功完成。

3)检查当前环境是否有可以安装的$LATEST的发行版。 (可能不存在的示例原因:只有轮子,但没有 sdists,并且轮子与当前环境不匹配。没有任何匹配的轮子,并且有 sdist,但用户已通过--binary-only :all: 。没有任何匹配的轮子,并且有一个 sdist,但是 sdist 有一些标志说“我只在 python 3 上工作”并且用户正在运行 python 2——ipython/jupyter 人可能会很快建议将此作为新功能,b/c 他们希望在 1 月份放弃对新版本的 python 2 支持,同时仍然提供支持 python-2 的 LTS。)

4) 如果$LATEST _does not_ 有一个可行的发行版:发出警告,告诉用户有更新的版本可用但不适用于他们的环境,最好是提示如果他们真的这样做了他们需要做什么想要新版本(例如,“ipython 6.0.1 可用,但需要 python >= 3.4,并且你有 python 2.7——考虑升级 python”,或“numpy 1.12 可用,但 ppc64 没有二进制文件,你有从源代码禁用构建 - 考虑--allow-source numpy )然后从候选版本列表中删除$LATEST并转到步骤 1。

5) 如果$LATEST _does_ 有一个可行的发行版,请尝试安装此发行版。

6) 如果安装失败(例如 b/c 它是一个 sdist 并且没有编译器),然后出错。 否则,成功完成。

@njsmith binary-only 有点正交,同意,但 IMO 如果我们试图设计“做用户期望的事情”的命令,那么同时做到这一点至关重要。

@dstufft的问题是“安装 numpy,除非用户说--binary-only在我之前的史诗文章中的示例中得到了解释-(1)说 foo 仅以源形式提供,并且(2)用户可能不会(实际上不需要)知道 foo 取决于 numpy。然后用户不能说--only-binary :all:并且不知道他们需要--only-binary numpy直到 _after_ (长)编译失败。或者(可能更糟糕)一个成功的编译,给用户留下了一个未优化的 numpy(现在,numpy 在 Windows 上开箱即用,但提供了一个未优化的构建)。

我完全同意,从长远来看,我们应该默认为仅二进制,但我们还远未达到这一点(至少,这意味着几乎每个纯 Python 包都可以作为轮子使用)。

@pradyunsg如您所见,这里仍有很多未解决的问题。 你还有兴趣推动这个吗? 如果它再次停滞不前,我不愿意再发起一场长时间的辩论......

@pradyunsg如您所见,这里仍有很多未解决的问题。 你还有兴趣推动这个吗? 如果它再次停滞不前,我不愿意再发起一场长时间的辩论......

我预计会有。 我有兴趣推进这项工作。 我们开工吧! :微笑:

我建议收集一个包含 _user_ 想要 pip 做的所有事情的列表,然后为每个人提出解决方案,直到所有(或足够数量)都被 pip 命令(带有选项/默认值)解决或可以处理“没有行动”。

首先,这是一个很可能不完整的列表:

  1. 用户想要安装尚未安装的软件包。
  2. 用户尝试安装已安装的软件包。
  3. 用户想要升级已安装的软件包。
  4. 用户尝试升级未安装的软件包。
  5. 用户想要确保他们安装了最新版本的软件包,无论它是否已经安装。
  6. 用户通常不希望升级所有依赖项,而是只让它们得到满足。
  7. 用户想要升级/安装包,但不想从源代码(包及其依赖项)构建。 可能比:
  8. 用户愿意从源升级/安装。

作为用户,我个人对此的建议是:

1) & 7) pip install foo应该尝试解析到最新的可用版本(考虑依赖项)并安装它。 算法将是@njsmith的。
2) pip install foo → 显示 foo 已经安装的警告并建议使用pip upgrade foo
3) & 7) pip upgrade foo尝试安装 foo 的最新可用版本,再次遵循@njsmith的算法。 如果更新版本无法安装,因为它不适用于平台并且没有 sdist 或用户不想从源代码构建,请显示。 在任何一种情况下都成功,只有在安装本身失败时才会失败。
4) 如果未安装软件包, pip upgrade foo失败。
5) pip install-uprade foopip install foo --ensure-latestpip install foo --upgrade (除非急切外,基本与当前相同)。
7) 所有操作都应该是非急切的,并且可以使用--eager标志来获得install --upgrade的旧功能。 如果尚未安装依赖项,请安装最新的。 如果已经满足,则什么都不做。 如果不满足,安装最新的仍然满足的版本(用于上限要求)。
8) pip upgrade foo --allow-sourcepip upgrade foo --allow-source numpy ,如果 foo 依赖于非二进制 numpy 版本。 编辑:我不知道这是否适用,请参阅下面的评论。

随意扩展列表并发布您自己的建议。

@pfmoore我不确定替代方案是什么? 当今世界的状况是轮子正在取得进展,但它们还远未普及,所以我不确定我是否真的看到了一个现在默认不允许发布源代码的好选择。

@dstufft我的提议是允许显式命名包的源,但默认情况下只有依赖项的二进制文件。 这样用户就不会得到“惊喜”的构建步骤。 当然,这是一种妥协,但它反映了我(必须)目前手动执行的操作。

@FichteFoll最重要的是,我的主要用例是“全部升级”功能。 查找当前安装的所有内容,如果有可用的更新版本,请升级它们。

我安装的软件包通常没有任何其他 ">=" 依赖项(大多数甚至没有),所以这里没有什么复杂的。 只需获取最新版本。 我最大的限制是有些包我无法构建(numpy、scipy、lxml、pyyaml、matplotlib、pyqt),所以我只想要二进制文件。 我大概可以把--only-binary <these>放在我的pip.ini (或者至少我希望我可以......)

次要:安装包 XXX(最新版本),以及我还没有的任何依赖项。 如果我已经拥有的依赖项满足新包的约束,请不要升级它们。 我一直都知道我目前没有 XXX。

第三级:升级我(知道我)已安装的单个软件包 XXX。 不要更改任何其他包,除非需要维护依赖项约束(即使这是理论上的 - 我在现实生活中从未遇到过这种情况,所以我不知道对我来说最好的解决方案是什么)。 我的意图始终是“升级到最新版本”。 我从未遇到过这会破坏已安装软件包的依赖关系的情况。 如果是这样,我_想_我想要一个警告,说明我没有获得最新版本(以及为什么)以及升级到可接受的最新版本。 在我看来,这种情况目前转化为pip install -U尽管依赖项的行为不是我想要的。 不过,我这样做的主要原因是因为目前缺乏合适的“全部升级”(或处理新的“全部升级”命令无法像我想要的那样工作的情况)。

根据我的经验,所有关于依赖和约束的讨论几乎完全是理论性的。 我目前在我的系统 Python 中安装了 160 个包(科学、数据分析、Web 和通用编程模块的组合)。 其中100个没有要求。 对于其余部分,没有比包列表更复杂的东西 - 没有版本限制或比Requires: six, dask, pillow, networkx更复杂的东西。 最长的依赖项列表有 9 个项目。

@pfmoore这不是会破坏很多东西吗? 我能想到的一些我知道非常受欢迎的软件包的快速列表取决于:

  • SQLAlchemy(可选地需要编译器,否则将使用纯 Python)。
  • PyYAML(可选地需要编译器,否则将使用纯 Python)。
  • Markupsafe(可选地需要编译器,否则将使用纯 Python)。
  • PyCrypto(总是需要编译器)
  • pycparser(从不需要编译器)
  • httplib2(从不需要编译器)
  • anyjson(从不需要编译器)
  • zope.interface(可选地需要编译器,否则将使用纯 Python)。
  • docopt(从不需要编译器)
  • Mako(从不需要编译器)
  • 它的危险(从不需要编译器)
  • amqp(从不需要编译器)
  • ordereddict(从不需要编译器)

等等,您可以在http://pythonwheels.com/上看到一长串最流行的软件包以及它们是否有轮子

@pfmoore

查找当前安装的所有内容,如果有可用的更新版本,请升级它们。

不久前,我从一些 SO 问题中获取了此命令,我目前正在为此使用该问题。 这是次优的,但适用于我的大多数包,除了一个。 (它使用py启动器,因为我使用的是 Windows。)

pip list -o | cut -d " " -f 1 | xargs -n1 py -m pip install -U

现在,我遇到的一个问题是 flake8 包,它具有以下要求:

Requires-Dist: pyflakes (>=0.8.1,<1.1)
Requires-Dist: pep8 (>=1.5.7,!=1.6.0,!=1.6.1,!=1.6.2)
Requires-Dist: mccabe (>=0.2.1,<0.5)

特别是 pyflakes 是一个问题,因为它有一个更新的版本可用并使用上述命令进行更新,导致 flake8 无法执行任何操作(因为它检查版本)。
所以这确实是需要考虑的事情,我也希望有适当的升级所有功能(不破坏要求!)。

@dstufft为什么? 如果 foo 依赖于 pyyaml 并且我要求升级 foo,pyyaml 不会升级(没有新的二进制文件)但 foo 仍然可以升级,因为仍然存在原始的 pyyaml。

对于新的依赖项(或依赖项并不总是存在的安装),您必须安装,因此如果没有二进制文件,则使用源代码。 我个人认为“选择带有二进制的旧版本而不是带有源的新版本”,但这已经接近默认为--binary-only的危险,我同意我们还没有准备好。

嗯,也许我的问题实际上是与--only-binary选项有关,它太粗糙了。 如果我们有一个--prefer-binary选项,即“只使用二进制文件,除非这意味着没有候选文件,在这种情况下重试允许源代码”,我怀疑我的许多担忧过度升级会导致损坏可能会缓解。 正如@njsmith建议的那样,这意味着我关注的二进制/源代码区别很可能与这张票正交(尽管它只会将我的立场改变为“如果没有比--only-binary更好的东西,我的要求就没有令人满意的解决方案”

特别是pyflakes是一个问题

好的,所以这不是我遇到的情况(正如我所说,我没有安装任何复杂的依赖项)。 我对精炼“全部升级”以将事物升级到“不会导致损坏的最新版本”没有问题,但是 AIUI 需要“SAT 求解器”方法来制定正确的解决方案。 不过,这是一个实现问题 - 设计确实应该始终给出正确的结果。

@pfmoore我认为--prefer-binary标志可能是一个不错的选择,无论这张票的结果如何。 当最终未安装本应安装的最新版本时,可能会与警告捆绑在一起。

@FicheFoll :我不认为尝试从第一原则重新派生整个 ui 会很有成效。 有一个相对明确定义的问题是这个特定问题的主题,如果我们尝试立即将范围扩展到所有内容,那么它只会再次陷入困境。

在这个主题上,看起来我们不同的关键地方在于:假设用户有这样的心理模型,即pip install foo仅用于将事物从卸载状态转换为已安装状态,并且他们了解foo已经安装。 我断言具有这种心理模型的用户永远不会键入pip install foo _。 因此,当某些用户_确实_在foo已安装的情况下键入pip install foo时,我们可以得出结论,他们的心智模型与您的 (2) 不同。 _Either_第一部分是错误的:他们知道foo已安装,并且他们希望 pip 像其他一些流行的包管理器一样升级,_或_,第二部分是错误的:他们不知道foo已安装,在这种情况下,他们希望install为他们保留最新版本(因为这就是未安装软件包时 install 所做的,并且他们认为未安装此软件包)。

作为记录,我不喜欢pip install ...只从卸载到安装和pip upgrade ...只从安装到安装新东西的原因之一是因为我找到了用户体验很糟糕。 软件知道你想让它做什么,但它告诉你调用一些不同的命令而不是去做那件事,这令人难以置信地令人沮丧。

$ pip install foobar
I'm sorry, but foobar is already installed, you want to run ``pip upgrade foobar``
$ pip upgrade foobar
...

除了惹恼我之外,不会对我做任何事情,即使它在技术上是“正确的”。

另一方面,如果你说“好吧,如果pip install foobar已经安装了foobar ,那么我们会表现得好像它没有安装,如果你这样做了pip upgrade foobar那么我们会像它已经安装一样,我们最终得到两个基本相同的命令,除了_maybe_在处理事情的方式上有一些细微的差别,这对我说它们属于带有一些--options的单一命令--flags的成本。

行。 认为我相信。 我已经做了一些研究,甚至我(据说 :-))熟悉的 Windows 安装程序也很熟悉 do install-as-upgrade(如果你安装了 VirtualBox 之类的东西,它会说“你已经安装了以前的版本,是吗?要升级吗?”)Powershell 有安装包,它没有说明任何具体内容,但没有升级包。 等等。所以我想只有一个“安装”命令是常态。

这当然意味着,除非有人想争论,否则从技术上讲,这个 PR 可以简单地关闭为“不会实施”。 但我想它仍然是一个讨论_如何_我们想要改造安装命令的好地方。

OTOH,也许我们确实在拒绝时关闭了它,有人提出了一个新问题,并提出了他们建议如何修改安装命令的具体建议。 它至少可以为讨论提供一个更清晰的起点。

一个问题。 有没有人认为我们已经到了有人可以从这里和其他地方的所有建议中组合出完整的建议行为的地步? 涵盖如何处理依赖关系、约束会发生什么(以及它们何时发生冲突)、二进制与源代码、我们如何支持“全部升级”场景等? 我个人的感觉是,我们需要有人来做出决定,为讨论提供一个参考点,否则我们就可以永远争论细节。 我可能会这样做,但我不太可能实现我的建议(例如,我会提出一种“最佳依赖解决方案”方法,这意味着 SAT 求解器 AIUI)。 因此,对于愿意实施他们的建议的人来说,最好加紧(并处理不可避免的辩论和自行车棚:-))。

我仍然担心这里提出的观点中的一些含义,但我不确定我是否有精力讨论它们,直到真正有可能实施。

我完全同意@dstufft的最新https://github.com/pypa/pip/issues/59#issuecomment -224341218
这就是为什么(再次)我提倡--eager / --non-eager选项的简单解决方案。

我也同意@dstufft的评论,如前所述(我们选择一个install命令,没有update命令)。

但是,我不确定--eager / --non-eager意味着什么。 我猜--non-eager意味着不要升级任何不需要更新的东西(因为用户明确指定了它,或者因为它太旧而无法满足新的依赖集)。 --eager是否意味着将每个依赖项升级到最新的可能版本,无论是否有必要? 哪个是默认值? (我会为--non-eager争论)

还有一个问题——这会鼓励科学包正确声明它们的依赖关系吗? 这必须是一个重要的考虑因素。

自行车棚点。 选项名称--eager--non-eager非常不直观。 我认为我们需要更好的条件。 也许像--upgrade-dependencies这样明确的东西。

此 PR 还建议使用upgrade-all命令,这对我来说是关键用例。 您是说我们拒绝该命令,还是只是您对此没有意见?

我对--eager-non-eager理解与@pfmoore刚才所说的相符(无论依赖项是仅在需要时还是始终安装),我同意--non-eager应该是默认值。 我也同意这个名字有点糟糕,尽管我没有更好的解决方案,而不是满嘴。 也许--[no-]recursive或其他什么,我不知道。

我认为像upgrade-all命令这样的东西可能是一个很好的补充(只要它确保不违反任何版本说明符)。 不过,我可能只会称其upgrade并且不带任何参数来限制它的操作。

tl;博士
讨论upgrade-all-packages - 留在这里。
首选二进制的讨论 - 转到 #3785
安装即升级的讨论 - 转到 #3786


如果我们有一个 --prefer-binary 选项,表示“只使用二进制文件,除非这意味着没有候选文件,在这种情况下重试允许源”

这是一个好主意。 虽然与这个问题有关,但我确实认为它应该是它自己的问题。 ( @dstufft的评论让我觉得有兴趣去追求它)。 我冒昧地打开#3785 进一步讨论这个问题。

我对 --eager 和 -non-eager 含义的理解与@pfmoore刚刚所说的相符(依赖项是仅在需要时还是始终安装)

Eager upgrade 将安装所有(子)依赖项的最新允许版本非紧急升级才会升级(子)依赖项。

选项名称 --eager 和 --non-eager 非常不直观。

我同意。 我喜欢将行为置于单一标志之后的想法。
--upgrade-strategy=eager/non-eager

这也是一口,但它确实更明确地传达了意图。 是不是太啰嗦了? 或许。

我认为最好在完成语义后完成自行车脱落。

有没有人认为我们已经到了有人可以从这里和其他地方的所有建议中组合出完整的建议行为的地步?

我认同。 我们至少需要确定一些我们同意的基本事实。 我在这

OTOH,也许我们确实在拒绝时关闭了它,有人提出了一个新问题,并提出了他们建议如何修改安装命令的具体建议。 它至少可以为讨论提供一个更清晰的起点。

我认为我们应该暂时保留这个问题,因为它提出了upgrade-all 。 您已经注意到升级没有发生。 我打开 #3786 以进一步讨论 install-as-upgrade 命令。

我仍然担心这里提出的观点中的一些含义,但我不确定我是否有精力讨论它们,直到真正有可能实施。

我愿意将其一直推进到实施。 我绝对不想浪费其他人的努力来就此达成共识。

我想每个人都同意“升级世界”命令真的很好,但是 IIUC 在我们等待解析器工作时它被阻止了。 与此同时,我在@pradyunsg的新专刊上发布了一份更具体的单包升级提案,以供讨论。

我想每个人都同意“升级世界”命令真的很好,但是 IIUC 在我们等待解析器工作时它被阻止了。

事实上,这个问题现在被#988 正确阻止了。 提及用于交叉链接两个问题的问题编号。

我差点忘了...

我不确定你所说的“保持”更新是什么意思。 请澄清。

现在这个问题是专门针对升级所有的,我应该澄清一下。

在某些情况下,当我们运行 upgrade-all 时,阻止某个包的升级可能会很有用。 我想到的具体问题是...如果安装了 pkg 并且我不想费心去重新配置一个潜在的更新版本,那么,我想在运行“升级”时阻止 pip 升级该特定包世界'。 基本上我在阻止 pkg 的升级。

使用逗号分隔的软件包列表来阻止升级的标志会很好。

一旦出现 SAT 求解器,添加它应该很容易。 这只是一些 IIUC 的额外条款。 (是的,我也在复习 SAT 求解器)

我不知道这是常见的还是有人想要的。 但是,我不认为这起源于我的头脑。 一定有人在某个线程中的某个地方提到过它。

啊,我明白了。 这是有道理的,而且似乎是一件合情合理的事情。

快速请求:有人可以在描述中添加一个小提示,升级命令不会发生吗? 如果你愿意,也可以写一个关于为什么会这样的小摘要。

_去睡觉_

apt 有两个不错的功能(我认为其他成熟的系统包管理器,如 dnf 也有类似的功能):

  • 将包标记为“持有”,这是一个附加到包的持久标志,并导致它被 upgrade-the-world 命令跳过。 通常设置在您必须在本地降级或修补的软件包上。
  • 跟踪哪些包是用户明确请求的,哪些包只是隐式安装来满足依赖性约束。 如果后者不再被依赖,则可以通过升级世界将其删除。

这两者都可以看作是最近的项目环境包管理器(如 npm 和货物)所做的事情的特殊情况,他们将某种面向人的“需求”文件与完全指定的“锁定”文件区分开来。 显式保留的包类似于具有人工指定版本约束的包,而显式安装的包是在人工可编辑文件中列出的包。

同上。 如果我们要添加“升级世界”,我们需要添加标记包的功能(如held / user-installed或更多)以添加信息以更好地确定升级。 我认为这是一项要求,而不是一件好事。

我其实很喜欢 Cargo 使用的技术并且喜欢。 使用文件而不是某种形式的 meta-data-hidden-behind-a-cli-command 使其更易于掌握、管理,并且还可以创建可重现的环境。

如果我看到某种形式的pyproject.lock ...

第 200 条评论。 哇。 :笑脸:

添加对 #654 的引用,用于我们谈到的包的“标记”。

你能解释一下货物的作用吗? 您会在哪里看到存储在用户机器上的pyproject.lock文件?

Rust 的 Cargo 锁文件存储在项目根目录中,以记录当前安装的依赖项的版本。 将此文件提交到 git 允许您与其他开发人员和 CI 共享一组一致的依赖版本。 PHP 的 Composer 有一个类似的锁文件 Composer.lock。

我一直认为 pip 的 'pip freeze' 和 'pip install -r' 是为了做类似的事情,不幸的是,锁定文件格式很容易被人类读取/写入,人们选择直接编辑它。 requirements.txt 最初不是被设想为锁定文件的吗?

@triplepoint感谢您的解释。 这确实听起来更像是一个需求文件。 但是需求文件是可选的,基于版本和每个项目。 标记(据我所知)应该针对每个环境(virtualenv 或系统安装),并且应该简单地说“不要自动升级包 X”(但如果用户明确请求按名称升级该包,则允许手动升级)。

为了帮助理清有关upgrade-all和“升级行为”的讨论,以下是@rbtcollins@ncoghlan在后者的列表讨论中的评论,关于upgrade-all的第一次实现不需要 SAT 求解器

罗伯特:

我意识到关于票证的共识是它被阻止了,但我没有
其实同意。

是的,如果没有完整的解析器,你就做不到_正确_,但你可以做到
一个比没有好得多的近似值(只​​是窄
在所有要求中给出的说明符)。 那实际上是
当您处理一组假定良好的版本时是合理的
(安装不处理)。

缺口:

在没有合适的 SAT 求解器的情况下,“yum upgrade”多年来一直运行良好,并且典型的 Linux 安装中的包集比典型的虚拟环境中的包大得多(尽管发行版确实减少了在第一次出现冲突的可能性)地方)。

也就是说,重新运行 pip-compile 然后执行 pip-sync 已经是升级所有操作的功能等价物(就像销毁和重新创建 venv 一样),所以我同意没有必要将支持批量升级的问题结合起来基线 pip 改变升级命名组件的行为。

IMO, pip upgrade-all是迄今为止所有各种“升级功能”讨论中最重要的提案。 拥有“全部升级”将提供一种使您的系统保持最新状态的明显方法,提出有关非急切更新的问题,使旧级别的事情变得不那么紧迫,并填补当前存在的空白。

虽然一个完整的求解器会很好,但我认为没有理由pip upgrade-all的起点不应该是pip install -U <list every package that's installed here>所做的。 这就是我作为用户所期望的,并且在大多数情况下,它完全符合需要。 可以参考上面的第一个实例来处理围绕冲突需求的复杂边角情况。 如果这还不够,那么我们可以查看修改install -U行为来解决它,或者特殊情况下update-all命令,或者甚至在此时实现完整的求解器。

你会在未来 10 年内实施这个吗?

FWIW,我将在本周末重新访问这个。


@magicgoose说:
你会在未来 10 年内实施这个吗?

@pfmoore说得比我好:

我们知道人们想要这个,缺少的是任何人愿意开发一个解决方案来满足所有已经提出的各种担忧和问题,而这将在 PR 审查期间不可避免地出现。

因此,就我个人而言,如果人们避免 ping 这个问题,我将不胜感激,除非他们有至少为实现提供起点的工作代码 - 并且他们愿意遵循它直到实现。

完全个人意见

我认为根据 pip 的本质(它是从没有全局 QA 的 repo 安装包,比如 debian、redhat 或 ubuntu)
我觉得实际上完全避免实现和更新所有功能是必要和/或可以接受的,

因为我们 pip 曾经保证一组可安装的 python 包的已知状态

@RonnyPfannschmidt IMO pip 用户明确禁止使用 update-all 命令是完全合理的,如果这符合他们的要求/工作流程。 但并非所有 pip 用户都与这些人有同样严格的要求。 对于有更宽松需求的用户,update-all 命令很有用,但缺少它会使他们的系统保持“最新”变得更加困难。 所以我认为 pip 提供这样的命令是合理的。 我们的工作是提供人们需要的工具,而不是强制执行关于用户如何选择使用这些工具的特定政策。

@pfmoore我个人在一个环境中更新所有包的经验是,它打破了

需要轻松更新的用户听起来都像是普通的最终用户(例如,应该只使用普通的 linux 发行版)

upgrade-all 是否有问题取决于您拥有多少依赖项,以及他们对 API 维护的纪律性如何。 它还可以与精心策划的私有存储库结合使用,以控制实际发生的升级,而不必仔细配置您在每个虚拟环境中运行的升级命令。

@RonnyPfannschmidt Windows 用户的数量仍然比 Linux 用户多约 18 比 1,并且此时他们没有任何可与发行版软件包管理社区相提并论的东西(虽然核心技术在最近的版本中存在,但打包和管理社区不是)。 这意味着他们更加依赖 pip 和 conda 等用户级工具来弥补不足。

我们知道人们想要这个,缺少的是任何人愿意开发一个解决方案来满足所有已经提出的各种担忧和问题,而这将在 PR 审查期间不可避免地出现。

@pfmoore你知道这样的评论会贬低贡献者的努力吗? 在我看来就是这样。 我不确定您是否了解了这个问题的整个历史,但在这种特殊情况下,您非常偏离基础。 与任何贡献者相比,pip 开发团队的问题更多。

只是其中一部分的粗略总结(PR gh-3194):

  1. 有一个记录在案的决定是欢迎使用upgrade命令(在 pip 邮件列表以及文档和 GitHub 上)。
  2. 然后一位杰出的开发人员(在本例中为@njsmith
  3. 新的贡献者出现,实施一切,快速处理所有评论。 PR 准备合并。
  4. 核心贡献者改变了想要upgrade想法。
  5. 接下来是很长的讨论,没有结论。
  6. 贡献者放弃并消失(大多数人会,这样的事情令人沮丧)。

甚至在@pradyunsg出现之前,他就表现出了非凡的毅力。

在一个运行良好的项目中,真正关心这个问题的核心开发人员会组织一个快速的聚会并做出某种决定。 或者委派一两个人进行足够的工作以得出该结论。 或者至少向 PR 提交者道歉并表示感谢,而不是责怪他“没有完成”。

我知道你有最好的意图,但请对这种评论更加小心。

我认为通过讨论来改变要求和意见是完全合理的,尤其是对于像这样没有正确答案的棘手问题。 在任何代码库中获得补丁的一部分是跟上作为围绕任何更改的审查和讨论的一部分而散列的更改。 有些变化相当小,变化较少,有些变化较多。 一个人决定他们不想处理它并退出并没有错(添加更改的每个障碍都会导致一定量的下降,包括测试、文档等)。

这个特殊的变化特别讨厌,因为它改变了 pip 主要用途的默认行为。 这既困难又可怕,如果我们仓促行事并且在致力于一个方向或另一个方向之前没有完全解决问题,这将对我们的用户造成伤害。 此命令每月使用 10 到 100 百万次。 这不是一个小的、容易的改变,也不会是那些提出这个问题的人必须应对因做出任何改变而引起的愤怒反弹。

之前实施 PR 的人,他们的时间是值得赞赏的,但他们没有坚持到底是事实。 由于这里的核心开发人员_我们的_时间有限,我们要么是志愿者,要么分散在许多项目中,我们参与和退出。 有很多不同的问题都需要注意,这只是其中之一。 Paul 只是说 ping 这个问题没有帮助(事实并非如此),如果有人想要它,他们将需要等待某人(包括其中一位核心开发人员)决定付出相当大的努力改变数百万人的默认行为或自己做。

我们知道人们想要这个,缺少的是任何人愿意开发一个解决方案来满足所有已经提出的各种担忧和问题,而这将在 PR 审查期间不可避免地出现。

@pfmoore你知道这样的评论会贬低贡献者的努力吗? 在我看来就是这样。 我不确定您是否了解了这个问题的整个历史,但在这种特殊情况下,您非常偏离基础。

@rgommers 是认真的吗? 那条评论是几个月前的,在这里被断章取义地引用(但坦率地说,我对@pradyunsg引用它以回应他正在回复的无益和讽刺的评论没有任何问题)。 我建议如果你回顾了整个历史,你会在上下文中看到我的评论,希望你能理解我想说的。

如果我是那个“基地外”,那么你可以在我说这件事的时候在五月份这么说,而不是现在就断章取意。

如果我冒犯了任何人,我道歉,这不是我的本意。 老实说,我和其他人一样感到沮丧,因为事实证明,这个问题很难达成一个所有人都能接受的设计。 在我的评论中,我试图取得平衡 - 一方面,我真诚地感谢人们所做的贡献,但另一方面,我觉得向人们明确表示,在这样的问题上,坦率地说,编码是所需工作中最少的。 很多时候,贡献者不理解这个事实,这就是我们得到不完整 PR 的地方,人们对说服人们他们的设计是好的所需的工作感到沮丧,和/或重新修改更改,可能以他们不喜欢的方式不是真的喜欢,要考虑其他人的(通常是相互矛盾和不一致的!)观点。 我宁愿他们在了解所涉及的内容的情况下进入流程,而不是带着不切实际的期望进入流程,从而导致糟糕的体验。

参与该问题讨论的每个人都投入了大量时间来讨论各种方法的利弊。 我想没有人会因为花了多长时间而感到高兴。 就我个人而言,缺少upgrade-all命令(只是更改的一部分,不太可能是第一个实施的)经常让我感到震惊。 我们偶尔会(老实说,这不仅仅是“偶尔”)让人们(通常是实际上没有对讨论或代码做出贡献的人)评论“这很重要,你为什么还没有实施它?” 坦率地说,很难对这样的人保持冷静和_不_生气。

在一个运行良好的项目中,真正关心问题的核心开发人员

您确实意识到此评论很容易被解释为说 pip 开发人员不关心修复此问题(以及对 pip 的暗示)? 我们都有可能会冒犯他人的措辞。 我敢肯定,您的意思并不是批评 pip 开发人员,请假设我同样不想冒犯任何人。

会组织一个快速的聚会并做出某种决定。

如果这样的事情在这里可行,我会感到惊讶,但我愿意尝试。 不确定谁会参与或我们将如何管理它,但可以肯定,如果它有帮助并且有人想尝试这种方法。 我想说的是,由于这一变化对 pip 用户的影响如此之大,因此在像这样的私人渠道上做出的任何决定都应该写成提案并发布以征求一般意见——我怀疑这样做只会触发又一轮我们一直在进行的相同辩论。

或者委派一两个人进行足够的工作以得出该结论。

所以你是说这么大的决定应该由几个人单方面做出? 也许这是我们获得解决方案的唯一方法,但这并不是在 pip 上做出决定的真正方式(与 Python 不同,我们没有具有执行决策权的 BDFL)。 如果您愿意,您可以声称这使我们不是“运行良好的项目”,这不是我的观点,但如果您愿意,我们可以不同意。

或者至少向 PR 提交者道歉并说声谢谢,

我不确定我们应该为什么道歉,但如果有帮助,那么我会很高兴地道歉 - 因为没有人让他清楚地了解完成这项提案将是多么困难的工作,或帮助他管理辩论并引导参与者达成共识。 但公平地说,我认为当时没有任何_其他_参与者知道情况会如此,所以我认为这里主要是事后的看法。

他当然感谢我。 说“那不言而喻”很容易,但不应该——开源项目对贡献者的感谢不够,这是一个问题。 当我谈到这个主题时,我要感谢为这场辩论做出贡献的_每个人 - 我在这里是认真的 - 因为我从经验中知道它是多么令人筋疲力尽。 但尤其要感谢@pradyunsg ,因为他目前是所有无休止的讨论和方向变化的受害者。 谢谢你不放弃! (然而!!)

而不是责怪他“没有完成”。

好吧,我认为没有任何责任(尽管很难知道他是否感到受到责备,因为他已经不在了)。 但他的原始 PR 确实没有完成。 不过,这只是事实。 我希望没有人暗示贡献者有权让他们的 PR 被接受_仅仅因为他们提交了_。 并不是所有的 PR 在第一次提交时都是可以接受的,它们需要修改和更新,有时甚至在完成所有工作之后它们_仍然_不被接受。 对不起,但这就是生活。

[如果我在上述声明中显得严厉,我道歉(再次!)。 但是我的很多空闲时间都花在阅读和处理我(或我参与的项目)不知何故做得不够的投诉上。 这是一个恶性循环 - 由于唠叨,我在业余时间失去了从事开源工作的动力,这当然意味着完成的工作更少。 虽然我尽量保持礼貌,但有时并不容易]

我不打算在这个关于如何管理 PR 的元讨论中进一步说明。 今晚我花了一个小时来处理这个回复,尽量避免说任何可能冒犯某人的事情(我敢打赌我失败了:-()。我本可以更好地度过那段时间——和我的家人一起放松,或者做一些更有成效的事情。

那么我可以建议我们重新尝试帮助@pradyunsg提出一个我们都满意的公关,并放弃毫无结果的元讨论吗?

那么我可以建议我们重新尝试帮助@pradyunsg提出一个我们都满意的公关,并放弃毫无结果的元讨论吗?

是的,请。 :清白的:

哦,我忘记了。

@rgommers说:
甚至在@pradyunsg出现之前,他就表现出了非凡的毅力。

我会将此作为补充...谢谢。

@pfmoore说:
尤其是@pradyunsg ,他是所有无休止的讨论和方向变化的当前受害者。 谢谢你不放弃!

别客气。

(然而!!)

真希望不要到那种地步。 IMO,如果确实如此,那将是一个非常糟糕的事态。 (我就是这么傲慢)

我在回顾历史时写了以下内容,并认为不妨将其放在这里,以供将来参考并让其他人纠正我以防万一。

  • 在意识到非技术:技术比率有多大(它比我_真的_保守地认为的要大得多)并意识到已经有一次失败的尝试之后,决定着手解决这个问题。
  • 写了一篇关于事态的文章,因为我很无聊,无论如何我需要知道发生了什么。

    • 可能花在它上面的时间(和空间?)比需要的要多,但至少我自己(和其他人?)对这个问题有一个很好的概述。

  • 写完就激动了。 :smiley: 向全世界展示了它!
  • 发起了关于实施升级命令的(长!!!)讨论。

    • 讨论中提出了一些有用的副业想法。 为此创建了新问题。

  • 讨论导致了将安装行为更改为 upstall 的想法,这将在默认情况下进行非急切升级并删除 --target 选项提供的部分功能 - 3 件事。

    • 这就是我们犯了一个错误的地方——将 3 个(相当)独立的更改捆绑在一起,并将作为一个实施,因为没有人意识到这一部分。

  • 我实现了相同的。 由于这 3 个更改是捆绑在一起的,因此当没有就将安装行为更改为 upstall 达成共识时,它们都被卡住了,这可能是有争议的更改。
  • 缺乏共识引发了长时间的讨论,最终人们退出了讨论,我猜几乎被推到了精疲力竭的地步。

    • 一些较早的假设被打破,我们决定首先进行最小的中断更改。

  • 我没有空闲时间来处理这个问题,所以我创建了一些新问题,以便其他人可以独立处理它们,理想情况下不会像我们在这里那样犯同样的错误。
  • 停滞了。
  • 我回来了! 默认情况下,我会尝试在 9 月 25 日之前切换到非急切升级。

是的,让我们只专注于修复pip install --upgrade而暂时搁置其他一切。 无论如何,这是任何其他工作的要求。

@pfmoore @dstufft感谢您的深思熟虑的答复。 我无意冒犯任何人,所以如果遇到这种情况,我深表歉意。

我不会一一回复,因为没有人想在这里进行长时间的讨论。

你可以在我说的时候在五月这么说,

那时我离开 Github 有 2 个月了,但是当我第一次看到这条评论时,它确实让我感到困扰。

所以你是说这么大的决定应该由几个人单方面做出?

桌面上的所有选项都比现状好得多。 在 5.5 年之后,数百条评论散布在此处的多个问题/PR 和邮件列表中,我不相信会有更多评论来解决它。 我希望它会得到解决,但如果这再次停滞,那么肯定是 - 提名一个或几个人,然后做出选择。

我不确定我们应该为什么道歉,但如果有帮助,那么我会很高兴地道歉 - 因为没有人让他清楚地了解完成这项提案将是多么困难的工作,或帮助他管理辩论并引导参与者达成共识。

我指的是后者。 有时我会改变我对我的一个项目的决定的想法,这种情况会发生。 然后我觉得有责任明确新的方向。 如果我没有时间处理这种变化的后果(只需要 30 秒......),我深表歉意。

但他的原始 PR 确实没有完成。 不过,这只是事实。

那是一种看法,而不是事实。 在我看来,PR 已经完成——剩下要做的就是点击绿色按钮或拒绝它。 他做了我对贡献者的所有期望。

在您的回复之后,我意识到 pip 开发人员对贡献者和核心开发人员的期望与我熟悉的几乎任何其他项目都有很大不同。 我希望核心开发人员能够指导新的贡献者,鼓励他们,在需要时给予他们反馈,并帮助他们解决有争议的问题(大多数贡献者既没有技能也没有兴趣,而那些经常最终成为核心开发者的人)如果需要。 你对新的贡献者说:_“你必须管理我们。我们可能会改变主意,彼此不同意,或者失去兴趣 - 管理这些是你的工作”_。 也许这就是这个项目的性质,它必须是这样,我不知道。

在谈到这个话题时,我要感谢所有为这场辩论做出贡献的人

同意。 感谢所有做出贡献的人。

  • 我在这里是非常认真的——正如我从经验中知道的那样会让人筋疲力尽。

它正在排水。 就我个人而言,我坚持使用 distutils-sig 是因为它对 Python 生态系统和我的包的用户很重要,但这两个地方并没有给我正能量。

以防万一它滑倒在雷达下 - #3972 :smile:

你对新的贡献者说:“你必须管理我们。我们可能会改变主意,彼此不同意,或者失去兴趣——管理这些是你的工作”。 也许这就是这个项目的性质,它必须是这样,我不知道。

我说我不会继续这个,但这一点很重要。 这不是我对我们方法的看法,但现在你这样说,我确实看到它可以以这种方式出现。 老实说,“我们可能会改变主意,彼此不同意,或者失去兴趣”是真的——毕竟我们都只是有其他承诺的人——但我不认为这是一个新的贡献者必须要做的事情“管理”。 相反,这只是与人打交道的现实,但如果过分强调将问题转嫁给新的贡献者,那就错了。

感谢您指出这一点 - 我会尽量记住这一点,并避免在未来给人留下这种印象。

我认为很多问题实际上归结为我们人手严重不足的事实,这最终导致很难跟上和跟进所有事情。 潜在的贡献者比我们多,因此当有多个人都试图同时进行更改时,很容易感到不知所措。 更大的变化,或者没有明确共识的变化,往往是最难处理的,所以它们往往是受害最深的 :(

可悲的是,虽然我认为我们都希望在这里帮助指导每个贡献者完成整个过程,但我们根本没有人力。 这也往往有一点粘性循环,因为我们没有人力来做到这一点,我们不容易找到似乎真正开始摸索 pip 运作方式背后的心态的新人,他们已经学会了足够(因为我们不是在那里教他们)给他们提交 pip 的权利。 这意味着我们经常人手不足,努力保持头脑清醒(至少,我的感觉是这样。每周持续 70-90 小时对一个人来说真的很难:/)。

@pradyunsg Reviewing #3972 在我的待办事项清单上,只是还没有达到。

@pradyunsg Reviewing #3972 在我的待办事项清单上,只是还没有达到。

谢谢!

这意味着我们经常人手不足,努力保持头脑清醒(至少,我的感觉是这样。每周持续 70-90 小时对一个人来说真的很难:/)。

那很难。 当我开始研究它们时,Numpy 和 Scipy 就处于这种情况。 不好玩。 我感谢你所做的一切。

这个问题现在真的很长很老了,已经讨论了很多事情,发生了太多事情,这个问题几乎达到了低信噪比。 很难看出发生了什么。

FWIW, upgrade出现在卡片上的原因是因为install --upgrade的默认值已损坏。 由于我们现在离解决这个问题又近了一步,我想我们最好为此提出一个新问题。

由于上述原因,我建议关闭此问题,并为此处视为未解决的任何问题创建新问题。 我可以看到两件事:

  • 将默认升级策略改为only-if-needed
  • 添加依赖于#988的“升级世界”功能。

2016 年 9 月 15 日,Nick Coghlan通知@github.com 写道:

@RonnyPfannschmidt Windows 用户数量仍然超过 Linux 用户~18:1,并且
他们没有任何可与发行版软件包管理社区相提并论的东西
在这一点上依靠(虽然核心技术在最近
版本,包装和策展社区不是)。 这意味着他们是
更依赖于像 pip 和 conda 这样的用户级工具来获取
松弛。

那是不是
康达更新 --all
够好了?

@Liso77
嗯,不,不是。

Conda 和 pip 是具有不同目标的工具。 是关于这个主题的很好的读物。 第 3 点最为相关。


如果对 upgrade-all 的讨论再次浮出水面(希望在新一期中),我会投票支持将其拼写如下:

pip install --upgrade :all:

pip install --upgrade :all:非常奇怪。 让我们坚持 POSIX 语义,现在基本上每个人都在这样做: pip install --upgrade --all

没有任何包名或说明符的pip install --upgrade怎么样? 容易误跑?

pip-tools就是这样处理pip-compile -P

也许一旦我们有某种工作,我们就应该去自行车棚
执行... :)

在Sun,2017年2月12日,20:55 FichteFoll [email protected]写道:

不带任何包名的 pip install --upgrade 怎么样?
说明符? 容易误跑?


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/pypa/pip/issues/59#issuecomment-279225595或静音
线程
https://github.com/notifications/unsubscribe-auth/ADH7SfnSBflH8rK3nFLw1hvYBaovjbcGks5rbyRUgaJpZM4AJ4Py
.

pip list --outdated的版本如何以可以直接(即,没有sedcut等)摄取的格式生成其列表, pip install --upgrade (例如, pip list --outdated --format install | xargs pip install --upgrade或类似的反引号)?

无论使用什么语法,最重要的是引入这个命令,令人难以置信的是仍然缺少

同时我建议你尝试
https://github.com/jgonggrijp/pip-review
pip-review --local --interactive包一包问你是否要更新,不是很好但总比没有好

@SMH17完全可以相信它仍然缺失,因为完全有零个商业 Python 供应商正式提供资助的开发时间来代表他们的客户进行 Python 打包可用性改进。

所以,如果你想看到的局面改善,很可能是你可以亲自做的最有用的东西是要么鼓励你的Python支持的供应商在提高,你所使用的工具进行投资开发的时间,或者如果你没有支持供应商,鼓励您的雇主支付一个。

作为关于此问题缺乏紧迫性的额外背景,值得记住的是,一般建议是

  • 将您的工作环境定义置于源代码控制之下,以提高在其他系统上的可重现性(使用诸如 https://github.com/jazzband/pip-tools 或 https://github.com/kennethreitz/pipenv 之类的东西来使这些定义保持最新)
  • 旨在定期升级到新版本的依赖项,以最大限度地减少未知或未公开的安全漏洞的暴露窗口

这并不意味着这里提出的命令没有用,如果当前的工作环境已经通过pip-compile + pip-syncpipenv lock进行维护,它们的价值就会明显降低pipenv install

更新原始描述会很有价值,因为我猜自从@qwcode 进行更新以来,对pip install进行了一些更改。

大家好。

我已经破坏了我的一些 python 包依赖项,因为以下命令:

pip install --upgrade packageName已递归升级包。

为什么不更改--upgrade选项的默认行为,即仅从命令行卸载并重新安装给定的包?

这个怎么样 ?

@sebma我认为不应更改默认行为。 也许下次您可以尝试使用-no-dependencies标志。 它应该工作:+1:

@sebma@aaossa ,我会让你们都知道,默认升级策略将在未来发生变化几乎已经决定(参考:https://github.com/pypa/pip/issues/3871#问题评论-247789343)。 在https://github.com/pypa/pip/pull/3972 中添加了必要的功能(即--upgrade-strategy参数)

正如@pradyunsg之前提到

我为需求文件发布了一个很好的交互式升级程序: https :

将默认升级策略改为仅在需要时。

4500 做到了这一点。

添加依赖于#988的“升级世界”功能。

4551 对此进行讨论。


解决当前顶帖中提出的观点:

pip upgrade 就像 pip install --upgrade 一样,除了默认情况下它是非递归的(并提供 --recursive 选项)。 它当前的递归默认行为已引起许多人的悲痛(#304)。 至于现在如何进行非递归升级,请看这里。

已决定不添加升级命令或使 pip install 升级已安装的包。 pip 现在默认有非递归升级,递归行为在--upgrade-strategy eager后面可用。

pip upgrade-all 将升级所有已安装的软件包。

4551 存在,对此进行新的讨论会很好; 当#988 完成时。


@dstufft @xavfernandez @pfmoore你们中有人认为这个问题应该关闭吗?

编辑(05-18-2017):添加标点符号 + 次要文本

似乎有道理。

大家好,
我制作了一个简单的脚本/要点来完成这项工作。

https://gist.github.com/serafeimgr/b4ca5d0de63950cc5349d4802d22f3f0

为什么不简单地这样做呢?

pip install --upgrade $(pip list --outdated | awk '{print $1}' | tr '\n' ' ')

因为这在现实中并不容易,因为您可能会安装不满足其他一些软件包依赖项的版本。

基于并感谢@serafeimgr要点,我编写了一个可能有用的命令行工具pip_upgrade_outdated ; 源码在 github 上。 欢迎反馈。

(另请参阅此问题:是的,并行执行特别危险,而且,是的,这可能会破坏事情。尽管如此,许多人一直手动运行类似的程序,因此可能会发现它很有用。)

感谢您花时间构建完整的解决方案。
尽管我的建议是找到一种方法将此功能推送到 pip。

我认为 pipenv & pipfile 无论如何都会替换 pip/requirements.txt 。
也许@kennethreitz对路线图和

@qheniac | tr ...是多余的。

由于关闭后没有任何近期活动,因此该线程已自动锁定。 请为相关错误打开一个新问题。

此页面是否有帮助?
0 / 5 - 0 等级