Document Module¶
Fountain document representation and analysis functionality.
This module contains the FountainDocument class, which serves as the primary container for parsed Fountain screenplay content. It provides methods for document analysis, statistics generation, format conversion, and character/scene extraction.
Example
Basic document creation and analysis:
>>> from fountain.elements import ElementType, FountainElement
>>> from fountain.document import FountainDocument
>>> elements = [
... FountainElement(ElementType.TITLE_PAGE, "Title: My Script", [], 1),
... FountainElement(ElementType.SCENE_HEADING, "INT. OFFICE - DAY", [], 2),
... FountainElement(ElementType.CHARACTER, "JOHN", [], 3),
... FountainElement(ElementType.DIALOGUE, "Hello, world!", [], 4)
... ]
>>> doc = FountainDocument(elements)
>>> len(doc.elements)
4
>>> doc.get_characters()
['JOHN']
- class fountain.document.FountainDocument(elements, metadata=None, issues=None)[source]¶
Bases:
objectRepresents a complete Fountain screenplay document with analysis capabilities.
FountainDocument is the primary container for parsed Fountain content, providing methods for document analysis, statistics generation, and format conversion. It contains a list of FountainElement objects and optional document metadata.
- Parameters:
- elements¶
List of all parsed FountainElement objects in document order
- metadata¶
Dictionary containing document metadata like title, author, etc.
Example
Creating a document with basic elements:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> elements = [ ... FountainElement(ElementType.SCENE_HEADING, "EXT. PARK - DAY", [], 1), ... FountainElement(ElementType.ACTION, "Birds are singing.", [], 2), ... FountainElement(ElementType.CHARACTER, "ALICE", [], 3), ... FountainElement(ElementType.DIALOGUE, "What a beautiful day!", [], 4) ... ] >>> doc = FountainDocument(elements) >>> len(doc.elements) 4 >>> doc.elements[0].type.value 'scene_heading'
Creating a document with metadata:
>>> metadata = {"title": "My Script", "author": "Jane Doe"} >>> doc_with_meta = FountainDocument(elements, metadata) >>> doc_with_meta.metadata["title"] 'My Script' >>> doc_with_meta.metadata["author"] 'Jane Doe'
- __init__(elements, metadata=None, issues=None)[source]¶
Initialize a FountainDocument with elements and optional metadata.
- Parameters:
elements (list[FountainElement]) – Ordered list of FountainElement objects
metadata (dict[str, str] | None) – Optional dictionary of document metadata
issues (list[ValidationIssue] | None) – Optional diagnostics recorded during parsing (unclosed constructs, orphan cues, empty document). Empty when the document is well formed.
Example
Basic initialization:
>>> from fountain.elements import ElementType, FountainElement >>> element = FountainElement(ElementType.ACTION, "Test action", [], 1) >>> doc = FountainDocument([element]) >>> len(doc.elements) 1 >>> doc.metadata {} >>> doc.issues []
- to_dict()[source]¶
Convert the entire document to a dictionary representation.
Creates a dictionary representation of the document, including all metadata and element details. This format is useful for serialization, debugging, and integration with other tools.
- Returns:
Dictionary containing ‘schema_version’, ‘metadata’, and ‘elements’ keys, where elements is a list of dictionaries representing each FountainElement with all its properties including type, text, formatting, line_number, and metadata. See JSON Schema Reference for the full documented shape.
- Return type:
Example
Converting a simple document to dictionary:
>>> from fountain.elements import ElementType, FountainElement, FormatSpan >>> from fountain.document import FountainDocument >>> elements = [ ... FountainElement(ElementType.CHARACTER, "JANE", [], 1), ... FountainElement( ... ElementType.DIALOGUE, ... "Hello there!", ... [FormatSpan(0, 5, 'bold')], ... 2 ... ) ... ] >>> doc = FountainDocument(elements, {"title": "Test"}) >>> result = doc.to_dict() >>> result["schema_version"] 1 >>> result["metadata"]["title"] 'Test' >>> len(result["elements"]) 2 >>> result["elements"][0]["type"] 'character' >>> result["elements"][1]["formatting"][0]["format_type"] 'bold'
- to_json()[source]¶
Convert the document to a formatted JSON string.
Converts the document to a JSON string representation using the same structure as to_dict(). The output is formatted with 2-space indentation for readability.
- Returns:
Formatted JSON string representation of the document.
- Return type:
Example
Converting document to JSON:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> elements = [FountainElement(ElementType.ACTION, "Test", [], 1)] >>> doc = FountainDocument(elements, {"title": "Sample"}) >>> json_str = doc.to_json() >>> '"title": "Sample"' in json_str True >>> '"type": "action"' in json_str True >>> json_str.count('\n') > 5 # Multiple lines due to formatting True
- classmethod from_dict(data)[source]¶
Reconstruct a FountainDocument from its dictionary form.
Inverse of
to_dict(). Rebuilds every element, including nested FountainElement values in metadata (such as dual-dialogue’s left/right character and dialogue blocks), via_element_from_dict().- Parameters:
data (dict[str, object]) – Dictionary with schema_version, metadata, and elements keys, as produced by
to_dict().- Returns:
The reconstructed FountainDocument.
- Raises:
ValueError – If schema_version does not match JSON_SCHEMA_VERSION, or if any field is missing or has the wrong type.
- Return type:
Example
Round-tripping a document through its dict form:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> doc = FountainDocument([FountainElement(ElementType.ACTION, "He runs.", [], 1)]) >>> FountainDocument.from_dict(doc.to_dict()).to_dict() == doc.to_dict() True
An unrecognized schema version is a hard error:
>>> FountainDocument.from_dict({"schema_version": 999, "metadata": {}, "elements": []}) Traceback (most recent call last): ... ValueError: Unsupported schema_version 999; expected 1
- classmethod from_json(text)[source]¶
Reconstruct a FountainDocument from its JSON string form.
- Parameters:
- Returns:
The reconstructed FountainDocument.
- Raises:
ValueError – If the text is not a JSON object, or if
from_dict()rejects the decoded data.- Return type:
Example
Round-tripping through JSON:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> doc = FountainDocument([FountainElement(ElementType.ACTION, "He runs.", [], 1)]) >>> FountainDocument.from_json(doc.to_json()).to_dict() == doc.to_dict() True
- get_characters()[source]¶
Extract and return all unique character names from the document.
Scans all CHARACTER elements in the document and extracts unique character names. Character names are cleaned by removing dual dialogue markers (^) and normalizing to uppercase. The returned list is sorted alphabetically.
Note
Character names are automatically converted to uppercase and sorted. Dual dialogue markers (^) are stripped from character names.
Example
Extracting characters from a document:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> elements = [ ... FountainElement(ElementType.CHARACTER, "alice", [], 1), ... FountainElement(ElementType.DIALOGUE, "Hello!", [], 2), ... FountainElement(ElementType.CHARACTER, "BOB", [], 3), ... FountainElement(ElementType.DIALOGUE, "Hi there!", [], 4), ... FountainElement(ElementType.CHARACTER, "alice", [], 5), # Duplicate ... FountainElement(ElementType.CHARACTER, "CHARLIE^", [], 6) # Dual dialogue ... ] >>> doc = FountainDocument(elements) >>> characters = doc.get_characters() >>> characters ['ALICE', 'BOB', 'CHARLIE'] >>> len(characters) 3
- get_scenes()[source]¶
Extract and return all scene headings from the document in order.
Scans all SCENE_HEADING elements and returns their text content. Scene headings typically follow the format “INT./EXT. LOCATION - TIME” and are returned in the order they appear in the document.
Example
Extracting scene headings:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> elements = [ ... FountainElement(ElementType.SCENE_HEADING, "INT. COFFEE SHOP - DAY", [], 1), ... FountainElement(ElementType.ACTION, "People are chatting.", [], 2), ... FountainElement(ElementType.SCENE_HEADING, "EXT. PARK - EVENING", [], 3), ... FountainElement(ElementType.ACTION, "The sun is setting.", [], 4) ... ] >>> doc = FountainDocument(elements) >>> scenes = doc.get_scenes() >>> scenes ['INT. COFFEE SHOP - DAY', 'EXT. PARK - EVENING'] >>> len(scenes) 2
- get_statistics()[source]¶
Generate statistics about the document content.
Calculates various statistics about the document including total element count, number of unique characters, number of scenes, and counts for each element type. This provides a useful overview of document structure.
- Returns:
‘total_elements’: Total number of elements in document
’characters’: Number of unique characters
’scenes’: Number of scene headings
’{element_type}_count’: Count for each ElementType (e.g., ‘dialogue_count’)
- Return type:
Dictionary containing document statistics with the following keys
Example
Getting document statistics:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> elements = [ ... FountainElement(ElementType.SCENE_HEADING, "INT. ROOM - DAY", [], 1), ... FountainElement(ElementType.CHARACTER, "ALICE", [], 2), ... FountainElement(ElementType.DIALOGUE, "Hello!", [], 3), ... FountainElement(ElementType.CHARACTER, "BOB", [], 4), ... FountainElement(ElementType.DIALOGUE, "Hi!", [], 5), ... FountainElement(ElementType.ACTION, "They smile.", [], 6) ... ] >>> doc = FountainDocument(elements) >>> stats = doc.get_statistics() >>> stats['total_elements'] 6 >>> stats['characters'] 2 >>> stats['scenes'] 1 >>> stats['dialogue_count'] 2 >>> stats['action_count'] 1
- to_html()[source]¶
Convert the document to a standalone HTML page with embedded CSS.
Renders the entire document as properly formatted HTML suitable for saving as a self-contained HTML file. The output includes embedded CSS styling and maintains the screenplay format structure.
- Returns:
Complete HTML string with embedded CSS, suitable for saving to a file.
- Return type:
Note
This method creates an HTMLRenderer instance and delegates to
render_page(). For an HTML fragment without CSS (e.g., for embedding in another page), useHTMLRenderer.render()directly.Example
Converting to HTML:
>>> from fountain.elements import ElementType, FountainElement >>> from fountain.document import FountainDocument >>> elements = [ ... FountainElement(ElementType.SCENE_HEADING, "INT. ROOM - DAY", [], 1), ... FountainElement(ElementType.ACTION, "A simple room.", [], 2) ... ] >>> doc = FountainDocument(elements) >>> html = doc.to_html() >>> 'INT. ROOM - DAY' in html True >>> 'A simple room.' in html True >>> '<style>' in html True
The document module provides the main container for parsed Fountain documents.