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 (when published)

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/update the OSV vulnerability database
  • --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)

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.1.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.1.0
File Size Uploaded
dependency_update_metrics-0.1.0.tar.gz 98.8 kB Details

Built distribution (wheel)

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

Total release size: 166.1 kB

Release files / dependency_update_metrics-0.1.0.tar.gz

Download URL dependency_update_metrics-0.1.0.tar.gz
Size 98.8 kB
Tags Source
SHA-256 checksum
How to use checksums
797b3ff1efeffd19d7f11243e0b9777bef50c03daca3c3cbd752b4cc05d76172
BLAKE2b-256 checksum
How to use checksums
1a0682f4b3f7dfbec216135dc2a79d8928448795df5e578359034a9717e10ab2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 18, 2026.

Transparency log

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

Download URL dependency_update_metrics-0.1.0-py3-none-any.whl
Size 67.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
af4d639c50a875c7092f16796ba052abc52f866c2bc33a46bf6d79510212c384
BLAKE2b-256 checksum
How to use checksums
08384ebe880db1a78b3de921f7db870a350d04013b35f7b01caf106176fbdebe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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