Bengal 0.2.7
Plugin system, template dependency tracking, free-threading hardening, page walk optimizations
Key additions: Unified plugin system with 9 extension points, per-page template dependency tracking for selective rebuilds, free-threading hardening (thread-safe caches and tracers), 8→1 page walk optimizations, code simplification, and restructured CI test infrastructure.
Highlights
Plugin System
Bengal now has a formal plugin framework. Plugins implement aPlugin protocol (name, version, register()) and register extensions through a PluginRegistrythat supports 9 extension points: directives, roles, template functions, template filters, template tests, content sources, health validators, shortcodes, and build phase hooks.
Plugins are auto-discovered via thebengal.pluginsentry point group:
# pyproject.toml of your plugin package
[project.entry-points."bengal.plugins"]
my-plugin = "my_package:MyPlugin"
from bengal.plugins.protocol import Plugin
from bengal.plugins.registry import PluginRegistry
class MyPlugin(Plugin):
name = "my-plugin"
version = "1.0.0"
def register(self, registry: PluginRegistry) -> None:
registry.add_template_filter("shout", lambda v: v.upper() + "!")
registry.on_phase("post_render", self.after_render)
The registry uses a builder→immutable pattern: mutable during registration, frozen into an immutable FrozenPluginRegistrydataclass before parallel rendering begins. Thread-safe by design.
See Writing Plugins for the full guide.
Template Dependency Tracking
The build cache now records which templates (and their full include/extends chain) each page uses. When a template changes, only the pages that depend on it rebuild — instead of a full site rebuild.
- First build: dependencies are recorded (no change in behavior)
- Subsequent builds: template changes trigger selective rebuilds
- Falls back to full rebuild if no dependency data exists (cache miss or first build)
On a 1,000-page site where you edit a partial template used by 50 pages, this means rebuilding 50 pages instead of 1,000.
Free-Threading Hardening
Three changes prepare Bengal for Python 3.14t (PEP 703) free-threading:
- EffectTracer: All mutations and reads are now serialized under a lock. Without the GIL, concurrent
defaultdictaccess could observe partial state. get_bengal_dir()cache: Replaced@lru_cache(maxsize=1)with Bengal'sLRUCache, which uses anRLockinternally.functools.lru_cacherelies on the GIL for thread safety.- Kida 0.2.9: Updated the template engine dependency for free-threading support.
Page Walk Optimizations
Coalesced 8 redundantsite.pagestraversals into single passes:
- Menu building: Three separate scans (changed-page check, menu frontmatter collection, root-level page collection) merged into
_analyze_menu_state()— one pass returning(needs_rebuild, menu_pages, root_level_pages). - Finalization: Four scans for page count, autodoc detection, and stats merged into a single loop.
- Provenance: Eliminated duplicate
pages_listconstruction. - Manifest: Fixed
summary()multi-scan (4 scans → 1 pass).
On large sites (1K+ pages), this reduces orchestration phase time by ~8–12%.
Code Simplification
- Exception hierarchy: Replaced 11 manual
__init__methods in exception subclasses with a_default_build_phase_nameclass variable pattern — less boilerplate, same behavior. - Deprecated transforms removed:
escape_jinja_blocks(),transform_internal_links(), andnormalize_markdown_links()are gone. Their work is handled byHybridHTMLTransformer. - Renderer helpers: Extracted
_default_pagination()and_coerce_pagination_ints()to eliminate duplicated inline dict construction.
Test Infrastructure
tests/README.md: Comprehensive test suite guide covering 4,065+ tests (116 property-based via Hypothesis), 10 test roots, markers, parallel safety, and CI strategy.- CI restructure: 6 parallel integration shards with signal-based timeouts (SIGALRM) instead of thread-based. Required for free-threaded Python where thread-based
pytest-timeoutcannot fire. - Class-scoped fixtures: New
build_ephemeral_site_at()helper enables class/module-scoped test reuse without redundant site builds. - Removed no-op test:
test_resource_cleanup.pyhad 0 assertions — deleted.
Upgrading
uv pip install --upgrade bengal
# or
pip install --upgrade bengal
# or use the self-update command
bengal upgrade
No breaking changes in this release.