A tool for compliance with the REUSE recommendations for software licensing and copyright management.
—
The REUSE project management system provides core functionality for discovering, configuring, and analyzing projects for REUSE compliance. The central Project class manages project root detection, file discovery, and metadata extraction.
Create and configure Project instances for REUSE analysis.
class Project:
"""
Central class holding project root and configuration.
Attributes:
root: Path - Project root directory
include_submodules: bool - Whether to include VCS submodules
include_meson_subprojects: bool - Whether to include Meson subprojects
vcs_strategy: VCSStrategy - VCS strategy for the project
global_licensing: Optional[GlobalLicensing] - Global licensing configuration
license_map: dict[str, dict] - License mapping
licenses: dict[str, Path] - License files mapping
licenses_without_extension: dict[str, Path] - License files without extensions
"""
@classmethod
def from_directory(
cls,
root: Path,
include_submodules: bool = False,
include_meson_subprojects: bool = False
) -> Project:
"""
Factory method to create Project from directory.
Args:
root: Project root directory path
include_submodules: Include VCS submodules in analysis
include_meson_subprojects: Include Meson subprojects in analysis
Returns:
Project instance configured for the directory
Raises:
FileNotFoundError: If root directory doesn't exist
"""Usage Examples:
from reuse.project import Project
from pathlib import Path
# Create project from current directory
project = Project.from_directory(Path.cwd())
# Create project with submodules included
project = Project.from_directory(
Path("/path/to/project"),
include_submodules=True
)
# Create project with all options
project = Project.from_directory(
Path("/path/to/project"),
include_submodules=True,
include_meson_subprojects=True
)Discover and iterate over project files with intelligent filtering.
def all_files(self, directory: Optional[Path] = None) -> Iterator[Path]:
"""
Iterator over all files in project.
Args:
directory: Optional directory to limit search (default: project root)
Yields:
Path: File paths within the project
Note:
Respects VCS ignore patterns and project configuration for submodules
and subprojects. Files are yielded in a deterministic order.
"""Usage Examples:
# Iterate over all project files
for file_path in project.all_files():
print(f"Processing: {file_path}")
# Iterate over files in specific directory
src_dir = project.root / "src"
for file_path in project.all_files(src_dir):
print(f"Source file: {file_path}")
# Count total files
total_files = sum(1 for _ in project.all_files())
print(f"Total files: {total_files}")Extract REUSE licensing and copyright information from project files.
def reuse_info_of(self, path: Path) -> list[ReuseInfo]:
"""
Get REUSE info for a specific file.
Args:
path: File path to analyze (absolute or relative to project root)
Returns:
List of ReuseInfo objects containing licensing and copyright data
Note:
Checks multiple sources: file headers, .license files, global
licensing files (.reuse/dep5, REUSE.toml), and license directories.
Returns empty list if no REUSE information is found.
"""Usage Examples:
# Get REUSE info for a single file
file_path = Path("src/example.py")
reuse_info = project.reuse_info_of(file_path)
for info in reuse_info:
print(f"Source: {info.source_type}")
print(f"Licenses: {info.spdx_expressions}")
print(f"Copyright: {info.copyright_lines}")
print(f"Contributors: {info.contributor_lines}")
# Check if file has REUSE information
has_info = any(info.contains_info() for info in reuse_info)
print(f"Has REUSE info: {has_info}")
# Get copyright and licensing status
has_both = any(info.contains_copyright_or_licensing() for info in reuse_info)
has_one = any(info.contains_copyright_xor_licensing() for info in reuse_info)Utility methods for path manipulation within projects.
def relative_from_root(self, path: Path) -> Path:
"""
Convert path to relative from project root.
Args:
path: Absolute or relative path
Returns:
Path relative to project root
Raises:
ValueError: If path is not within project
"""Usage Examples:
# Convert absolute path to relative
abs_path = Path("/full/path/to/project/src/file.py")
rel_path = project.relative_from_root(abs_path)
print(rel_path) # src/file.py
# Works with paths already relative to project
rel_path = project.relative_from_root(Path("src/file.py"))
print(rel_path) # src/file.pyDiscover and access global licensing configuration files.
class GlobalLicensingFound(NamedTuple):
"""
Result of global licensing file discovery.
Attributes:
path: Path - Path to global licensing file
cls: Type[GlobalLicensing] - Class type of global licensing implementation
"""
path: Path
cls: Type[GlobalLicensing]Usage Examples:
# Check if project has global licensing
if project.global_licensing:
print(f"Global licensing type: {type(project.global_licensing).__name__}")
# Access licensing configuration
if hasattr(project.global_licensing, 'path'):
print(f"Config file: {project.global_licensing.path}")Access and manage project license files.
# Project attributes for license management
licenses: dict[str, Path] # License files mapping
licenses_without_extension: dict[str, Path] # License files without extensions
license_map: dict[str, dict] # License mapping configurationUsage Examples:
# List all license files
for spdx_id, license_path in project.licenses.items():
print(f"{spdx_id}: {license_path}")
# Check for specific license
if "MIT" in project.licenses:
mit_path = project.licenses["MIT"]
print(f"MIT license at: {mit_path}")
# Access license files without extensions
for spdx_id, license_path in project.licenses_without_extension.items():
print(f"{spdx_id}: {license_path}")Access version control system information and strategies.
# Project attribute for VCS integration
vcs_strategy: VCSStrategy # VCS strategy for the projectUsage Examples:
# Check VCS type
vcs_name = type(project.vcs_strategy).__name__
print(f"VCS Strategy: {vcs_name}")
# Access VCS-specific functionality
if hasattr(project.vcs_strategy, 'root'):
vcs_root = project.vcs_strategy.root
print(f"VCS root: {vcs_root}")from reuse.project import Project
from pathlib import Path
import json
def analyze_project(project_path: Path) -> dict:
"""Comprehensive project analysis example."""
# Create project instance
project = Project.from_directory(project_path, include_submodules=True)
analysis = {
"root": str(project.root),
"vcs_strategy": type(project.vcs_strategy).__name__,
"has_global_licensing": project.global_licensing is not None,
"license_files": len(project.licenses),
"files_analyzed": 0,
"files_with_reuse_info": 0,
"files_missing_info": []
}
# Analyze all files
for file_path in project.all_files():
analysis["files_analyzed"] += 1
reuse_info = project.reuse_info_of(file_path)
if any(info.contains_info() for info in reuse_info):
analysis["files_with_reuse_info"] += 1
else:
rel_path = project.relative_from_root(file_path)
analysis["files_missing_info"].append(str(rel_path))
# Calculate compliance percentage
if analysis["files_analyzed"] > 0:
compliance = (analysis["files_with_reuse_info"] / analysis["files_analyzed"]) * 100
analysis["compliance_percentage"] = round(compliance, 2)
return analysis
# Usage
project_analysis = analyze_project(Path("/path/to/project"))
print(json.dumps(project_analysis, indent=2))Install with Tessl CLI
npx tessl i tessl/pypi-reuse