在Ubuntu上无需使用pip安装Python

7
我需要在我正在构建的自定义Docker容器中安装Python包,该容器是从官方“ ubuntu” Docker镜像构建的,因此我想尽量减少空间使用。 Python3安装得很好并运行良好,但由于某种原因,未包含pip。
因此,我通过apt install python3-pip进行安装,这可以工作,但其大小为300兆字节,并且需要几分钟才能安装(显然是因为它安装了大量用于从gcc等构建二进制软件包的东西)。
当然,我可以在安装所需的依赖项后从镜像中卸载python3-pip,并另外使用apt autoremove来清除299兆字节。但这需要再花费一分钟的时间。
虽然上述方法可行,但它显著增加了我的Docker镜像构建时间。因此,我尝试查看是否有一种无需使用pip安装依赖项的方法:
我尝试从PyPI下载依赖项的.tar.gz文件,解压缩后尝试python3 setup.py install,但这会使我遇到奇怪的错误:
Traceback (most recent call last):
  File "setup.py", line 59, in <module>
    from distutils import log
ImportError: cannot import name 'log'

我想也许我需要安装setuptools或升级distutils。
我尝试使用官方网站上的get-pip.py,但那也失败了。
Traceback (most recent call last):
  File "get-pip.py", line 20890, in <module>
    main()
  File "get-pip.py", line 197, in main
    bootstrap(tmpdir=tmpdir)
  File "get-pip.py", line 82, in bootstrap
    import pip._internal
  File "/tmp/tmpjpa5gs_x/pip.zip/pip/_internal/__init__.py", line 40, in <module>
  File "/tmp/tmpjpa5gs_x/pip.zip/pip/_internal/cli/autocompletion.py", line 8, in <module>
  File "/tmp/tmpjpa5gs_x/pip.zip/pip/_internal/cli/main_parser.py", line 8, in <module>
  File "/tmp/tmpjpa5gs_x/pip.zip/pip/_internal/cli/cmdoptions.py", line 17, in <module>
  File "/tmp/tmpjpa5gs_x/pip.zip/pip/_internal/locations.py", line 10, in <module>
ImportError: cannot import name 'sysconfig'

很奇怪,因为如果我启动python3,import sysconfig可以正常工作。

我也尝试了apt install python-pyyaml(我在Docker镜像中需要的依赖项),但似乎不存在。

所以我已经没有其他选择了。


“pip” 实际上确实需要所有这些(C 编译器和其他构建工具),因为 pip 包可能包含 C 代码或链接二进制包。 - digitalarbeiter
是的,我知道为什么需要覆盖所有可能的构建/安装情况,但对于不需要 C 的一个或两个库来说,这似乎有些过度。应该有一个“轻量级”版本的 pip 适用于纯 Python 包,它可能只有原版的 1/100 大小。 - Oliver
4个回答

3

我遇到了类似的问题,并想提供一种可替代的解决方案。

在Ubuntu 20.04上,python3-pip需要建议包build-essential和python3-dev, 因此您可以使用选项--no-install-recommends跳过它们:

RUN apt update -y && \
    apt install python3 python3-pip --no-install-recommends -y && \
    apt clean

这样做能将我的图像从420MB缩小到165MB,构建时间也更快。

注意:这对于纯Python包来说效果很好,但如果你想编译任何东西,你可能需要安装build-essential和python3-dev。

有用的链接


2
Debian和Ubuntu中PyYAML的软件包名为python-yaml,而非python-pyyaml
sudo apt install python-yaml

或者

sudo apt install python3-yaml

分别安装它们。(在Debian/Ubuntu软件包名称中,通常会省略Python软件包可能具有的任何额外的“py”前缀:例如,安装python-tz而不是python-pytz。他们似乎不喜欢py-冗余。)

+1 如果有一种完全避免安装pip的方法,那太好了!但我的问题仍然存在:如果你有一个纯Python包,是否有一种不需要完整的pip,只使用setuptools或其他方式进行安装的方法?我希望我问题中的错误能够给出一些提示。 - Oliver
我添加了一个答案,针对那些没有python-something apt安装的情况来回答问题。 - Oliver
在Ubuntu 18.04中,它没有为我提供Python模块。自2018年以来,软件包名称是否已更改? - Addison Klinke

