Сравнение инструментов для управления пакетами

Тимур Салимов — Techlead DS

Настоящее время: Зоопарк инструментов

Категоризация

Для целей этого сравнения было выделено 10 основных категорий, которые важны, когда речь идет об управлении Python проектом:

  • Управление версией Python
  • Виртуальные окружения
  • Управление пакетами
  • Управление научными пакетами
  • Воспроизводимые зависимости (lock-file)
  • Сборка и публикация пакетов (PyPI)
  • Сборка и публикация научных пакетов (conda-like)
  • Единый файл мета данный (PEP 621)
  • Автоматизация выполнения команд (Task runner/workflow manager)
  • Шаблонизация структуры проекта

Специализированные инструменты

Управление версией Python

  • pyenv
    •   $ pyenv versions
          2.7.10
        * 3.5.0 (set by /Users/yuu/.pyenv/version)
          miniconda3-3.16.0
          pypy-2.6.0
      
        $ python --version
        Python 3.6.0
      
        $ pyenv global pypy-2.6.0
      
        $ python --version
        Python 2.7.9 [PyPy 2.6.0 with GCC 4.9.2]
      
        $ cd /Volumes/treasuredata/jupyter
      
        $ pyenv version
        miniconda3-3.16.0 (set by /Volumes/treasuredata/.python-version)
      
        $ python --version
        Python 3.4.3 :: Continuum Analytics, Inc.

Виртуальные окружения

  • venv - простой вариант доступный сразу.
  • virtualenv - если не устраивает venv.
  • Наиболее важные отличия venv от virtualenv:
    • работает медленнее (из-за отсутствия метода начальной фиксации app-data);
    • не так расширяем;
    • не может создавать виртуальные среды для произвольно установленных версий Python (и автоматически обнаруживать их);
    • не обновляется через pip;
    • не имеет такого богатого программного API;

Управление пакетами

  • pip
    •   $ python -m pip install SomePackage            # latest version
        $ python -m pip install 'SomePackage>=1.0.4'   # with version
        $ python -m pip install --upgrade SomePackage  # upgrade package
        $ python -m pip uninstall SomePackage          # uninstall
      
        $ python -m pip install -r requirements.txt    # using requirements
      
        $ python -m pip list
        Package Version
        ------------ -------
        SomePackage  0.0.1
      
        $ python -m pip freeze
        SomePackage==0.0.1
  • pipx
    •   $ pipx install hello
        installed package hello 2.0.3, Python 3.7.3
        These apps are now globally available
            - hello
        done!  🌟 ✨
      
        $ pipx list
        venvs are in /home/user/.local/share/pipx/venvs
        apps are exposed on your $PATH at /home/user/.local/bin
        package hello 2.0.3, Python 3.7.3
            - hello
      
        # Now you can run hello from anywhere
        $ hello World
        Hello, World!
      
        # This will install the package in an isolated, temporary directory and invoke the app.
        $ pipx run hello Isolated world
        Hello, Isolated world!

Сборка и публикация пакетов

  • build & setuptools & twine
  • flit
  • maturin
  • hatchling

Сборка и публикация научных пакетов

  • conda-build
  • rattler-build

Автоматизация выполнения команд

  • task (taskfile.dev)
    • Пример Taskfile.yml:
      • version: '3'
        
        tasks:
          test:
            cmds:
              - pytest --cov=my_app
  • poethepoet
    • Пример pyproject.toml:
      •     [tool.poe.tasks]
            test         = "pytest --cov=my_app" # a simple command task
            serve.script = "my_app:run(debug=True)" # python script based task
            tunnel.shell = "ssh -N -L 0.0.0.0:8080 $PROD"# (posix) shell based task

Шаблонизация структуры проекта

  • cookiecutter
    • Пример шаблона cookiecutter
      • Структура проекта:
        •     ├── README.md
              ├── {{ cookiecutter.repo_name }}/
              │   ├── src/
              │   ├── __init__.py
              │   ├── {pipeline name 1}.smk
              │   ├── ...
              │   └── {pipeline name n}.smk
              ├── research/
              ├── _quarto.yaml
              └── pyproject.toml
      • cookiecutter.json:
        •     {
                  "author_name": "John Doe",
                  "author_email": "doe@john.com",
                  "project_name": "Project name",
                  "description": "A short description of the project.",
              }
      • Пример вставки значений в файл:
        •     [project]
              name = "{{ cookiecutter.repo_name }}"
              version = "{{ cookiecutter.version }}"
              description = "{{ cookiecutter.description }}"
              authors = ["{{ cookiecutter.author_name }} <{{ cookiecutter.author_email }}>"]
  • copier
    • Пример шаблона copier:
      • Структура проекта:
        •     my_copier_template/
              ├── copier.yml
              ├── .git/
              ├── {{project_name}}
              │   └── {{module_name}}.py.jinja
              └── {{_copier_conf.answers_file}}.jinja
      • copier.yml:
        • project_name:
              type: str
              help: What is your project name?
          
          module_name:
              type: str
              help: What is your Python module name?
      • Пример вставки значений в файл:
        •     print("Hello from {{module_name}}!")

