CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-foliant

Modular, Markdown-based documentation generator that makes pdf, docx, html, and more.

Pending
Overview
Eval results
Files

utils.mddocs/

Utility Functions

Foliant's utility module provides helper functions for plugin discovery, package management, output handling, and common operations across the Foliant ecosystem. These functions support the plugin architecture and provide consistent interfaces for system integration.

Capabilities

Plugin Discovery Functions

Functions for discovering and loading available Foliant extensions dynamically.

def get_available_tags() -> Set[str]:
    """
    Extract tags from all installed preprocessor classes.
    Discovers all foliant.preprocessors.*.Preprocessor classes and
    collects their tag attributes.
    
    Returns:
    Set[str]: Set of all available preprocessor tags
    """

def get_available_config_parsers() -> Dict[str, Type]:
    """
    Get installed config parser submodules and their Parser classes.
    Used for constructing the dynamic Foliant config parser.
    
    Returns:
    Dict[str, Type]: Dictionary mapping parser names to Parser classes
    """

def get_available_clis() -> Dict[str, Type]:
    """
    Get installed CLI submodules and their Cli classes.
    Used for constructing the dynamic Foliant CLI class.
    
    Returns:
    Dict[str, Type]: Dictionary mapping CLI names to Cli classes
    """

def get_available_backends() -> Dict[str, Tuple[str]]:
    """
    Get installed backend submodules and their supported targets.
    Used for backend validation and interactive selection.
    
    Returns:
    Dict[str, Tuple[str]]: Dictionary mapping backend names to target tuples
    """

Package Management Functions

Functions for discovering and listing Foliant-related packages in the environment.

def get_foliant_packages() -> List[str]:
    """
    Get list of installed Foliant-related packages with versions.
    Includes core foliant package and all foliantcontrib.* extensions.
    
    Returns:
    List[str]: Package names and versions (e.g., ['foliant 1.0.13', 'mkdocs 1.2.0'])
    """

Output and Display Functions

Functions for consistent output handling and user interaction.

def output(text: str, quiet=False):
    """
    Output text to STDOUT in non-quiet mode.
    Provides consistent output handling across Foliant.
    
    Parameters:
    - text (str): Message to output
    - quiet (bool): Suppress output if True
    """

def spinner(text: str, logger: Logger, quiet=False, debug=False):
    """
    Context manager for long-running operations with progress indication.
    Shows spinner during operation and handles exceptions gracefully.
    
    Parameters:
    - text (str): Operation description to display
    - logger (Logger): Logger for capturing errors
    - quiet (bool): Hide messages if True
    - debug (bool): Show full tracebacks on errors
    
    Usage:
    with spinner('Processing files', logger):
        # Long-running operation here
        process_files()
    """

File System Utilities

Functions for temporary directory management and cleanup.

def tmp(tmp_path: Path, keep_tmp=False):
    """
    Context manager for temporary directory cleanup.
    Removes directory before and after operation unless keep_tmp is True.
    
    Parameters:
    - tmp_path (Path): Path to temporary directory
    - keep_tmp (bool): Skip cleanup if True
    
    Usage:
    with tmp(Path('./temp'), keep_tmp=False):
        # Work with temporary files
        create_temp_files()
    # Directory automatically cleaned up
    """

Usage Examples

Plugin Discovery

from foliant.utils import (
    get_available_backends, 
    get_available_tags,
    get_available_clis,
    get_available_config_parsers
)

# Discover available backends
backends = get_available_backends()
print("Available backends:")
for name, targets in backends.items():
    print(f"  {name}: {', '.join(targets)}")

# Discover preprocessor tags
tags = get_available_tags()
print(f"Available tags: {', '.join(sorted(tags))}")

# Discover CLI extensions
clis = get_available_clis()
print(f"Available CLI commands: {', '.join(clis.keys())}")

# Discover config parsers
parsers = get_available_config_parsers()
print(f"Available config parsers: {', '.join(parsers.keys())}")

Package Information

from foliant.utils import get_foliant_packages

# Get installed Foliant packages
packages = get_foliant_packages()
print("Installed Foliant packages:")
for package in packages:
    print(f"  {package}")

# Example output:
# foliant 1.0.13
# mkdocs 1.4.2
# pandoc 2.1.0
# plantuml 1.2.1

