Modular, Markdown-based documentation generator that makes pdf, docx, html, and more.
—
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.
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
"""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'])
"""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()
"""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
"""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())}")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.1from 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)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 silentlyfrom 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 inspectionfrom 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())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")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