or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcomment-handling.mdglobal-licensing.mdindex.mdproject-management.mdreport-generation.mdreuse-info.mdvcs-integration.md

report-generation.mddocs/

0

# Report Generation

1

2

REUSE provides comprehensive compliance reporting capabilities with multiple output formats. The reporting system generates detailed analysis of project compliance status, missing information, and file-by-file breakdowns.

3

4

## Capabilities

5

6

### Project Report Classes

7

8

Core report classes for comprehensive project analysis.

9

10

```python { .api }

11

class ProjectReport:

12

"""

13

Main project compliance report.

14

15

Contains comprehensive analysis of all files in a project,

16

including compliance status, missing information, and detailed

17

file-by-file breakdowns.

18

"""

19

20

def __init__(

21

self,

22

file_reports: list[FileReport],

23

missing_licenses: set[str],

24

unused_licenses: set[str],

25

read_errors: list[tuple[Path, Exception]]

26

):

27

"""

28

Initialize project report.

29

30

Args:

31

file_reports: List of individual file reports

32

missing_licenses: Set of referenced but missing license files

33

unused_licenses: Set of license files not referenced by any file

34

read_errors: List of files that couldn't be read with their errors

35

"""

36

37

class ProjectSubsetReport:

38

"""

39

Subset report for specific files.

40

41

Used when analyzing only a portion of the project files

42

rather than the complete project.

43

"""

44

45

def __init__(self, file_reports: list[FileReport]):

46

"""

47

Initialize subset report.

48

49

Args:

50

file_reports: List of file reports for the subset

51

"""

52

53

class FileReport:

54

"""

55

Report for individual file compliance.

56

57

Contains detailed information about a single file's

58

REUSE compliance status, including copyright, licensing,

59

and any issues found.

60

"""

61

62

def __init__(

63

self,

64

path: Path,

65

reuse_infos: list[ReuseInfo],

66

missing_copyright: bool,

67

missing_license: bool,

68

bad_licenses: set[str]

69

):

70

"""

71

Initialize file report.

72

73

Args:

74

path: File path being reported on

75

reuse_infos: List of REUSE information found for the file

76

missing_copyright: Whether file is missing copyright information

77

missing_license: Whether file is missing license information

78

bad_licenses: Set of invalid or problematic license identifiers

79

"""

80

```

81

82

### Report Protocol

83

84

Protocol definition for report implementations.

85

86

```python { .api }

87

class ProjectReportSubsetProtocol(Protocol):

88

"""

89

Protocol for report subset implementations.

90

91

Defines the interface that report classes must implement

92

to be compatible with formatting functions.

93

"""

94

95

file_reports: list[FileReport]

96

97

def is_compliant(self) -> bool:

98

"""Check if all files in the report are compliant."""

99

100

def non_compliant_files(self) -> list[FileReport]:

101

"""Get list of non-compliant files."""

102

103

def files_missing_copyright(self) -> list[FileReport]:

104

"""Get files missing copyright information."""

105

106

def files_missing_license(self) -> list[FileReport]:

107

"""Get files missing license information."""

108

```

109

110

### Plain Text Formatting

111

112

Format reports as human-readable plain text output.

113

114

```python { .api }

115

def format_plain(report: ProjectReport) -> str:

116

"""

117

Format report as plaintext for stdout output.

118

119

Args:

120

report: ProjectReport to format

121

122

Returns:

123

Multi-line string with human-readable report

124

125

Note:

126

Includes summary statistics, file-by-file analysis,

127

missing licenses, unused licenses, and overall compliance status.

128

"""

129

```

130

131

**Usage Examples:**

132

133

```python

134

from reuse.lint import format_plain

135

from reuse.project import Project

136

from reuse.report import ProjectReport

137

from pathlib import Path

138

139

# Generate project report (this would typically be done internally)

140

project = Project.from_directory(Path.cwd())

141

# ... report generation logic ...

142

143

# Format as plain text

144

plain_report = format_plain(project_report)

145

print(plain_report)

146

147

# Example output:

148

# ========================= SUMMARY =========================

149

#

150

# * Bad licenses: 0

151

# * Deprecated licenses: 0

152

# * Licenses without file extension: 0

153

# * Missing licenses: MIT

154

# * Unused licenses: 0

155

# * Used licenses: GPL-3.0-or-later

156

# * Read errors: 0

157

# * Files with copyright information: 15 / 20

158

# * Files with license information: 18 / 20

159

#

160

# ========================= MISSING COPYRIGHT ===============

161

#

162

# The following files have no copyright information:

163

# * src/utils.py

164

# * tests/test_helper.py

165

#

166

# ======================= MISSING LICENSES ==================

167

#

168

# The following files have no license information:

169

# * src/config.py

170

# * README.md

171

#

172

# Congratulations! Your project is compliant with version 3.3 of the REUSE Specification :-)

173

```