Многозадачные инструменты

pipenv

  • ❌ Управление версией Python
  • ✅ Виртуальные окружения
  • ✅ Управление пакетами
  • ❌ Управление научными пакетами
  • ✅ Воспроизводимые зависимости
  • ❌ Сборка и публикация пакетов
  • ❌ Сборка и публикация научных пакетов
  • ❌ Единый файл мета данный
  • ❌ Автоматизация выполнения команд
  • ❌ Шаблонизация структуры проекта

pipenv: примеры

  • Установка pipenv:
    •       $ pip install pipenv
  • Активация виртуального окружения:
    •       $ pipenv shell
  • Установка зависимостей:
    •       $ pipenv install flask==0.12.1
            Adding flask==0.12.1 to Pipfile's [packages]...
            Pipfile.lock not found, creating...
  • Установка dev зависимостей:
    •       $ pipenv install pytest --dev
  • Фиксация зависимостей:
    •       $ pipenv lock
  • Установка последней зафиксированной версии проекта:
    •       $ pipenv install --ignore-pipfile

poetry

  • ❌ Управление версией Python
  • ✅ Виртуальные окружения
  • ✅ Управление пакетами
  • ❌ Управление научными пакетами
  • ✅ Воспроизводимые зависимости
  • ✅ Сборка и публикация пакетов
  • ❌ Сборка и публикация научных пакетов
  • ❌ Единый файл мета данный
  • ❌ Автоматизация выполнения команд
  • ❌ Шаблонизация структуры проекта

poetry: примеры

  • Активация окружения:
    •       poetry shell
  • Запуск скрипта в окружении:
    •       poetry run python your_script.py
  • Для управления пакетами в poetry можно воспользоваться командой:
    •       poetry add numpy
  • Для сборки пакета:
    •       poetry build
  • Для публикации пакета:
    •       poetry publish
  • Пример poetry scripts:
    •       [tool.poetry.scripts]
            my_package_cli = 'my_package.console:run'

conda/mamba

  • ✅ Управление версией Python
  • ✅ Виртуальные окружения
  • ❌ Управление пакетами
  • ✅ Управление научными пакетами
  • ❌ Воспроизводимые зависимости
  • ❌ Сборка и публикация пакетов
  • ✅ Сборка и публикация научных пакетов
  • ❌ Единый файл мета данный
  • ❌ Автоматизация выполнения команд
  • ❌ Шаблонизация структуры проекта

conda/mamba: примеры

  • Создание виртуального окружения:
    •       conda create -n myenvironment python=3.10 numpy pandas
  • Создание виртуального окружения из файла:
    •       conda env create -f environment.yml
  • Пример environment.yml файла:
    •       name: stats2
            channels:
            - javascript
            dependencies:
            - python=3.9
            - conda-forge::numpy=1.21.*
            - nodejs=16.13.*
            - flask
            - pip
            - pip:
                - Flask-Testing
  • Активация и дезактивация виртуального окружения:
    •       conda activate myenvironment
    •       conda deactivate
  • Установка пакета
    •       conda install --name myenvironment numpy

hatch

  • ❌ Управление версией Python
  • ✅ Виртуальные окружения
  • ✅ Управление пакетами
  • ❌ Управление научными пакетами
  • ❌ Воспроизводимые зависимости
  • ✅ Сборка и публикация пакетов
  • ❌ Сборка и публикация научных пакетов
  • ✅ Единый файл мета данный
  • ✅ Автоматизация выполнения команд
  • ❌ Шаблонизация структуры проекта

