Module

core.section

Section representation for organizing pages into hierarchical groups.

Sections represent directories in the content tree and provide navigation, sorting, and hierarchical query interfaces. Sections can be nested and maintain parent-child relationships. Each section can have an index page and contains both regular pages and subsections.

Key Concepts:

  • Hierarchy: Sections form a tree structure with parent-child relationships
  • Index pages: Special pages (_index.md or index.md) that represent the section
  • Weight-based sorting: Pages and subsections sorted by weight metadata
  • Hashability: Sections are hashable by path for set operations

Related Modules:

  • bengal.core.page: Page objects contained within sections
  • bengal.core.site: Site container that manages all sections
  • bengal.orchestration.content: Content discovery that builds section hierarchy

See Also:

  • bengal/core/section.py: Section class for section representation

Classes

WeightedPage dataclass
1

Attributes

Name Type Description
page Page
weight float
title_lower str
Internal Methods 1
__lt__
1 bool
def __lt__(self, other: WeightedPage) -> bool
Parameters 1
other WeightedPage
Returns

bool

Section dataclass
Represents a folder or logical grouping of pages. HASHABILITY: ============ Sections are hashable …
30

Represents a folder or logical grouping of pages.

HASHABILITY:

============ Sections are hashable based on their path (or name for virtual sections), allowing them to be stored in sets and used as dictionary keys. This enables:

  • Fast membership tests and lookups
  • Type-safe Set[Section] collections
  • Set operations for section analysis

Two sections with the same path are considered equal. The hash is stable throughout the section lifecycle because path is immutable.

VIRTUAL SECTIONS:

================= Virtual sections represent API documentation or other dynamically-generated content that doesn't have a corresponding directory on disk. Virtual sections:

  • Have _virtual=True and path=None
  • Are discovered via VirtualAutodocOrchestrator during build
  • Work with menu system via name-based lookups
  • Don't write intermediate markdown files

Attributes

Name Type Description
name str

Section name

path Path | None

Path to the section directory (None for virtual sections)

pages list[Page]

List of pages in this section

subsections list[Section]

Child sections

metadata dict[str, Any]

Section-level metadata

index_page Page | None

Optional index page for the section

parent Section | None

Parent section (if nested)

_virtual bool

True if this is a virtual section (no disk directory)

_relative_url_override str | None
_site Any | None

Methods 27

is_virtual property
Check if this is a virtual section (no disk directory). Virtual sections are u…
bool
def is_virtual(self) -> bool

Check if this is a virtual section (no disk directory).

Virtual sections are used for:

  • API documentation generated from Python source code
  • Dynamically-generated content from external sources
  • Content that doesn't have a corresponding content/ directory
Returns

bool

True if this section is virtual (not backed by a disk directory)

slug property
URL-friendly identifier for this section. For virtual sections, uses the name …
str
def slug(self) -> str

URL-friendly identifier for this section.

For virtual sections, uses the name directly. For physical sections, uses the directory name.

Returns

str

Section slug (e.g., "api", "core", "bengal-core")

title property
Get section title from metadata or generate from name.
str
def title(self) -> str

Get section title from metadata or generate from name.

Returns

str

icon property
Get section icon from index page metadata (cached). Icons can be specified in …
str | None
def icon(self) -> str | None

Get section icon from index page metadata (cached).

Icons can be specified in a section's _index.md frontmatter:

---
title: API Reference
icon: book
---

The icon name should match a Phosphor icon in the icon library (e.g., 'book', 'folder', 'terminal', 'code').

Returns

str | None

Icon name string, or None if no icon is specified

hierarchy property
Get the full hierarchy path of this section.
list[str]
def hierarchy(self) -> list[str]

Get the full hierarchy path of this section.

Returns

list[str]

List of section names from root to this section

depth property
Get the depth of this section in the hierarchy.
int
def depth(self) -> int

Get the depth of this section in the hierarchy.

Returns

int

root property
Get the root section of this section's hierarchy.
Section
def root(self) -> Section

Get the root section of this section's hierarchy.