1
我已经在Docker(Ubuntu)容器中使用pip-get.py安装pip已经几年了,没有遇到任何问题。对我来说,这是不会出现pip过期警告或(在某个时刻)SSL相关错误的最佳方式。
因此,你答案的第二部分接近正确,但你的Python安装似乎有点太简单了,需要python-distutils提供的sysconfig。你可以尝试使用这个相当简单的Dockerfile:
FROM ubuntu:latest

MAINTAINER Anthon

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && apt-get install -y \
  python3 \
  python3-distutils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# this gets you the latest pip
COPY pip/get-pip.py /tmp/get-pip.py
RUN python3 /tmp/get-pip.py

RUN pip3 install pyyaml

我使用这个 Makefile 运行了它:
doit:   pip/get-pip.py
        docker build .

pip/get-pip.py:
        -@mkdir pip
        curl https://bootstrap.pypa.io/get-pip.py -o pip/get-pip.py

(这些需要在缩进的行上使用TAB字符)以确保pip-get.py可以从上下文中使用(当然您可以从Dockerfile内部下载它,但这并不是必要的)。这将导致成功安装PyYAML,但速度会很慢。

我建议您开始使用ruamel.yaml(免责声明:我是该软件包的作者),方法是将Dockerfile的最后一行更改为:

RUN pip3 install ruamel.yaml

除了对原始PyYAML代码进行许多错误修复外,ruamel.yaml还支持YAML 1.2和YAML 1.1(2009年被替换并由PyYAML支持的版本),并从.whl文件安装适当的版本,因此您将在容器中拥有快速的C加载程序(PyYAML不支持此功能)。
您可以使用ruamel.yaml中的C加载程序加载YAML文件,方法如下:
from pathlib import Path
from ruamel.yaml import YAML


path = Path('yourfile.yaml')
yaml = YAML(typ='safe')
data = yaml.load(path)

你问题中的第一个错误也是由于容器中没有安装 python-distutils 导致的。 - Anthon

1
当Python包没有可用的apt install something时,以下是如何处理的。感谢@Anthon和@digitalarbeiter的回答,他们提供了重要信息以得出解决方案。
  • To install via a setup.py file (esp. useful in Ubuntu Docker container):

    • it was sufficient for me to

      apt install python3-distutils
      <download package, tar xvf, cd to folder>
      python3 setup.py install
      
    • This method of installation only works for pure Python packages (should not not be a surprise), which means that Python packages that have non-pure Python dependencies may not install or, if they do, will have some functionality unavailable.

    • Note that even before installing python3-distutils, python3 -m distutils worked; this implies that the builtin distutils, that comes with Python3 via apt install python3, is not the full distutils; I did not know that, is this fact ever mentioned anywhere?
  • To install pip without the gcc toolchain: it was sufficient for me to

    apt install python3-distutils
    wget https://bootstrap.pypa.io/get-pip.py
    python3 get-pip.py
    

    Then pip install pyyaml completed. It seemed to install from a .tar.gz so it is the pure Python implementation too. Not surprising. This technique is useful if a package is not installable via apt install python3-<package>

以上方法只需要几兆磁盘空间。
对我而言,还有另外两个缺失的重要环节是:
  • apt install python3-<something>:

    • 我错过了在Debian中许多Python软件包是以这种方式分发的事实,对于具有C实现(或C依赖项)的软件包非常方便,因为无需编译。
    • 而且我不知道在PyPI上被称为py<something>的软件包,apt安装是python3-<something>而不是python3-py<something>。不幸的是,apt search pyyaml没有帮助。
  • apt search <something>

    • 我有点忘记了它,因为在(桌面)Ubuntu上的bash会自动建议下载正确的软件包,当命令未找到时。
    • 特别是,apt search yaml会产生81个软件包,提供多种语言(Python 2、Python 3、nodejs、Java、Go、Ruby、Erlang、Lua、Perl、C、C ++、Clojure)的YAML读/写、linter、模式验证器等。
    • 多个搜索条件是AND操作,因此apt search yaml python3显示了我错过的python3-yaml。
    • 不幸的是,apt search pyyaml没有结果,即使apt show python3-yamlSourceHomepage字段包含单词“pyyaml”。我找不到一种方法使search包括这些字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接