Skip to content

Consider using uv for Python dependency management #149

@danielbowne

Description

@danielbowne

Problem

Building emdash requires Python for node-gyp to compile native modules (sqlite3, node-pty, keytar). The current setup has friction points:

  1. Inconsistent Python detection: Users with pyenv or multiple Python installations hit errors like "Python is not set from command line or npm configuration"
  2. Manual configuration: Developers must manually set PYTHON=/usr/bin/python3 or configure npm globally
  3. CI maintenance: Each CI job must install and configure Python separately (see lines 46-54 in release.yml)
  4. Onboarding friction: New contributors on different systems (Windows/Linux/macOS) have unpredictable Python setup experiences

Proposed Solution: Use uv

uv is a Python package and project manager written in Rust. It solves the Python environment problem elegantly:

  • Reads .python-version or pyproject.toml to pin Python version
  • Auto-installs the specified Python version if missing
  • Overrides system Python for the project, eliminating conflicts
  • Works identically across Windows, Linux, macOS
  • 10-100x faster than pip for CI builds

Implementation

  1. Add uv to the bootstrap process:

    # For Linux/macOS
    curl -LsSf https://astral.sh/uv/install.sh | sh
    
    # For Windows (Powershell)
    powershell -ExecutionPolicy BypassUser -c "irm https://astral.sh/uv/install.ps1 | iex"
  2. Create .python-version:

    3.11.0
    
  3. Update release.yml:

    - name: Install uv
      uses: astral-sh/setup-uv@v2
      with:
        version: "0.4.x"
    
    - name: Set up Python
      run: uv python install
    
    - name: Install dependencies
      run: uv pip install -r requirements.txt
  4. Create requirements.txt (minimal, just for node-gyp):

    setuptools>=67.0
    wheel
    
  5. Update local development docs to mention uv as the recommended Python setup.

Benefits

  • Single source of truth for Python version (.python-version)
  • Eliminates npm config set python workarounds
  • CI becomes faster and more reliable
  • New contributors have a consistent experience
  • Aligns with industry trends (uv is adopted by major projects: Ruff, Astral tools, etc.)

Industry Adoption

Major projects have adopted uv for Python management:

  • Ruff (Python linter)
  • Anthropic's various Python projects
  • Increasing adoption in JavaScript/Electron projects that need Python build tools

Backwards Compatibility

This is additive and transparent:

  • Developers who already have Python set up won't see changes
  • Developers without Python get a clear setup path
  • CI becomes more deterministic

Questions for Discussion

  1. Should we pin Python 3.11 (current CI version) or allow flexibility?
  2. Do we want to manage additional Python dependencies beyond node-gyp, or keep it minimal?
  3. Should this be documented in CONTRIBUTING.md alongside other setup instructions?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions