Pip: 默认为 --user

创建于 2014-03-21  ·  170评论  ·  资料来源: pypa/pip

当 pip 安装在安装了 OS Python 的系统上时,当前存在pip install foo将引发错误的问题,因为它没有文件权限。 这会导致人们转而运行sudo pip install foo ,它会全局安装到系统 Python。 这会产生一个问题,即人们在应该使用系统包管理器时却使用 pip 来管理系统级包。

所以我的意图是 pip 应该默认为 --user 但是有一些问题:

  • 这如何与 Windows 交互? 这在那里有意义吗?
  • 这如何与 altinstall'd Python 交互? 特别是使用https://github.com/yyuu/pyenv等工具安装
  • 当人们确实以 root 身份调用 pip 时,我们该怎么办? 安装到/root/.local/似乎不是很有用。
  • 这对get-pippypa 安装说明意味着什么?
  • ~/.local/bin 不在很多人的 $PATH 上,对此有什么可以做的吗?
  • --user安装缺少全局easy_install 'd 包的优先级,这可能是非常出乎意料的。

这里有许多相关的问题:#624 #1443 #1153 #1500 #1051

/cc @ncoghlan

user scheme auto-locked enhancement

最有用的评论

我在晚上梦想--user选项成为默认选项(不是开玩笑),我的梦想很快就会实现吗?

所有170条评论

这对 pypa 安装说明意味着什么?

目前在脚注中提到了 root 或管理员访问权限,因此说明基本上保持不变(假设get-pip也自动默认为--user )。 更改将解释他们最终将获得仅适用于当前用户的安装。

不管--user的变化如何,当前的说明都需要解释一些发行版,如 debian,正在禁用 ensurepip,所以他们不应该去寻找它作为获取 pip 的方法。

从长远来看,我很确定他们会保持启用它,他们只是想知道如何去做。

虽然这个问题被描述为关于 pip 默认应该在哪里管理包,但几乎更重要的(至少对我来说)是这间接地是关于get-pip将默认放置 pip 的位置。

这如何与 altinstall'd Python 交互?
特别是使用https://github.com/yyuu/pyenv等工具安装

用户方案是.local/lib/pythonX.Y/site-packages ,所以如果你管理多个具有相同主要/次要版本的python,我猜你最终可能会一团糟。

对于像这样管理真正 python 的工具,将 pip 固定到全局模式对那些人来说是有意义的。

关于 redhat/fedora 错误跟踪器的相关问题https://bugzilla.redhat.com/show_bug.cgi?id=662034#c10

看起来 Fedora/RedHat 的PATH=$PATH:$HOME/.local/bin:$HOME/bin已经在他们的/etc/skel/.bash_profile中了。 这将使使用--user安装的东西仍然默认显示,至少对于 bash 用户(默认 shell)。 也许其他发行版已经有了这个?

据我所知,Windows 没有什么特别的不同。 但是我们只是将标准 Python 目录放到了人们的 PATH 中,我不认为获得每个用户的脚本目录会特别容易——而且可能还有技术上的困难,我不确定将像%LOCALAPPDATA%这样的用户级环境变量放入系统级%PATH%甚至可以工作:-(

我反对仓促行事。 我宁愿等到我们有更多的用户安装经验并设法首先解决问题。 我知道这是一个先有鸡还是先有蛋的问题,但我不认为仓促做出改变是有帮助的。

另外,在我戴上 Windows 帽子的情况下,我不得不说,让尚未发现粗心使用 sudo 会做愚蠢事情的 Unix 用户更难,这并不是一个很好的理由。 .

我假设这仅适用于从系统 Python 运行 pip 时。

好吧,Windows 上的不同之处在于没有像 *nix 上那样提供系统提供的 Python,它还附带系统提供的 Python 包:)

我也不是特别想着急。 我只是想开始讨论。

这并不会真正影响键入sudo pip install的人,因为我认为默认情况下以 root 身份安装某些东西仍应转到系统站点包。 这将引导人们在以非特权用户身份运行时使用--user 。 现在你得到的是pip install作为普通用户只是因为权限错误而爆炸。 即使我们改进该消息以轰炸并建议--user这仍然不是最好的用户体验。

在与 Fedora 的一位人员交谈时,我认为这样做的方式可能是实施权限检查。 如果我有权写入 site-packages 目录,那么我是特权用户,并且 pip 安装到全局 Python,如果我没有,那么我是非特权用户,它安装到--user

就 Windows 而言,我们通常会回避这个问题,因为我们默认将 Python 安装到非特权目录,因此 pip 在全局安装时不会触发 UAC。 如果有人将其更改为安装到 Program Files 中,那么 UAC 将在他们运行 pip 时触发(这也可以)。 我不确定如果他们在安装程序中选择按用户安装会发生什么。

正如 Paul 所指出的,Windows 上的 PATH 还不包括 _user_ 脚本目录(只是全局目录),所以这绝对值得考虑。

不过,我在 POSIX 方面没有看到任何重大障碍。 这个 UX 想法听起来如何:对于基于轮子的安装,检查安装目标目录的权限,如果用户没有写权限,则提示询问他们是否愿意进行 --user 安装? 新的“--global”或“--system”标志将强制回答“否”。

然后在将来的某个时候,我们可以跳过提示并简单地假设 --user 如果权限不适合全局安装。

提示(除了 --no-input 的情况)可能对转换步骤有意义。 我认为检查权限也应该使 Windows 也能正常工作,因为默认情况下,该位置位于人们有权访问的位置,因此他们唯一会遇到此问题的情况是,如果他们使用的是系统管理员提供的 Python,而 Python 明确没有不给他们许可。

从本质上讲,这使我们的故障模式变得更好。

使尚未解决粗心使用 sudo 的 Unix 用户更难
做愚蠢的事情是不好的,这不是一个很好的理由..

sudo和安全性确实是 IMO 的次要问题。
这主要是为了防止操作系统打包和系统python中的pip之间的冲突。
目前,linux用户经常被置于一个不可能的境地。

  1. 操作系统授权:'使用操作系统 pkg mgr; 不要用 roque pip 安装的软件包感染你的系统(包括get-pip 'd pip)'
  2. 现实:“操作系统包(包括 pip)太旧了,我无法升级到发行版的实验版本,只是为了升级一些包。我要流氓了......”

另一个小步骤是记录(假设我们对其进行测试)您可以get-pip.py --user ,并让 PUG 提及--user作为安装virtualenv (和wheeltwine也是,如果不在虚拟环境中)

FWIW,发行版供应商也认为现状是一个问题,并正在寻找各种方法来改进在不影响核心操作系统组件的情况下进行选择性升级的工具。 尽管如此,仍然值得我们从上游解决,因为这些努力处于不同的成熟阶段,我们希望为最终用户提供一致的跨平台解决方案。

我对改变事物以帮助与 Unix 上的发行版合作没有问题; 如果在 Unix 上默认为--user而不是在 Windows 上是可以接受的,那对我来说很好。 我只是不认为从 Unix 上的糟糕体验切换到 Windows 上的糟糕体验是一个很好的权衡。 而且我还不能确信 Windows 上的--user已经准备好迎接黄金时段了。

请注意,在 Windows 上运行 pip _is_ bad 时触发 UAC,因为它实际上意味着 pip 不会运行,除非在提升的控制台窗口中运行。 这并不意味着 pip 用户会得到一个很好的提示,他们可以说“OK”,不幸的是,这只是 GUI 应用程序的工作方式......

@pfmoore当您pip install某些东西并且您没有写入目录的权限时,您认为 Windows 的用户体验应该是什么?

FWIW 我完全可以根据 Windows 是否选择此选项。 我只是想知道“我是否有权写入站点包文件夹”检查是否在 99% 的安装中都无法实现,如果安装到 --user 会是更好的体验您没有对站点包目录的写入权限的情况的一小部分。

换句话说,如果我们检查权限,提案不是用用户安装替换全局安装,而是用--user安装替换权限错误。

该提案没有用用户安装替换全局安装
它正在用 --user install 替换权限错误