Returns

Section

The topmost ancestor section

regular_pages property
Get only regular pages (non-sections) in this section.
list[Page]
def regular_pages(self) -> list[Page]

Get only regular pages (non-sections) in this section.

Returns

list[Page]

List of regular Page objects (excludes subsections)

sections property
Get immediate child sections.
list[Section]
def sections(self) -> list[Section]

Get immediate child sections.

Returns

list[Section]

List of child Section objects

sorted_pages property
Get pages sorted by weight (ascending), then by title (CACHED). This property …
list[Page]
def sorted_pages(self) -> list[Page]

Get pages sorted by weight (ascending), then by title (CACHED).

This property is cached after first access for O(1) subsequent lookups. The sort is computed once and reused across all template renders.

Pages without a weight field are treated as having weight=float('inf') and appear at the end of the sorted list, after all weighted pages. Lower weights appear first in the list. Pages with equal weight are sorted alphabetically by title.

Performance:

  • First access: O(n log n) where n = number of pages
  • Subsequent accesses: O(1) cached lookup
  • Memory cost: O(n) to store sorted list
Returns

list[Page]

List of pages sorted by weight, then title

sorted_subsections property
Get subsections sorted by weight (ascending), then by title (CACHED). This pro…
list[Section]
def sorted_subsections(self) -> list[Section]

Get subsections sorted by weight (ascending), then by title (CACHED).

This property is cached after first access for O(1) subsequent lookups. The sort is computed once and reused across all template renders.

Subsections without a weight field in their index page metadata are treated as having weight=999999 (appear at end). Lower weights appear first.

Performance:

  • First access: O(m log m) where m = number of subsections
  • Subsequent accesses: O(1) cached lookup
  • Memory cost: O(m) to store sorted list
Returns

list[Section]

List of subsections sorted by weight, then title

subsection_index_urls property
Get set of URLs for all subsection index pages (CACHED). This pre-computed set…
set[str]
def subsection_index_urls(self) -> set[str]

Get set of URLs for all subsection index pages (CACHED).

This pre-computed set enables O(1) membership checks for determining if a page is a subsection index. Used in navigation templates to avoid showing subsection indices twice (once as page, once as subsection link).

Performance:

  • First access: O(m) where m = number of subsections
  • Subsequent lookups: O(1) set membership check
  • Memory cost: O(m) URLs
Returns

set[str]

Set of URL strings for subsection index pages

has_nav_children property
Check if this section has navigable children (CACHED). A section has navigable…
bool
def has_nav_children(self) -> bool

Check if this section has navigable children (CACHED).

A section has navigable children if it contains either:

  • Regular pages (excluding the index page itself)
  • Subsections

This property is used by navigation templates to determine whether to render a section as an expandable group (with toggle button) or as a simple link. Sections without children should not show an expand/collapse toggle since there's nothing to expand.

Performance:

  • First access: O(1) - uses cached sorted_pages/sorted_subsections
  • Subsequent accesses: O(1) cached lookup
Returns

bool

True if section has pages or subsections to display in nav

regular_pages_recursive property
Get all regular pages recursively (including from subsections).
list[Page]
def regular_pages_recursive(self) -> list[Page]

Get all regular pages recursively (including from subsections).

Returns

list[Page]

List of all descendant regular pages

relative_url property
Get relative URL without baseurl (for comparisons). This is the identity URL -…
str
def relative_url(self) -> str

Get relative URL without baseurl (for comparisons).

This is the identity URL - use for comparisons, menu activation, etc. Always returns a relative path without baseurl.

For virtual sections, uses the _relative_url_override set during creation. Virtual sections MUST have explicit URLs - they never fall back to construction.

Returns

str

url property
Get URL with baseurl applied (cached after first access). This is the primary …
str
def url(self) -> str

Get URL with baseurl applied (cached after first access).

This is the primary URL property for templates - automatically includes baseurl when available. Use .relative_url for comparisons.

Returns

str

URL path with baseurl prepended (if configured)

