A tool for compliance with the REUSE recommendations for software licensing and copyright management.
npx @tessl/cli install tessl/pypi-reuse@5.1.00
# REUSE
1
2
REUSE is a comprehensive Python tool for compliance with the REUSE recommendations developed by the Free Software Foundation Europe (FSFE). It simplifies copyright and licensing processes by offering automated tools to choose and provide licenses, add copyright and licensing information to files, and confirm REUSE compliance.
3
4
## Package Information
5
6
- **Package Name**: reuse
7
- **Language**: Python
8
- **Installation**: `pip install reuse`
9
- **Python Version**: 3.9+
10
11
## Core Imports
12
13
```python
14
import reuse
15
from reuse import ReuseInfo, SourceType
16
from reuse.project import Project, GlobalLicensingFound
17
from reuse.types import StrPath
18
```
19
20
For working with collections:
21
22
```python
23
from typing import Collection, Optional, Iterator
24
```
25
26
For report generation:
27
28
```python
29
from reuse.report import ProjectReport, FileReport
30
from reuse.lint import format_plain, format_json, format_lines, format_lines_subset
31
```
32
33
CLI usage:
34
35
```bash
36
reuse --help
37
```
38
39
## Basic Usage
40
41
```python
42
from reuse.project import Project
43
from pathlib import Path
44
45
# Create a project instance
46
project = Project.from_directory(Path.cwd())
47
48
# Get REUSE information for a file (accepts StrPath)
49
reuse_info = project.reuse_info_of("src/example.py")
50
for info in reuse_info:
51
print(f"Licenses: {info.spdx_expressions}")
52
print(f"Copyright: {info.copyright_lines}")
53
54
# Iterate through all files in project
55
for file_path in project.all_files():
56
print(f"Processing: {file_path}")
57
58
# Get subset of files
59
files_to_check = ["src/main.py", "src/utils.py"]
60
for file_path in project.subset_files(files_to_check):
61
print(f"Checking: {file_path}")
62
```
63
64
CLI usage:
65
66
```bash
67
# Lint project for REUSE compliance
68
reuse lint
69
70
# Add copyright and license to files
71
reuse annotate --copyright="2023 Jane Doe" --license="MIT" src/example.py
72
73
# Generate SPDX bill of materials
74
reuse spdx --format=json > project.spdx.json
75
76
# Download a license
77
reuse download MIT
78
```
79
80
## Architecture
81
82
The REUSE tool is built around several key components:
83
84
- **Project**: Central class managing project root, configuration, and file discovery
85
- **ReuseInfo**: Data container holding licensing and copyright information for files
86
- **Global Licensing**: Support for project-wide licensing configuration via .dep5 and REUSE.toml files
87
- **Comment Handling**: Extensible system supporting 25+ file types for comment-based headers
88
- **VCS Integration**: Pluggable version control system support (Git, Mercurial, Jujutsu, Pijul)
89
- **Report Generation**: Comprehensive compliance reporting with multiple output formats
90
91
**Important**: The Python API is documented but **NOT guaranteed stable** between minor or patch releases. Semantic versioning applies exclusively to the CLI command. Library users should pin to exact versions.
92
93
## Capabilities
94
95
### Command Line Interface
96
97
Complete CLI with 7 subcommands for REUSE compliance management including linting, annotation, SPDX generation, and license management.
98
99
```bash { .api }
100
reuse [OPTIONS] COMMAND [ARGS]...
101
102
# Global options:
103
--debug Enable debug statements
104
--suppress-deprecation Hide deprecation warnings
105
--include-submodules Do not skip Git submodules
106
--include-meson-subprojects Do not skip Meson subprojects
107
--no-multiprocessing Do not use multiprocessing
108
--root PATH Define project root directory
109
```
110
111
[Command Line Interface](./cli.md)
112
113
### Project Management and Analysis
114
115
Core project discovery, configuration management, and file analysis capabilities.
116
117
```python { .api }
118
class Project:
119
"""Central class holding project root and configuration."""
120
121
root: Path
122
include_submodules: bool = False
123
include_meson_subprojects: bool = False
124
vcs_strategy: VCSStrategy
125
global_licensing: Optional[GlobalLicensing] = None
126
license_map: dict[str, dict]
127
licenses: dict[str, Path]
128
licenses_without_extension: dict[str, Path]
129
130
@classmethod
131
def from_directory(
132
cls,
133
root: StrPath,
134
include_submodules: bool = False,
135
include_meson_subprojects: bool = False
136
) -> Project:
137
"""Factory method to create Project from directory.
138
139
Raises:
140
FileNotFoundError: if root does not exist.
141
NotADirectoryError: if root is not a directory.
142
UnicodeDecodeError: if the global licensing config file could not be decoded.
143
GlobalLicensingParseError: if the global licensing config file could not be parsed.
144
GlobalLicensingConflictError: if more than one global licensing config file is present.
145
"""
146
147
@classmethod
148
def find_global_licensing(
149
cls,
150
root: Path,
151
include_submodules: bool = False,
152
include_meson_subprojects: bool = False,
153
vcs_strategy: Optional[VCSStrategy] = None,
154
) -> list[GlobalLicensingFound]:
155
"""Find the path and corresponding class of a project directory's GlobalLicensing.
156
157
Raises:
158
GlobalLicensingConflictError: if more than one global licensing config file is present.
159
"""
160
161
def all_files(self, directory: Optional[StrPath] = None) -> Iterator[Path]:
162
"""Yield all files in directory and its subdirectories."""
163
164
def subset_files(
165
self, files: Collection[StrPath], directory: Optional[StrPath] = None
166
) -> Iterator[Path]:
167
"""Like all_files, but all files that are not in files are filtered out."""
168
169
def reuse_info_of(self, path: StrPath) -> list[ReuseInfo]:
170
"""Return REUSE info of path."""
171
172
def relative_from_root(self, path: StrPath) -> Path:
173
"""Return path relative to the project root."""
174
```
175
176
[Project Management](./project-management.md)
177
178
### REUSE Information Processing
179
180
Data structures and functions for processing REUSE licensing and copyright information.
181
182
```python { .api }
183
@dataclass(frozen=True)
184
class ReuseInfo:
185
spdx_expressions: set[Expression] = field(default_factory=set)
186
copyright_lines: set[str] = field(default_factory=set)
187
contributor_lines: set[str] = field(default_factory=set)
188
path: Optional[str] = None
189
source_path: Optional[str] = None
190
source_type: Optional[SourceType] = None
191
192
def copy(self, **kwargs: Any) -> ReuseInfo: ...
193
def union(self, value: ReuseInfo) -> ReuseInfo: ...
194
def contains_copyright_or_licensing(self) -> bool: ...
195
196
class SourceType(Enum):
197
DOT_LICENSE = "dot-license"
198
FILE_HEADER = "file-header"
199
DEP5 = "dep5"
200
REUSE_TOML = "reuse-toml"
201
```
202
203
[REUSE Information Processing](./reuse-info.md)
204
205
### Comment Handling System
206
207
Extensible comment processing system supporting 25+ file types for adding and parsing copyright headers.
208
209
```python { .api }
210
def get_comment_style(path: Path) -> Optional[Type[CommentStyle]]: ...
211
def is_uncommentable(path: Path) -> bool: ...
212
def has_style(path: Path) -> bool: ...
213
214
class CommentStyle:
215
# Base class for comment style implementations
216
pass
217
```
218
219
[Comment Handling](./comment-handling.md)
220
221
### Global Licensing Configuration
222
223
Support for project-wide licensing configuration through .reuse/dep5 and REUSE.toml files.
224
225
```python { .api }
226
class GlobalLicensing(ABC):
227
# Abstract base class for global licensing
228
pass
229
230
class ReuseDep5(GlobalLicensing):
231
# Implementation for .reuse/dep5 files
232
pass
233
234
class ReuseTOML(GlobalLicensing):
235
# Implementation for REUSE.toml files
236
pass
237
```
238
239
[Global Licensing](./global-licensing.md)
240
241
### Report Generation
242
243
Comprehensive compliance reporting with multiple output formats including plain text, JSON, and line-based formats.
244
245
```python { .api }
246
class ProjectReport:
247
"""Object that holds linting report about the project."""
248
249
# Main attributes
250
path: StrPath
251
licenses: dict[str, Path]
252
missing_licenses: dict[str, set[Path]]
253
bad_licenses: dict[str, set[Path]]
254
deprecated_licenses: set[str]
255
read_errors: set[Path]
256
file_reports: set[FileReport]
257
licenses_without_extension: dict[str, Path]
258
259
def __init__(self, do_checksum: bool = True): ...
260
261
# Properties
262
@property
263
def used_licenses(self) -> set[str]: ...
264
265
@property
266
def unused_licenses(self) -> set[str]: ...
267
268
@property
269
def files_without_licenses(self) -> set[Path]: ...
270
271
@property
272
def files_without_copyright(self) -> set[Path]: ...
273
274
@property
275
def is_compliant(self) -> bool: ...
276
277
class FileReport:
278
"""Report for individual file compliance."""
279
pass
280
281
# Formatting functions (from reuse.lint module)
282
def format_plain(report: ProjectReport) -> str:
283
"""Format report as plain text."""
284
285
def format_json(report: ProjectReport) -> str:
286
"""Format report as JSON."""
287
288
def format_lines(report: ProjectReport) -> str:
289
"""Format report as line-based output."""
290
291
def format_lines_subset(report: ProjectReportSubsetProtocol) -> str:
292
"""Format subset report as line-based output."""
293
```
294
295
[Report Generation](./report-generation.md)
296
297
### VCS Integration
298
299
Pluggable version control system support for Git, Mercurial, Jujutsu, and Pijul.
300
301
```python { .api }
302
class VCSStrategy(ABC):
303
# Abstract base class for VCS strategies
304
pass
305
306
def find_root(cwd: Optional[StrPath] = None) -> Optional[Path]: ...
307
def all_vcs_strategies() -> Generator[Type[VCSStrategy], None, None]: ...
308
```
309
310
[VCS Integration](./vcs-integration.md)
311
312
## Core Data Types
313
314
```python { .api }
315
# Type definitions
316
StrPath = Union[str, PathLike[str]]
317
318
# Named tuples
319
class MultiLineSegments(NamedTuple):
320
start: str
321
middle: str
322
end: str
323
324
class GlobalLicensingFound(NamedTuple):
325
path: Path
326
cls: Type[GlobalLicensing]
327
```
328
329
## Exception Hierarchy
330
331
```python { .api }
332
class ReuseError(Exception):
333
"""Base exception for all REUSE-specific errors"""
334
pass
335
336
class SpdxIdentifierNotFoundError(ReuseError):
337
"""Could not find SPDX identifier for license file"""
338
pass
339
340
class GlobalLicensingParseError(ReuseError):
341
"""Error parsing GlobalLicensing file"""
342
def __init__(self, *args, source: Optional[str] = None): ...
343
344
class GlobalLicensingParseTypeError(GlobalLicensingParseError, TypeError):
345
"""Type error while parsing a GlobalLicensing file"""
346
pass
347
348
class GlobalLicensingParseValueError(GlobalLicensingParseError, ValueError):
349
"""Value error while parsing a GlobalLicensing file"""
350
pass
351
352
class GlobalLicensingConflictError(ReuseError):
353
"""Two global licensing files in the project are not compatible"""
354
pass
355
356
class MissingReuseInfoError(ReuseError):
357
"""Missing REUSE information from result"""
358
pass
359
360
class CommentError(ReuseError):
361
"""Error during comment interaction"""
362
pass
363
364
class CommentCreateError(Exception):
365
"""Error occurred during the creation of a comment"""
366
pass
367
368
class CommentParseError(Exception):
369
"""Error occurred during the parsing of a comment"""
370
pass
371
```