好的,但请记住权限检查的想法(#1048)不是最简单的事情

在 Wheel 案例中会很容易,我们可以让 sdists 覆盖 99.9% 的案例,这应该只是 setup.py 中的一个问题,它会做一些非常时髦的事情。

当您 pip install 某些东西并且您没有写入目录的权限时,您认为 Windows 的用户体验应该是什么?

好吧,能够写入 site-packages 目录在 Windows 上是如此罕见,以至于我不确定这个问题在实践中的相关性。 但如果发生这种情况,我会说“系统站点包不可写 - 你的意思是使用--user吗?” 将是明智的做法。

实际上,我认为这在 Unix 上也会更好。 根据可写性切换行为是奇怪的,我不清楚在可写目录中将--user用于个人构建的 Python 是否是正确的方法(但我对这种设置的经验恰好为零,所以我没有任何证据支持这种观点)。

建议:从上面提示--user的错误开始。 一旦人们更常使用--user ,并且我们对它有更多经验,那么让我们考虑切换默认值。

Paul 建议的方法大致是我的想法,但是提示是/否,而不是通过错误消息来解决问题。 这两种方法各有利弊(主要与从另一个脚本调用它们如何失败有关)。

是否可以在 Python 中添加 sys.localprefix 之类的东西(我在这里看到了 python-dev)?
Sys.localprefix 将默认为 sys.prefix。 发行版可以像定义前缀一样定义它(例如前缀='/usr',localprefix='/usr/local')。 Pip 和 easy_install 将使用 sys.localprefix 作为安装位置(如果用作 sudo),如果它们没有足够的权限回退到 --user。

我们在 Fedora 17 中使用“gem install”完成了类似的操作,Ruby 开发人员通常对此非常满意,所以我想我会分享:

  • "gem install foo" 将 "foo" 安装到 ~/somedir 如果 uid != 0
  • 如果 uid == 0,“gem install foo”将“foo”安装到 /usr/local/somedir
  • "yum install ruby​​gem-foo" 将 RPM 打包的 "foo" 安装到 /usr/somedir

我认为根据用户权限选择安装目录会让人们非常困惑; “pip install foo”应该对所有非 root 用户以相同的方式工作。 如果您考虑大多数用户,他们会希望“pip install”进入他们的家,“sudo pip install”进入系统范围的目录。 因此,我认为这是基于 uid 执行此操作的最佳方法,如上所示 - 对于那些不是 root 但想要安装到系统范围的目录的用户,总是有 --target 选项。

@bkabrda只要您不担心将脚本添加到 $PATH,这是一个简单的选择。 你在那里做了什么?

@Ivoz正如@dstufft所指出的,Fedora 已经在 PATH 上有 $HOME/.local/bin ,所以一切都是开箱即用的(说到脚本)。

对于 POSIX 系统,Slavek 的建议对我来说听起来不错。 它也应该很好地与容器一起工作,因为可以告诉在容器中运行的东西认为它是 uid 0,即使它完全来自容器外部。

对于 Windows,我不太确定正确的答案是什么。 我们在与系统包管理器进行争论时没有完全相同的问题,尽管它在某种程度上确实存在(pip install 与 MSI 安装程序),并且即使在 Python 3.4 中,安装程序的可选 PATH 也有额外的复杂性修改只添加全局脚本目录,而不是每个用户的目录。

根据 Python 是安装到默认位置(不受控制)还是安装到程序文件(需要进行更改的 UAC 权限升级),Windows 也有奇怪的地方。

@rkuska建议的“localprefix”想法对我来说看起来不错,简单易行。 我也很喜欢@bkabrda建议的方法,特别是对于像 Arch 这样的发行版,它们使 python 3.x 成为默认 python。

还有一点需要注意的是,Arch 在 3.4.0 版本中禁用了 ensurepip,就像 Debian 一样(主要是因为我们想提供最新版本的 setuptools 和 pip,而捆绑的版本可能已经过时了很多年),所以最好有一个小费。

@lvoz
对于 Arch,我们没有在 $HOME 下将任何路径添加到 PATH,但我仍然认为这很好。 我们已经有Ruby 的 wiki 条目,告诉用户添加它。

如果不只是禁用它,Arch 和 Debian 开发人员将帮助 Slavek 处理他的补丁以确保 pip 从系统版本重建轮子并将其安装到虚拟环境中,那就太好了。

仅供参考,我们已经在 Fedora 的 Copr 构建系统中构建了工作的 Python 3.4 RPM(测试,如果您不想破坏任何东西,不建议安装它们)。 如果您想了解更多关于我们如何处理此问题的信息,请查看代码等,请参阅我在 debian-python ML 上与 Barry Warsaw [2] 的讨论。
(在我们向上游提出补丁之前,我们的补丁仍然需要一些爱,但对我们下游的 ATM 来说一切正常)

[1] http://copr-fe.cloud.fedoraproject.org/coprs/bkabrda/python-3.4/
[2] https://lists.debian.org/debian-python/2014/03/msg00046.html

抱歉,AFAIK Arch 从来不支持 wheel,我们也不想让 ensurepip 调用包管理器(如果我理解这种方法错误,请纠正我)。

对于 ensurepip,警告用户不要使用 ensurepip 安装 pip 是个好主意,这是我目前能想到的最多的。

我们的 ensurepip 永远不会调用包管理器。 简而言之,Fedora 的 ensurepip 将依赖系统打包的 setuptools 并且 pip 始终存在(我们的 python3 包将依赖它们,这将创建一个依赖循环,但我们可以处理)并且当用户创建新的 virtualenv 时,它将重新打包system setuptools 和 pip into wheel 并将它们安装到新的 virtualenv 中。
我们开始有点跑题了,所以我想我们应该在其他地方继续讨论......

@felixonmars 这是否意味着在 Arch venv 上的损坏与在 Debian 上的一样?

好的,谢谢你的解释,我想我明白了。 我会看看我能做什么,并为此跟进 debian-python。

@dstufft是的,安装的是捆绑版本而不是系统版本。

@bkabrda因此,如果您使用系统 Python 调用 pip 就可以解决问题,在这种情况下我们必须对 virtualenv/venv 进行特殊处理(这不是世界末日)。 但这也意味着我们假设所有 Python 都是系统 Python,即使是用户安装到其 homedir 中的那些,例如https://github.com/yyuu/pyenv (这就是我实际运行 Python 的方式)。 所以我不确定,这就是我想到权限检查的原因。

@dstufft所说的一样,在使用像pyenv这样的工具来处理非 root 蟒蛇时, root成为进行全局安装的关键(其中“全局” != "系统")

我们在 Fedora 17 中使用“gem install”完成了类似的操作

你的意思是 Fedora 17 的 gem 的 rpm 有这个作为发行版的黑客?或者 gem 本身有这个逻辑?

一种想法是 pip 应该提供一种“系统友好模式”,可以由打包 pip 的发行版打开,或者当用户知道他们正在将 pip 自己安装到系统管理的 python 中时。 否则, pip 是否是正常的默认全局逻辑。

@felixonmars我刚刚看到https://projects.archlinux.org/svntogit/packages.git/tree/trunk/PKGBUILD?h=packages/python ,如果你正在做的只是调用--without-ensurepip那很好. 这使 venv 模块的 ensurepip 模块完好无损。 Ubuntu(Debian?)当前的补丁实际上在 ensurepip 包本身上调用rm -rf ,使其无法在 venv 中调用。

我认为默认用户安装是尼克两年前提出的,或者可能是其他人在更早之前提出的,但该线程进入了多个方向并且没有成果。 主要障碍是向后兼容 IIRC,但现在系统管理员和 pip 用户可能更习惯于小心 virtualenv/pip/setuptools 更新,无论好坏。 我不记得那个讨论是在 distutils-sig 还是 pypa-dev 上发生的。

它是目录签名: https ://mail.python.org/pipermail/catalog-sig/2013-February/004773.html

@dstufft哦,我明白了...但是我仍然觉得在系统方面安装了软件包的情况下安装了捆绑的(可能是旧的)版本是错误的:)

@felixonmars问题是你不能将系统包安装到 virtualenv afaik :) (即使你对系统包和 virtualenv 中的内容有不同的担忧)

@dstufft这就是 Slavek 的轮回开始的地方,但这有点离题了 :)

@dstufft谢谢!

不知道我是否应该在那里继续讨论,因为这应该不是问题,因为我们没有在 Arch 中解开 pip,并且 rewheel 应该会生成可用的轮子 :)

@dstufft说得对,我们可能需要对 virtualenv 甚至 pyenv 进行特殊处理,这看起来很难看。 我不得不承认我对 pyenv 不是很熟悉,所以我现在想不出任何“合适的”解决方案。 我会试着仔细看看它并想出一些东西。

@qwcode用于 Fedora 上的“gem install”,它是一个下游补丁。 TBH 我很久没有接触 Fedora 的 Rubygems,但我上次检查时,它只是下游。

我已经在 python [1] 中发布了指向此问题的相关错误的链接。 我想将此讨论移至python setup.py install核心,以便easy_install pip可以使用 (例如)如果uid==0 sys.localprefix 目录,如果uid!=0@bkabrda所述,则安装到用户目录。

目前我可以默认将 pip 安装到用户目录。

[1] http://bugs.python.org/issue1298835

正如尼克指出的那样,我将讨论从 issue1298835 转移到了 pypa-dev [1]。
[1] https://groups.google.com/forum/#!topic/pypa -dev/r6qsAmJl9t0

默认为 --user

好主意!

pip install foo会抛出错误,因为它没有文件权限。 这会导致人们转而运行sudo pip install foo全局安装到系统 Python

比那更糟。 许多人(例如大学计算机网络的用户)没有 sudo 权限。 当 pip 因权限错误而失败时,它们将:

  1. 向他们的管理员发送电子邮件并要求他们安装该软件包。 这对每个人来说都是缓慢而乏味的。
  2. 放弃并放弃包裹。

只有当他们特别有经验或消息灵通时,他们才会尝试pip install --user

如果我们最终决定反对“默认为--user”,我们应该考虑破坏性较小的替代方案:

  1. 回退到 --user (如果安装由于权限错误而失败)
  2. (如果由于权限错误导致安装失败),鼓励用户(用大字体)尝试 --user

