Static site generator supporting Markdown and reStructuredText
—
Configuration system providing default settings, file-based configuration loading, and runtime setting management for all aspects of site generation including paths, URLs, themes, and plugin behavior.
Functions for loading and managing Pelican configuration from files and runtime overrides.
def read_settings(path: str = None, override: dict = None) -> dict:
"""
Load settings from configuration file with optional overrides.
Parameters:
- path (str, optional): Path to settings file (defaults to pelicanconf.py in current directory)
- override (dict, optional): Dictionary of settings to override loaded values
Returns:
dict: Complete settings dictionary with defaults, file settings, and overrides merged
"""
def load_source(name: str, path: str) -> ModuleType:
"""
Load Python module from file path.
Parameters:
- name (str): Module name for import system
- path (str): File path to Python module
Returns:
ModuleType: Loaded Python module object
"""Type definitions and constants for configuration management.
Settings = dict[str, Any] # Type alias for settings dictionary
DEFAULT_CONFIG: dict # Default configuration dictionary with all standard settings
DEFAULT_THEME: str # Path to default theme directoryConfigure content source paths, organization, and file handling:
# Content source paths
PATH = 'content' # Main content directory
ARTICLE_PATHS = [''] # Article subdirectories (relative to PATH)
ARTICLE_EXCLUDES = [] # Exclude patterns for articles
PAGE_PATHS = ['pages'] # Page subdirectories
PAGE_EXCLUDES = [] # Exclude patterns for pages
STATIC_PATHS = ['images'] # Static file subdirectories
STATIC_EXCLUDES = [] # Exclude patterns for static files
IGNORE_FILES = ['.#*'] # Global ignore patternsConfigure output paths and URL structure:
# Output configuration
OUTPUT_PATH = 'output' # Output directory
DELETE_OUTPUT_DIRECTORY = False # Clean output before generation
OUTPUT_RETENTION = [] # Files to retain when cleaning
# URL patterns for articles
ARTICLE_URL = '{slug}.html'
ARTICLE_SAVE_AS = '{slug}.html'
ARTICLE_LANG_URL = '{slug}-{lang}.html'
ARTICLE_LANG_SAVE_AS = '{slug}-{lang}.html'
# URL patterns for pages
PAGE_URL = 'pages/{slug}.html'
PAGE_SAVE_AS = 'pages/{slug}.html'
PAGE_LANG_URL = 'pages/{slug}-{lang}.html'
PAGE_LANG_SAVE_AS = 'pages/{slug}-{lang}.html'
# URL patterns for categories, tags, authors
CATEGORY_URL = 'category/{slug}.html'
CATEGORY_SAVE_AS = 'category/{slug}.html'
TAG_URL = 'tag/{slug}.html'
TAG_SAVE_AS = 'tag/{slug}.html'
AUTHOR_URL = 'author/{slug}.html'
AUTHOR_SAVE_AS = 'author/{slug}.html'
# Archive URL patterns
YEAR_ARCHIVE_URL = '' # Year archive URL pattern
MONTH_ARCHIVE_URL = '' # Month archive URL pattern
DAY_ARCHIVE_URL = '' # Day archive URL patternBasic site metadata and branding:
SITENAME = 'A Pelican Blog' # Site title
SITEURL = '' # Site base URL (for absolute URLs)
AUTHOR = '' # Default author name
DEFAULT_LANG = 'en' # Default content language
TIMEZONE = 'UTC' # Site timezoneConfigure theming and template rendering:
THEME = DEFAULT_THEME # Theme directory path
THEME_STATIC_DIR = 'theme' # Theme static files directory name
THEME_STATIC_PATHS = ['static'] # Theme static source directories
THEME_TEMPLATES_OVERRIDES = [] # Additional template directories
# Template configuration
DIRECT_TEMPLATES = ['index', 'tags', 'categories', 'authors', 'archives']
TEMPLATE_PAGES = {} # Custom template pages
PAGINATED_TEMPLATES = { # Templates with pagination
'index': None,
'tag': None,
'category': None,
'author': None,
}
# Jinja2 environment settings
JINJA_ENVIRONMENT = {
'trim_blocks': True,
'lstrip_blocks': True,
'extensions': [],
}
JINJA_FILTERS = {} # Custom Jinja2 filters
JINJA_GLOBALS = {} # Custom Jinja2 global variables
JINJA_TESTS = {} # Custom Jinja2 testsConfigure RSS/Atom feed generation:
FEED_ALL_ATOM = 'feeds/all.atom.xml' # Main Atom feed
FEED_ALL_RSS = None # Main RSS feed (disabled by default)
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml' # Category-specific Atom feeds
CATEGORY_FEED_RSS = None # Category-specific RSS feeds
AUTHOR_FEED_ATOM = 'feeds/{slug}.atom.xml' # Author-specific Atom feeds
AUTHOR_FEED_RSS = 'feeds/{slug}.rss.xml' # Author-specific RSS feeds
TRANSLATION_FEED_ATOM = 'feeds/all-{lang}.atom.xml' # Translation feeds
FEED_MAX_ITEMS = 100 # Maximum items per feed
RSS_FEED_SUMMARY_ONLY = True # Include only summary in RSS
FEED_APPEND_REF = False # Append reference links to feedsConfigure content pagination:
DEFAULT_PAGINATION = False # Number of items per page (False = no pagination)
DEFAULT_ORPHANS = 0 # Minimum items on last page
PAGINATION_PATTERNS = [ # URL patterns for paginated pages
(1, '{name}{extension}', '{name}{extension}'),
(2, '{name}{number}{extension}', '{name}{number}{extension}'),
]Configure content processing for different markup formats:
# Markdown configuration
MARKDOWN = {
'extension_configs': {
'markdown.extensions.codehilite': {'css_class': 'highlight'},
'markdown.extensions.extra': {},
'markdown.extensions.meta': {},
},
'output_format': 'html5',
}
# reStructuredText configuration
DOCUTILS_SETTINGS = {} # Custom docutils settings
# Plugin configuration
PLUGINS = [] # List of enabled plugins
PLUGIN_PATHS = [] # Additional plugin search pathsConfigure caching and performance optimization:
CACHE_CONTENT = False # Enable content caching
CACHE_PATH = 'cache' # Cache directory path
LOAD_CONTENT_CACHE = True # Load existing cache on startup
CHECK_MODIFIED_METHOD = 'mtime' # Method for checking file modifications
CONTENT_CACHING_LAYER = 'reader' # Caching layer (reader or generator)Settings for development workflow:
RELATIVE_URLS = False # Use relative URLs (useful for development)
BIND = '127.0.0.1' # Development server bind address
PORT = 8000 # Development server port# pelicanconf.py - Basic site configuration
AUTHOR = 'John Doe'
SITENAME = 'My Personal Blog'
SITEURL = 'https://example.com'
PATH = 'content'
OUTPUT_PATH = 'output'
TIMEZONE = 'America/New_York'
DEFAULT_LANG = 'en'
# Feed generation
FEED_ALL_ATOM = 'feeds/all.atom.xml'
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
# Pagination
DEFAULT_PAGINATION = 10
# Theme
THEME = 'themes/my-custom-theme'
# Static paths
STATIC_PATHS = ['images', 'extra/CNAME']
EXTRA_PATH_METADATA = {
'extra/CNAME': {'path': 'CNAME'},
}from pelican.settings import read_settings
# Load default settings file
settings = read_settings() # Looks for pelicanconf.py
# Load specific settings file
settings = read_settings('mysite.conf')
# Load with overrides
settings = read_settings('pelicanconf.py', override={
'OUTPUT_PATH': 'dist',
'SITEURL': 'https://staging.example.com'
})
# Access settings
print(settings['SITENAME'])
print(settings['OUTPUT_PATH'])# pelicanconf.py - Advanced configuration
import os
# Site information
AUTHOR = 'Jane Smith'
SITENAME = 'Tech Blog'
SITEURL = 'https://techblog.example.com'
SITESUBTITLE = 'Thoughts on technology and programming'
# Content organization
PATH = 'content'
ARTICLE_PATHS = ['posts']
PAGE_PATHS = ['pages']
STATIC_PATHS = ['images', 'files', 'extra']
# URL structure
ARTICLE_URL = '{date:%Y}/{date:%m}/{slug}/'
ARTICLE_SAVE_AS = '{date:%Y}/{date:%m}/{slug}/index.html'
PAGE_URL = '{slug}/'
PAGE_SAVE_AS = '{slug}/index.html'
# Custom pagination
DEFAULT_PAGINATION = 5
PAGINATION_PATTERNS = [
(1, '{name}/', '{name}/index.html'),
(2, '{name}/page/{number}/', '{name}/page/{number}/index.html'),
]
# Markdown configuration
MARKDOWN = {
'extension_configs': {
'markdown.extensions.codehilite': {
'css_class': 'highlight',
'use_pygments': True,
},
'markdown.extensions.extra': {},
'markdown.extensions.meta': {},
'markdown.extensions.toc': {
'permalink': True,
'title': 'Table of Contents'
},
},
'output_format': 'html5',
}
# Plugin configuration
PLUGINS = ['pelican-seo', 'sitemap', 'related_posts']
PLUGIN_PATHS = ['plugins']
# Custom Jinja2 filters
def format_date(date):
return date.strftime('%B %d, %Y')
JINJA_FILTERS = {
'format_date': format_date,
}
# Environment-specific settings
if os.environ.get('PELICAN_ENV') == 'production':
SITEURL = 'https://techblog.example.com'
RELATIVE_URLS = False
DELETE_OUTPUT_DIRECTORY = True
else:
SITEURL = 'http://localhost:8000'
RELATIVE_URLS = True
DELETE_OUTPUT_DIRECTORY = Falsefrom pelican.settings import read_settings, DEFAULT_CONFIG
# Load settings with validation
def validate_settings(settings):
"""Validate required settings."""
required = ['SITENAME', 'AUTHOR', 'PATH']
for key in required:
if not settings.get(key):
raise ValueError(f"Required setting {key} is missing")
return settings
# Load and validate settings
settings = read_settings('pelicanconf.py')
settings = validate_settings(settings)
# Safe setting access with defaults
def get_setting(settings, key, default=None):
"""Get setting with fallback to default."""
return settings.get(key, DEFAULT_CONFIG.get(key, default))
# Use in generator or plugin
site_name = get_setting(settings, 'SITENAME', 'Unknown Site')
pagination = get_setting(settings, 'DEFAULT_PAGINATION', False)# pelicanconf.py - Dynamic configuration based on content
import os
from pathlib import Path
# Dynamic path detection
content_dir = Path('content')
if content_dir.exists():
# Discover article subdirectories
ARTICLE_PATHS = [
str(p.relative_to(content_dir))
for p in content_dir.iterdir()
if p.is_dir() and not p.name.startswith('.')
]
else:
ARTICLE_PATHS = ['']
# Dynamic plugin loading
available_plugins = []
plugin_dir = Path('plugins')
if plugin_dir.exists():
available_plugins = [
p.name for p in plugin_dir.iterdir()
if p.is_dir() and (p / '__init__.py').exists()
]
PLUGINS = available_plugins
# Environment-based configuration
class Config:
"""Configuration class for different environments."""
# Base configuration
SITENAME = 'My Blog'
AUTHOR = 'Author Name'
PATH = 'content'
@classmethod
def development(cls):
"""Development environment settings."""
return {
'SITEURL': 'http://localhost:8000',
'RELATIVE_URLS': True,
'DELETE_OUTPUT_DIRECTORY': False,
'DEBUG': True,
}
@classmethod
def production(cls):
"""Production environment settings."""
return {
'SITEURL': 'https://example.com',
'RELATIVE_URLS': False,
'DELETE_OUTPUT_DIRECTORY': True,
'DEBUG': False,
}
# Apply environment-specific settings
env = os.environ.get('PELICAN_ENV', 'development')
if env == 'production':
globals().update(Config.production())
else:
globals().update(Config.development())Install with Tessl CLI
npx tessl i tessl/pypi-pelican