Skip to content

Absolentia/AnimaDao

Repository files navigation

AnimaDao

ci tagger PyPI version Python License: MIT

AnimaDao is a pragmatic dependency health checker for Python projects.
It compares declared dependencies with actual imports, flags unused ones, and checks pinned specs (==) against the latest PyPI releases.
Works with uv and supports three declaration styles.


One-liner GitHub Action

Use the official composite Action to run AnimaDao in one step.
It writes a Markdown report to the Job Summary, optionally uploads artifacts, and can fail the job on policy violations.

Repo: https://github.com/Absolentia/animadao-action
Recommended pin: uses: Absolentia/animadao-action@v1 (moving major tag).
For full reproducibility you can pin a concrete version, e.g. @v1.0.3.

Minimal usage (declared mode)

- name: AnimaDao (declared)
  uses: Absolentia/animadao-action@v1
  with:
    mode: declared
    # One root is enough for most repos; you can also pass multiple roots (e.g. "anima_dao tests")
    src: "."
    ignore: pip,setuptools,wheel,ruff
    fail-if-outdated: "true"
    max-unused: "0"
    format: md
    artifact-name: anima-report-${{ matrix.python-version }}
    python-version: ${{ matrix.python-version }}

Installed mode (checks currently installed packages; no “unused” check):

- name: AnimaDao (installed)
  uses: Absolentia/animadao-action@v1
  with:
    mode: installed
    fail-if-outdated: "true"
    ignore: pip,setuptools,wheel
    python-version: ${{ matrix.python-version }}

Full example job (with cache + matrix)

jobs:
  anima:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: [ "3.10","3.11","3.12","3.13" ]
    steps:
      - uses: actions/checkout@v4

      # Speed up uv by caching
      - uses: actions/cache@v4
        with:
          path: ~/.cache/uv
          key: uv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}

      - name: AnimaDao (declared)
        uses: Absolentia/animadao-action@v1
        with:
          mode: declared
          src: "."                                  # or: "anima_dao tests"
          ignore: pip,setuptools,wheel,ruff
          fail-if-outdated: "true"
          max-unused: "0"
          format: md
          artifact-name: anima-report-${{ matrix.python-version }}
          python-version: ${{ matrix.python-version }}

Notes & tips

  • Artifacts in matrix: artifact names must be unique per shard (use anima-report-${{ matrix.python-version }}), or merge them later to avoid 409 conflicts.
  • Report visibility: the Action appends the Markdown report to the Job Summary; HTML/JSON are attached as artifacts when upload-artifact: "true".
  • Policies: tune to your process:
    • allow a small number of unused deps: max-unused: "1"
    • ignore dev tools (e.g., ruff, black, mypy, build, twine) via ignore.
  • Multiple source roots: pass them space-separated in src (e.g., src: "anima_dao tests"). The Action expands this into repeated --src flags for the report.
    The gate runs against the project root and policy checks (works out of the box).
  • Pre-release Python: if you run on RC versions (e.g., 3.14-rc), set allow-prereleases: true on your own actions/setup-python step (outside of this Action).

Features

  • 🗂 Multiple sources of declared deps:
    1. pyproject.tomlPEP 621 [project].dependencies
    2. pyproject.tomlPoetry [tool.poetry.dependencies]
    3. requirements.txt (incl. nested -r includes)
  • 🔍 Import scan: walks your source tree and extracts top-level imports (AST).
  • 🧹 Unused deps: declared but not imported (heuristic, import-name ≈ normalized dist name).
  • Outdated pins: checks only ==-pinned requirements against PyPI latest.
  • ⚙️ Two modes: --mode declared (default) and --mode installed.
  • 🚫 Ignore lists: skip tool packages (e.g. pip, setuptools, wheel) or any custom names.
  • 🧩 Config file: project-level .animadao.toml with sane defaults and CLI overrides.
  • 🗃️ PyPI cache: TTL + ETag with configurable concurrency for faster checks.
  • 📄 Reports: --format json | md | html.

Requirements

  • Python 3.10+
  • uv (modern Python package/dependency manager)

Installation

With uv

pip install uv
uv pip install anima-dao

With pip

pip install anima-dao

From sources

  1. Clone:
git clone https://github.com/Absolentia/AnimaDao.git
cd AnimaDao
  1. Install uv:
pip install --upgrade pip
pip install uv
  1. Create a virtual env:
uv venv
  1. Install project deps:
uv sync

Configuration

Create .animadao.toml in your project root (optional):

[core]
mode = "declared"          # declared | installed
src = ["src", "app"]       # optional, source roots for import scan

# PyPI cache / concurrency
pypi_ttl_seconds = 86400   # default: 24h
pypi_concurrency = 8       # default: 8 parallel requests

[ignore]
distributions = ["pip", "setuptools", "wheel"]
imports = []

CLI flags always override config values.


Usage (CLI)