实际上,我在所有安装中都使用--user有一段时间了,但通常人们并不知道这个选项。 我同意每次忘记选项时看到权限错误很烦人。 我注意到用户安装与 conda 不兼容(conda/conda#448)。

我想恢复它,因为人们将更频繁地在 Windows 上运行它,因为 3.5 默认安装到程序文件中(这需要管理员权限才能修改)。

我喜欢“在权限错误时回退到 --user”选项最适合安装,在卸载时使用“默认到 --user 并回退到系统”,并且可能添加--system--system-only选项以防止回退。 故意以管理员权限运行 pip 的用户将按预期进行系统安装,而当前没有权限的用户会收到错误消息,因此我认为这里不存在任何反向兼容问题。

我的目标是让不知情的用户能够在没有错误的情况下执行pip install spam; python -c "import spam" (尽管使用--user重试时可能会出现警告)。

我最近一直在考虑这个问题,特别是因为最近打开了 #2403 和 #2401,这让我想到了sudo pip install的使用以及它如何经常破坏除了权限问题之外的系统。

为此,我想知道更好的最终目标是否不仅仅是--user是默认值,没有神奇的权限检查,并添加一个新标志,如--global--system ,或--no-user将恢复以前的行为。 这更容易向人们解释,因为无论安装方式/安装位置如何,它都会具有相同的行为。

现在,如果我们决定这就是我们想要走的路,那么我们如何从今天的位置到达那个点仍然是个问题。 显然,无论何时我们切换默认设置都将是一个相当大的突破性更改,因此我们将需要相当长的准备时间。 我认为,如果我们决定这样做,最好的方法是继续保留--user选项,添加一个新选项,如--global ,然后如果一个或未配置其他选项执行我们讨论过的权限检查魔术,如果魔术决定使用--global行为,我们将发出非常响亮的弃用警告。 这个弃用警告会比我们发布的其他弃用警告持续更长时间,因为这将是一个相当大的行为变化。 我认为我们还想添加一个选项来关闭魔法回退并实现未来的行为,以便人们今天可以得到这种行为。

另一个重要的问题是,如果我们检测到我们正在安装的 Python 没有启用用户站点,我们应该怎么做。 在这种情况下,我会简单地声明--user是一个错误,对于那些 Python,我们将简单地回退到默认为--global 。 这将自动覆盖我认为的 virtualenv/venv,如果有人想要一个使用完全编译的 Python 的“更重”的重量隔离环境,他们可以简单地修补site.py以便他们将ENABLE_USER_SITE设置为False在文件的顶部。

+1,我会投票给--system。

我会注意到,我相信你会喜欢这个,Ubuntu 默认值已经改变:

https://launchpad.net/ubuntu/+source/python-pip/1.5.6-4ubuntu1

2015 年 2 月 9 日下午 04:41,唐纳德·斯图夫特写道:

为此,我想知道更好的最终目标是否不仅仅是--user
默认情况下,没有神奇的权限检查,并添加一个新标志,如--global
--system--no-user将恢复以前的行为。 这
更容易向人们解释,因为无论如何它都会有相同的行为
如何/在哪里安装东西。

我认为--system是错误的,因为这实际上只适用于某些 Python。 它不适用于:

  • Windows 上的 Python
  • pyenv 安装的 Python
  • Conda 安装的 Python
  • Nix 安装的 Python
  • 自定义编译的 Python。

它_仅_适用于 Python 恰好由系统提供的 *nix 系统。 我觉得--global是该标志的更好名称。

还有 FML,为什么 Debian/Ubuntu 觉得需要不断添加破坏预期用例的随机补丁?

因此,如果 Ubuntu 补丁被恢复,这里修复的时间表是什么? 一周/一个月/3个月/6个月/一年……?

这取决于您所说的固定是什么意思。

假设我们正在使用我在 2 个帖子之前的想法(仍然需要其他 pip 开发人员的签名),我们可能很快就会得到以下适用的过渡计划:

  • --user被传递时,我们_总是_安装到用户站点包中。
  • --global (或其他)被传递时,我们_总是_安装到全局站点包中。
  • 当两者都没有通过时,我们实现一个后备方法:

    • 检测我们是否在虚拟环境中,如果是,就好像--global已通过。

    • 检测用户站点包是否被禁用,如果是这样,就好像--global已通过。

    • 检测有效用户是否没有对sys.path的写入权限,以及他们是否没有像--user被传递一样行事。

    • 最后,如果所有其他检测方法都失败了,就好像--global已通过并打印一个弃用警告,说在将来的某个时候它的行为会改变,它会安装到--user .

这不会阻止某人在他们的系统 Python 中执行sudo pip install foo ,但是它会打印一个警告,在某些时候这将意味着--user并告诉他们明确开始使用--global 。 一旦上述内容发布了足够长的时间,我们就可以删除不推荐使用的代码路径并简化它,使其变得简单:

  • --user被传递时,我们_总是_安装到用户站点包中。
  • --global (或其他)被传递时,我们_总是_安装到全局站点包中。
  • 当两个选项都没有传入时,我们实现一个后备方法:

    • 检测我们是否在虚拟环境中,如果是,就好像--global已通过。

    • 检测用户站点包是否被禁用,如果是这样,就好像--global已通过。

    • 最后使用--user作为默认值。

然而,从第一种行为转移到第二种行为将有一个相当长的时间线。 这将是一个真正重大的突破性变化,它将破坏任何软件(例如 salt、chef、puppet)或部署脚本(例如定制的一次性 Fabric 脚本融入全球数千个项目),它期望sudo pip install <foo>将安装到全局 Python 中。 如果人们确实需要这种行为,我们需要给人们很长的时间让人们看到警告,并修改他们的软件和脚本以传递明确的--global标志。

我认为 Donald 建议的计划是一个很好的计划,尽管如果 pip 团队决定采用这种方法,我们还应该向 CPython 提交 3.5 版本阻止程序问题,以便将每个用户的脚本目录与全局一起添加到 Windows 的路径中一。 如果 3.5 添加了该选项以及默认情况下安装到 Program Files 的开关,那么我们应该获得所需的安装行为,即无需管理员权限即可继续“正常工作”。

能够通过 pip 配置文件更改默认安装位置也可能很有用,允许人们在他们自己的系统上选择“默认按用户”,即使默认尚未更改。 (例如“默认安装=用户”与“默认安装=全局”)

@dstufft :如果您需要我,我很乐意帮助您按照 ubuntu 错误中的说明实施您的建议。 一旦我们在主干中得到这种行为,我当然会反向移植并用这个替换当前的 ubuntu 补丁。

如果您需要任何帮助,请随时通知我。

我对@dstufft的计划 +1。 出于上述原因,我会选择--global作为名称。 我们已经坐在栅栏上够久了,让我们去吧。

@ncoghlan的建议中,O'n 和 +1 建议 Python 3.5 将用户站点目录添加到 Windows 上的 PATH 中。 让我们避免这个过渡的任何进一步的绊脚石。

我也为@dstufft的计划 +1 和 +1 --global ,尽管我仍然想知道sudo pip install foo需要--global 。 实际上,root 是否需要拥有用户站点包? 我们可以在特殊情况下默认关闭站点包吗? (这将使sudo pip install foo像现在一样工作)

我从未见过有人在当前状态下使用--user作为 root 用户,但如果有人真的知道这样的用例,我想知道。

我想到的一个想法是用户站点目录将如何与安装的多个版本的 Python 一起工作?

如果我在 Python 2.7 和 3.4 中执行pip install pytest --user (Python 3.4 我的默认 Python), py.test命令将执行哪个版本? 我怀疑这两个安装会相互覆盖,所以这是“最后一个获胜”的情况,这_不_好。 另外,如果它是“最后一个获胜”,并且我在 3.4 之后安装了 2.7 版本,我将如何修复它以再次使 3.4 成为默认版本?

那么卸载呢? 考虑以下场景(未经测试,因为如果我不想冒险破坏我的主笔记本电脑,我需要设置一台干净的机器):

    C:\Apps\Python34\python.exe -m pip install pytest --user
    C:\Apps\Python27\python.exe -m pip install pytest --user
    C:\Apps\Python34\python.exe -m pip uninstall -y pytest

首先,为什么第二个命令没有发出警告说它正在覆盖现有文件? 还是会? 不管有没有,我有什么选择吗?

其次,卸载不会因为py.test.exe的校验和与RECORD文件中的值不匹配而失败吗? 如果它确实失败了,我将如何卸载? 如果它没有失败,它会破坏我的 pytest 的 Python 2.7 副本(通过删除 exe)吗?

最后(现在!)用户脚本目录会在 PATH 中的系统脚本目录之前还是之后? IMO,它应该继续,否则用户在 Python 中安装的包 _not_ 被用户请求为“默认 Python”可能会覆盖安装在“默认”Python 的系统站点包中的相同包。

嗯,在我们做出这个改变之前,也许有一些悬而未决的问题需要解决......

我希望共享 Windows 用户脚本目录中的名称冲突的处理方式与在具有共享 bin 目录的 POSIX 系统上处理它们的方式相同:Python 3 不会为已安装的包安装不合格的脚本名称,因此不合格的name 指的是 Python 2 版本。

默认情况下,系统安装还是按用户安装优先也是如此:将用户脚本目录放在系统目录之后。

“Python 3 不会为已安装的包安装不合格的脚本名称” - 大概你的意思是 pip 和 setuptools (在 Python 3 下)不会,在这里? 所以这是对这些工具的改变?

哦,还有。 我的肌肉记忆经过 100% 的训练,可以输入“pip install foo”以安装到我的默认 Python (3.4) 中。 重新训练将是地狱。

此外,Windows 用户可以选择“python”是指 Python 2 还是 3(通过“将其设为默认 Python”和“添加到 PATH”)——这与 Unix 用户不同,Unix 用户是由系统 Python 制定规则的。 因此,如果我说我想让 Python 3.5 成为我的默认版本,为什么“pip”(或任何其他非限定名称)不应该引用该版本? 一个在 Windows 上只安装了 Python 3.5 的用户不能使用不合格的名称,这似乎很奇怪,这仅仅是因为 Unix 问题,即系统 Python 需要如何命名的东西。 (如果我对 Unix 约束的描述不准确,我深表歉意——我并不真正理解那里的问题)。 安装多个 Python 版本的人需要一个解决方案,但该解决方案不应该影响只需要一个版本的大多数人。

也许最简单的答案是应该对用户脚本目录进行版本控制,就像用户站点包目录一样?

哦,这个辩论应该是关于 python-dev 而不是在这里,因为它更普遍地是关于用户站点目录?

在 python-dev 上重新打开 Windows per-user scripts 目录的 PEP 370 设计讨论当然是合理的。 奇怪的是,Windows 上的全局脚本安装受 Python 版本的限制,但每个用户的脚本安装却不是。

这与 POSIX 上的情况形成鲜明对比,后者在两个级别(全局或每个用户)上始终为可执行文件使用共享命名空间,因此名称冲突更有可能出现在安装时,而不是在运行时通过名称隐藏。

就处理并行安装的一般解决方案而言,这将是“-m”开关——这样你总是知道你正在调用哪个 Python,而不是猜测单独脚本的 shebang 行的内容。

理解 re -m ,但上次在如何记录事物的背景下提出,强烈的偏好是我们应该将pip install foo视为安装事物的规范方式(使用-m和版本化命令被视为特殊情况的例外。

pip 手册甚至没有提到替代方案(除了在 Windows 上使用-m升级 pip 本身的一种情况)。

我建议在 stdlib 包文档中使用 -m 来处理 pip 调用
处理并行 Python 安装 - 这是唯一的调用样式
适用于所有平台,适用于全局安装、用户安装和虚拟
环境。

2015 年 2 月 9 日下午 7:58,ncoghlan 写道:

能够通过 pip 配置文件更改默认安装位置
也可能很有用,允许人们选择“默认为每个用户”
他们自己的系统,即使默认值没有改变
然而。 (例如“默认安装=用户”与“默认安装=全局”)

我喜欢这个。 我们正在努力解决的问题之一是如何解决
上游迁移到 --user 默认值的更保守的方法,使用
发行使 pip 系统安全并与其他系统保持一致的竞争目标
工具。 例如

https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1419695
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=725848

如果我们有一个系统范围的配置文件来选择默认值,那么在
至少所涉及的所有机器都是相同的,而发行版则不会
必须携带丑陋的三角洲。 我们所要做的就是改变
配置文件并将其记录给我们的用户。 导致的问题是
我们来处理,但至少它很容易解释。

我认为 Debuntu 目前没有安装站点范围的 pip.conf 文件(我会有
仔细检查)。

https://pip.pypa.io/en/latest/user_guide.html#configuration

一个复杂的问题:我们为 Python 2 和 Python 3 安装了不同的 pip 脚本,
所以我认为我们需要针对不同版本的单独配置文件
Python,例如 /etc/{xdg/pip/}/pip{2,3}.conf 或类似的。

2015 年 2 月 10 日上午 01:24,Paul Moore 写道:

我想到的一个想法是用户站点目录将如何使用
安装了多个版本的 Python?

在 Debian/Ubuntu 上(也许所有 *nixes?)我们没有冲突,因为
库安装到 ~/.local/lib/pythonX.Y/site-packages

不过,我们_do_ 会在 ~/.local/bin 上发生冲突。 安装一个包
使用pip install --user foopip3 install --user foo的脚本 'foo' 将
最终破坏了 ~/.local/bin/foo 脚本。

这种变化的一个缺点是我认为 Fedora 是唯一一个默认将~/.local/bin添加到$PATH的下游发行版(它应该在 /usr/bin 和 /usr/local/bin 之前就像用户站点包出现在站点包之前)。 理想情况下,下游将能够修改他们的系统,以便默认情况下~/.local/bin$PATH上。

2015 年 2 月 10 日上午 07:24,Donald Stufft 写道:

这种变化的一个缺点是我认为 Fedora 是唯一的下游
默认情况下将~/.local/bin添加到$PATH的发行版(它应该来
在 /usr/bin 和 /usr/local/bin 之前,就像用户站点软件包一样
在站点包之前)。 理想情况下,下游将能够修改他们的
系统,以便默认情况下~/.local/bin$PATH上。

是的,但我们可以对此做出单独的决定。 (或者更确切地说,下游
发行版可以做到这一点。)

(它应该像用户一样出现在 /usr/bin 和 /usr/local/bin 之前
站点包位于站点包之前)

嗯, @ncoghlan正好相反,那个(在 Windows 上,特别是
上下文)用户脚本目录应该是_after_系统之一。 哪一个
只要用户脚本目录未版本化,我就同意。 如果它是
版本,我不太担心。 但这可能反映了这样一个事实:
Windows 用户从不需要忍受无版本的脚本冲突和
像 pip2/pip3 这样的怪物,Unix 用户的方式;-)

哦,脚本破坏是一个更普遍的问题,与--user并不完全相关。 除了 Windows --global安装之外,到处都存在同样的问题。 我认为该问题的解决方案是我们应该单独解决的次要问题/问题。

所以目前的想法:

  • 我认为我之前发布的总体想法已经达成一致,所以我认为我们会希望推进类似的事情。
  • 我们将使用--global标志。
  • 如果我们要安装到--user并且~/.local/bin不在$PATH上,我们可能需要某种警告。
  • 我们需要某种default-install选项,它基本上会禁用回退行为,只需硬编码为--global--user
  • 从 pip 6.0 开始,我们在/etc/中拥有特定于机器的配置文件,但是这些文件并不特定于执行 pip 的 Python 版本。 我认为这是一个很好的功能,虽然也有些独立(并且可能与解决脚本破坏问题齐头并进)。

我仍然看到一个主要的悬而未决的问题:从长远来看,当有人执行sudo pip install foo或者更确切地说,如果有人有权写入site-packages目录时,我们希望发生什么?

我能想到的选项是:

  1. 安装到--global 。 这是最向后兼容的选项,可能代表了用户在键入时的期望。 但是它的缺点是它会(默默地)与全局 Python 混淆,这在许多系统上可能会导致系统损坏。
  2. 安装到--user中,这将保护系统免受损坏(我认为?),但我认为没有人会期望 root 用户安装/root/.local/
  3. 只是出错并要求用户手动选择--user--global
  4. 选择前两个选项之一,但提供一个发行版可以在/etc/中打开的开关,这将启用第三个选项。

第四个选项可能是最好的,但我觉得我们应该首先尝试选择其他选项之一,如果我们可以找到某种在所有平台/场景上都适用并且对所有平台/场景都有意义的解决方案,因为我如果可能的话,希望有一致的行为跨平台。

我觉得第三个选项可能不太好,因为“我有写权限”将是 Windows 上的任何人都在 Python 3.5 之前的情况,或者任何使用 Conda 的人,或者任何使用 pyenv 的人。 在所有这些情况下,出错似乎都是错误的做法,而且用户对启动很不友好。

所以我猜在 1 和 2 之间,这真的归结为我们认为人们(从概念上)做sudo pip install --global foo的做法有多糟糕。 在 Windows、Conda、pyenv 等上,我觉得答案是“我们认为这根本不是一个坏习惯”。 在 *nix 上,我觉得答案可能是“应该允许用户对他们的系统做他们想做的事,但我们应该提供导轨来引导他们远离“坏”的事情”。

所以再想一想,我认为我必须选择第一个选项,因为这是我们要选择的正确选项。 这或多或少地解决了向后兼容性问题,因为我们真正要改变的行为是,如果您在没有安装权限的情况下键入pip install foo到该全局目录,您将安装到--user而不是引发错误。 我认为在这种情况下,不太可能有人真的依赖 pip 引发错误。 我还认为pip install --user作为 root 用户不太可能是任何人所期望或想要的,它实际上只是为用户制造了一把枪。

那么我更新的建议是:

  • --user被传递时,我们总是安装到用户站点包中。
  • --global被传递时,我们总是安装到全局站点包中。
  • 当两者都没有通过时,我们实现一个后备方法:

    1. 检测我们是否在虚拟环境中,如果是,就好像--global已通过。

    2. 检测用户站点包是否被禁用,如果是这样,就好像--global已通过。

    3. 查看default-install ,如果存在则使用--user-global基于它。

    4. 检测有效用户是否没有对全局站点包的写入权限,以及他们是否没有像--user被传递一样行事。

    5. 最后,如果所有其他检测方法都失败了,就当--global通过了。

这意味着没有弃用期,并且期望在没有--user--global的情况下,我们将尝试根据我们正在运行的 Python 的功能做出最佳猜测、有效用户和任何已配置的默认安装方法。

(它应该像用户一样出现在 /usr/bin 和 /usr/local/bin 之前
站点包位于站点包之前)

嗯, @ncoghlan正好相反,那个(在 Windows 上,特别是
上下文)用户脚本目录应该是_after_系统之一。 哪一个
只要用户脚本目录未版本化,我就同意。 如果它是
版本,我不太担心。 但这可能反映了这样一个事实:
Windows 用户从不需要忍受无版本的脚本冲突和
像 pip2/pip3 这样的怪物,Unix 用户的方式;-)

