0
# Project Management and Analysis
1
2
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.
3
4
## Capabilities
5
6
### Project Creation and Configuration
7
8
Create and configure Project instances for REUSE analysis.
9
10
```python { .api }
11
class Project:
12
"""
13
Central class holding project root and configuration.
14
15
Attributes:
16
root: Path - Project root directory
17
include_submodules: bool - Whether to include VCS submodules
18
include_meson_subprojects: bool - Whether to include Meson subprojects
19
vcs_strategy: VCSStrategy - VCS strategy for the project
20
global_licensing: Optional[GlobalLicensing] - Global licensing configuration
21
license_map: dict[str, dict] - License mapping
22
licenses: dict[str, Path] - License files mapping
23
licenses_without_extension: dict[str, Path] - License files without extensions
24
"""
25
26
@classmethod
27
def from_directory(
28
cls,
29
root: Path,
30
include_submodules: bool = False,
31
include_meson_subprojects: bool = False
32
) -> Project:
33
"""
34
Factory method to create Project from directory.
35
36
Args:
37
root: Project root directory path
38
include_submodules: Include VCS submodules in analysis
39
include_meson_subprojects: Include Meson subprojects in analysis
40
41
Returns:
42
Project instance configured for the directory
43
44
Raises:
45
FileNotFoundError: If root directory doesn't exist
46
"""
47
```
48
49
**Usage Examples:**
50
51
```python
52
from reuse.project import Project
53
from pathlib import Path
54
55
# Create project from current directory
56
project = Project.from_directory(Path.cwd())
57
58
# Create project with submodules included
59
project = Project.from_directory(
60
Path("/path/to/project"),
61
include_submodules=True
62
)
63
64
# Create project with all options
65
project = Project.from_directory(
66
Path("/path/to/project"),
67
include_submodules=True,
68
include_meson_subprojects=True
69
)
70
```
71
72
### File Discovery and Iteration
73
74
Discover and iterate over project files with intelligent filtering.
75
76
```python { .api }
77
def all_files(self, directory: Optional[Path] = None) -> Iterator[Path]:
78
"""
79
Iterator over all files in project.
80
81
Args:
82
directory: Optional directory to limit search (default: project root)
83
84
Yields:
85
Path: File paths within the project
86
87
Note:
88
Respects VCS ignore patterns and project configuration for submodules
89
and subprojects. Files are yielded in a deterministic order.
90
"""
91
```
92
93
**Usage Examples:**
94
95
```python
96
# Iterate over all project files
97
for file_path in project.all_files():
98
print(f"Processing: {file_path}")
99
100
# Iterate over files in specific directory
101
src_dir = project.root / "src"
102
for file_path in project.all_files(src_dir):
103
print(f"Source file: {file_path}")
104
105
# Count total files
106
total_files = sum(1 for _ in project.all_files())
107
print(f"Total files: {total_files}")
108
```
109
110
### REUSE Information Extraction
111
112
Extract REUSE licensing and copyright information from project files.
113
114
```python { .api }
115
def reuse_info_of(self, path: Path) -> list[ReuseInfo]:
116
"""
117
Get REUSE info for a specific file.
118
119
Args:
120
path: File path to analyze (absolute or relative to project root)
121
122
Returns:
123
List of ReuseInfo objects containing licensing and copyright data
124
125
Note:
126
Checks multiple sources: file headers, .license files, global
127
licensing files (.reuse/dep5, REUSE.toml), and license directories.
128
Returns empty list if no REUSE information is found.
129
"""
130
```
131
132
**Usage Examples:**
133
134
```python
135
# Get REUSE info for a single file
136
file_path = Path("src/example.py")
137
reuse_info = project.reuse_info_of(file_path)
138
139
for info in reuse_info:
140
print(f"Source: {info.source_type}")
141
print(f"Licenses: {info.spdx_expressions}")
142
print(f"Copyright: {info.copyright_lines}")
143
print(f"Contributors: {info.contributor_lines}")
144
145
# Check if file has REUSE information
146
has_info = any(info.contains_info() for info in reuse_info)
147
print(f"Has REUSE info: {has_info}")
148
149
# Get copyright and licensing status
150
has_both = any(info.contains_copyright_or_licensing() for info in reuse_info)
151
has_one = any(info.contains_copyright_xor_licensing() for info in reuse_info)
152
```
153
154
### Path Utilities
155
156
Utility methods for path manipulation within projects.
157
158
```python { .api }
159
def relative_from_root(self, path: Path) -> Path:
160
"""
161
Convert path to relative from project root.
162
163
Args:
164
path: Absolute or relative path
165
166
Returns:
167
Path relative to project root
168
169
Raises:
170
ValueError: If path is not within project
171
"""
172
```
173
174
**Usage Examples:**
175
176
```python
177
# Convert absolute path to relative
178
abs_path = Path("/full/path/to/project/src/file.py")
179
rel_path = project.relative_from_root(abs_path)
180
print(rel_path) # src/file.py
181
182
# Works with paths already relative to project
183
rel_path = project.relative_from_root(Path("src/file.py"))
184
print(rel_path) # src/file.py
185
```
186
187
### Global Licensing Discovery
188
189
Discover and access global licensing configuration files.
190
191
```python { .api }
192
class GlobalLicensingFound(NamedTuple):
193
"""
194
Result of global licensing file discovery.
195
196
Attributes:
197
path: Path - Path to global licensing file
198
cls: Type[GlobalLicensing] - Class type of global licensing implementation
199
"""
200
path: Path
201
cls: Type[GlobalLicensing]
202
```
203
204
**Usage Examples:**
205
206
```python
207
# Check if project has global licensing
208
if project.global_licensing:
209
print(f"Global licensing type: {type(project.global_licensing).__name__}")
210
211
# Access licensing configuration
212
if hasattr(project.global_licensing, 'path'):
213
print(f"Config file: {project.global_licensing.path}")
214
```
215
216
### License File Management
217
218
Access and manage project license files.
219
220
```python { .api }
221
# Project attributes for license management
222
licenses: dict[str, Path] # License files mapping
223
licenses_without_extension: dict[str, Path] # License files without extensions
224
license_map: dict[str, dict] # License mapping configuration
225
```
226
227
**Usage Examples:**
228
229
```python
230
# List all license files
231
for spdx_id, license_path in project.licenses.items():
232
print(f"{spdx_id}: {license_path}")
233
234
# Check for specific license
235
if "MIT" in project.licenses:
236
mit_path = project.licenses["MIT"]
237
print(f"MIT license at: {mit_path}")
238
239
# Access license files without extensions
240
for spdx_id, license_path in project.licenses_without_extension.items():
241
print(f"{spdx_id}: {license_path}")
242
```
243
244
### VCS Integration
245
246
Access version control system information and strategies.
247
248
```python { .api }
249
# Project attribute for VCS integration
250
vcs_strategy: VCSStrategy # VCS strategy for the project
251
```
252
253
**Usage Examples:**
254
255
```python
256
# Check VCS type
257
vcs_name = type(project.vcs_strategy).__name__
258
print(f"VCS Strategy: {vcs_name}")
259
260
# Access VCS-specific functionality
261
if hasattr(project.vcs_strategy, 'root'):
262
vcs_root = project.vcs_strategy.root
263
print(f"VCS root: {vcs_root}")
264
```
265
266
## Complete Project Analysis Example
267
268
```python
269
from reuse.project import Project
270
from pathlib import Path
271
import json
272
273
def analyze_project(project_path: Path) -> dict:
274
"""Comprehensive project analysis example."""
275
276
# Create project instance
277
project = Project.from_directory(project_path, include_submodules=True)
278
279
analysis = {
280
"root": str(project.root),
281
"vcs_strategy": type(project.vcs_strategy).__name__,
282
"has_global_licensing": project.global_licensing is not None,
283
"license_files": len(project.licenses),
284
"files_analyzed": 0,
285
"files_with_reuse_info": 0,
286
"files_missing_info": []
287
}
288
289
# Analyze all files
290
for file_path in project.all_files():
291
analysis["files_analyzed"] += 1
292
293
reuse_info = project.reuse_info_of(file_path)
294
if any(info.contains_info() for info in reuse_info):
295
analysis["files_with_reuse_info"] += 1
296
else:
297
rel_path = project.relative_from_root(file_path)
298
analysis["files_missing_info"].append(str(rel_path))
299
300
# Calculate compliance percentage
301
if analysis["files_analyzed"] > 0:
302
compliance = (analysis["files_with_reuse_info"] / analysis["files_analyzed"]) * 100
303
analysis["compliance_percentage"] = round(compliance, 2)
304
305
return analysis
306
307
# Usage
308
project_analysis = analyze_project(Path("/path/to/project"))
309
print(json.dumps(project_analysis, indent=2))
310
```