all2md.ast.sections
Core section utilities for document AST structures.
This module provides the fundamental Section dataclass and basic section extraction and querying operations. Sections are the building blocks for document manipulation, representing a heading and all content up to the next same-or-higher level heading.
Functions
Section : Dataclass representing a document section get_all_sections : Extract all sections from a document with level filtering get_preamble : Get content before first heading parse_section_ranges : Parse section range specifications like “1-3,5” query_sections : Universal section query function (consolidates finding by heading, index, predicate) find_heading : Find a heading node in the document count_sections : Count sections in a document
Examples
- Get all sections:
>>> sections = get_all_sections(doc) >>> for section in sections: ... print(f"Level {section.level}: {section.get_heading_text()}")
- Query sections flexibly:
>>> sections = query_sections(doc, "Introduction") # by name >>> sections = query_sections(doc, 0) # by index >>> sections = query_sections(doc, lambda s: s.level == 2) # by predicate >>> sections = query_sections(doc, level=2) # by level
- Parse section ranges:
>>> indices = parse_section_ranges("1-3,5", total_sections=10) >>> indices [0, 1, 2, 4]
- class all2md.ast.sections.Section
Bases:
objectRepresents a document section with heading and content.
A section consists of a heading node and all content nodes that follow it until the next heading of the same or higher level.
- Parameters:
heading (Heading) – The heading node for this section
content (list of Node) – All nodes between this heading and the next same-or-higher level heading
level (int) – Heading level (1-6)
start_index (int) – Index of the heading in the parent document’s children list
end_index (int) – Exclusive end index (one past the last content node)
Examples
>>> section = Section( ... heading=Heading(level=1, content=[Text("Title")]), ... content=[Paragraph(content=[Text("Content")])], ... level=1, ... start_index=0, ... end_index=2 ... )
- level: int = 1
- start_index: int = 0
- end_index: int = 0
- to_document() Document
Convert this section to a standalone document.
- Returns:
New document containing the heading and content
- Return type:
Examples
>>> doc = section.to_document() >>> len(doc.children) 2
- get_heading_text() str
Extract plain text from the heading.
- Returns:
Plain text content of the heading
- Return type:
str
Examples
>>> section.get_heading_text() 'Introduction'
- all2md.ast.sections.get_all_sections(doc: Document, min_level: int = 1, max_level: int = 6) list[Section]
Extract all sections from a document.
- Parameters:
doc (Document) – Document to extract sections from
min_level (int, default = 1) – Minimum heading level to include (1 is highest)
max_level (int, default = 6) – Maximum heading level to include (6 is lowest)
- Returns:
All sections in document order
- Return type:
list of Section
Notes
A section is defined as a heading plus all content until the next same-or-higher level heading. Content before the first heading is not included in any section (see get_preamble).
Examples
>>> sections = get_all_sections(doc) >>> for section in sections: ... print(f"Level {section.level}: {section.get_heading_text()}")
- Get only top-level sections:
>>> top_sections = get_all_sections(doc, min_level=1, max_level=1)
- all2md.ast.sections.get_preamble(doc: Document) list[Node]
Get all content before the first heading.
- Parameters:
doc (Document) – Document to extract preamble from
- Returns:
All nodes before the first heading (empty if document starts with heading)
- Return type:
list of Node
Examples
>>> preamble = get_preamble(doc) >>> if preamble: ... print(f"Found {len(preamble)} preamble nodes")
- all2md.ast.sections.parse_section_ranges(section_spec: str, total_sections: int) list[int]
Parse section range specification into list of 0-based section indices.
Supports various formats (all 1-indexed input): - “1-3” -> [0, 1, 2] - “5” -> [4] - “10-” -> [9, 10, …, total_sections-1] - “1-3,5,10-” -> combined ranges - “5-3” -> [2, 3, 4] (automatically swaps to “3-5”)
Reversed ranges (where start > end) are automatically corrected by swapping the values. For example, “10-5” is treated as “5-10”.
- Parameters:
section_spec (str) – Section range specification (1-based section numbers)
total_sections (int) – Total number of sections in document
- Returns:
Sorted list of 0-based section indices
- Return type:
list of int
Examples
>>> parse_section_ranges("1-3,5", 10) [0, 1, 2, 4] >>> parse_section_ranges("8-", 10) [7, 8, 9] >>> parse_section_ranges("10-5", 10) [4, 5, 6, 7, 8, 9]
- all2md.ast.sections.query_sections(doc: Document, spec: str | int | list[int] | Callable[[Section], bool] | None = None, *, level: int | None = None, min_level: int = 1, max_level: int = 6, case_sensitive: bool = False) list[Section]
Universal section query function with flexible parameters.
This function consolidates multiple section-finding functions into one powerful interface that handles querying by name, index, pattern, predicate, or level filtering.
- Parameters:
doc (Document) – Document to search
spec (str, int, list[int], callable, or None) – Query specification: - None: return all sections (respects level filters) - str: heading text or pattern (“Introduction”, “Chapter*”) - int: single section index (0-based) - list[int]: multiple section indices (0-based) - callable: predicate function(section) -> bool
level (int or None, default = None) – If specified, only return sections at this exact level (1-6)
min_level (int, default = 1) – Minimum heading level to include
max_level (int, default = 6) – Maximum heading level to include
case_sensitive (bool, default = False) – Whether text matching is case-sensitive (for string specs)
- Returns:
Matching sections in document order
- Return type:
list of Section
- Raises:
ValueError – If spec is invalid or indices are out of range
IndexError – If a specified index is out of range
Examples
- Find all sections:
>>> sections = query_sections(doc)
- Find by exact heading text:
>>> sections = query_sections(doc, "Introduction")
- Find by pattern (wildcards):
>>> sections = query_sections(doc, "Chapter*")
- Find by single index:
>>> sections = query_sections(doc, 0) # First section
- Find by multiple indices:
>>> sections = query_sections(doc, [0, 2, 4])
- Find by predicate:
>>> sections = query_sections(doc, lambda s: len(s.content) > 5)
- Find by level:
>>> sections = query_sections(doc, level=2)
- Find by level range:
>>> sections = query_sections(doc, min_level=2, max_level=3)
- Combined filters:
>>> sections = query_sections(doc, "Chapter*", level=1)
- all2md.ast.sections.find_heading(doc: Document, text: str, level: int | None = None, case_sensitive: bool = False) tuple[int, Heading] | None
Find a heading node in the document.
This function finds heading nodes directly, not sections. Use query_sections() if you want to find sections (heading + content).
- Parameters:
doc (Document) – Document to search
text (str) – Text to search for
level (int or None, default = None) – If specified, only match headings at this level
case_sensitive (bool, default = False) – Whether to perform case-sensitive matching
- Returns:
Tuple of (index, heading_node) if found, None otherwise
- Return type:
tuple of (int, Heading) or None
Examples
>>> result = find_heading(doc, "Introduction") >>> if result: ... idx, heading = result ... print(f"Found at index {idx}, level {heading.level}")
- all2md.ast.sections.resolve_section_indices(sections: list[Section], spec: str | int | list[int], *, case_sensitive: bool = False) list[int]
Resolve an extraction spec to 0-based indices into
sections.This is the selection core shared by
extract_sections()(which builds a new Document) and the CLI line-number mapping (which slices the rendered output by section span). Centralizing it keeps the two in lockstep.- Parameters:
sections (list of Section) – Sections to select from, in document order.
spec (str or int or list of int) – Extraction specification: - Name: “Introduction” (exact match) - Pattern: “Intro*”, “Results” (uses fnmatch) - Single index: 0 (0-based) or “#:1” (1-based with #:) - Range: “#:1-3”, “#:3-” (1-based, inclusive) - Multiple: “#:1,3,5” or [0, 2, 4]
case_sensitive (bool, default False) – Whether name matching is case-sensitive.
- Returns:
0-based indices into
sections. Ordering follows the spec kind: index ranges are sorted ascending; explicit lists keep their order; name patterns are returned in document order.- Return type:
list of int
- Raises:
ValueError – If the spec is invalid or matches no sections.
TypeError – If the spec is of an unsupported type.
- all2md.ast.sections.extract_sections(doc: Document, spec: str | int | list[int], *, case_sensitive: bool = False, combine: bool = True, separator: Node | None = None) Document
Extract sections from document using flexible specification.
This function provides powerful section extraction with support for ranges, wildcards, multiple sections, and fuzzy matching with helpful suggestions.
- Parameters:
doc (Document) – Source document
spec (str or int or list of int) – Extraction specification: - Name: “Introduction” (exact match) - Pattern: “Intro*”, “Results” (uses fnmatch) - Single index: 0 or “#:1” (0-based or 1-based with #:) - Range: “#:1-3”, “#:3-” (1-based, inclusive) - Multiple: “#:1,3,5” or [0, 2, 4] (1-based or 0-based list)
case_sensitive (bool, default False) – Whether name matching is case-sensitive
combine (bool, default True) – If True, combine sections into single document with separators. If False, return document with just the first match.
separator (Node or None, default None) – Node to insert between sections (default: ThematicBreak)
- Returns:
Document with extracted sections
- Return type:
- Raises:
ValueError – If spec is invalid or no sections match
Examples
- Extract by name:
>>> extracted = extract_sections(doc, "Introduction")
- Extract with wildcards:
>>> extracted = extract_sections(doc, "Chapter*")
- Extract by range:
>>> extracted = extract_sections(doc, "#:1-3")
- Extract multiple specific sections:
>>> extracted = extract_sections(doc, "#:1,3,5") >>> extracted = extract_sections(doc, [0, 2, 4])
- Extract without separators:
>>> extracted = extract_sections(doc, "#:1-3", separator=None)
- all2md.ast.sections.count_sections(doc: Document, level: int | None = None) int
Count the number of sections in a document.
- Parameters:
doc (Document) – Document to count sections in
level (int or None, default = None) – If specified, only count sections at this level
- Returns:
Number of sections
- Return type:
int
Examples
>>> total_sections = count_sections(doc) >>> top_level = count_sections(doc, level=1)
- all2md.ast.sections.section_or_doc_to_nodes(content: Section | Document | list[Node]) list[Node]
Convert Section, Document, or list to list of nodes.
This helper consolidates the repeated pattern of converting various content types to a flat list of nodes.
- Parameters:
content (Section, Document, or list of Node) – Content to convert
- Returns:
Flat list of nodes
- Return type:
list of Node
Examples
>>> nodes = section_or_doc_to_nodes(section) >>> nodes = section_or_doc_to_nodes(document) >>> nodes = section_or_doc_to_nodes([para1, para2])
- all2md.ast.sections.generate_toc(doc: Document, max_level: int = 3, style: Literal['markdown', 'list', 'nested'] = 'markdown') str | List
Generate a table of contents from document headings.
- Parameters:
doc (Document) – Document to generate TOC from
max_level (int, default = 3) – Maximum heading level to include (1-6)
style ({"markdown", "list", "nested"}, default = "markdown") – Output style for the TOC
- Returns:
Table of contents as markdown string (for “markdown” style) or List node (for “list” and “nested” styles)
- Return type:
str or List
Notes
“markdown”: Returns markdown-formatted TOC as a string
“list”: Returns a flat List AST node with all headings
“nested”: Returns nested List AST nodes respecting heading hierarchy
Examples
>>> toc = generate_toc(doc, max_level=3) >>> print(toc) # Table of Contents
[Introduction](#introduction) - [Background](#background) - [Motivation](#motivation)
[Methods](#methods)
- all2md.ast.sections.insert_toc(doc: Document, position: Literal['start', 'after_first_heading'] = 'start', max_level: int = 3, style: Literal['markdown', 'list', 'nested'] = 'markdown') Document
Insert a table of contents into the document.
- Parameters:
doc (Document) – Document to modify
position ({"start", "after_first_heading"}, default = "start") – Where to insert the TOC
max_level (int, default = 3) – Maximum heading level to include
style ({"markdown", "list", "nested"}, default = "markdown") – Style of the TOC
- Returns:
New document with TOC inserted
- Return type:
Examples
>>> doc_with_toc = insert_toc(doc, position="start", max_level=3)