All commands accept a project root (where either pyproject.toml or requirements.txt resides) and an optional source root to scan imports.

Scan: declared vs imports

uv run animadao scan --project . --src src

Check against PyPI

Declared dependencies (default mode):

uv run animadao check --project . --mode declared --ignore pip --ignore setuptools

Installed packages in the current venv:

uv run animadao check --project . --mode installed --pypi-ttl 43200 --pypi-concurrency 16

Find unused deps (declared but not imported)

uv run animadao unused --project . --src src --ignore pip --ignore wheel

Generate report

JSON:

uv run animadao report --project . --src src --out report.json --format json

Markdown:

uv run animadao report --project . --src src --out report.md --format md

HTML:

uv run animadao report --project . --src src --out report.html --format html

Example report.json:

{
  "summary": {
    "declared": 12,
    "imports_found": 34,
    "outdated": 2,
    "unpinned": 7,
    "unused": 3
  },
  "outdated": [
    {
      "name": "requests",
      "current": "2.31.0",
      "latest": "2.32.3"
    }
  ],
  "unpinned": [
    {
      "name": "numpy",
      "spec": ">=1.26"
    }
  ],
  "unused": [
    "rich",
    "typer"
  ],
  "imports": [
    "requests",
    "json",
    "..."
  ],
  "mode": "declared"
}

Supported dependency sources & priority

When resolving declared dependencies, AnimaDao uses the first matching source:

  1. pyproject.tomlPEP 621 [project].dependencies (+ [project.optional-dependencies] merged)
  2. pyproject.tomlPoetry [tool.poetry.dependencies]
    • python = "^3.10" is ignored
    • Exact versions become name==X.Y.Z
    • Caret ^ ranges are converted to PEP 440 intervals (best-effort)
    • Poetry dev/group deps are not included
  3. requirements.txt — plain lines + nested includes via -r / --requirement

Only the first detected source is used to avoid mixing ecosystems.


How it works (quick notes)

  • Import mapping: compares normalized distribution names (-_) with top-level imports. Known alias: beautifulsoup4bs4.
  • Modes:
    • declared: checks only == pins from declarations; non-pinned specs appear under unpinned.
    • installed: checks versions of packages currently installed in the environment.
  • Networking: PyPI queries via httpx with timeouts, using a TTL/ETag cache; failures fall back to cached data.

CI & Releases

  • CI (ci.yml): runs pytest with uv on every push/PR to main (matrix: Python 3.10–3.13).
  • Tagger (tag.yml): manual tagging vX.Y.Z.
  • Publish: recommended trigger by tag v* or via workflow_run after tagger.

Create a release:

# bump version in pyproject.toml
git commit -am "chore: bump version to 0.1.1"
git tag -a v0.1.1 -m "v0.1.1"
git push origin v0.1.1

Support matrix

  • Python: 3.10 / 3.11 / 3.12 / 3.13
  • OS: Linux, macOS, Windows
  • Packaging: PEP 621 (project), Poetry, requirements.txt
  • Manager: uv (install & run)

Troubleshooting

  • No module named build
    uv pip install build twine or uv sync --extra dev.

  • Hatch: “Unable to determine which files to ship”
    Ensure package directory exists and add to pyproject.toml:

    [tool.hatch.build.targets.wheel]
    packages = ["anima_dao"]
  • Publish doesn’t start after tagger
    Events from GITHUB_TOKEN don’t trigger other workflows. Push tag with a PAT or use workflow_run trigger.

  • 403 after moving repo to org
    Update remote: git remote set-url origin git@github.com:<ORG>/AnimaDao.git and check org permissions/SSO.


Contributing

pip install uv
uv sync --extra dev
uv run pytest -vvvv

Please keep type hints (3.10+), docstrings and comments in English, and add tests for new loaders/edge cases.

pre-commit

  1. Add AnimaDao hooks to .pre-commit-config.yaml:
repos:
  - repo: https://github.com/Absolentia/AnimaDao
    rev: v0.1.2        # <-- use the latest tag
    hooks:
      - id: animadao-check
        args: [ --ignore, pip, --ignore, setuptools ]
        files: '^(pyproject.toml|requirements.*txt|.*\.py)$'
      - id: animadao-report
        stages: [ manual ]  # optional: run on-demand via `pre-commit run -a animadao-report`
  1. Install and run:
pip install pre-commit
pre-commit install
pre-commit run -a

Policy examples:

  • Fail on outdated pins only:
    - id: animadao-check
      args: [--mode, declared, --fail-if-outdated]
  • Strict mode (declared): no outdated, no unpinned, no unused:
    - id: animadao-check
      args: [--mode, declared, --fail-if-outdated, --fail-if-unpinned, --max-unused, "0"]
  • Installed mode (CI on lockstep env):
    - id: animadao-check-installed
      args: [--fail-if-outdated]

About

AnimaDao is a pragmatic dependency health checker for Python projects.

Topics

Resources

License

Stars

Watchers

Forks