我什至没有考虑脚本名称冲突。 我只是认为我们的$PATH变量的行为与sys.path不同是完全错误的。 据我所知sys.path的顺序是:stdlib > 用户站点包 > 全局站点包。 我认为如果some-script的顺序是全局 bin dir > user bin dir 而python -m some-script是用户站点包 > 全局站点包,那真的会令人困惑。

如果脚本目录(以及版本化与非版本化)存在问题,那么我认为我们应该解决这个问题,但它与它们应该采用的顺序无关,因为我觉得除了匹配sys.path之外的任何东西

好点,我们应该假设(并推荐)$PATH 遵循 sys.path,(在 Windows 术语中)C:PythonXY 在 %APPDATA%PythonXYScripts 在 C:PythonXYScripts 之前。 我会在 python-dev 线程上注意到这一点。

Donald 的最新提议对我来说听起来不错(与我最初的提议相同,加上我遗漏的所有重要细节 :))。 我也 100% 同意“所以多想想……”这一段。

至于在 Windows 上配置 PATH,这几乎是不可能的。 系统范围的安装程序只能配置系统范围的环境变量,它们不能包含扩展,因此您不能为每个用户设置不同的路径。 (每个用户的安装程序可以做到这一点,但在这种情况下--global会成功,所以没有必要。)

此外,由于 Windows 的 PATH 处理中断,系统范围的设置_总是_优于每个用户的设置。 这导致我不久前(在 python-dev,IIRC 上)关于将 py.exe 启动器用于非版本化脚本的半建议,这样pip.exe将始终转到最新的系统或用户 Python 而不是安装它的一个,并且(例如) pip.exe -3.5将允许选择特定的版本。

使它真正起作用的唯一方法是让 Python 安装程序开始安装批处理文件以根据请求配置 PATH(也许是运行批处理文件的快捷方式)。 所以用户输入的第一件事是activate-py35 ,然后他们的 PATH 被正确配置为 3.5。 不过,我对此感到非常痛苦,因为我不想进入 vcvarsall.bat 的情况,但同时它对于当前对安装位置做出假设或尝试通过注册表的脚本来说非常有用找到它。

也许是运行批处理文件的快捷方式

在我看来,这是一个“Python 3.5(32 位)命令提示符”快捷方式。 Visual Studio 用户应该识别并行。

我对 Windows 的了解还不够,无法完全理解所有这些的含义,但是我对恢复到安装脚本foopip install foo不能立即执行的情况感到非常糟糕在命令行上作为foo执行。 如果我们要安装到--user并且默认情况下不在他们的路径上,那么这对我来说就像是一个相当大的回归。

我不确定我是否完全理解将py.exe用于未版本控制的脚本在实践中如何工作以及它是否真的能解决问题。 我个人并不像我们今天那样热衷于创建脚本,所以如果它_确实_有效,我认为我们也许可以做到,但我必须更好地理解其中的含义,然后才能给出我的 +1。

至于在 Windows 上配置 PATH,这几乎是不可能的。 系统范围的安装程序只能配置系统范围的环境变量,它们不能包含扩展,因此您不能为每个用户设置不同的路径。

哦,呸。 我忘记了。

也许是运行批处理文件的快捷方式
在我看来,这是一个“Python 3.5(32 位)命令提示符”快捷方式。 Visual Studio 用户应该识别并行。

...对于我们这些默认使用 Powershell 的人来说,这太可怕了。

但是我对恢复到安装脚本 foo 的 pip install foo 不能立即在命令行上作为 foo 执行的情况感到非常糟糕。

同意。 这将是一个糟糕的回归,需要解决。 我只是希望有人能想办法:-)

我不确定我是否完全了解将 py.exe 用于未版本控制的脚本在实践中如何工作

我认为重点(仅与py.exe有点相关)是 exe 包装器,而不是像目前那样调用特定的硬编码 Python 解释器,应该根据“什么”动态选择解释器是默认值”(注册表, py.exe ini 文件,无论 Python %PATH% 给你什么,...)。 不过,我不确定它会有什么帮助,因为我们仍然需要一个版本化的用户脚本目录(以避免文件相互覆盖或使用没有安装包的解释器运行文件),我们仍然不会'无法将其放在 %PATH% 中的正确位置。

...对于我们这些默认使用 Powershell 的人来说,这太可怕了。

我刚刚尝试过,我可以轻松地制作外观和行为相同的activate-py35.batactivate-py35.ps1文件(即,每个人都只需编写activate-py35并更新路径)。 仍然不理想,但可能是最糟糕的情况。

我不确定我是否完全了解将 py.exe 用于未版本控制的脚本在实践中如何工作

我认为重点(仅与py.exe有点相关)是 exe 包装器,而不是像目前那样调用特定的硬编码 Python 解释器,应该根据“什么”动态选择解释器是默认的”不知何故

“不知何故”是py.exe出现的地方 - 应该使用相同的规则。 如果更新启动器以检查其自己的名称,那么它可以尝试启动'scripts\\{}{}.{}.exe'.format(argv[0], major_version, minor_version) (在argv[0]上进行适当的扩展修剪等),而不是启动python.exe 。 然后安装程序需要为未版本化的启动器使用与完全版本化的启动器不同的文件(从今天起将保持不变),但该文件将只是具有新名称的普通py.exe 。 (在pip-script.py文件的旧时代,这可能会更简单,但现在那些已经消失了......)

但正如你所说, PATH 仍然是问题所在。 我没有任何好的解决方案,甚至没有那么多糟糕的解决方案。 环境变量实际上是供管理员或用户配置的,而不是安装程序。

我们可以调整我们安装脚本的方式以提供更好的用户体验。 这完全是一种平衡, .exe.py文件的组合使用户感觉更好,因为只有单个.exe文件。 但是我觉得为pip install foo && foo获得最好的故事比那个特定的事情更重要,所以如果我们需要让.exe.py再次分开,我认为这是一个一个好的答案的好权衡。

.exe / .py分离是最少的问题:)

我实际上正在热身(或勉强接受?) activate-py35的想法。 我从来都不是安装程序将 Python 添加到 PATH 的粉丝,而且py -m pip命令并没有真正获得牵引力(而且它也不适用于例如 Sphinx)。 我将更详细地描述activate-py如何工作并将其发布到 python-dev 以查看它是否有任何吸引力。

这些activate-whatever文件会类似于虚拟环境中的文件吗? 除了将虚拟环境添加到$PATH之外,它正在添加真正的 Python?

是的,几乎一模一样。 在 python-dev 上,我刚刚建议他们采用-x.y参数,将其传递给py.exe并使用sysconfig获取路径。

好的。 因为我不是 Windows 用户,所以我不知道这对 Windows 用户会有多糟糕。 这听起来并不可怕(也许?),但这就是我的 Windows 知识所能带给我的。

2015 年 2 月 10 日上午 08:02,唐纳德·斯塔夫特写道:

哦,脚本破坏是一个更普遍的问题,不是
确实与--user完全相关。 到处都存在同样的问题
Windows --global安装除外。 我认为解决这个问题的方法是
我们应该单独解决这个问题的次要问题/问题。

同意。

我们将使用--global标志。

+1

如果我们要安装到--user
~/.local/bin不在$PATH上。

+1,也许有一个配置选项来抑制警告?

