Skip to main content

Dependency Update Metrics

A Python tool for analyzing time-to-update (TTU) and time-to-remediate (TTR) metrics for package dependencies across different ecosystems (npm, PyPI, Cargo/crates.io).

Features

  • Multi-ecosystem support: Analyze packages from npm, PyPI, and Cargo/crates.io
  • Time-to-Update (TTU): Measure how long dependencies stay behind the latest version
  • Time-to-Remediate (TTR): Measure how long known vulnerabilities remain unpatched
  • Flexible weighting: Support for linear, exponential, inverse, or no weighting
  • OSV integration: Uses the Open Source Vulnerabilities database for security analysis
  • Export capabilities: Export detailed worksheets and OSV data

Installation

From PyPI

pip install dependency-update-metrics

From source

git clone https://github.com/imranur-rahman/dependency-update-metrics.git
cd dependency-update-metrics
pip install -e .

Usage

As a command-line tool

# Basic usage
dependency-metrics --ecosystem npm --package express

# With date range
dependency-metrics --ecosystem npm --package express \
  --start-date 2020-01-01 \
  --end-date 2023-12-31

# With exponential weighting
dependency-metrics --ecosystem npm --package express \
  --weighting-type exponential \
  --half-life 180

# Build OSV database first (one-time operation)
dependency-metrics --ecosystem npm --package express --build-osv

# Export detailed worksheets
dependency-metrics --ecosystem npm --package express --get-worksheets

# Get OSV vulnerability data
dependency-metrics --ecosystem npm --package express --get-osv

# Test a PyPI package
dependency-metrics --ecosystem pypi --package requests --start-date 2020-01-01 --end-date 2021-01-01 --get-worksheets

# Test a Cargo/crates.io package
dependency-metrics --ecosystem cargo --package serde --start-date 2020-01-01 --end-date 2024-01-01

# Bulk CSV input (parallel by default)
dependency-metrics --input-csv ./input.csv --workers 8 --output-dir ./output

# Resume an interrupted bulk run
dependency-metrics --input-csv ./input.csv --output-dir ./output --resume

# Per-release analysis: MTTU/MTTR at every release of the parent package
dependency-metrics --ecosystem pypi --package requests \
  --start-date 2020-01-01 --end-date 2021-01-01 \
  --per-release --get-worksheets

# Per-release in bulk CSV mode
dependency-metrics --input-csv ./input.csv --per-release --workers 4

Input CSV columns: ecosystem, package_name, optional start_date, optional end_date. Accepted ecosystem values are npm, pypi, cargo, and crates.io; crates.io is normalized to cargo in outputs. If end_date is omitted, the CLI --end-date value is used; when --end-date is also omitted, it defaults to today. Extra columns are allowed; duplicates are removed by ecosystem, package_name, end_date. Bulk mode computes metrics per package using the latest dependency set.

As a Python module

from datetime import datetime
from pathlib import Path
from dependency_metrics.analyzer import DependencyAnalyzer

# Create analyzer
analyzer = DependencyAnalyzer(
    ecosystem="npm",
    package="express",
    start_date=datetime(2020, 1, 1),
    end_date=datetime(2023, 12, 31),
    weighting_type="exponential",
    half_life=180,
    output_dir=Path("./output")
)

# Run analysis
results = analyzer.analyze()

print(f"Average TTU: {results['ttu']:.2f} days")
print(f"Average TTR: {results['ttr']:.2f} days")

Command-line Arguments

  • --ecosystem: Ecosystem to analyze (npm, pypi, cargo, or crates.io) [Required unless --input-csv]
  • --package: Package name to analyze [Required unless --input-csv]
  • --input-csv: CSV file with columns ecosystem, package_name, optional start_date, and optional end_date. If end_date is omitted, --end-date is used.
  • --start-date: Start date for analysis (YYYY-MM-DD) [Default: 1900-01-01]
  • --end-date: End date for analysis (YYYY-MM-DD) [Default: today]
  • --weighting-type: Weighting method (linear, exponential, inverse, disable) [Default: disable]
  • --half-life: Half-life in days (required for exponential weighting)
  • --build-osv: Build or rebuild the OSV vulnerability database. It downloads the npm, PyPI, and crates.io OSV zips (about 260 MB in total). Without --package, it only rebuilds the database.
  • --osv-index-date: Print the build date of the OSV database as JSON (null when there is no database), then exit
  • --cache-stats: Show the rows and the size of each namespace in the resolver cache (<output-dir>/cache/cache.db), then exit
  • --cache-prune-gb N: Remove the least recently used cache rows until the cache holds less than N GB of data, then exit. The prune does not run VACUUM, so the file does not shrink; SQLite reuses the freed pages
  • --cache-clear: Remove all cache rows, then exit
  • --cache-namespace X: With --cache-clear, remove only the rows of namespace X
  • --get-osv: Export OSV data for the package's dependencies
  • --get-worksheets: Export detailed analysis worksheets to Excel
  • --output-dir: Output directory for results [Default: ./output]
  • --workers: Number of parallel workers for bulk CSV mode [Default: min(8, CPU count)]
  • --package-timeout: Per-package analysis timeout in seconds (bulk CSV mode only). Packages that exceed this time receive an error row and are skipped [Default: disabled]
  • --resume: Resume bulk CSV runs by skipping completed rows and retrying errors
  • --per-release: Compute MTTU/MTTR at every release of the parent package within the window (one output row per release)
  • --json: Print the result as one JSON object on stdout, in the result shape of the Host API (needs --package; see USAGE.md)

Weighting Methods

Disable (default)

No weighting applied. All time periods are weighted equally.

Linear

Weight decreases linearly with age:

weight = 1 - (age / max_age)

Exponential