174

175

### JSON Formatting

176

177

Format reports as structured JSON for programmatic processing.

178

179

```python { .api }

180

def format_json(report: ProjectReport) -> str:

181

"""

182

Format report as JSON string.

183

184

Args:

185

report: ProjectReport to format

186

187

Returns:

188

JSON string with structured report data

189

190

Note:

191

Includes all report data in structured format suitable

192

for consumption by other tools and scripts.

193

"""

194

```

195

196

**Usage Examples:**

197

198

```python

199

from reuse.lint import format_json

200

import json

201

202

# Format as JSON

203

json_report = format_json(project_report)

204

report_data = json.loads(json_report)

205

206

print(f"Compliant: {report_data['summary']['compliant']}")

207

print(f"Total files: {report_data['summary']['file_count']}")

208

209

# Access detailed file information

210

for file_info in report_data['files']:

211

if not file_info['compliant']:

212

print(f"Non-compliant: {file_info['path']}")

213

if file_info['missing_copyright']:

214

print(" - Missing copyright")

215

if file_info['missing_license']:

216

print(" - Missing license")

217

218

# Example JSON structure:

219

# {

220

# "summary": {

221

# "compliant": false,

222

# "file_count": 20,

223

# "compliant_files": 15,

224

# "non_compliant_files": 5,

225

# "missing_licenses": ["MIT"],

226

# "unused_licenses": [],

227

# "bad_licenses": [],

228

# "read_errors": 0

229

# },

230

# "files": [

231

# {

232

# "path": "src/main.py",

233

# "compliant": true,

234

# "missing_copyright": false,

235

# "missing_license": false,

236

# "licenses": ["GPL-3.0-or-later"],

237

# "copyrights": ["2023 Jane Doe"]

238

# }

239

# ]

240

# }

241

```

242

243

### Line-based Formatting

244

245

Format reports as line-based output for processing by text tools.

246

247

```python { .api }

248

def format_lines_subset(report: ProjectReportSubsetProtocol) -> str:

249

"""

250

Format subset report as lines.

251

252

Args:

253

report: Report implementing ProjectReportSubsetProtocol

254

255

Returns:

256

Line-based string output with one item per line

257

"""

258

259

def format_lines(report: ProjectReport) -> str:

260

"""

261

Format full report as lines.

262

263

Args:

264

report: ProjectReport to format

265

266

Returns:

267

Line-based string output suitable for grep, awk, etc.

268

"""

269

```

270

271

**Usage Examples:**

272

273

```python

274

from reuse.lint import format_lines, format_lines_subset

275

276

# Format full report as lines

277

lines_report = format_lines(project_report)

278

print(lines_report)

279

280

# Example output:

281

# NON_COMPLIANT src/utils.py

282

# MISSING_COPYRIGHT src/utils.py

283

# MISSING_LICENSE src/config.py

284

# COMPLIANT src/main.py

285

# COMPLIANT tests/test_main.py

286

287

# Format subset report

288

subset_files = [report for report in project_report.file_reports[:5]]

289

subset_report = ProjectSubsetReport(subset_files)

290

subset_lines = format_lines_subset(subset_report)

291

print(subset_lines)

292

293

# Process with shell tools

294

# reuse lint --format=lines | grep "NON_COMPLIANT" | cut -d' ' -f2

295

```

296

297

## Report Analysis Functions

298

299

Functions for analyzing and extracting information from reports.

300

301

```python { .api }

302

# Report analysis methods (available on report classes)

303

def is_compliant(self) -> bool:

304

"""Check if the project/subset is fully compliant."""

305

306

def non_compliant_files(self) -> list[FileReport]:

307

"""Get list of files that are not compliant."""

308

309

def files_missing_copyright(self) -> list[FileReport]:

310

"""Get files missing copyright information."""

311

312

def files_missing_license(self) -> list[FileReport]:

313

"""Get files missing license information."""

314

315

def files_with_bad_licenses(self) -> list[FileReport]:

316

"""Get files with invalid license identifiers."""

317

```

318

319

**Usage Examples:**

320

321

