CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-license-expression

A comprehensive utility library to parse, compare, simplify and normalize license expressions using boolean logic

Pending
Overview
Eval results
Files

factories.mddocs/

Factory Functions

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.

Capabilities

SPDX Licensing Factory

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
    """

ScanCode Licensing Factory

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
    """

License Index Loading

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
    """

Builder Functions

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
    """

Usage Examples

Basic SPDX Usage

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 SPDX

Basic ScanCode Usage

from 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 DB

Custom License Index

from 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')

Comparing Factory Outputs

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)}")

Working with License Index Data

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}")

Custom Index Location

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 data

Building from Index Step-by-Step

from 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))

Default License Database

The library includes a comprehensive license database:

  • Location: Bundled within the package at data/scancode-licensedb-index.json
  • Size: ~971KB containing extensive license metadata
  • Content: SPDX license list (v3.26) + ScanCode LicenseDB
  • Update: Based on ScanCode toolkit v32.3.1
  • Coverage: Hundreds of license identifiers with aliases and metadata

Accessing Bundled Database

from 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")

Error Handling

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

docs

constants.md

expressions.md

factories.md

index.md

licensing.md

symbols.md

tile.json