Weight decreases exponentially based on half-life:

weight = exp(-λ * age)
where λ = ln(2) / half_life

Inverse

Weight is inversely proportional to age:

weight = 1 / (1 + age)

Output

The tool generates several outputs in the specified output directory:

  1. JSON results file: Contains TTU, TTR, and metadata
  2. OSV data (with --get-osv): CSV file with vulnerability information
  3. Excel worksheets (with --get-worksheets): Detailed analysis for each dependency
  4. Bulk CSV results (with --input-csv): Summary CSV, plus an optional dependency details CSV with --write-dependency-details
  5. Per-release results (with --per-release): One row per package release with package_version, package_release_date, window_start, window_end, mttu, mttr

Example JSON output

{
  "package": "express",
  "ecosystem": "npm",
  "version": "4.18.2",
  "start_date": "2020-01-01T00:00:00",
  "end_date": "2023-12-31T00:00:00",
  "weighting_type": "exponential",
  "half_life": 180,
  "ttu": 45.32,
  "ttr": 12.15,
  "num_dependencies": 30
}

How It Works

  1. Package Analysis: Fetches package metadata from the registry
  2. Dependency Extraction: Extracts dependencies from the package version closest to the end date
  3. Timeline Construction: Creates a timeline of version releases for each dependency
  4. Version Resolution: Resolves dependency versions at each time interval via ecosystem resolvers
  5. Remediation Check: Uses the OSV service to determine vulnerability remediation
  6. Metric Calculation:
    • TTU: Measures time when dependency is not at the highest available version
    • TTR: Measures time when dependency has known vulnerabilities
  7. Weighting: Applies optional time-based weighting to prioritize recent periods
  8. Aggregation: Averages metrics across all dependencies

Architecture Notes

  • Ecosystem-specific resolution is encapsulated in dependency_metrics/resolvers.py.
  • OSV remediation checks are handled by dependency_metrics/osv_service.py.
  • Reporting/export helpers live in dependency_metrics/reporting.py.
  • Bulk CSV mode groups rows by (ecosystem, package_name) and processes each group sequentially while running groups in parallel to maximize cache reuse.
  • For bulk runs, a single package analysis computes metrics across multiple end dates using the latest dependency set.
  • --per-release mode uses analyze_at_release_points() which fetches per-version dependency sets and builds a shared dep-cache covering the full window; it slices that cache for each release sub-window [start_date, release_date].
  • Cache invalidation: ResolverCache (dependency_metrics/resolvers.py) persists all HTTP responses to a SQLite file at <output-dir>/cache/cache.db, keyed only by (namespace, key) — there is no TTL. This is fine for per-version data (a specific version's dependencies/metadata never changes), but package-level version-list lookups (DepsDevClient.get_package()'s depsdev_package namespace, and each resolver's fetch_package_metadata()/_get_npm_time_data() under the metadata/npm_time namespaces) cache the entire, mutable version list. Those lookups compare the requested end_date against the newest publish date already in the cached listing and transparently re-fetch whenever the cache can't yet rule out a newer release — so re-running against the same --output-dir won't silently miss versions published since the last run. The tradeoff: analyzing "as of today" re-fetches each package's version list on every run (since "today" is always newer than the last known release), which is the correct behavior — only truly historical, fixed end_date values benefit from the cache staying warm across runs.

Requirements

  • Python 3.10+
  • git (for auto-installing the patched pip on first PyPI analysis)
  • npm CLI (for npm ecosystem analysis) sudo apt install nodejs npm
  • Internet connection (for fetching package metadata and OSV data)

Note: PyPI analysis uses a patched pip fork that adds date-bounded version resolution. The tool clones it automatically to ~/.dependency_metrics/vendor/pip on first use — no manual setup required.

Development

Setup development environment

git clone https://github.com/imranur-rahman/dependency-update-metrics.git
cd dependency-update-metrics
pip install -e ".[dev]"

Run tests

pytest

Code formatting

black dependency_metrics/

Publishing to PyPI

Prepare for publishing

# Install build tools
pip install build twine

# Build distribution
python -m build

# Check distribution
twine check dist/*

Upload to PyPI

# Upload to Test PyPI first
twine upload --repository testpypi dist/*

# If all looks good, upload to PyPI
twine upload dist/*

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Citation

If you use this tool in your research, please cite:

@software{dependency_metrics,
  author = {Rahman, Imranur},
  title = {Dependency Update Metrics},
  year = {2025},
  url = {https://github.com/imranur-rahman/dependency-update-metrics}
}

Acknowledgments

Metadata

Release files for dependency-update-metrics 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dependency-update-metrics 0.2.0
File Size Uploaded Provenance
dependency_update_metrics-0.2.0.tar.gz 119.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dependency-update-metrics 0.2.0
File Interpreter ABI Platform
dependency_update_metrics-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 196.4 kB

Release files / dependency_update_metrics-0.2.0.tar.gz

Download URL dependency_update_metrics-0.2.0.tar.gz
Size 119.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0f032314790acb72999db6db92990f2f9a2e551d1041141a962be1b5c8137ba5
BLAKE2b-256 checksum
How to use checksums
804d928370ca2ed8ab5bdee8222b139e849cf982afcd9fef8ac4fb8d784a1397
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Release files / dependency_update_metrics-0.2.0-py3-none-any.whl

Download URL dependency_update_metrics-0.2.0-py3-none-any.whl
Size 77.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
699b8d32e3e94a04992882a8fe523688cfee23c64ba3202e46acab484077d96e
BLAKE2b-256 checksum
How to use checksums
95571a796aceca69b1975fb7791211cec9f285f3be9dbc7dcf52a54c70adb71d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

Security for dependency-update-metrics 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for dependency_update_metrics-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page