点下载而不执行setup.py

时间:2018-09-24 20:36:58

标签: python pip setuptools distutils pypi

如何在可能不执行setup.py文件(可能包含恶意代码)的情况下下载发行版(可能是sdist)?

我不想递归获取依赖项,仅下载一个文件用于指定的发行版。尝试不起作用:

pip download --no-deps mydist

在上述情况下,仍将执行一个演示setup.py的示例:

$ pip --version  # pip v18.0 on Python 3.7.0 / Linux
pip 18.0 from /tmp/.venv/lib/python3.7/site-packages/pip (python 3.7)
$ pip download --no-deps suds
Collecting suds
  Downloading https://files.pythonhosted.org/packages/bc/d6/960acce47ee6f096345fe5a7d9be7708135fd1d0713571836f073efc7393/suds-0.4.tar.gz (104kB)
    100% |████████████████████████████████| 112kB 10.2MB/s 
  Saved ./suds-0.4.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-download-56eyyp0s/suds/setup.py", line 20, in <module>
        import suds
      File "/tmp/pip-download-56eyyp0s/suds/suds/__init__.py", line 154, in <module>
        import client
    ModuleNotFoundError: No module named 'client'

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-download-56eyyp0s/suds/

我不能使用--no-binary选项,因为我不想排除源分发。我只想避免执行其源代码。

2 个答案:

答案 0 :(得分:7)

我一直在研究pip,但不幸的是,那里的代码非常复杂。看来目前尚无办法,而且根据link provided by @doctaphred,尚无计划朝着这个方向取得进展。

下一步取决于您的情况;例如,如果您需要此“程序包下载器”进行生产,建议您编写自己的pypi客户端。编写起来非常简单,并且可以根据需要对其进行优化,使其比pip更快,更简单。为此,您可以尝试使用pip中的一些现有代码,但是我认为这很困难(在看到该代码之后)。

否则,我会考虑采用更快,更骇人的方法来完成工作。我想到的第一个解决方案就是在尝试运行pip命令时停止egg_info。为此,您可以使用各种方法在运行时修补pip的代码。我最喜欢的是使用usercutomize文件。

例如,创建具有以下内容的补丁文件并将其放置在您选择的目录中:

/pypatches/pip_pure_download/usercustomize.py

from pip._internal.req.req_install import InstallRequirement

print('Applying pure download patch!')

def override_run_egg_info(*args, **kwargs):
    raise KeyboardInterrupt # Joke's on you, evil hackers! :P

InstallRequirement.run_egg_info = override_run_egg_info

现在要将补丁应用于python执行,只需将补丁的目录添加到PYTHONPATH,例如:

PYTHONPATH=/pypatches/pip_pure_download:$PYTHONPATH pip download --no-deps suds

答案 1 :(得分:1)

从第19.3.1点开始似乎无法实现:(

请参见https://github.com/pypa/pip/issues/1884