CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-webassets

Media asset management for Python, with glue code for various web frameworks

Overview
Eval results
Files

utilities.mddocs/

Utilities

Essential utility functions and classes that provide core infrastructure for webassets, including path operations, context managers, object resolution, registry management, and security features.

Capabilities

Hash Functions

def hash_func(data):
    """
    Create hash from arbitrary data using webassets cache system.
    
    Args:
        data: Data to hash (can be complex objects)
        
    Returns:
        str: MD5 hash string
    """

md5_constructor = hashlib.md5

Path Operations

def common_path_prefix(paths, sep=os.path.sep):
    """
    Find common directory path prefix from multiple paths.
    
    Improved version of os.path.commonpath() that handles both
    forward and backward slashes correctly.
    
    Args:
        paths: List of file paths
        sep: Path separator to use in result (default: os.path.sep)
        
    Returns:
        str: Common directory prefix
    """

def is_url(s):
    """
    Check if string is a valid URL.
    
    Args:
        s: String to check
        
    Returns:
        bool: True if string has valid URL scheme and netloc
    """

Context Managers

@contextlib.contextmanager
def working_directory(directory=None, filename=None):
    """
    Context manager to temporarily change working directory.
    
    Useful for filters that need to run in specific directories.
    Restores original directory on exit.
    
    Args:
        directory: Directory to change to
        filename: File path (directory will be extracted)
        
    Note: Exactly one of directory or filename must be provided.
    
    Usage:
        with working_directory('/path/to/dir'):
            # commands run in /path/to/dir
        # back to original directory
    """

Object Resolution System

def make_option_resolver(clazz=None, attribute=None, classes=None,
                        allow_none=True, desc=None):
    """
    Create a function that resolves options to objects.
    
    The resolver can handle:
    - Object instances (returned as-is)
    - Class objects (instantiated)
    - String identifiers (resolved from registry)
    - Arguments in format "key:argument"
    
    Args:
        clazz: Base class for type checking
        attribute: Duck-typing attribute to check for
        classes: Registry dictionary for string resolution
        allow_none: Whether None values are allowed
        desc: Description for error messages
        
    Returns:
        function: Resolver function that takes (option, env=None)
    """

Registry Metaclass

def RegistryMetaclass(clazz=None, attribute=None, allow_none=True, desc=None):
    """
    Create a metaclass that maintains a registry of subclasses.
    
    Classes using this metaclass are automatically registered by their
    'id' attribute and can be resolved from strings.
    
    Args:
        clazz: Base class for type checking
        attribute: Duck-typing attribute
        allow_none: Whether None resolution is allowed
        desc: Description for error messages
        
    Returns:
        type: Metaclass with REGISTRY dict and resolve() method
        
    Features:
        - Automatic subclass registration by 'id' attribute
        - String-to-class resolution via resolve() method
        - Automatic __eq__, __str__, __unicode__ methods
        - Integration with make_option_resolver
    """

Debug Level Management

def cmp_debug_levels(level1, level2):
    """
    Compare debug levels for filter execution.
    
    Debug levels: False < 'merge' < True
    
    Args:
        level1: First debug level
        level2: Second debug level
        
    Returns:
        int: -1 if level1 < level2, 0 if equal, 1 if level1 > level2
        
    Raises:
        BundleError: If invalid debug level provided
    """

Security Functions

def calculate_sri(data):
    """
    Calculate Subresource Integrity (SRI) hash for data.
    
    Args:
        data: Bytes data to hash
        
    Returns:
        str: SRI string in format 'sha384-<base64hash>'
    """

def calculate_sri_on_file(file_name):
    """
    Calculate SRI hash for file contents.
    
    Args:
        file_name: Path to file
        
    Returns:
        str or None: SRI string, or None if file not found
    """

Module Exports

# Compatibility imports for different Python versions
md5_constructor = hashlib.md5
set = set  # Built-in set for older Python versions
StringIO = io.StringIO  # String buffer for text operations
pickle = pickle  # Serialization module

Key Features

Flexible Object Resolution

The option resolver system enables flexible configuration:

# String resolution with arguments
resolver = make_option_resolver(classes={'file': FileCache, 'mem': MemoryCache})
cache = resolver('file:/tmp/cache', env)  # Creates FileCache('/tmp/cache')

# Class resolution with factory method
cache = resolver(FileCache, env)  # Uses FileCache.make(env) if available

# Instance resolution
cache = resolver(existing_cache)  # Returns existing_cache as-is

Registry Pattern

The metaclass provides automatic registration:

class BaseUpdater(metaclass=RegistryMetaclass(desc='updater')):
    pass

class TimestampUpdater(BaseUpdater):
    id = 'timestamp'  # Automatically registered

# String resolution
updater = BaseUpdater.resolve('timestamp')  # Returns TimestampUpdater instance

Cross-Platform Path Handling

Path utilities work consistently across operating systems:

# Handles mixed separators correctly
paths = ['/home/user/project\\assets\\css', '/home/user/project/assets/js']
common = common_path_prefix(paths)  # '/home/user/project/assets'

Safe Working Directory Changes

Context manager ensures directory restoration even on exceptions:

original_dir = os.getcwd()
with working_directory('/tmp/build'):
    # Process files in /tmp/build
    run_build_command()
    # Exception here still restores directory
# Back in original_dir

Security Integration

SRI support for Content Security Policy compliance:

# Generate SRI for inline content
content = "console.log('hello');"
sri = calculate_sri(content.encode('utf-8'))
# Use in HTML: <script integrity="sha384-...">

# Generate SRI for files
sri = calculate_sri_on_file('app.js')
if sri:
    print(f'<script src="app.js" integrity="{sri}"></script>')

Usage Examples

Factory Pattern with Environment

class CustomCache:
    @classmethod
    def make(cls, env, path):
        # Initialize with environment-specific settings
        return cls(path, debug=env.debug)

resolver = make_option_resolver(classes={'custom': CustomCache})
cache = resolver('custom:/tmp/cache', env)  # Uses make() method

Registry-Based Plugin System

class FilterBase(metaclass=RegistryMetaclass(desc='filter')):
    def apply(self, content):
        raise NotImplementedError

class JSMinFilter(FilterBase):
    id = 'jsmin'
    def apply(self, content):
        return minify_js(content)

# Automatic resolution
filter_obj = FilterBase.resolve('jsmin')  # Gets JSMinFilter instance

Debug Level Filtering

# Filter selection based on debug level
available_filters = [dev_filter, prod_filter, debug_filter]
current_level = 'merge'

active_filters = [f for f in available_filters 
                 if cmp_debug_levels(current_level, f.max_debug_level) <= 0]

Install with Tessl CLI

npx tessl i tessl/pypi-webassets

docs

bundle-management.md

caching-versioning.md

command-line.md

configuration-loading.md

environment-configuration.md

filter-system.md

framework-integration.md

index.md

merge-system.md

updater-system.md

utilities.md

tile.json