跳转到主要内容

这个概念证明展示了如何在不使用virtualenv的情况下使用python包

项目描述

概念证明:Monotrail

这个概念证明展示了如何在不使用virtualenv的情况下使用python包。它将安装python本身和你的依赖项,前提是在目录中有一个requirement.txtpyproject.toml/poetry.lock。可以使用pipx、pip或从发布主分支的二进制文件进行安装。

pipx install monotrail # or `pip install monotrail`
monotrail run python my_script.py

每个依赖项只全局安装一次,并连接到你的代码。没有venv目录,没有明确安装,没有激活,没有pyenv。

这是一个概念证明,因此只有大多数功能缺失,可能会崩溃或产生无意义的结果。例如,非Linux系统测试不佳,安装不便,错误消息不佳,只支持PyPI,启动缓慢,只支持某些requirement.txt语法,交互模式下的lockfiles不保存,某些pkg_resources使用不起作用等。

monotrail意味着向你展示可以在不使用传统的“在环境中安装包”的情况下使用python。它还集成了python-build-standalone,因此你不再需要安装python。

它包括pipx和tox的简单实现。还有一个针对notebooks的pip包,其中可以在运行时交互式添加包,为每个notebook获取独立的包集,并避免版本冲突。

用法

首先下载二进制文件并将其放入PATH中(例如,通过.local/bin

wget -O ~/.local/bin/monotrail https://konstin.github.io/poc-monotrail/main/ubuntu/monotrail
chmod +x ~/.local/bin/monotrail

确保你有一个requirements.txtpyproject.toml/poetry.lock

monotrail run python my_script.py

选择python版本和额外功能

monotrail run -p 3.9 --extras fancy-pants python my_script.py --some-option

运行之前在.venv/bin中的命令

monotrail run command pytest

还有一个具有入口点的python包

pip install monotrail
monotrail_python path/to/your/script.py

与jupyter notebooks一起使用

!pip install monotrail
import monotrail

monotrail.interactive(
    numpy="^1.21",
    pandas="^1"
)

Screenshot of the jupyter browser UI using monotrail

在google colab中,你可能想要导入你的git仓库

import monotrail

monotrail.from_git(
    "https://github.com/sokrypton/ColabFold", "63b42b8f5b5da418efecf6c4d11490a96595020d"
)

作为pipx的替代品

monotrail ppipx --extras jupyter black .

作为tox的替代品

monotrail run -p 3.8 -p 3.9 -p 3.10 command pytest

你可以将monotrail链接到名为pythonpython3python3.x的文件,它将作为python3.8或指定的python版本运行。

还有一个扁平源布局的演示,其中你可以在src中直接放置__init__.py,而不是在src/srcery/__init__.py中嵌套。

srcery
├── poetry.lock
├── pyproject.toml
└── src
    ├── __init__.py
    └── potion.py

设置RUST_LOG=debug将提供详细信息以跟踪错误。

背景

monotrail 首先解析您想要的 Python 版本(默认为 3.8),如果不存在,则从 PyOxy 下载。它不是作为可执行文件运行 Python,而是加载 libpython.so 并使用 C API

接下来,我们搜索依赖项列表(poetry.lockrequirements.txt)。如果需要,我们将运行 poetry 解析依赖项(通过为 poetry 本身预先录制的 poetry.lock 进行引导)。我们将所有缺少的包安装到 .cache/monotrail 中的单独目录,并记录所有位置。

我们初始化 Python 并注入一个包含所有内容的自定义 PathFinder,并将其添加到 sys.meta_path。当 Python 搜索从哪里导入某个内容时,它会通过 sys.meta_path 中的所有 Finder 直到其中一个返回位置。我们的知道从锁定文件中包的位置,Python 看不到其他任何东西,因此您只能从与锁定文件匹配的包中加载。

交互式模式几乎与上面相同,只是我们跳过了 Python 安装,并有一个检查,以确认已导入的包版本没有更改。

基准测试(wheel 安装)

无 venv 安装的便利之处在于我们只安装每个包版本一次,因此不再需要为 pytorch 安装 3 个不同的版本。这需要很少的磁盘空间(即使清理缓存仍然是一个未解决的问题),但更重要的是,这意味着如果之前已使用所有所需的包版本,则“安装”将立即完成。它还消除了重新创建损坏的 venv 的需求。

通过在 Rust 中重新实现 wheel 安装,它也变得更快。 install-wheel-rs 有一个单独的 Python 接口,因此您可以将其作为快速的 wheel 安装程序单独重用。

安装单个大型 wheel(plotly)

$ rm -rf .venv-benchmark && virtualenv .venv-benchmark
$ VIRTUAL_ENV=.venv-benchmark hyperfine -p ".venv-benchmark/bin/pip uninstall -y plotly" \
  "target/release/monotrail venv-install test-data/popular-wheels/plotly-5.5.0-py2.py3-none-any.whl" \
  ".venv-benchmark/bin/pip install --no-deps test-data/popular-wheels/plotly-5.5.0-py2.py3-none-any.whl"
          
Benchmark #1: target/release/monotrail install test-data/popular-wheels/plotly-5.5.0-py2.py3-none-any.whl
  Time (mean ± σ):      5.797 s ±  0.069 s    [User: 3.796 s, System: 1.979 s]
  Range (min … max):    5.699 s …  5.906 s    10 runs
 
Benchmark #2: .venv-benchmark/bin/pip install --no-deps test-data/popular-wheels/plotly-5.5.0-py2.py3-none-any.whl
  Time (mean ± σ):      7.658 s ±  0.061 s    [User: 5.448 s, System: 2.085 s]
  Range (min … max):    7.598 s …  7.758 s    10 runs
 
Summary
  'target/release/monotrail install test-data/popular-wheels/plotly-5.5.0-py2.py3-none-any.whl' ran
    1.32 ± 0.02 times faster than '.venv-benchmark/bin/pip install --no-deps test-data/popular-wheels/plotly-5.5.0-py2.py3-none-any.whl'

一个数据科学堆栈示例(numpy、pandas、matplotlib)

test-data/poetry/data-science -E tqdm_feature
pip 22.0.4 from /home/konsti/monotrail/.venv-b/lib/python3.8/site-packages/pip (python 3.8)
Poetry version 1.1.13
Benchmark 1: .venv/bin/pip install -q -r requirements-benchmark.txt
  Time (mean ± σ):     11.745 s ±  1.159 s    [User: 9.637 s, System: 1.339 s]
  Range (min … max):   10.830 s … 13.048 s    3 runs
 
Benchmark 2: poetry install -q --no-root -E tqdm_feature
  Time (mean ± σ):     15.039 s ±  0.153 s    [User: 41.032 s, System: 5.934 s]
  Range (min … max):   14.894 s … 15.199 s    3 runs
 
Benchmark 3: monotrail poetry-install -E tqdm_feature
  Time (mean ± σ):      5.232 s ±  0.135 s    [User: 12.850 s, System: 2.334 s]
  Range (min … max):    5.089 s …  5.357 s    3 runs
 
Summary
  'monotrail poetry-install -E tqdm_feature' ran
    2.24 ± 0.23 times faster than '.venv/bin/pip install -q -r requirements-benchmark.txt'
    2.87 ± 0.08 times faster than 'poetry install -q --no-root -E tqdm_feature'

一个中等规模 django 项目

test-data/poetry/mst -E import-json
pip 22.0.4 from /home/konsti/monotrail/.venv-b/lib/python3.8/site-packages/pip (python 3.8)
Poetry version 1.1.13
Benchmark 1: .venv/bin/pip install -q -r requirements-benchmark.txt
  Time (mean ± σ):     29.481 s ±  0.186 s    [User: 21.001 s, System: 3.313 s]
  Range (min … max):   29.331 s … 29.690 s    3 runs
 
Benchmark 2: poetry install -q --no-root -E import-json
  Time (mean ± σ):     70.291 s ±  1.366 s    [User: 355.966 s, System: 46.958 s]
  Range (min … max):   69.020 s … 71.735 s    3 runs
 
Benchmark 3: monotrail poetry-install -E import-json
  Time (mean ± σ):     10.714 s ±  1.423 s    [User: 43.583 s, System: 10.551 s]
  Range (min … max):    9.504 s … 12.282 s    3 runs
 
Summary
  'monotrail poetry-install -E import-json' ran
    2.75 ± 0.37 times faster than '.venv/bin/pip install -q -r requirements-benchmark.txt'
    6.56 ± 0.88 times faster than 'poetry install -q --no-root -E import-json'

启动时间

hello world

$ hyperfine --warmup 2 "python hello.py" "../target/release/monotrail run python hello.py"
Benchmark 1: python hello.py
  Time (mean ± σ):      17.3 ms ±   0.8 ms    [User: 14.5 ms, System: 2.9 ms]
  Range (min … max):    16.3 ms …  20.5 ms    159 runs
 
Benchmark 2: ../target/release/monotrail run python hello.py
  Time (mean ± σ):     218.4 ms ±   5.4 ms    [User: 161.6 ms, System: 55.9 ms]
  Range (min … max):   212.0 ms … 232.5 ms    13 runs
 
Summary
  'python hello.py' ran
   12.65 ± 0.64 times faster than '../target/release/monotrail run python hello.py'

最简单的 numpy 使用方法

import sys
import numpy
print(
    f"hi from python {sys.version_info.major}.{sys.version_info.minor} and "
    f"numpy {numpy.__version__}"
)
$ hyperfine --warmup 2 "python numpy_version.py" "../target/release/monotrail run python numpy_version.py"
Benchmark 1: python numpy_version.py
  Time (mean ± σ):      99.8 ms ±   1.2 ms    [User: 127.3 ms, System: 171.7 ms]
  Range (min … max):    98.1 ms … 103.1 ms    29 runs
 
Benchmark 2: ../target/release/monotrail run python numpy_version.py
  Time (mean ± σ):     285.9 ms ±   1.8 ms    [User: 247.6 ms, System: 169.3 ms]
  Range (min … max):   283.4 ms … 289.9 ms    10 runs
 
Summary
  'python numpy_version.py' ran
    2.86 ± 0.04 times faster than '../target/release/monotrail run python numpy_version.py'

开发设置

我使用了两个 venv,我激活的 venv 称为 .venv-b,另一个是用于安装 monotrail 的 .venv。设置如下

virtualenv .venv-b
. .venv-b/bin/activate
pip install -U maturin[zig] black pip pytest ipython
virtualenv .venv
# pytest runs the tests, jupyter nbconvert is for testing the notebook
.venv/bin/pip install pytest jupyter nbconvert

由支持