我们需要某种default-install选项,它本质上是
禁用回退行为,只需硬编码为--global
--user

+1

从 pip 6.0 开始,我们的机器特定配置文件位于/etc/
但是这些并不特定于正在执行的 Python 版本
点。 我认为这是一个很好的功能,虽然也有些分开(和
也可能与解决脚本破坏问题齐头并进)。

我会建议一个搜索顺序,例如:

  • pipXY.conf
  • pipX.conf
  • 点子配置文件

首先(?)在 /etc/xdg/pip 然后 /etc,其中 XY 当然是
major.minor 版本号。 找到第一个,获胜。

我仍然看到一个主要的悬而未决的问题:从长远来看,我们希望什么时候发生
有人做sudo pip install foo或者更确切地说,如果有人有权
写入site-packages目录?

请注意,不只有一个“站点包”目录。 例如,
在 Debian/Ubuntu 上,我们不希望sudo pip install _ever_ 安装到
/usr/lib,但只有 /usr/local/lib。 别忘了,这里是 dist-packages
不是站点包(在 ~/.local 中除外,因为 $reasons)。

这确实是很重要的一点,有时会被遗忘(即使是我)。
当唐纳德说有一个站点本地目录和一个
供应商本地目录。 在 Debian 上,站点本地是
/usr/lib/pythonX.Y/dist-packages 并且任何 pip 命令都不应该触及它,
而 vendor-local 是 /usr/local/lib/pythonX.Y/dist-packages 并且它是
一些系统管理员进行 pip 安装的文档化和流行用例
进入那个目录。

所以我建议,因为我们已经在配置文件路径下,是
使这些可配置,例如

  • 全局安装目录
  • global_install_as_sudo(真/假)
  1. 安装到--global 。 这是最向后兼容的选项
    并且可能代表用户在键入时的期望。 然而它有
    它会(默默地)与全球 Python 混为一谈的缺点,这在许多
    系统可能会导致系统损坏。

通过上述可配置性,这将与 Debian 完全兼容。
Debian 超级用户期望sudo pip install进入
/usr/local/lib/pythonX.Y/dist-packages。 我不会说它“与
系统”,因为它不会破坏包管理器,虽然它可以
覆盖系统安装的软件包(位于
/usr/lib/pythonX.Y/dist-packages),它以定义的、记录的方式执行此操作。

  1. 安装到--user ,这将防止系统损坏(我认为?)
    但我认为没有人会期望 root 用户获得
    /root/.local/安装。

同意,那将是出乎意料的。

  1. 只是出错并要求用户选择--user
    --global手动。

我可以接受,但请参阅上面的配置开关。

  1. 选择前两个选项之一,但提供发行版可以的开关
    上交/etc/将启用第三个选项。

嘿,多么棒的选择!

第四个选项可能是最好的,但我觉得我们应该尝试
如果我们能找到某种解决方案,请先选择其他选项之一
在所有平台/场景上都一样,并且对所有平台/场景都有意义
因为如果可能的话,我希望有一致的跨平台行为。

我可以接受不同的、平台定义的行为,如果说 pip 有一个
--dry-run 选项至少会告诉用户它正在做什么
做和在哪里。

我觉得第三种选择可能不太好,因为“我已经写了
权限”将是 Windows 上的任何人都在预
Python 3.5,或者任何使用 Conda 的人,或者任何使用 pyenv 的人。 出错
在所有这些情况下似乎都是错误的做法,并且是用户
开机不友好。

如果默认配置允许 --global install 如果你
有权限。 我什至不认为 Debian 会改变它(也许其他人有
不同的意见,但至少这给了我们选择)。

所以我猜在 1 到 2 之间,这真的归结为练习的糟糕程度
我们认为人们应该(从概念上)做sudo pip install --global foo

在 Debian 上,这是一个预期的用例,只要它转到 /usr/local/lib。
它不能转到 /usr/lib。

(所有这些都描述了外部行为 BTW。)

  • --user被传递时,我们总是安装到用户站点包中。

+1

  • --global被传递时,我们总是安装到全局站点中
  • 包。

全球 _vendor_ 包 == +1,全球站点包 == -1。

  • 当两者都没有通过时,我们实现一个后备方法:

    1. 检测我们是否在虚拟环境中,如果是,就好像

      --global已通过。

+1,虽然我会重复 venv 中的这个目录被命名为
/lib/pythonX.Y/site-packages

  1. 检测用户站点包是否被禁用,如果是这样,就好像
    --global已通过。

嗯,这个我不确定。

  1. 查看default-install ,如果存在则使用--user
    -global基于它。

+1

  1. 检测有效用户是否没有全局写入权限
    站点包,如果它们没有像--user被传递一样。

+1

  1. 最后,如果所有其他检测方法都失败了,就当--global
    通过了。

也不确定。

这意味着没有弃用期,并且期望在
没有--user--global我们将尝试做出最好的猜测
关于我们正在运行的 Python 的功能、有效用户以及
任何配置的默认安装方法。

听起来是一个合理的目标。

需要明确的是,当我谈论“全局站点包”时,我主要是指“distutils 告诉我们将东西安装到全局的任何东西”。 由于 Python 本身没有“供应商本地”与“站点本地”的区别,这将是任何未修补其 Python 的下游的同一目录。 然而,在 debian 上,它实际上是一个dist-packages目录,而“global”实际上意味着“站点本地”。 这不是 pip 需要做任何特殊的事情来支持的,因为这是由 Debuntu 的 Python 补丁处理的。

换句话说,pip 已经在 Debuntu 上安装到/usr/local/../dist-packages/ ,因为 Debuntu 已经修补了 distutils 以支持这种区别。 唯一一次 pip 会在没有用户传入某种标志的情况下与/usr/../dist-packages/混淆的是 pip 会从那里卸载文件(因为 pip 不认为该目录是特殊的,它只是将其视为一个东西在sys.path上)。 Debian 已经修补了 pip 以防止从那里卸载,我认为对此的真正支持取决于在 Python 上游获得对“供应商本地”站点包的真正支持。

如果我们要安装到 --user 并且 ~/.local/bin 不在 $PATH 上,我们可能需要某种警告

这个警告有多脆弱? 它会转换为绝对路径吗? 在不区分大小写的文件系统上是否不区分大小写? 它会在 Windows 上将和/视为等效吗? 符号链接呢?

如果您正在安装一个不安装任何脚本的包,那么警告无论如何都无关紧要。

就个人而言,我认为警告可能弊大于利。

如果我们要安装到--user
~/.local/bin不在$PATH上。

+1,也许有一个配置选项来抑制警告?

我们可以让它使用 Python 警告,这样人们就可以保持沉默
它使用内置的 Python 警告。 如果我们觉得有必要在
全部。

从 pip 6.0 开始,我们的机器特定配置文件位于/etc/
但是这些并不特定于正在执行的 Python 版本
点。 我认为这是一个很好的功能,虽然也有些分开(和
也可能与解决脚本破坏问题齐头并进)。

我会建议一个搜索顺序,例如:

  • pipXY.conf
  • pipX.conf
  • 点子配置文件

首先(?)在 /etc/xdg/pip 然后 /etc,其中 XY 当然是
major.minor 版本号。 找到第一个,获胜。

将其拆分为#2417,因为我相信它仅与此相关
讨论。

我仍然看到一个主要的悬而未决的问题:从长远来看,我们希望什么时候发生
有人做sudo pip install foo或者更确切地说,如果有人有权
写入site-packages目录?

请注意,不只有一个“站点包”目录。 例如,
在 Debian/Ubuntu 上,我们不希望sudo pip install _ever_ 安装到
/usr/lib,但只有 /usr/local/lib。 别忘了,这里是 dist-packages
不是站点包(在 ~/.local 中除外,因为 $reasons)。

这确实是很重要的一点,有时会被遗忘(即使是我)。
当唐纳德说有一个站点本地目录和一个
供应商本地目录。 在 Debian 上,站点本地是
/usr/lib/pythonX.Y/dist-packages 并且任何 pip 命令都不应该触及它,
而 vendor-local 是 /usr/local/lib/pythonX.Y/dist-packages 并且它是
一些系统管理员进行 pip 安装的文档化和流行用例
进入那个目录。

所以我建议,因为我们已经在配置文件路径下,是
使这些可配置,例如

  • 全局安装目录
  • global_install_as_sudo(真/假)

pip 并没有真正控制这些(我的意思是,显然在高层它确实
因为它是一个移动文件),它们来自 distutils/sysconfig。

我认为 pip 可能永远不应该触及供应商本地目录,除非
给出了某种标志,例如--vendor ,这将使供应商能够使用
pip 在他们的构建链中。 这个概念在 debuntu 之外并不真正存在
现在他们的补丁已经处理了这个,所以我不认为它是超级的
与本次讨论相关,除了要注意的是,当我说
“全球站点包”我的意思是 Debubuntu 上的/usr/local/.../dist-packages
如果 Python 接受 Debuntu,则“站点本地”包在某个时候
系统上游。

  1. 安装到--global 。 这是最向后兼容的选项
    并且可能代表用户在键入时的期望。 然而它有
    它会(默默地)与全球 Python 混为一谈的缺点,这在许多
    系统可能会导致系统损坏。

通过上述可配置性,这将与 Debian 完全兼容。
Debian 超级用户期望sudo pip install进入
/usr/local/lib/pythonX.Y/dist-packages。 我不会说它“与
系统”,因为它不会破坏包管理器,虽然它可以
覆盖系统安装的软件包(位于
/usr/lib/pythonX.Y/dist-packages),它以定义的、记录的方式执行此操作。

是的,“系统混乱”可能太苛刻了。 主要是我的意思
如果系统依赖于 $# sudo pip install foo foo
您安装了不兼容的版本。 然而,同样的情况也成立
基本上你安装到`/usr/local`的任何东西都是如此。

  • --global被传递时,我们总是安装到全局站点中
  • 包。

全球 _vendor_ 包 == +1,全球站点包 == -1。

你的意思是反过来吧?

  • 当两者都没有通过时,我们实现一个后备方法:

    1. 检测我们是否在虚拟环境中,如果是,就好像

      --global已通过。

+1,虽然我会重复 venv 中的这个目录被命名为
/lib/pythonX.Y/site-packages

是的,我们只是问 Python 那个目录在哪里,我们不计算它
我们自己,所以“那个目录在哪里”是一个 venv/virtualenv 的东西。

  1. 检测用户站点包是否被禁用,如果是这样,就好像
    --global已通过。

嗯,这个我不确定。

我认为没有办法解决这个问题,如果用户站点包被禁用,我
不要认为我们应该安装在那里,因为我们无法知道
如果禁用意味着没有用户站点包,或者为什么。 我们只能
假设没有。

  1. 最后,如果所有其他检测方法都失败了,就当--global
    通过了。

也不确定。

这基本上归结为:

如果我们还没有找到我们应该使用 --user 的原因,比如 --user 标志,或者
没有权限写入目录,然后不要使用它。 这
是什么将保留sudo pip install foo没有--global标志
在职的。 这也意味着这是不违反的最重要的规则
期望sudo pip install foo以这种方式运行的工作软件。