permalink property
Alias for url (for backward compatibility). Both url and permalink now return …
str
def permalink(self) -> str

Alias for url (for backward compatibility).

Both url and permalink now return the same value (with baseurl). Use .relative_url for comparisons.

Returns

str

create_virtual classmethod
Create a virtual section for dynamically-generated content. Virtual sections a…
4 Section
def create_virtual(cls, name: str, relative_url: str, title: str | None = None, metadata: dict[str, Any] | None = None) -> Section

Create a virtual section for dynamically-generated content.

Virtual sections are not backed by a disk directory but integrate with the site's section hierarchy, navigation, and menu system.

Parameters 4
name str

Section name (used for lookups, e.g., "api")

relative_url str

URL for this section (e.g., "/api/")

title str | None

Display title (defaults to titlecase of name)

metadata dict[str, Any] | None

Optional section metadata

Returns

Section

A new virtual Section instance

add_page
Add a page to this section.
1 None
def add_page(self, page: Page) -> None

Add a page to this section.

Parameters 1
page Page

Page to add

add_subsection
Add a subsection to this section.
1 None
def add_subsection(self, section: Section) -> None

Add a subsection to this section.

Parameters 1
section Section

Child section to add

sort_children_by_weight
Sort pages and subsections in this section by weight, then by title. This modi…
0 None
def sort_children_by_weight(self) -> None

Sort pages and subsections in this section by weight, then by title.

This modifies the pages and subsections lists in place. Pages/sections without a weight field are treated as having weight=float('inf'), so they appear at the end (after all weighted items). Lower weights appear first in the sorted lists.

This is typically called after content discovery is complete.

needs_auto_index
Check if this section needs an auto-generated index page.
0 bool
def needs_auto_index(self) -> bool

Check if this section needs an auto-generated index page.

Returns

bool

True if section needs auto-generated index (no explicit _index.md)

has_index
Check if section has a valid index page.
0 bool
def has_index(self) -> bool

Check if section has a valid index page.

Returns

bool

True if section has an index page (explicit or auto-generated)

get_all_pages
Get all pages in this section.
1 list[Page]
def get_all_pages(self, recursive: bool = True) -> list[Page]

Get all pages in this section.

Parameters 1
recursive bool

If True, include pages from subsections

Returns

list[Page]

List of all pages

aggregate_content
Aggregate content from all pages in this section.
0 dict[str, Any]
def aggregate_content(self) -> dict[str, Any]

Aggregate content from all pages in this section.

Returns

dict[str, Any]

Dictionary with aggregated content information

apply_section_template
Apply a section template to generate a section index page.
1 str
def apply_section_template(self, template_engine: Any) -> str

Apply a section template to generate a section index page.

Parameters 1
template_engine Any

Template engine instance

Returns

str

Rendered HTML for the section index

walk
Iteratively walk through all sections in the hierarchy.
0 list[Section]
def walk(self) -> list[Section]

Iteratively walk through all sections in the hierarchy.

Returns

list[Section]

List of all sections (self and descendants)

Internal Methods 3
__hash__
Hash based on section path (or name for virtual sections) for stable identity. …
0 int
def __hash__(self) -> int

Hash based on section path (or name for virtual sections) for stable identity.

The hash is computed from the section's path, which is immutable throughout the section lifecycle. This allows sections to be stored in sets and used as dictionary keys.

For virtual sections (path=None), uses the name and _relative_url_override for hashing to ensure stable identity.

Returns

int

Integer hash of the section path or name

__eq__
Sections are equal if they have the same path (or name+URL for virtual). Equal…
1 bool
def __eq__(self, other: Any) -> bool

Sections are equal if they have the same path (or name+URL for virtual).

Equality is based on path only, not on pages or other mutable fields. This means two Section objects representing the same directory are considered equal, even if their contents differ.

For virtual sections (path=None), equality is based on name and URL.

Parameters 1
other Any

Object to compare with

Returns

bool

True if other is a Section with the same path

__repr__
0 str
def __repr__(self) -> str
Returns

str