Framework for Python

Features

Packages

Managing a project's Python packages with pyproject.toml and uv

Overview

A Python project lists its packages in pyproject.toml, and uv locks the exact versions in uv.lock. Framework follows these Python conventions. The package_add() and packages_*() functions call uv, so you can manage packages from a notebook or from the terminal with the same result.

New projects start with one dependency.

[project]
name = "vaccine-study"
version = "0.1.0"
description = "Vaccine Study"
requires-python = ">=3.11"
dependencies = [
    "framework-py",
]

[tool.uv]
package = false

package = false tells uv that the project is an analysis and not a library to build.

Commit pyproject.toml and uv.lock. A collaborator who clones the project installs the same versions with uv sync or bootstrap().

Adding Packages

package_add() adds a requirement to pyproject.toml, updates uv.lock, and installs the package. It runs uv add in the project root.

import framework as fw

fw.package_add("statsmodels")
fw.package_add("seaborn>=0.13")

The install=False argument updates pyproject.toml and uv.lock without installing. The dev=True argument adds the package to the dev dependency group, for tools such as pytest that the analysis itself does not need.

fw.package_add("pytest", dev=True)

The terminal command is equivalent.

uv add statsmodels

A requirement can pin a version or point at a git repository, using the standard Python requirement syntax.

fw.package_add("pandas==2.2.3")
fw.package_add("mytools @ git+https://github.com/example/mytools@v1.2")

Quarto runs the Python chunks of .qmd notebooks through Jupyter, so projects that render notebooks need it in their environment.

fw.package_add("jupyter")

Listing and Checking

packages_list() returns the dependencies in pyproject.toml with the version installed in the running environment.

fw.packages_list()

packages_status() checks whether uv.lock matches pyproject.toml and whether the environment matches uv.lock. It prints a short report and returns a PackagesStatus whose ok attribute is True when everything matches.

status = fw.packages_status()
status.ok
status.missing

Installing, Locking, and Updating

These functions wrap uv commands and run them in the project root.

Function uv command Effect
packages_install() uv sync Installs the dependencies
packages_snapshot() uv lock Records the resolved versions in uv.lock
packages_restore() uv sync --frozen Installs exactly the versions in uv.lock
packages_update() uv lock --upgrade and uv sync Upgrades all locked versions, or only the named packages
fw.packages_update(["pandas", "statsmodels"])

Without uv

uv is the supported tool. When it is not installed, package_add() edits the dependencies list in pyproject.toml as text and installs the package with pip into the running environment. packages_install() installs the listed dependencies with pip. Locking, restoring, updating, and dev dependencies need uv and raise an error that says how to install it.

Packages in Notebooks

Run notebooks with the project's environment, so that the packages in uv.lock are the ones imported. In VS Code and Positron, select the project's .venv interpreter. The workspace file Framework creates points at .venv/bin/python. From the terminal, prefix commands with uv run.

uv run quarto render notebooks/exploration.qmd

Differences from R

The R package lists packages in a packages section of the settings and uses renv for locking. Python projects use pyproject.toml and uv.lock instead, and scaffold() does not import or attach packages. Each notebook imports what it uses.