如果我们要安装到 --user 并且 ~/.local/bin 不在 $PATH 上,我们可能需要某种警告

这个警告有多脆弱? 它会转换为绝对路径吗? 在不区分大小写的文件系统上是否不区分大小写? 它会在 Windows 上将和/视为等效吗? 符号链接呢?

如果您正在安装一个不安装任何脚本的包,那么警告无论如何都无关紧要。

就个人而言,我认为警告可能弊大于利。

好吧,我们可以将其实现为(跨平台等效):

def user_bin_on_path():
    paths = os.environ.get("PATH").split(":")
    for path in paths:
        if os.path.realpath(path) == os.path.realpath(USER_BIN_DIR):
            return True
    return False

我认为这样的东西应该处理符号链接、路径分隔符等。 细节上的魔鬼,也许我们无法获得足够准确的信息来涵盖各种跨平台的极端情况。

我同意如果没有安装脚本,警告是无关紧要的,我的意思是说,我们只会在安装脚本时才关心警告。

基本思想是,我不希望有人在 --user 是隐式的地方做类似pip install [--user] foo的事情,然后在没有任何指导的情况下做foo并获得“找不到命令”为什么它可能找不到。 一个警告至少会告诉他们他们需要向 PATH 添加东西。 它还可能有助于提示 Windows 上的用户手动将他们的用户目录添加到他们的 PATH 中(或运行一些脚本来执行此操作),这可能会减轻 Steve 指出的对activate脚本的需求。 尽管我认为这仍然意味着系统值优先于用户值,因此仍然可能会令人困惑,因为 PATH 和 sys.path 的顺序仍然会颠倒。

多哈。 我忘记了realpath规范了路径。 是的,当然效果很好。

困扰我的事情是_if_ 测试错误地发现了一个问题,用户得到一个恼人的和不正确的警告,除了改变他们的系统来解决 pip 的错误之外,没有办法避免它。 但是鉴于您提出的测试可能足够强大,并且我们仅在安装脚本时才进行检查,因此该问题可能很少见,可以忽略不计。

好吧,我想我们在这里达成了一些广泛的共识。 我认为下一步是修补。 我会继续尝试今晚或明天晚些时候做点什么。

2015 年 2 月 10 日下午 12:14,唐纳德·斯图夫特写道:

基本思想是我不希望有人在 --user 是隐式的地方做类似pip install [--user] foo的事情,然后做foo
得到一个“找不到命令”,而没有任何关于为什么它可能没有的指导
成立。

Debian,也许还有其他 Linux,实际上有一个 command-not-found 软件包
如果他们调用一个命令,它会提示用户安装一个包
没有安装。

% 墨水景观
当前未安装程序“inkscape”。 您可以通过键入以下内容来安装它:
sudo apt-get install inkscape

也许我们可以将其用于支持平台。

2015 年 2 月 10 日下午 12:06,唐纳德·斯图夫特写道:

  • --global被传递时,我们总是安装到全局站点中
  • 包。

全球 _vendor_ 包 == +1,全球站点包 == -1。

你的意思是反过来吧?

我可能会混淆我的术语,所以我会明确:

/usr/local/lib/pythonX.Y/dist-packages == +1
/usr/lib/pythonX.Y/dist-packages == -1

但正如你之前所说,这不是 pip 真正需要担心的事情
大约因为它是从 distutils 继承的,并且 Debuntu 的 distutils 已修补
做正确的事。

  1. 检测用户站点包是否被禁用,如果是这样,就好像
    --global已通过。

嗯,这个我不确定。

我认为没有办法解决这个问题,如果用户站点包被禁用,我
不要认为我们应该安装在那里,因为我们无法知道
如果禁用意味着没有用户站点包,或者为什么。 我们只能
假设没有。

哦,我明白你现在的意思了。 我想这是有道理的。 我担心的是
可能更难预测点子实际上会做什么,但正如我
比如说,我会很高兴有一个 --dry-run 标志,这样 pip 就可以明确地_告诉_
你要做什么。

  1. 最后,如果所有其他检测方法都失败了,就当--global
    通过了。

也不确定。

这基本上归结为:

如果我们还没有找到我们应该使用 --user 的原因,比如 --user 标志,或者
没有权限写入目录,然后不要使用它。 这
是什么将保留sudo pip install foo没有--global标志
在职的。 这也意味着这是不违反的最重要的规则
期望sudo pip install foo以这种方式运行的工作软件。

我知道了。 我认为这没关系,因为我们要避免的主要反用例是:

normal_user$ pip install foo
嘿,你没有权限
normal_user$ sudo pip install foo
嘿,你刚刚破坏了你的系统

并且“无权写入目录意味着--user”规则
照顾那个。

哦,是的,我忘记了找不到命令。 可能有用。 顺便说一句,您知道建议 devubtu 默认在路径上有用户本地 bin 的正确位置吗?

2015 年 2 月 10 日下午 4:05,Barry Warsaw [email protected]写道:

2015 年 2 月 10 日下午 12:14,唐纳德·斯图夫特写道:

基本思想是我不希望有人在 --user 是隐式的地方做类似pip install [--user] foo的事情,然后做foo
得到一个“找不到命令”,而没有任何关于为什么它可能没有的指导
成立。

Debian,也许还有其他 Linux,实际上有一个 command-not-found 软件包
如果他们调用一个命令,它会提示用户安装一个包
没有安装。

% 墨水景观
当前未安装程序“inkscape”。 您可以通过键入以下内容来安装它:
sudo apt-get install inkscape

也许我们可以将其用于支持平台。


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

2015 年 2 月 10 日下午 1:17,唐纳德·斯图夫特写道:

哦,是的,我忘记了找不到命令。 可能有用。 顺便说一句,你
知道正确的地方建议devubtu在用户本地bin上
默认路径?

不确定,但可能是 adduser 或 passwd 包? 前者拥有
/usr/sbin/adduser 和后者拥有 /usr/bin/useradd。

第一遍: https ://github.com/pypa/pip/pull/2418

我不确定这是否有帮助,但是……

  • ~/.local/bin 不在很多人的 $PATH 上,对此有什么可以做的吗?

其他一些项目使用/etc/profiled.d/将目录添加到 $PATH。 至少在 Antergos 上,我看到以下内容(除非我误解了它们的作用)jre.csh、jre.sh、perlbin.csh、perlbin.sh。

# Do not change this unless you want to completely by-pass Arch Linux' way
# of handling Java versions and vendors. Instead, please use script `archlinux-java`
setenv PATH "${PATH}:/usr/lib/jvm/default/bin"
# Do not change this unless you want to completely by-pass Arch Linux' way
# of handling Java versions and vendors. Instead, please use script `archlinux-java`
export PATH=${PATH}:/usr/lib/jvm/default/bin
# Set path to perl scriptdirs if they exist
# https://wiki.archlinux.org/index.php/Perl_Policy#Binaries_and_Scripts
# Added /usr/bin/*_perl dirs for scripts
# Remove /usr/lib/perl5/*_perl/bin in next release

[ -d /usr/bin/site_perl ] && setenv PATH ${PATH}:/usr/bin/site_perl
[ -d /usr/lib/perl5/site_perl/bin ] && setenv PATH ${PATH}:/usr/lib/perl5/site_perl/bin

[ -d /usr/bin/vendor_perl ] && setenv PATH ${PATH}:/usr/bin/vendor_perl
[ -d /usr/lib/perl5/vendor_perl/bin ] && setenv PATH ${PATH}:/usr/lib/perl5/vendor_perl/bin

[ -d /usr/bin/core_perl ] && setenv PATH ${PATH}:/usr/bin/core_perl

# If you have modules in non-standard directories you can add them here.
#export PERLLIB=dir1:dir2
# Set path to perl scriptdirs if they exist
# https://wiki.archlinux.org/index.php/Perl_Policy#Binaries_and_Scripts
# Added /usr/bin/*_perl dirs for scripts
# Remove /usr/lib/perl5/*_perl/bin in next release

[ -d /usr/bin/site_perl ] && PATH=$PATH:/usr/bin/site_perl
[ -d /usr/lib/perl5/site_perl/bin ] && PATH=$PATH:/usr/lib/perl5/site_perl/bin

[ -d /usr/bin/vendor_perl ] && PATH=$PATH:/usr/bin/vendor_perl
[ -d /usr/lib/perl5/vendor_perl/bin ] && PATH=$PATH:/usr/lib/perl5/vendor_perl/bin

[ -d /usr/bin/core_perl ] && PATH=$PATH:/usr/bin/core_perl

export PATH

# If you have modules in non-standard directories you can add them here.
#export PERLLIB=dir1:dir2

作为一个随机的 pip 用户,我只想说 _thank you_ 解决这样的用户体验问题以及在改善我们的用户体验里程碑中捕获的其他问题。 有什么地方我可以为这项工作做出经济贡献吗?

顺便说一句,我使用Homebrew并且一直很欣赏这样一个事实,即我可以brew install something并且它可以在没有任何权限的情况下工作。

一旦我理解了为什么使用 Homebrew 安装从来不需要sudo ,我就尝试养成使用pip install --user something的习惯,但具有讽刺意味的是,由于 distutils 中报告的错误, Homebrew 禁用了此功能。

鉴于 Homebrew 在 OS X 上的流行,也许你们都想调查一下 Homebrew 和pip install --user的这种所谓的不兼容性。

无论如何,我 +1 将--user设为默认值。

快速跟进。 Didier 以生动的方式上传了对 Ubuntu 的 pip 的更改,将 --user 设置为默认值。 我大多也允许它,但现在我认为这是一个错误,我打算将它还原为狡猾的(但可能不会 SRU 改变为生动)。 有关详细信息和基本原理,请参阅https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1460203

+1 让上游推动这一变化的时机,因为用户与系统的区别已经足够令人困惑,而没有平台差异发挥作用。

也就是说,一旦 --global 支持进入上游 pip(pip 8?),Linux 发行版开始将默认设置翻转为 --user 可能是合理的,因为在 Linux 上进行全局安装,而不是按用户或per-venv 安装,被认为是一个坏主意,具有潜在的不可预测的副作用。

我私下告诉@warsaw ,但我也会在这里说:

我认为这个改变很重要,我计划回到我的拉取请求来完成它。 然而,我是一个负责多个项目的人,现在仓库对我来说比这种变化更重要,因为 PyPI 遗留的操作变得越来越繁重,我觉得我们需要尽快更换它。 因此,我在 pip 上的时间并没有专注于自己进行许多更改,而是专注于指导其他贡献者所做的更改以及任何发布过程的内容。

话虽这么说,如果有人真的关心这个功能早晚登陆,他们可以接我的工作并完成它,我很乐意审查(并希望合并)它。 我很高兴与任何想要这样做并提供更改指导的人讨论这个问题。 否则它会等到我完成对我来说更紧迫的项目之后。

也许值得在这个时刻重复:

如果我们最终决定反对“默认为 --user”,我们应该考虑破坏性较小的替代方案

  1. 回退到 --user (如果安装由于权限错误而失败)
  2. (如果由于权限错误导致安装失败),鼓励用户(用大字体)尝试 --user

FWIW,既然 Python 3.5 的 Windows 安装程序强烈鼓励按用户安装,我不太担心 pip 中发生的这种变化。 它可能会为发行版(使用--global覆盖)提供比新默认值或后备更好的配置选项。

只是想对此问题 +1 并表示感谢您的工作! 我们目前正在运营一所科学 Python 暑期学校,并且有很多人遇到权限问题时sudo pip install

FWIW 我赞成默认为--user ,或者如果由于权限错误而导致安装失败,则回退到--user 。 在这种情况下,我宁愿给他们指示来扭转他们所做的事情(例如, We installed to your user directory. If you don't want this, then 'pip uninstall my_package' ),而不是失败并告诉他们如何再试一次。

由于--user,我看到了很多关于mock的错误报告-至少在Ubuntu上--user在路径上的位置位于dist-packages之后,因此对于任何常见的依赖项(例如六)在dist-packages中。

他们把它放在_after_ dist-packages之后? 这是一个损坏的安装 IMO。

是的,用户安装应该在站点(/dist)包之前,然后系统脚本和实用程序应该使用 -I(或 Python 2 中的 -Es)运行。

是的我同意 :)。 它可能是生动的,但我肯定似乎报告了事情来自完全错误的地方。

我只是使用系统 pip 在我的生动机器上安装 setuptools 进行实验。

>>> import setuptools
>>> setuptools.__path__
['/home/robertc/.local/lib/python2.7/site-packages/setuptools']
>>> import sys
>>> sys.path
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/home/robertc/.local/lib/python2.7/site-packages', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/home/robertc/work/mock']

所以这个是理智的。 但令人困惑的是,这是以生动的方式介绍的 - 所以 IDK。 我会看看我是否可以在某个时候挖掘一个复制器(在 Ubuntu BTS 中归档)

寻呼@warsaw

用户站点包最终可能会被 setuptools 的邪恶 .pth 文件重新排列到全局站点包之后。 这些对我来说是一个反复出现的问题,直到我学会了永远不要直接使用setup.py - 我会安装一些东西,突然间我正在使用各种其他东西的旧版本。 几次之后,我写了一个激进的工具来解开我的系统。

我认为至少暂时,pip 应该只打印一条友好的消息,要求用户在命令失败时运行--user 。 虽然将其切换为默认值有其好处,但打印更好的消息应该不会太难。

在我们真正开始默认为--user之前,这是一个很好的“快速修复”问题。

如果在 /etc/pip.conf 中设置了用户模式,则还需要 --global、--system 或 --no-user。 据我所知,用户没有简单的方法来覆盖它。

这是一个很好的“快速修复”问题

延迟更新:#4233 这样做了。

不使用 Windows 的人(尤其是新手)如果想要获得良好的体验,真的应该被引导到https://github.com/pyenv/pyenv 。 PEP 370 今天对我来说意义不大,尤其是因为~/.local是 XDG_DATA_HOME。

我认为如果/当这种行为发生时,我不会是唯一一个会选择退出的人。 希望过渡顺利,我不必更改系统的工作方式并传递额外的 CLI 标志,因为我对 pyenv 非常满意。 当然,我不知道 pyenv 在 Windows 上的工作情况如何,但 bash 子系统可以提供帮助......

@jcrben pyenv对人们如何使用 Python(尤其是他们如何获取 Python 二进制文件)做了很多假设,这意味着它对那些假设有效的人非常有效,但是不够普遍,不能作为默认推荐(在这方面它类似于conda )。

--user默认值在pip级别将在正确配置的 Python 虚拟环境中无效,因此此更改对condapyenv等第 3 方环境管理器的影响pip和其他工具将检测到的方式正确地发出环境状态信号(即virtualenv报告它的方式,或标准库的venv的方式)。

相关提案: https ://github.com/pypa/pip/issues/1056#issuecomment -218130183。

~是否考虑过允许用户自定义目录(可能通过环境变量)以避免直接安装到~/.local中? 我可能宁愿将它们嵌套到~/.local/pip或其他东西中 - 就我而言,Python 对该共享空间的顶层没有特殊权利。 ~ 在 9.0.1 上,它似乎在~/.local/lib/python<version> ~/.local/bin添加了可执行文件,我想这很好......

@jcrben是的,目标位置实际上是Python的用户站点目录,它反映了系统站点包目录的命名方案: https ://docs.python.org/3/library/site.html#site.USER_SITE

这已经可以通过PYTHONUSERBASE环境变量在解释器级别进行配置: https: //docs.python.org/3/using/cmdline.html#envvar -PYTHONUSERBASE

对于那些感兴趣的人,我刚刚发布了https://github.com/ofek/hatch ,其中包含默认为这种行为的包命令installuninstallupdate 。 对于系统更改,用户可以使用类似于https://github.com/npm/npm-g/--global选项。

鉴于最近PyPI 上受恶意软件感染的软件包的问题,​​我认为 pip 的最大利益是尽其所能阻止使用sudo pip install ... ,特别是考虑到安装脚本可以在安装时执行任意代码。 以用户身份安装受感染的软件包已经够糟糕的了,但如果以 root 身份安装它们就更糟了。

默认为用户安装意味着更少的人会在他们的 pip 命令前添加 sudo,这意味着意外安装的恶意软件可以做的更少。

作为具体的下一步,我针对添加--global标志提出了一个单独的问题: https ://github.com/pypa/pip/issues/4865

这在 virtualenv 或 conda 环境中几乎可以肯定是一个坏主意。 当一个环境处于活动状态时,在.local中安装的任何内容都可能很容易破坏另一个环境。 那么在这些情况下的想法是什么?

抄送@msarahan @kalefranz

此问题在活动虚拟环境中不适用 - 它仅在未检测到活动环境且未提供任何目标定义选项( --prefix--root等)时适用在命令行上。

这是如何确定的?

我们一直在考虑在 conda 环境中为 python 在sys.path $ 上默认禁用~/.local ,根据定义,它恰好是 conda 安装的任何 python。 不过这很棘手。 无论哪种方式,我们最终都可能违反一组用户的期望。 在https://github.com/conda/conda/issues/7173讨论

pip 不能从以PIP_开头的环境变量加载任何参数吗? 这适用于--user吗? 完整的变量名是什么?

那将是PIP_USER

文档: https: //pip.pypa.io/en/stable/user_guide/#environment -variables

PIP_USER=yes准确地说,谢谢! 使用环境变量对于 CI 的使用要容易得多,因为您只需定义一次它们,并且在调用命令时将使用它们。

我不得不为 travis 做一些非常丑陋的逻辑,显然有些阶段是在没有 virtualemv 的情况下作为普通用户运行的,有些是在 virtualenv 中运行的,你不知道它会是哪一个。

如果您不使用站点包(这会导致其他问题),则 virtualenv 内部很可能会失败。

我必须在 bash 中检测 virtualenv 并避免添加 --user,否则运行将失败。

这很丑陋,导致我浪费了大量时间调试,我相信其他人也会面临同样的问题。

我认为我们需要一个选项来激活有关安装的回退:如果可以的话,将其安装在用户身上并回退到系统。

只有在找不到安装软件包的位置时,pip 才会失败。

这有什么动静吗?

我没有看到它提到它,但是如果在 sudo 下运行时通过了 --user ,也许 pip 应该抱怨。

这些未解决的问题导致程序员远离 pip 甚至 python,并迫使他们使用其他包甚至其他编程语言,如 javascript 和 npm,这样的问题更少。 对于想要使用 python 的新手来说,这些额外的必要选项令人沮丧。

为什么 --user 是默认值? 不能明确指定吗? 我无法运行 pip --target 因为它抱怨它不能与用户一起使用。 知道如何避免它吗?

@dmikov :这不是默认设置。 除非您使用的是 Debian/Ubuntu损坏的版本,在这种情况下,您可以使用以下方法自动设置--userPIP_USER=0 pip install -t ... 。 或者更好的是,安装官方版本并使用它。

我在晚上梦想--user选项成为默认选项(不是开玩笑),我的梦想很快就会实现吗?

我需要帮助安装 pygame 它一直说语法无效

我用了
python3 -m pip install -U pygame --user
这是错的,我该怎么办?

@flamedro56 : 不要随便评论一个问题,请打开一个新问题,并提供更多信息:Python 版本、pip 版本、操作系统、命令输出...

安装程序 reCAPTCHA

有一个新的配置选项 default=system,user 怎么样? 它足够明确,没有人会认为这意味着“始终是用户,即使在 virtualenv 中也是如此”。 它将允许一个优雅的迁移路径。

参见#4575。

看起来Manjaro正在尝试将--user设置为默认值。

关于这个问题,上游有什么新消息吗?

@Tids :“filesystem-2018.9-3 默认将 $HOME/.local/bin 添加到您的 $PATH 中。” 是 Manjaro 做得对的关键额外部分。

Debian 将 Python 级别的“默认为 --user”与用户帐户级别的“默认情况下 $HOME/.local/bin 不在您的 $PATH 上”结合起来,这就是破坏事物的组合。

在#7002 中,当全局站点包目录不可写并且启用了用户站点包时,我尝试让 pip 默认执行用户安装。 当您打算安装到环境中时,这应该在很大程度上避免进行用户安装,只要您有权修改环境。

我正在寻找首先讨论这个想法 - 在我们考虑这样做是否有意义之前,让我们不要陷入审查实施的困境。

值得注意的是,混合用户安装和非用户安装(pip 本身)充满了问题 - 参见 #7209 作为最近的一个示例。

虽然与这个问题没有直接关系(事实上,如果我们默认为用户,这可能会在一定程度上缓解这种情况),但它确实强调需要仔细考虑我们如何处理任何默认转换为--user

