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

symbols.mddocs/

License Symbol Management

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.

Capabilities

LicenseSymbol Class

The primary class for representing individual licenses within expressions.

class LicenseSymbol:
    """
    Represents a license symbol with key, aliases, and metadata.
    """
    
    def __init__(self, key: str, aliases: tuple = tuple(), is_deprecated: bool = False, is_exception: bool = False, *args, **kwargs):
        """
        Create a license symbol.
        
        Parameters:
        - key: Primary identifier for the license
        - aliases: Tuple of alternative names/identifiers (default: empty tuple)
        - is_deprecated: Whether this license identifier is deprecated (default: False)
        - is_exception: Whether this symbol represents a license exception (default: False)
        - *args, **kwargs: Additional arguments for extensibility
        """
    
    @property
    def key(self) -> str:
        """Primary license identifier."""
    
    @property
    def aliases(self) -> tuple:
        """Tuple of alternative identifiers for this license."""
    
    @property
    def is_deprecated(self) -> bool:
        """True if this license identifier is deprecated."""
    
    @property
    def is_exception(self) -> bool:  
        """True if this symbol represents a license exception."""
    
    def __eq__(self, other) -> bool:
        """License symbols are equal if they have the same key."""
    
    def __hash__(self) -> int:
        """Hash based on the license key."""
    
    def __str__(self) -> str:
        """String representation using the key."""

LicenseSymbolLike Class

A symbol class for licenses that should match similar or related licenses.

class LicenseSymbolLike(LicenseSymbol):
    """
    License symbol that matches similar licenses with flexible matching.
    Extends LicenseSymbol with similarity-based matching capabilities.
    """
    
    def __init__(self, key: str, aliases: list = None, is_exception: bool = False):
        """
        Create a license-like symbol with flexible matching.
        
        Parameters:
        - key: Primary identifier for the license
        - aliases: List of alternative names/identifiers  
        - is_exception: Whether this symbol represents a license exception
        """

LicenseWithExceptionSymbol Class

Represents complex license WITH exception constructs.

class LicenseWithExceptionSymbol:
    """
    Represents a license WITH exception construct (e.g., 'GPL-2.0 WITH Classpath-exception-2.0').
    """
    
    def __init__(self, license_symbol: LicenseSymbol, exception_symbol: LicenseSymbol, strict: bool = False):
        """
        Create a license WITH exception symbol.
        
        Parameters:
        - license_symbol: The main license symbol
        - exception_symbol: The exception symbol (must have is_exception=True)
        - strict: Validate that license_symbol is not an exception and exception_symbol is an exception (default: False)
        """
    
    @property
    def license_symbol(self) -> LicenseSymbol:
        """The main license symbol."""
    
    @property 
    def exception_symbol(self) -> LicenseSymbol:
        """The exception symbol."""
    
    @property
    def key(self) -> str:
        """Combined key representing the license WITH exception."""
    
    def __eq__(self, other) -> bool:
        """Equality based on both license and exception symbols."""
    
    def __str__(self) -> str:
        """String representation as 'license WITH exception'."""

BaseSymbol Class

Abstract base class for all license symbols.

class BaseSymbol:
    """
    Base class for all license symbols providing common functionality.
    """
    
    def render(self, template: str = None) -> str:
        """
        Render the symbol using a template string.
        
        Parameters:
        - template: Format template (default: '{symbol.key}')
        
        Returns:
        Formatted string representation
        """
    
    def decompose(self):
        """
        Yield the underlying symbols of this symbol.
        For most symbols, this yields the symbol itself.
        """
    
    def __contains__(self, other) -> bool:
        """
        Test if the other symbol is contained in this symbol.
        """

Renderable Class

Base interface class for renderable objects.

