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: object

Represents 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[FountainElement]) – List of FountainElement objects representing the document content

  • metadata (dict[str, str] | None) – Optional dictionary containing document-level metadata (title page data)

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:

dict[str, object]

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:

str

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:

Self

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:

text (str) – JSON string as produced by to_json().

Returns:

The reconstructed FountainDocument.

Raises:

ValueError – If the text is not a JSON object, or if from_dict() rejects the decoded data.

Return type:

Self

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.

Returns:

Sorted list of unique character names found in the document.

Return type:

list[str]

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.

Returns:

List of scene heading strings in document order.

Return type:

list[str]

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:

str

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), use HTMLRenderer.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.