Output Handling

from foliant.utils import output

# Standard output
output("Processing started...")

# Quiet mode (no output)
output("This won't be shown", quiet=True)

# Conditional output based on configuration
def process_with_output(files, quiet=False):
    output(f"Processing {len(files)} files...", quiet)
    for file in files:
        output(f"  Processing {file}", quiet)
    output("Processing complete!", quiet)

Progress Indication

from foliant.utils import spinner
import logging
import time

logger = logging.getLogger('foliant')

# Basic spinner usage
with spinner('Loading configuration', logger):
    time.sleep(2)  # Long operation
    # Prints: "Loading configuration... Done"

# Spinner with error handling
try:
    with spinner('Generating PDF', logger, debug=True):
        # Simulate operation that might fail
        raise RuntimeError("PDF generation failed")
except RuntimeError:
    print("Operation failed - check logs")

# Quiet mode (no visual output)
with spinner('Background processing', logger, quiet=True):
    process_files()  # Operation runs silently

Temporary Directory Management

from foliant.utils import tmp
from pathlib import Path
import shutil

# Automatic cleanup
with tmp(Path('./build_temp')):
    # Create temporary files
    temp_dir = Path('./build_temp')
    temp_dir.mkdir(exist_ok=True)
    
    (temp_dir / 'temp_file.txt').write_text('temporary content')
    
    # Process files
    process_temporary_files(temp_dir)
    
# Directory automatically cleaned up here

# Keep temporary files for debugging
with tmp(Path('./debug_temp'), keep_tmp=True):
    # Create files for debugging
    debug_dir = Path('./debug_temp')
    debug_dir.mkdir(exist_ok=True)
    
    create_debug_files(debug_dir)
    
# Directory preserved for inspection

Dynamic Class Construction

from foliant.utils import get_available_clis, get_available_config_parsers

# Create dynamic CLI class (how Foliant CLI works)
available_clis = get_available_clis()

class DynamicCli(*available_clis.values()):
    """Dynamic CLI combining all available commands."""
    
    def __init__(self):
        super().__init__()
        print(f"Loaded {len(available_clis)} CLI extensions")

# Create dynamic config parser (how Foliant config works)  
available_parsers = get_available_config_parsers()

class DynamicParser(*available_parsers.values()):
    """Dynamic parser combining all available parsers."""
    pass

# Use dynamic classes
cli = DynamicCli()
parser = DynamicParser(Path('.'), 'foliant.yml', logging.getLogger())

Error Handling with Spinner

from foliant.utils import spinner
import logging

logger = logging.getLogger('foliant')

def safe_operation_with_spinner(operation_name, operation_func, *args, **kwargs):
    """Wrapper for operations with spinner and error handling."""
    try:
        with spinner(operation_name, logger, debug=True):
            return operation_func(*args, **kwargs)
    except Exception as e:
        logger.error(f"{operation_name} failed: {e}")
        return None

# Usage
result = safe_operation_with_spinner(
    "Building documentation",
    build_docs,
    source_dir="./src",
    output_dir="./build"
)

if result:
    print(f"Build successful: {result}")
else:
    print("Build failed - check logs")

Backend Validation Utility

from foliant.utils import get_available_backends

def validate_target_backend_combination(target: str, backend: str = None) -> tuple:
    """
    Validate target/backend combination and suggest alternatives.
    
    Returns:
    tuple: (is_valid, suggested_backend_or_error_message)
    """
    available = get_available_backends()
    
    if backend:
        # Validate specific backend
        if backend not in available:
            return False, f"Backend '{backend}' not available"
        
        if target not in available[backend]:
            return False, f"Backend '{backend}' doesn't support target '{target}'"
        
        return True, backend
    
    else:
        # Find suitable backend
        suitable = [name for name, targets in available.items() if target in targets]
        
        if not suitable:
            return False, f"No backend available for target '{target}'"
        
        return True, suitable[0]  # Return first suitable backend

# Usage
valid, result = validate_target_backend_combination('pdf', 'pandoc')
if valid:
    print(f"Using backend: {result}")
else:
    print(f"Error: {result}")

Install with Tessl CLI

npx tessl i tessl/pypi-foliant

docs

backends.md

cli.md

config.md

index.md

preprocessors.md

utils.md

tile.json