```python

322

# Analyze project compliance

323

if project_report.is_compliant():

324

print("Project is fully REUSE compliant!")

325

else:

326

print("Project has compliance issues:")

327

328

# Show files missing copyright

329

missing_copyright = project_report.files_missing_copyright()

330

if missing_copyright:

331

print(f"\nFiles missing copyright ({len(missing_copyright)}):")

332

for file_report in missing_copyright:

333

print(f" - {file_report.path}")

334

335

# Show files missing license

336

missing_license = project_report.files_missing_license()

337

if missing_license:

338

print(f"\nFiles missing license ({len(missing_license)}):")

339

for file_report in missing_license:

340

print(f" - {file_report.path}")

341

342

# Show files with bad licenses

343

bad_license_files = project_report.files_with_bad_licenses()

344

if bad_license_files:

345

print(f"\nFiles with invalid licenses ({len(bad_license_files)}):")

346

for file_report in bad_license_files:

347

print(f" - {file_report.path}: {file_report.bad_licenses}")

348

```

349

350

## Custom Report Processing

351

352

Examples of custom report processing and analysis.

353

354

```python

355

from reuse.report import ProjectReport, FileReport

356

from reuse.project import Project

357

from pathlib import Path

358

import json

359

from typing import Dict, List

360

361

def generate_compliance_dashboard(project_path: Path) -> Dict:

362

"""Generate a compliance dashboard with detailed metrics."""

363

364

project = Project.from_directory(project_path)

365

# Note: In practice, you'd use the actual REUSE linting functionality

366

# This is a simplified example showing report structure usage

367

368

dashboard = {

369

"project_root": str(project_path),

370

"compliance_overview": {},

371

"file_categories": {

372

"compliant": [],

373

"missing_copyright": [],

374

"missing_license": [],

375

"bad_licenses": []

376

},

377

"license_analysis": {

378

"used_licenses": set(),

379

"missing_licenses": set(),

380

"unused_licenses": set()

381

},

382

"file_type_breakdown": {}

383

}

384

385

# This would typically use the actual report generation

386

# For demonstration, we'll show the structure

387

388

return dashboard

389

390

def export_compliance_report(report: ProjectReport, output_dir: Path) -> None:

391

"""Export compliance report in multiple formats."""

392

393

output_dir.mkdir(exist_ok=True)

394

395

# Plain text report

396

plain_path = output_dir / "compliance-report.txt"

397

with open(plain_path, 'w') as f:

398

f.write(format_plain(report))

399

400

# JSON report

401

json_path = output_dir / "compliance-report.json"

402

with open(json_path, 'w') as f:

403

f.write(format_json(report))

404

405

# Lines format for processing

406

lines_path = output_dir / "compliance-report.lines"

407

with open(lines_path, 'w') as f:

408

f.write(format_lines(report))

409

410

# Summary CSV

411

csv_path = output_dir / "compliance-summary.csv"

412

with open(csv_path, 'w') as f:

413

f.write("path,compliant,missing_copyright,missing_license,bad_licenses\n")

414

for file_report in report.file_reports:

415

compliant = not (file_report.missing_copyright or

416

file_report.missing_license or

417

file_report.bad_licenses)

418

bad_licenses_str = ";".join(file_report.bad_licenses)

419

f.write(f"{file_report.path},{compliant},"

420

f"{file_report.missing_copyright},"

421

f"{file_report.missing_license},"

422

f'"{bad_licenses_str}"\n')

423

424

print(f"Reports exported to {output_dir}")

425

426

# Usage

427

# dashboard = generate_compliance_dashboard(Path("/path/to/project"))

428

# export_compliance_report(project_report, Path("./reports"))

429

```

430

431

## Report Integration Examples

432

433

Examples of integrating REUSE reports with other tools and workflows.

434

435

```python

436

def ci_compliance_check(project_path: Path) -> bool:

437

"""CI/CD integration example for compliance checking."""

438

439

project = Project.from_directory(project_path)

440

# Generate report (simplified - would use actual REUSE linting)

441

442

# For CI integration, typically you'd:

443

# 1. Generate report

444

# 2. Check compliance status

445

# 3. Export results

446

# 4. Return exit code

447

448

# if not report.is_compliant():

449

# print("REUSE compliance check failed!")

450

# print(format_plain(report))

451

# return False

452

453

print("REUSE compliance check passed!")

454

return True

455

456

def generate_license_inventory(report: ProjectReport) -> Dict[str, List[str]]:

457

"""Generate license inventory from compliance report."""

458

459

inventory = {}

460

461

for file_report in report.file_reports:

462

for reuse_info in file_report.reuse_infos:

463

for license_expr in reuse_info.spdx_expressions:

464

license_id = str(license_expr)

465

if license_id not in inventory:

466

inventory[license_id] = []

467

inventory[license_id].append(str(file_report.path))

468

469

return inventory

470

471

# Usage in CI/CD pipelines:

472

# exit_code = 0 if ci_compliance_check(Path(".")) else 1

473

# sys.exit(exit_code)

474

```