hatch: примеры

  • Создание виртуального окружения:
    •       $ hatch env create
            Creating environment: default
            Installing project in development mode
            Syncing dependencies
  • Пример pyproject.toml для сборки:
    •   [build-system]
        requires = ["hatchling"]
        build-backend = "hatchling.build"
      
        [tool.hatch.build.targets.sdist]
        include = [ "pkg/*.py", ]
        exclude = [ "pkg/_compat.py", ]
      
        [tool.hatch.build.targets.wheel]
        packages = ["src/foo"]
  • Пример автоматизации команд pyproject.toml:
    •   [tool.hatch.envs.test.scripts]
        run-coverage = "pytest --cov-config=pyproject.toml --cov=tests"
        run = "run-coverage --no-cov"
      
        [tool.hatch.envs.style.scripts]
        check = [ "flake8 .", "black --check --diff .", "isort --check-only --diff ." ]
        fmt = [ "isort .", "black .", "check" ]

pixi

  • ✅ Управление версией Python
  • ✅ Виртуальные окружения
  • ✅ Управление пакетами
  • ✅ Управление научными пакетами
  • ✅ Воспроизводимые зависимости
  • ❌ Сборка и публикация пакетов
  • ❌ Сборка и публикация научных пакетов
  • ❌ Единый файл мета данный
  • ✅ Автоматизация выполнения команд
  • ❌ Шаблонизация структуры проекта

pixi: примеры

  • Пример pixi.toml с несколькими окружениями:
    •       [dependencies]
            python = ">=3.12"
            fastapi = ">=0.105.0"
            uvicorn = "*"
            [feature.test.dependencies]
            pytest = "*"
            pytest-md = "*"
            [feature.test.tasks]
            test = "pytest --md=report.md"
            [environments]
            default = {features = ["test"], solve-group = "prod-group"}
            prod = {features = [], solve-group = "prod-group"}
  • Пример автоматизации команд в pixi.toml:
    •       [tasks]
            fmt = "ruff"
            lint = "pylint"
            style = { depends_on = ["fmt", "lint"] }
            run = "python main.py $PIXI_PROJECT_ROOT"
  • Пример цепочки команд, которые выполняются в своем окружении:
    •       [tasks]
            build = { cmd = "quarto render", depends_on = ["build-cs"] } 
            [feature.codestyle.tasks]
            build-cs = "quarto render codestyle/"

rye(uv)

  • ✅ Управление версией Python
  • ✅ Виртуальные окружения
  • ✅ Управление пакетами
  • ❌ Управление научными пакетами
  • ✅ Воспроизводимые зависимости
  • ✅ Сборка и публикация пакетов
  • ❌ Сборка и публикация научных пакетов
  • ✅ Единый файл мета данный
  • ✅ Автоматизация выполнения команд
  • ❌ Шаблонизация структуры проекта

rye: примеры

  • Для того, чтобы зафиксировать или изменить версию Python необходимо выполнить команду:
    •       rye pin <python-version>
  • После чего синхронизировать изменение:
    •       rye sync
  • Пример автоматизации команд в pyproject.toml:
    •   [project.scripts]
        my-hello-script = 'hello:main'
      
        [tool.rye.scripts]
        # These three options are equivalent:
        devserver = "flask run --app ./hello.py --debug"
        devserver-alt = ["flask", "run", "--app", "./hello.py", "--debug"]
        devserver-explicit = { cmd = "flask run --app ./hello.py --debug" }
      
        # Using env vars
        devserver-env = { cmd = "flask run --debug", env = { FLASK_APP = "./hello.py" } }
        devserver-env-file = { cmd = "flask run --debug", env-file = ".dev.env" }
      
        # Chain call
        lint = { chain = ["lint:black", "lint:flake8" ] }
        "lint:black" = "black --check src"
        "lint:flake8" = "flake8 src"

pdm

  • ✅ Управление версией Python
  • ✅ Виртуальные окружения
  • ✅ Управление пакетами
  • ❌ Управление научными пакетами
  • ✅ Воспроизводимые зависимости
  • ✅ Сборка и публикация пакетов
  • ❌ Сборка и публикация научных пакетов
  • ✅ Единый файл мета данный
  • ✅ Автоматизация выполнения команд
  • ✅ Шаблонизация структуры проекта

Выводы

Категория/Инструмент pipenv poetry conda hatch pixi rye(uv) pdm
Управление версией Python
Виртуальные окружения
Управление пакетами
Управление научными пакетами
Воспроизводимые зависимости
Сборка и публикация пакетов
Сборка и публикация научных пакетов
Единый файл мета данный
Автоматизация выполнения команд
Шаблонизация структуры проекта