(我主要是在此处添加此评论,因此将其记录在某处 - 这根本不是 pip 问题,而是 Python 的 USER_SITE 目录通常如何工作的复杂情况,使用--user安装的用户不太了解

看起来问题在于PATH (用于查找命令)和sys.path (用于查找 Python 导入)具有相反的优先级,因此来自一个安装的启动器脚本尝试从其他。 它可能并不特定于 pip - 它可能会影响任何安装脚本的包。

我不确定我们能做些什么,如果有的话,但我同意这值得考虑。

是的,这就是我想到的主要“USER_SITE 的并发症”。 IMO,弃用包装脚本并仅支持python -m pip是最有效的解决方案。 (我并不反对包装器本身,但我们看到的问题通常是人们不小心运行了错误的包装器,因此修复包装器脚本问题通常不是 pip 问题,更多的是“诊断和修复用户环境错误配置“ 问题)

您的意思是弃用pip包装脚本,或者弃用包装脚本作为 pip 可以安装的东西?

我对后者当然是-1 - 安装命令的能力非常有用,即使它会导致问题。

弃用pip以支持python -m pip可能更合理。 当 pip 安装到它正在运行的 Python 环境中时,明确是哪一个是有意义的。 但这仍然是便利性的丧失,也是人们习惯的重大突破。

我确实是指 pip 本身的包装脚本。 同意这是一种方便的损失,我不会反对以某种形式保留它们(#3164 建议有一个新的pip-cli项目,它只提供包装器)但关键点是python -m pip是运行 pip 的支持方式。

如果当前python (在 PATH 中或与python -m pip一起使用的任何内容中)不是 $# 使用的pip python ,则无法调用 pip 包装脚本显示警告pip ? 如果以这种方式调用,甚至可以委托给python -m pip

同样,如果用户已经在 virtualenv 中,pipenv 会发出警告,如果是,则在发出警告后使用该 virtualenv 而不是管理它自己的。

好的,请注意 #7002 目前已被 6 位点子维护者中的 3 位批准。

默认情况下,它确实使 pip 从非用户安装切换到用户安装,在大多数情况下,我们确实应该进行用户安装。 我对进行此更改有两个更广泛的担忧,我们应该在发布进行该增强的版本之前弄清楚这一点。

  • 一旦我们默认切换到它,我们是否需要一种机制来明确选择退出用户安装? 如果是这样,它与--no-user有何不同? (我同意将--no-user重命名为--global作为明确的选择退出)。
  • 我们的“转型”战略是什么?

    • 我们希望如何传达这种变化?

    • 告诉用户在进行此升级时要小心?

    • 当此更改实施 + 发布时,我们希望用户提出什么样的问题?

如果您在环境中,我会说--global名称错误。 对于flit install--user的对立面是--env ,我松散地打算包括“系统 Python 环境”,但我认为这也不是很清楚。 也许--no-user仍然是最好的选择——它显然与--user正好相反。

我认为--no-user (或等效的环境变量或配置条目)应该让您恢复现有行为,因为目前的默认值实际上是user = False

我提出的唯一一种更改会令人困惑的情况是,如果您认为您有权安装到环境中(启用了用户站点,例如 conda),而实际上您并没有:失败比做一个更清楚用户安装,即使有关于它的日志消息。 我还没有想到任何改善它的好方法。

可写性检测也可能出错。 误报只会给您现有的行为(尝试进行正常安装但失败)。 当用户可以正常安装时,假阴性会进行用户安装。

默认情况下,它确实使 pip 从非用户安装切换到用户安装。

不是(例如)在 Windows 上,其中(默认情况下)Python 安装是按用户安装的,并且站点包默认情况下可写的。 这是我对#7002 的总体偏好,因为我在打开此问题 (#1668) 后的经验是,在站点包中都安装了诸如 pip 之类的包的“混合”环境很容易陷入混乱和用户站点。 因此,我现在支持尽可能进行系统安装,并且仅在 Linux 系统管理的 Python 等无法写入站点包的情况下进行用户安装。

话说回来:

  1. --no-user选项似乎没有意义,因为#7002 意味着您只有在系统安装无论如何都会失败时才能获得用户安装。
  2. 我认为我们需要就过渡进行沟通的最重要的事情是人们需要非常小心多次安装,而这只能通过用户理解和教育来处理,而不是通过任何 pip 中的解决方法。 这基本上是一个核心 Python 问题。 我们可以扩展pip check以报告何时有一个站点和一个用户安装了一个包,并且用户一个正在跟踪站点一个,我猜......

--no-user 选项似乎没有意义

需要明确的是,这已经存在,尽管它可能并不经常有用。 如果您在配置文件中有user=true ,则--no-user应该覆盖它。

需要明确的是,这已经存在

对不起,我应该更清楚。 我认为“一旦我们默认切换到它,就明确选择退出用户安装的机制”没有意义,至少在我假设@pradyunsg的意思的意义上,这是关于选择退出 #7002 行为,正如所说,与“默认切换到用户安装”不同。

实际上,我不确定这是否更清楚;-) 也许我想说的是“我们不需要比我们目前拥有的更多的选择”......

嗯... @pfmoore #7002 之后,需要什么才能解决这个问题?

PS:之前的评论是我匆忙写的,不小心被贴出来了。 子弹没问题; 当它发布时,我仍在起草它之前的段落。 对于可能造成的任何混乱,我们深表歉意。

@pradyunsg鉴于我现在不太倾向于将--user作为默认值是一个好主意,除非它是绝对必要的(案例 #7002 解决)我宁愿说我们可以放弃这个问题,因为现在 #7002 已经完成,这不再是一个好主意。

将您的 2 个要点作为我们可能需要将 #7002 视为完整的内容,我在上面的评论涵盖了这一点。

我在这里遵循了发行说明。
https://pip.pypa.io/en/stable/news/#id3
“当主站点包目录不可写并且启用了用户站点包时,默认执行用户安装(就像传递了 --user 一样)。(#1668)”

我的构建现在失败了

ERROR: Can not perform a '--user' install. User site-packages are not visible in this virtualenv.

这似乎可以通过从我的 pip 命令中删除 --user 来解决。

这是预期的行为吗? 发行说明似乎没有反映这一点。

链接到现在在 pip 20.0.1 上失败的脚本(删除 --user 修复了硬失败)
https://github.com/lfit/releng-global-jjb/blob/master/shell/python-tools-install.sh

如果用户站点包不能从该环境导入是正确的,那么这是预期的行为,但它与此 PR 正交。 该检查是几年前引入的(#567),但它看起来直到最近才被 venv 破坏(#7155)。 有一个发布说明:

在使用 venv (PEP 405) 创建的虚拟环境中正确处理系统站点包。

啊,是的,谢谢你的意见。 我想通了...
我的脚本正在填充 .local/bin/
当我跑的时候

python3 -m venv ~/.local

然后在 ubuntu 登录 shell (#!/bin/bash -l) .local/bin 被添加到路径中(因此调用 python3 现在调用 .local/bin/python3 可执行文件)这是我们不想要的。
我从来不需要运行 python3 -m venv ~/.local
或从登录 shell 调用我的脚本,并删除这两个或其中一个问题来修复它。

#fresh ubuntu docker
root<strong i="13">@7d8107816f64</strong>:/# python3 -m pip install  --user --upgrade pip
Successfully installed pip-20.0.1
root<strong i="14">@7d8107816f64</strong>:/# python3 -m pip --version
pip 20.0.1 from /root/.local/lib/python3.6/site-packages/pip (python 3.6)
root<strong i="15">@7d8107816f64</strong>:/# ls root/.local/bin/pip
pip     pip3    pip3.6
#Now we populate ~/.local/bin/
root<strong i="16">@7d8107816f64</strong>:/# python3 -m venv ~/.local
root<strong i="17">@7d8107816f64</strong>:/# ls root/.local/bin/
activate          activate.fish     easy_install-3.6  pip3              python
activate.csh      easy_install      pip               pip3.6            python3
root<strong i="18">@7d8107816f64</strong>:/# ./root/.local/bin/python --version
Python 3.6.9
root<strong i="19">@7d8107816f64</strong>:/# ./root/.local/bin/python -m pip install  --user --upgrade pip
ERROR: Can not perform a '--user' install. User site-packages are not visible in this virtualenv.

因此,如果我们曾经运行可执行文件 .local/bin/python,我们就不能使用 --user 进行 pip install

哦,我错过了你在做python3 -m venv ~/.local 。 这可能会混淆像 pip 这样的工具,因为~/.local--user安装的前缀(在 Linux 上)。 venvs 和--user是两种_不同_的方式,您可以在不进行系统范围更改的情况下安装软件包:您应该使用其中一种。 在~/.local中创建一个 venv 会使两者产生一些奇怪的混合。

新行为可能对许多人来说很方便,但是“用户”安装让我作为一名 Web 开发人员感到有些悲伤——我经常需要准备将部署到我们的生产机器上的 virtualenvs,如果我的用户库中安装了任何包,那么默认情况下pip将拒绝将其安装到我正在准备的 virtualenv 中,并且仍然会以 success 退出。 它决定不安装包的通知隐藏在我用来准备 virtualenv 的脚本的 30 或 40 页输出中。 最终结果是,一旦部署了 virtualenv,我的主目录中的包就不再可用,所以我的生产 Web 应用程序中缺少一些随机包,它就死了。

我愿意承认我的用例不是典型的用例,所以从一般可用性的角度来看,这可能仍然是一个好主意。

对于遇到类似问题的其他人,有几种解决方法:

  • --force-reinstall添加到脚本等中的所有pip install命令行
  • 删除~/.local/lib/python*并编辑~/.pip/pip.conf以在global部分添加user = no
[global]
user = no
  • 做一些更激烈的事情,比如将~/.local/lib更改为文件而不是目录 :smirk:

与往常一样,亲爱的包装维护者,感谢你们所做的一切——我确信在不破坏某人的东西的情况下改变任何东西几乎是不可能的,而且不管怎样,你们坚持下去的事实确实很棒,因为它让我们取得了进步。

啊,用户安装也可能在持续集成环境中造成巨大的问题,其中许多不同的东西作为同一个用户帐户运行,但人们仍然希望构建相互隔离。 我们通过将~/.local设为只读来解决此问题,但上述解决方案可能也可以工作。

当您使用默认选项创建 virtualenv 时,它是隔离的:它看不到您的用户或系统站点包,因此 pip 应该只适用于安装在 env 中的包。 由于您所描述的问题的种类,这在多年前已成为默认设置。

如果您使用--system-site-packages选项创建 virtualenvs(或非常旧的 virtualenv 版本,这是默认设置),它们将充当您安装的软件包的覆盖层,无论是系统范围内还是在您的家中目录。 如果您希望系统包可见但用户包不可见,您可以使用-s选项PYTHONNOUSERSITE环境变量运行 Python。

哦! 非常抱歉,你完全正确。 我的组织奇怪的系统站点包政策再次来袭。 感谢您指出一些解决方案。

没问题。 几年前,当我们经常依赖系统包管理器来处理诸如 numpy 之类的事情时,系统站点包更为常见,因此也许值得重新审视该策略。 但是今天仍然有合理的理由使用它。

关闭符合https://github.com/pypa/pip/issues/1668#issuecomment -544569965。

非常感谢@takluyver! ^>^

@takluyver谢谢解决困扰我很久的问题
但是我注意到,在使用非特权用户安装软件包时,带有 pip 20.0.2 的 Windows 10 python 3.8.2 仍然很难失败。

ERROR: Exception:
Traceback (most recent call last):
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\cli\base_command.py", line 186, in _main
    status = self.run(options, args)
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\commands\install.py", line 253, in run
    options.use_user_site = decide_user_install(
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\commands\install.py", line 604, in decide_user_install
    if site_packages_writable(root=root_path, isolated=isolated_mode):
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\commands\install.py", line 548, in site_packages_writable
    return all(
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\commands\install.py", line 549, in <genexpr>
    test_writable_dir(d) for d in set(get_lib_location_guesses(**kwargs))
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\utils\filesystem.py", line 140, in test_writable_dir
    return _test_writable_dir_win(path)
  File "c:\program files (x86)\python38-32\lib\site-packages\pip\_internal\utils\filesystem.py", line 153, in _test_writable_dir_win
    fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL)
PermissionError: [Errno 13] Permission denied: 'c:\\program files (x86)\\python38-32\\Lib\\site-packages\\accesstest_deleteme_fishfingers_custard_m59lch'

我认为这可能是因为OSErrorerrnoerrno.EACCES但是errno.EPERM

@catPill请打开一个新问题,以便正确跟踪。 我在 Windows 上错过了一些东西是完全合理的。

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