A tool for scanning Python environments for known vulnerabilities
—
Core data structures representing dependencies, vulnerabilities, and related information used throughout the pip-audit API.
Base classes representing Python packages and their states.
@dataclass(frozen=True)
class Dependency:
"""
Represents an abstract Python package.
This class cannot be constructed directly.
"""
name: str
"""
The package's uncanonicalized name.
Use the canonical_name property when a canonicalized form is necessary.
"""
@property
def canonical_name(self) -> str:
"""
The Dependency's PEP-503 canonicalized name.
Returns:
Canonicalized package name according to PEP-503
"""
def is_skipped(self) -> bool:
"""
Check whether the Dependency was skipped by the audit.
Returns:
True if this is a SkippedDependency, False otherwise
"""Represents a fully resolved Python package with a specific version.
@dataclass(frozen=True)
class ResolvedDependency(Dependency):
"""
Represents a fully resolved Python package.
"""
version: Version
"""
The resolved version of the package.
"""Represents a Python package that was unable to be audited.
@dataclass(frozen=True)
class SkippedDependency(Dependency):
"""
Represents a Python package that was unable to be audited and therefore, skipped.
"""
skip_reason: str
"""
The reason why this package was skipped during audit.
"""Represents vulnerability information for a package.
@dataclass(frozen=True)
class VulnerabilityResult:
"""
Represents a vulnerability result from a vulnerability service.
"""
id: VulnerabilityID
"""
A service-provided identifier for the vulnerability.
"""
description: str
"""
A human-readable description of the vulnerability.
"""
fix_versions: list[Version]
"""
A list of versions that can be upgraded to that resolve the vulnerability.
"""
aliases: set[str]
"""
A set of aliases (alternative identifiers) for this result.
"""
published: datetime | None = None
"""
When the vulnerability was first published.
"""
def alias_of(self, other: VulnerabilityResult) -> bool:
"""
Returns whether this result is an alias of another result.
Two results are aliases if their respective sets of {id, *aliases} intersect.
Parameters:
- other: VulnerabilityResult, the other result to compare
Returns:
True if this result is an alias of the other result
"""
def merge_aliases(self, other: VulnerabilityResult) -> VulnerabilityResult:
"""
Merge other's aliases into this result, returning a new result.
Parameters:
- other: VulnerabilityResult, the result to merge aliases from
Returns:
New VulnerabilityResult with merged aliases
"""
def has_any_id(self, ids: set[str]) -> bool:
"""
Returns whether ids intersects with {id} | aliases.
Parameters:
- ids: set[str], set of IDs to check
Returns:
True if any of the IDs match this result's ID or aliases
"""Type definitions used throughout the API.
VulnerabilityID = NewType("VulnerabilityID", str)
"""
Type alias for vulnerability identifiers.
"""from pip_audit._service.interface import ResolvedDependency, SkippedDependency
from packaging.version import Version
# Create a resolved dependency
dependency = ResolvedDependency(name="requests", version=Version("2.28.0"))
print(f"Package: {dependency.name}")
print(f"Canonical: {dependency.canonical_name}")
print(f"Version: {dependency.version}")
print(f"Is skipped: {dependency.is_skipped()}")
# Create a skipped dependency
skipped = SkippedDependency(name="broken-package", skip_reason="Invalid version format")
print(f"Skipped: {skipped.name} - {skipped.skip_reason}")
print(f"Is skipped: {skipped.is_skipped()}")from pip_audit._service.interface import VulnerabilityResult, VulnerabilityID
from packaging.version import Version
from datetime import datetime
# Create vulnerability result
vuln = VulnerabilityResult(
id=VulnerabilityID("GHSA-xxxx-yyyy-zzzz"),
description="Cross-site scripting vulnerability in user input handling",
fix_versions=[Version("2.28.1"), Version("2.29.0")],
aliases={"CVE-2022-12345", "SNYK-PYTHON-REQUESTS-12345"}
)
print(f"Vulnerability ID: {vuln.id}")
print(f"Description: {vuln.description}")
print(f"Fix versions: {[str(v) for v in vuln.fix_versions]}")
print(f"Aliases: {vuln.aliases}")from pip_audit._service.interface import ResolvedDependency, SkippedDependency
def filter_resolved_dependencies(dependencies):
"""Filter out skipped dependencies and return only resolved ones."""
resolved = []
skipped = []
for dep in dependencies:
if dep.is_skipped():
skipped.append(dep)
else:
resolved.append(dep)
return resolved, skipped
# Example usage
dependencies = [
ResolvedDependency(name="requests", version=Version("2.28.0")),
SkippedDependency(name="broken-pkg", skip_reason="Parse error"),
ResolvedDependency(name="flask", version=Version("2.0.0")),
]
resolved, skipped = filter_resolved_dependencies(dependencies)
print(f"Resolved: {len(resolved)}, Skipped: {len(skipped)}")from pip_audit._service.interface import ResolvedDependency
from packaging.version import Version
# Demonstrate canonical name handling
packages = [
ResolvedDependency(name="Django", version=Version("4.0.0")),
ResolvedDependency(name="PILLOW", version=Version("9.0.0")),
ResolvedDependency(name="beautifulsoup4", version=Version("4.10.0")),
]
for pkg in packages:
print(f"Original: {pkg.name}")
print(f"Canonical: {pkg.canonical_name}")
print("---")Install with Tessl CLI
npx tessl i tessl/pypi-pip-audit