0
# License Symbol Management
1
2
License symbols represent individual licenses and exceptions within license expressions. The library provides several symbol classes to handle different types of license identifiers, including standard licenses, license-like symbols, and complex WITH exception constructs.
3
4
## Capabilities
5
6
### LicenseSymbol Class
7
8
The primary class for representing individual licenses within expressions.
9
10
```python { .api }
11
class LicenseSymbol:
12
"""
13
Represents a license symbol with key, aliases, and metadata.
14
"""
15
16
def __init__(self, key: str, aliases: tuple = tuple(), is_deprecated: bool = False, is_exception: bool = False, *args, **kwargs):
17
"""
18
Create a license symbol.
19
20
Parameters:
21
- key: Primary identifier for the license
22
- aliases: Tuple of alternative names/identifiers (default: empty tuple)
23
- is_deprecated: Whether this license identifier is deprecated (default: False)
24
- is_exception: Whether this symbol represents a license exception (default: False)
25
- *args, **kwargs: Additional arguments for extensibility
26
"""
27
28
@property
29
def key(self) -> str:
30
"""Primary license identifier."""
31
32
@property
33
def aliases(self) -> tuple:
34
"""Tuple of alternative identifiers for this license."""
35
36
@property
37
def is_deprecated(self) -> bool:
38
"""True if this license identifier is deprecated."""
39
40
@property
41
def is_exception(self) -> bool:
42
"""True if this symbol represents a license exception."""
43
44
def __eq__(self, other) -> bool:
45
"""License symbols are equal if they have the same key."""
46
47
def __hash__(self) -> int:
48
"""Hash based on the license key."""
49
50
def __str__(self) -> str:
51
"""String representation using the key."""
52
```
53
54
### LicenseSymbolLike Class
55
56
A symbol class for licenses that should match similar or related licenses.
57
58
```python { .api }
59
class LicenseSymbolLike(LicenseSymbol):
60
"""
61
License symbol that matches similar licenses with flexible matching.
62
Extends LicenseSymbol with similarity-based matching capabilities.
63
"""
64
65
def __init__(self, key: str, aliases: list = None, is_exception: bool = False):
66
"""
67
Create a license-like symbol with flexible matching.
68
69
Parameters:
70
- key: Primary identifier for the license
71
- aliases: List of alternative names/identifiers
72
- is_exception: Whether this symbol represents a license exception
73
"""
74
```
75
76
### LicenseWithExceptionSymbol Class
77
78
Represents complex license WITH exception constructs.
79
80
```python { .api }
81
class LicenseWithExceptionSymbol:
82
"""
83
Represents a license WITH exception construct (e.g., 'GPL-2.0 WITH Classpath-exception-2.0').
84
"""
85
86
def __init__(self, license_symbol: LicenseSymbol, exception_symbol: LicenseSymbol, strict: bool = False):
87
"""
88
Create a license WITH exception symbol.
89
90
Parameters:
91
- license_symbol: The main license symbol
92
- exception_symbol: The exception symbol (must have is_exception=True)
93
- strict: Validate that license_symbol is not an exception and exception_symbol is an exception (default: False)
94
"""
95
96
@property
97
def license_symbol(self) -> LicenseSymbol:
98
"""The main license symbol."""
99
100
@property
101
def exception_symbol(self) -> LicenseSymbol:
102
"""The exception symbol."""
103
104
@property
105
def key(self) -> str:
106
"""Combined key representing the license WITH exception."""
107
108
def __eq__(self, other) -> bool:
109
"""Equality based on both license and exception symbols."""
110
111
def __str__(self) -> str:
112
"""String representation as 'license WITH exception'."""
113
```
114
115
### BaseSymbol Class
116
117
Abstract base class for all license symbols.
118
119
```python { .api }
120
class BaseSymbol:
121
"""
122
Base class for all license symbols providing common functionality.
123
"""
124
125
def render(self, template: str = None) -> str:
126
"""
127
Render the symbol using a template string.
128
129
Parameters:
130
- template: Format template (default: '{symbol.key}')
131
132
Returns:
133
Formatted string representation
134
"""
135
136
def decompose(self):
137
"""
138
Yield the underlying symbols of this symbol.
139
For most symbols, this yields the symbol itself.
140
"""
141
142
def __contains__(self, other) -> bool:
143
"""
144
Test if the other symbol is contained in this symbol.
145
"""
146
```
147
148
### Renderable Class
149
150
Base interface class for renderable objects.
151
152
```python { .api }
153
class Renderable:
154
"""
155
Interface for renderable objects that can be formatted as strings.
156
"""
157
158
def render(self, template: str = "{symbol.key}", *args, **kwargs) -> str:
159
"""
160
Return a formatted string rendering for this object.
161
162
Parameters:
163
- template: Format string template
164
- *args, **kwargs: Additional arguments for rendering
165
166
Returns:
167
Formatted string representation
168
"""
169
170
def render_as_readable(self, template: str = "{symbol.key}", *args, **kwargs) -> str:
171
"""
172
Return a formatted string with extra parentheses for improved readability.
173
174
Parameters:
175
- template: Format string template
176
- *args, **kwargs: Additional arguments for rendering
177
178
Returns:
179
Formatted string with improved readability
180
"""
181
```
182
183
### RenderableFunction Class
184
185
Base class for renderable boolean functions (AND/OR operators).
186
187
```python { .api }
188
class RenderableFunction(Renderable):
189
"""
190
Base class for renderable boolean functions like AND and OR operators.
191
"""
192
193
def render(self, template: str = "{symbol.key}", *args, **kwargs) -> str:
194
"""
195
Render a boolean expression recursively applying the template to symbols.
196
197
Parameters:
198
- template: Format string template for symbols
199
- *args, **kwargs: Additional arguments passed to symbol render methods
200
201
Returns:
202
Formatted boolean expression string
203
"""
204
```
205
206
## Usage Examples
207
208
### Creating License Symbols
209
210
```python
211
from license_expression import LicenseSymbol
212
213
# Create a standard license symbol
214
mit = LicenseSymbol('MIT', ['MIT License', 'Expat'])
215
print(mit.key) # 'MIT'
216
print(mit.aliases) # ('MIT License', 'Expat')
217
print(mit.is_exception) # False
218
219
# Create an exception symbol
220
classpath = LicenseSymbol('Classpath-exception-2.0', is_exception=True)
221
print(classpath.is_exception) # True
222
```
223
224
### Working with License-Like Symbols
225
226
```python
227
from license_expression import LicenseSymbolLike
228
229
# Create a symbol that matches similar licenses
230
generic_gpl = LicenseSymbolLike('GPL', ['GNU GPL', 'General Public License'])
231
```
232
233
### Creating WITH Exception Symbols
234
235
```python
236
from license_expression import LicenseSymbol, LicenseWithExceptionSymbol
237
238
# Create license and exception symbols
239
gpl = LicenseSymbol('GPL-2.0')
240
classpath = LicenseSymbol('Classpath-exception-2.0', is_exception=True)
241
242
# Combine into WITH exception symbol
243
gpl_with_classpath = LicenseWithExceptionSymbol(gpl, classpath)
244
print(str(gpl_with_classpath)) # 'GPL-2.0 WITH Classpath-exception-2.0'
245
print(gpl_with_classpath.license_symbol.key) # 'GPL-2.0'
246
print(gpl_with_classpath.exception_symbol.key) # 'Classpath-exception-2.0'
247
```
248
249
### Symbol Equality and Comparison
250
251
```python
252
# Symbol equality is based on keys
253
mit1 = LicenseSymbol('MIT', ['MIT License'])
254
mit2 = LicenseSymbol('MIT', ['Expat License'])
255
print(mit1 == mit2) # True - same key
256
257
# Different keys are not equal
258
mit = LicenseSymbol('MIT')
259
apache = LicenseSymbol('Apache-2.0')
260
print(mit == apache) # False
261
```
262
263
### Using Symbols in Sets and Dictionaries
264
265
```python
266
# Symbols can be used in sets (hashable by key)
267
symbols = {
268
LicenseSymbol('MIT'),
269
LicenseSymbol('Apache-2.0'),
270
LicenseSymbol('MIT', ['Expat']) # Duplicate key, won't be added twice
271
}
272
print(len(symbols)) # 2
273
274
# Use as dictionary keys
275
license_info = {
276
LicenseSymbol('MIT'): 'Permissive license',
277
LicenseSymbol('GPL-2.0'): 'Copyleft license'
278
}
279
```
280
281
### Custom Rendering
282
283
```python
284
# Render symbols with custom templates
285
mit = LicenseSymbol('MIT', ['MIT License'])
286
print(mit.render()) # 'MIT' (default)
287
print(mit.render('{symbol.key}')) # 'MIT'
288
print(mit.render('License: {symbol.key}')) # 'License: MIT'
289
```
290
291
## Symbol Validation
292
293
The library provides utilities for validating collections of symbols:
294
295
```python
296
from license_expression import validate_symbols, LicenseSymbol
297
298
symbols = [
299
LicenseSymbol('MIT'),
300
LicenseSymbol('Apache-2.0'),
301
LicenseSymbol('GPL-2.0', is_exception=True), # Invalid: GPL-2.0 is not an exception
302
]
303
304
warnings, errors = validate_symbols(symbols, validate_keys=True)
305
print(errors) # List of validation errors
306
```