A comprehensive utility library to parse, compare, simplify and normalize license expressions using boolean logic
—
Factory functions provide convenient ways to create preconfigured Licensing instances with built-in license databases. These functions eliminate the need to manually load and configure license data, offering ready-to-use instances for SPDX and ScanCode license databases.
Create a Licensing instance configured with SPDX license database.
def get_spdx_licensing(license_index_location=None) -> Licensing:
"""
Create a Licensing instance configured with SPDX license database.
Parameters:
- license_index_location: Path to license index JSON file (optional, uses bundled database)
Returns:
Licensing instance with SPDX license symbols and compatibility rules
"""Create a Licensing instance configured with ScanCode license database.
def get_scancode_licensing(license_index_location=None) -> Licensing:
"""
Create a Licensing instance configured with ScanCode license database.
Parameters:
- license_index_location: Path to license index JSON file (optional, uses bundled database)
Returns:
Licensing instance with ScanCode license symbols and extended database
"""Load license index data from JSON files.
def get_license_index(license_index_location=None) -> dict:
"""
Load license index from JSON file.
Parameters:
- license_index_location: Path to license index JSON file (optional, uses bundled database)
Returns:
Dictionary containing license index data with symbols, aliases, and metadata
"""Lower-level functions for creating Licensing instances from license index data.
def build_licensing(license_index: dict) -> Licensing:
"""
Build a Licensing instance from license index data.
Parameters:
- license_index: Dictionary containing license data
Returns:
Licensing instance with symbols from the index
"""
def build_spdx_licensing(license_index: dict) -> Licensing:
"""
Build SPDX-compatible Licensing instance from license index data.
Parameters:
- license_index: Dictionary containing license data
Returns:
Licensing instance configured for SPDX compatibility
"""
def load_licensing_from_license_index(license_index: dict) -> Licensing:
"""
Load Licensing instance from license index data.
Parameters:
- license_index: Dictionary containing license data
Returns:
Configured Licensing instance
"""from license_expression import get_spdx_licensing
# Create SPDX-compatible licensing instance
licensing = get_spdx_licensing()
# Parse SPDX expressions with automatic normalization
expression = 'GPL-2.0 or LGPL-2.1+'
parsed = licensing.parse(expression)
print(str(parsed)) # 'GPL-2.0-only OR LGPL-2.1-or-later'
# Validate against SPDX license list
result = licensing.validate('MIT and Apache-2.0')
print(result.errors) # [] - both are valid SPDX licenses
# Test with deprecated SPDX identifiers
deprecated = licensing.parse('GPL-2.0+') # Old format
print(str(deprecated)) # 'GPL-2.0-or-later' - normalized to current SPDXfrom license_expression import get_scancode_licensing
# Create ScanCode licensing instance (more comprehensive database)
licensing = get_scancode_licensing()
# ScanCode includes additional license identifiers beyond SPDX
expression = 'proprietary-license or commercial-license'
parsed = licensing.parse(expression)
print(str(parsed))
# Access extended license database
result = licensing.validate('scancode-specific-license')
print(result.errors) # May be empty if license exists in ScanCode DBfrom license_expression import get_license_index, build_licensing
# Load custom license index
custom_index = get_license_index('/path/to/custom/licenses.json')
# Build licensing from custom index
custom_licensing = build_licensing(custom_index)
# Use custom licensing instance
expr = custom_licensing.parse('CustomLicense1 or CustomLicense2')from license_expression import get_spdx_licensing, get_scancode_licensing
spdx_licensing = get_spdx_licensing()
scancode_licensing = get_scancode_licensing()
# Test expression with both instances
test_expr = 'MIT and (Apache-2.0 or GPL-2.0+)'
spdx_result = spdx_licensing.parse(test_expr)
scancode_result = scancode_licensing.parse(test_expr)
print("SPDX result:", str(spdx_result))
print("ScanCode result:", str(scancode_result))
# Check license symbol counts
spdx_symbols = spdx_licensing.license_symbols(spdx_result)
scancode_symbols = scancode_licensing.license_symbols(scancode_result)
print(f"SPDX symbols found: {len(spdx_symbols)}")
print(f"ScanCode symbols found: {len(scancode_symbols)}")from license_expression import get_license_index
# Load and examine license index
index = get_license_index()
# Explore index structure
print("Index keys:", list(index.keys()))
# Access license data (structure depends on index format)
if 'licenses' in index:
licenses = index['licenses']
print(f"Total licenses in index: {len(licenses)}")
# Show first few licenses
for i, license_data in enumerate(licenses[:3]):
print(f"License {i+1}: {license_data}")from license_expression import get_spdx_licensing, get_scancode_licensing
# Use custom license index file
custom_spdx = get_spdx_licensing('/path/to/custom-spdx-index.json')
custom_scancode = get_scancode_licensing('/path/to/custom-scancode-index.json')
# These instances will use the custom license data instead of bundled datafrom license_expression import (
get_license_index,
build_licensing,
build_spdx_licensing
)
# Load license index
index = get_license_index()
# Build different types of licensing instances
general_licensing = build_licensing(index)
spdx_licensing = build_spdx_licensing(index)
# Compare behavior
test_expr = 'MIT or GPL-2.0+'
general_result = general_licensing.parse(test_expr)
spdx_result = spdx_licensing.parse(test_expr)
print("General:", str(general_result))
print("SPDX:", str(spdx_result))The library includes a comprehensive license database:
data/scancode-licensedb-index.jsonfrom license_expression import get_license_index
import json
# Load the bundled database
index = get_license_index()
# Save for examination (if needed)
with open('license_database.json', 'w') as f:
json.dump(index, f, indent=2)
print(f"Database contains {len(index.get('licenses', []))} licenses")Factory functions include error handling for missing or invalid license data:
from license_expression import get_spdx_licensing
try:
# This will work with bundled database
licensing = get_spdx_licensing()
except Exception as e:
print(f"Error loading SPDX licensing: {e}")
try:
# This may fail if custom file doesn't exist
licensing = get_spdx_licensing('/nonexistent/path/licenses.json')
except Exception as e:
print(f"Error loading custom licensing: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-license-expression