class Renderable:
    """
    Interface for renderable objects that can be formatted as strings.
    """
    
    def render(self, template: str = "{symbol.key}", *args, **kwargs) -> str:
        """
        Return a formatted string rendering for this object.
        
        Parameters:
        - template: Format string template
        - *args, **kwargs: Additional arguments for rendering
        
        Returns:
        Formatted string representation
        """
    
    def render_as_readable(self, template: str = "{symbol.key}", *args, **kwargs) -> str:
        """
        Return a formatted string with extra parentheses for improved readability.
        
        Parameters:
        - template: Format string template
        - *args, **kwargs: Additional arguments for rendering
        
        Returns:
        Formatted string with improved readability
        """

RenderableFunction Class

Base class for renderable boolean functions (AND/OR operators).

class RenderableFunction(Renderable):
    """
    Base class for renderable boolean functions like AND and OR operators.
    """
    
    def render(self, template: str = "{symbol.key}", *args, **kwargs) -> str:
        """
        Render a boolean expression recursively applying the template to symbols.
        
        Parameters:
        - template: Format string template for symbols
        - *args, **kwargs: Additional arguments passed to symbol render methods
        
        Returns:
        Formatted boolean expression string
        """

Usage Examples

Creating License Symbols

from license_expression import LicenseSymbol

# Create a standard license symbol
mit = LicenseSymbol('MIT', ['MIT License', 'Expat'])
print(mit.key)      # 'MIT'
print(mit.aliases)  # ('MIT License', 'Expat')
print(mit.is_exception)  # False

# Create an exception symbol
classpath = LicenseSymbol('Classpath-exception-2.0', is_exception=True)
print(classpath.is_exception)  # True

Working with License-Like Symbols

from license_expression import LicenseSymbolLike

# Create a symbol that matches similar licenses
generic_gpl = LicenseSymbolLike('GPL', ['GNU GPL', 'General Public License'])

Creating WITH Exception Symbols

from license_expression import LicenseSymbol, LicenseWithExceptionSymbol

# Create license and exception symbols
gpl = LicenseSymbol('GPL-2.0')
classpath = LicenseSymbol('Classpath-exception-2.0', is_exception=True)

# Combine into WITH exception symbol
gpl_with_classpath = LicenseWithExceptionSymbol(gpl, classpath)
print(str(gpl_with_classpath))  # 'GPL-2.0 WITH Classpath-exception-2.0'
print(gpl_with_classpath.license_symbol.key)   # 'GPL-2.0'
print(gpl_with_classpath.exception_symbol.key) # 'Classpath-exception-2.0'

Symbol Equality and Comparison

# Symbol equality is based on keys
mit1 = LicenseSymbol('MIT', ['MIT License'])
mit2 = LicenseSymbol('MIT', ['Expat License'])
print(mit1 == mit2)  # True - same key

# Different keys are not equal
mit = LicenseSymbol('MIT')
apache = LicenseSymbol('Apache-2.0')
print(mit == apache)  # False

Using Symbols in Sets and Dictionaries

# Symbols can be used in sets (hashable by key)
symbols = {
    LicenseSymbol('MIT'),
    LicenseSymbol('Apache-2.0'),
    LicenseSymbol('MIT', ['Expat'])  # Duplicate key, won't be added twice
}
print(len(symbols))  # 2

# Use as dictionary keys
license_info = {
    LicenseSymbol('MIT'): 'Permissive license',
    LicenseSymbol('GPL-2.0'): 'Copyleft license'
}

Custom Rendering

# Render symbols with custom templates
mit = LicenseSymbol('MIT', ['MIT License'])
print(mit.render())                    # 'MIT' (default)
print(mit.render('{symbol.key}'))      # 'MIT'
print(mit.render('License: {symbol.key}'))  # 'License: MIT'

Symbol Validation

The library provides utilities for validating collections of symbols:

from license_expression import validate_symbols, LicenseSymbol

symbols = [
    LicenseSymbol('MIT'),
    LicenseSymbol('Apache-2.0'),
    LicenseSymbol('GPL-2.0', is_exception=True),  # Invalid: GPL-2.0 is not an exception
]

warnings, errors = validate_symbols(symbols, validate_keys=True)
print(errors)  # List of validation errors

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