Skip to main content

Enforce proper dependency declaration in shared Python environments

Project description

Depyty

/ˈdɛpaɪti/ as in the english word "deputy", but for Python dependencies.

Enforce proper dependency declaration in shared Python environments.

Usage

Install the package using

uv add --dev depyty

then run it via

uv run depyty "packages/*"

You can pass glob.glob strings that lead to all pyproject.toml files in your repository that you want to check. Note the use of "s to prevent your shell from expanding the references.

Example

Given the following pyproject.toml file

name = "my-awesome-api"
version = "1.2.3"
dependencies = ["fastapi"]

from fastapi import FastAPI

✅ This is fine, we explicitly declared this module as a dependency


import pandas as pd

❌ This will very likely fail at runtime. We have not declared a dependency on pandas in our pyproject.toml file.


from pydantic import BaseModel

⚠️ This is also not allowed, even though it will likely not crash at runtime. Pydantic will be installed, as it is a dependency of fastapi. However, since you imported it in your code, you'll likely also depend on Pydantics API. If they decide to publish a breaking change, and FastAPI increments their minimum Pydantic version to the new one, your code can easily break. By explicitly declaring a version and dependency upon pydantic in your pyproject.toml, you are in full control.

Motivation

Tools like uv make it very convenient to create monorepos.

Scenario

Imagine this hypothetical scenario, where our main application is a REST API, and we have a few lambdas that do auxiliary tasks. All of them live in a shared monorepo:

depyty-demo-api
├── lambdas
│   ├── cleanup-old-db-entries-lambda
│   │   ├── main.py
│   │   └── pyproject.toml
│   └── data-warehouse-export-lambda
│       ├── main.py
│       └── pyproject.toml
├── packages
│   └── demo-database-models
│       ├── pyproject.toml
│       └── src
│           └── demo_database_models
│               ├── __init__.py
│               └── py.typed
├── pyproject.toml
└── src
    └── depyty_demo_api
        ├── __init__.py
        └── api.py

The lambdas may execute tasks like cleaning up database tables, or exporting them to S3. They contain dependencies (e.g. boto3 to interact with S3), that are not needed in your main application, so you declare them separately. At the same time, they share code with your main application, e.g. the database models.

The pyproject.toml files would then look like this for the main application

# pyproject.toml
name = "depyty-demo-api"
dependencies = [
    "demo-database-models",
    "fastapi>=0.115.12",
]

[dependency-groups]
dev = ["pytest>=8.3.5"]

[tool.uv.workspace]
members = ["packages/*", "lambdas/*"]

[tool.uv.sources]
demo-database-models = { workspace = true }

and like this for a lambda

# lambdas/data-warehouse-export-lambda/pyproject.toml
[project]
name = "data-warehouse-export-lambda"
dependencies = [
    "boto3>=1.37.23",
    "demo-database-models",
]

[tool.uv.sources]
demo-database-models = { workspace = true }

Again, we don't want to inlcude boto3 in our main application, so during deployment we run

uv sync

for our main application and

uv sync --package data-warehouse-export-lambda

for the exporter lambda.

Problem

Imagine you add a new feature, which you decide to develop in a new library under packages/my-new-utility-package, since it contains very generic functionality. Once its done, you run uv add at the project root and integrate it into the main application.

The next day, your intuition turns out to be right, and you need the functionality in one of the lambdas. You immediately adjust the source code, your IDE happily autocompletes everything. You also write unit tests, run pytest, and everything works like a charm. Then you push everything, and everything fails ✨spectacularly✨.

Turns out you did not run uv add my-new-utility-package for your lambda, so it was never included as a dependency in its pyproject.toml. Since you use uv sync --all-packages during local development, the dependencies of all packages are available locally. But during deployment, you only install everything listed in each pyproject.toml.

Solution

This is exactly what depyty solves. It analyzes the packages available in the current environment, and checks the source files of each provided package, that it only imports modules that are also declared in its pyproject.toml. To prevent an error like this, we'd just need to add

uv run depyty "lambdas/*" "."

to our CI and we should not get nasty surprises when deploying the next time. At least not due to unspecified dependencies.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

depyty-0.2.0.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

depyty-0.2.0-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

File details

Details for the file depyty-0.2.0.tar.gz.

File metadata

  • Download URL: depyty-0.2.0.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.12

File hashes

Hashes for depyty-0.2.0.tar.gz
Algorithm Hash digest
SHA256 bea56fec94bb89a582c12bf42287337a6f6dec1b034f30e59fcbef8084969de9
MD5 fe382509f733381b69acb555e54da429
BLAKE2b-256 0352785c15d6ecf69eff4c3d89635bc91b94dbbe4e3353312026c3e97f508941

See more details on using hashes here.

File details

Details for the file depyty-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: depyty-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 18.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.12

File hashes

Hashes for depyty-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 009326a9a294f99fcf618070dec7247c3077a2f55068cb0a8f656b23bae7e2a9
MD5 e36ac6d1266897ba16cb784c8f3353a6
BLAKE2b-256 3b61c80816f46307f0e955443a24367ecc587f1f7ed534fccdd6fed013f437ec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page