fountain-py 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. fountain_py-0.1.0/.gitignore +210 -0
  2. fountain_py-0.1.0/.vale.ini +69 -0
  3. fountain_py-0.1.0/CHANGELOG.md +61 -0
  4. fountain_py-0.1.0/CONTRIBUTING.md +84 -0
  5. fountain_py-0.1.0/LICENSE +21 -0
  6. fountain_py-0.1.0/PKG-INFO +186 -0
  7. fountain_py-0.1.0/README.md +161 -0
  8. fountain_py-0.1.0/docs/source/_templates/sidebar/brand.html +14 -0
  9. fountain_py-0.1.0/docs/source/api/document.rst +9 -0
  10. fountain_py-0.1.0/docs/source/api/elements.rst +10 -0
  11. fountain_py-0.1.0/docs/source/api/index.rst +16 -0
  12. fountain_py-0.1.0/docs/source/api/parser.rst +8 -0
  13. fountain_py-0.1.0/docs/source/api/renderer.rst +9 -0
  14. fountain_py-0.1.0/docs/source/changelog.rst +73 -0
  15. fountain_py-0.1.0/docs/source/conf.py +125 -0
  16. fountain_py-0.1.0/docs/source/contributing/development.rst +86 -0
  17. fountain_py-0.1.0/docs/source/contributing/documentation.rst +76 -0
  18. fountain_py-0.1.0/docs/source/contributing/index.rst +18 -0
  19. fountain_py-0.1.0/docs/source/contributing/testing.rst +74 -0
  20. fountain_py-0.1.0/docs/source/examples/coffee_shop.fountain +45 -0
  21. fountain_py-0.1.0/docs/source/explanation/pipeline.rst +75 -0
  22. fountain_py-0.1.0/docs/source/explanation/roundtrip-and-notes.rst +78 -0
  23. fountain_py-0.1.0/docs/source/explanation/what-is-fountain.rst +44 -0
  24. fountain_py-0.1.0/docs/source/how-to/embed-fragment.rst +40 -0
  25. fountain_py-0.1.0/docs/source/how-to/export-to-json.rst +31 -0
  26. fountain_py-0.1.0/docs/source/how-to/extract-character-dialogue.rst +50 -0
  27. fountain_py-0.1.0/docs/source/how-to/render-to-html-file.rst +37 -0
  28. fountain_py-0.1.0/docs/source/how-to/roundtrip-to-fountain.rst +28 -0
  29. fountain_py-0.1.0/docs/source/how-to/style-the-html.rst +50 -0
  30. fountain_py-0.1.0/docs/source/how-to/validate-a-file.rst +122 -0
  31. fountain_py-0.1.0/docs/source/index.rst +124 -0
  32. fountain_py-0.1.0/docs/source/installation.rst +66 -0
  33. fountain_py-0.1.0/docs/source/quickstart.rst +111 -0
  34. fountain_py-0.1.0/docs/source/reference/elements.rst +472 -0
  35. fountain_py-0.1.0/docs/source/reference/parsing-behavior.rst +651 -0
  36. fountain_py-0.1.0/docs/source/reference/rendering.rst +409 -0
  37. fountain_py-0.1.0/docs-plan.md +280 -0
  38. fountain_py-0.1.0/examples/README.md +57 -0
  39. fountain_py-0.1.0/pyproject.toml +121 -0
  40. fountain_py-0.1.0/src/fountain/__init__.py +25 -0
  41. fountain_py-0.1.0/src/fountain/document.py +359 -0
  42. fountain_py-0.1.0/src/fountain/elements.py +291 -0
  43. fountain_py-0.1.0/src/fountain/parser.py +2042 -0
  44. fountain_py-0.1.0/src/fountain/py.typed +0 -0
  45. fountain_py-0.1.0/src/fountain/renderer.py +1056 -0
  46. fountain_py-0.1.0/test-plan.md +977 -0
  47. fountain_py-0.1.0/tests/__init__.py +1 -0
  48. fountain_py-0.1.0/tests/conftest.py +38 -0
  49. fountain_py-0.1.0/tests/fixtures/simple_script.fountain +41 -0
  50. fountain_py-0.1.0/tests/test_document.py +175 -0
  51. fountain_py-0.1.0/tests/test_edge_cases.py +2581 -0
  52. fountain_py-0.1.0/tests/test_parser.py +1219 -0
  53. fountain_py-0.1.0/tests/test_quickstart_examples.py +376 -0
  54. fountain_py-0.1.0/tests/test_renderer.py +1138 -0
  55. fountain_py-0.1.0/tests/test_validation.py +105 -0
  56. fountain_py-0.1.0/uv.lock +1130 -0
@@ -0,0 +1,210 @@
1
+ # Testing stuff for now
2
+ *macbeth*
3
+ scratchpad.md
4
+ .claude/*
5
+ commit-msg.md
6
+ goal.md
7
+ .ai-sessions/handoffs/
8
+ .token.txt
9
+
10
+ # Byte-compiled / optimized / DLL files
11
+ __pycache__/
12
+ *.py[codz]
13
+ *$py.class
14
+
15
+ # C extensions
16
+ *.so
17
+
18
+ # Distribution / packaging
19
+ .Python
20
+ build/
21
+ develop-eggs/
22
+ dist/
23
+ downloads/
24
+ eggs/
25
+ .eggs/
26
+ lib/
27
+ lib64/
28
+ parts/
29
+ sdist/
30
+ var/
31
+ wheels/
32
+ share/python-wheels/
33
+ *.egg-info/
34
+ .installed.cfg
35
+ *.egg
36
+ MANIFEST
37
+
38
+ # PyInstaller
39
+ # Usually these files are written by a python script from a template
40
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
41
+ *.manifest
42
+ *.spec
43
+
44
+ # Installer logs
45
+ pip-log.txt
46
+ pip-delete-this-directory.txt
47
+
48
+ # Unit test / coverage reports
49
+ htmlcov/
50
+ .tox/
51
+ .nox/
52
+ .coverage
53
+ .coverage.*
54
+ .cache
55
+ nosetests.xml
56
+ coverage.xml
57
+ *.cover
58
+ *.py,cover
59
+ .hypothesis/
60
+ .pytest_cache/
61
+ cover/
62
+
63
+ # Translations
64
+ *.mo
65
+ *.pot
66
+
67
+ # Django stuff:
68
+ *.log
69
+ local_settings.py
70
+ db.sqlite3
71
+ db.sqlite3-journal
72
+
73
+ # Flask stuff:
74
+ instance/
75
+ .webassets-cache
76
+
77
+ # Scrapy stuff:
78
+ .scrapy
79
+
80
+ # Sphinx documentation
81
+ docs/_build/
82
+
83
+ # PyBuilder
84
+ .pybuilder/
85
+ target/
86
+
87
+ # Jupyter Notebook
88
+ .ipynb_checkpoints
89
+
90
+ # IPython
91
+ profile_default/
92
+ ipython_config.py
93
+
94
+ # pyenv
95
+ # For a library or package, you might want to ignore these files since the code is
96
+ # intended to run in multiple environments; otherwise, check them in:
97
+ # .python-version
98
+
99
+ # pipenv
100
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
101
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
102
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
103
+ # install all needed dependencies.
104
+ #Pipfile.lock
105
+
106
+ # UV
107
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
108
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
109
+ # commonly ignored for libraries.
110
+ #uv.lock
111
+
112
+ # poetry
113
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
114
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
115
+ # commonly ignored for libraries.
116
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
117
+ #poetry.lock
118
+ #poetry.toml
119
+
120
+ # pdm
121
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
122
+ #pdm.lock
123
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
124
+ # in version control.
125
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
126
+ .pdm.toml
127
+ .pdm-python
128
+ .pdm-build/
129
+
130
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
131
+ __pypackages__/
132
+
133
+ # Celery stuff
134
+ celerybeat-schedule
135
+ celerybeat.pid
136
+
137
+ # SageMath parsed files
138
+ *.sage.py
139
+
140
+ # Environments
141
+ .env
142
+ .envrc
143
+ .venv
144
+ env/
145
+ venv/
146
+ ENV/
147
+ env.bak/
148
+ venv.bak/
149
+
150
+ # Spyder project settings
151
+ .spyderproject
152
+ .spyproject
153
+
154
+ # Rope project settings
155
+ .ropeproject
156
+
157
+ # mkdocs documentation
158
+ /site
159
+
160
+ # mypy
161
+ .mypy_cache/
162
+ .dmypy.json
163
+ dmypy.json
164
+
165
+ # Pyre type checker
166
+ .pyre/
167
+
168
+ # pytype static type analyzer
169
+ .pytype/
170
+
171
+ # Cython debug symbols
172
+ cython_debug/
173
+
174
+ # PyCharm
175
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
176
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
177
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
178
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
179
+ #.idea/
180
+
181
+ # Abstra
182
+ # Abstra is an AI-powered process automation framework.
183
+ # Ignore directories containing user credentials, local state, and settings.
184
+ # Learn more at https://abstra.io/docs
185
+ .abstra/
186
+
187
+ # Visual Studio Code
188
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
189
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
190
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
191
+ # you could uncomment the following to ignore the entire vscode folder
192
+ # .vscode/
193
+
194
+ # Ruff stuff:
195
+ .ruff_cache/
196
+
197
+ # PyPI configuration file
198
+ .pypirc
199
+
200
+ # Cursor
201
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
202
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
203
+ # refer to https://docs.cursor.com/context/ignore-files
204
+ .cursorignore
205
+ .cursorindexingignore
206
+
207
+ # Marimo
208
+ marimo/_static/
209
+ marimo/_lsp/
210
+ __marimo__/
@@ -0,0 +1,69 @@
1
+ # Vale configuration for the fountain-py docs (reStructuredText under docs/source).
2
+ #
3
+ # StylesPath points at Mason's shared vale-styles checkout, following the
4
+ # convention in that repo's README (one styles directory per machine that every
5
+ # project points at). Contributors linting locally should set StylesPath to
6
+ # their own checkout of https://github.com/MasonEgger/vale-styles.
7
+ #
8
+ # Vale parses .rst natively. The vale-styles OneSentencePerLine rule skips
9
+ # .. code-block:: / .. doctest:: bodies; note that SentenceLength can still flag
10
+ # the occasional line inside a Sphinx doctest, which is a known limitation.
11
+ #
12
+ # Three base rules are tuned down for this project, in every section below:
13
+ # FirstUse off - the acronyms here (HTML, CSS, JSON, API, UTF) and the
14
+ # screenplay terms (INT, EXT, V.O., NOTE) are known to
15
+ # the audience or defined by the linked Fountain spec.
16
+ # BoldBulletHeaders off - the reference catalogs and landing pages use bold
17
+ # labels for reference and navigation, which the writing
18
+ # style rules permit for reference material.
19
+ # FleschReadingEase sug - a document-level readability nudge, not a per-line fix;
20
+ # kept visible as a suggestion rather than a warning.
21
+
22
+ StylesPath = /home/mmegger/Code/vale-styles/styles
23
+ MinAlertLevel = suggestion
24
+
25
+ # The tutorial: full technical register. The quickstart closes with a
26
+ # "Next Steps" section rather than a literal "Conclusion" heading.
27
+ [docs/source/quickstart.rst]
28
+ BasedOnStyles = MasonBase, MasonTechnical
29
+ MasonBase.We = suggestion
30
+ MasonBase.Conclusion = NO
31
+ MasonBase.FirstUse = NO
32
+ MasonBase.BoldBulletHeaders = NO
33
+ MasonBase.FleschReadingEase = suggestion
34
+
35
+ # How-to guides and reference: technical register for the STE clarity rules,
36
+ # but these are not tutorials, so drop the Prerequisites and Conclusion
37
+ # expectations.
38
+ [docs/source/{how-to,reference}/**/*.rst]
39
+ BasedOnStyles = MasonBase, MasonTechnical
40
+ MasonBase.We = suggestion
41
+ MasonBase.Conclusion = NO
42
+ MasonTechnical.Prerequisites = NO
43
+ MasonBase.FirstUse = NO
44
+ MasonBase.BoldBulletHeaders = NO
45
+ MasonBase.FleschReadingEase = suggestion
46
+
47
+ # Explanation: discursive prose. Base rules only, so the procedural sentence-
48
+ # length cap does not flatten conceptual writing.
49
+ [docs/source/explanation/**/*.rst]
50
+ BasedOnStyles = MasonBase
51
+ MasonBase.Conclusion = NO
52
+ MasonBase.FirstUse = NO
53
+ MasonBase.BoldBulletHeaders = NO
54
+ MasonBase.FleschReadingEase = suggestion
55
+
56
+ # Landing, install, changelog, contributing, and autodoc stubs: base prose only.
57
+ [docs/source/{index,installation,changelog}.rst]
58
+ BasedOnStyles = MasonBase
59
+ MasonBase.Conclusion = NO
60
+ MasonBase.FirstUse = NO
61
+ MasonBase.BoldBulletHeaders = NO
62
+ MasonBase.FleschReadingEase = suggestion
63
+
64
+ [docs/source/{contributing,api}/**/*.rst]
65
+ BasedOnStyles = MasonBase
66
+ MasonBase.Conclusion = NO
67
+ MasonBase.FirstUse = NO
68
+ MasonBase.BoldBulletHeaders = NO
69
+ MasonBase.FleschReadingEase = suggestion
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-04-09
11
+
12
+ ### Added
13
+
14
+ #### Parser — Full Fountain Spec Compliance
15
+ - Two-pass parser: title page metadata extraction, then line-by-line element classification
16
+ - All 14 body element types emitted by the parser: scene headings, action, character, dialogue, parenthetical, transitions, notes, boneyard, sections, synopses, dual dialogue, page breaks, centered text, lyrics (the `ElementType` enum has 15 members; the 15th, `TITLE_PAGE`, is not emitted as an element: title page data is parsed into `FountainDocument.metadata`)
17
+ - Forced element prefixes (`.`, `!`, `@`, `>`) override natural detection rules
18
+ - Scene number extraction (`#1#`, `#2A#`)
19
+ - Character extensions (`V.O.`, `O.S.`, `CONT'D`) and automatic continuation detection
20
+ - Section level metadata (`# Act` = level 1, `## Scene` = level 2, etc.)
21
+ - Ellipsis protection on forced scene headings (`.` + alphanumeric only)
22
+ - Arbitrary title page keys (any `Key: Value` pair accepted, not just known fields)
23
+ - Blank-line-before requirement for natural scene headings, character names, and transitions
24
+ - Blank-line-after requirement for transitions
25
+ - Inline note stripping (`[[notes]]` removed from element text in non-note elements)
26
+ - Multi-line note support (`[[note\nspanning\nlines]]`)
27
+ - Dialogue continuation with whitespace-only lines (two spaces preserves blank line in dialogue)
28
+ - Backslash escaping for emphasis markers (`\*` → literal `*`, `\_` → literal `_`)
29
+ - Tabs in action elements are converted to four spaces in the element text at parse time; indentation is preserved in HTML via `white-space: pre-wrap` on `.fountain-action`
30
+ - Inline formatting: bold (`**`), italic (`*`), underline (`_`), bold-italic (`***`)
31
+
32
+ #### Renderers
33
+ - `HTMLRenderer` with three output modes:
34
+ - `render(doc)` — pure HTML fragment for embedding (no `<style>` tags)
35
+ - `render_page(doc)` — standalone HTML with embedded CSS
36
+ - `get_css()` — raw CSS string for external stylesheet use
37
+ - `FountainRenderer` for round-trip conversion back to Fountain markup
38
+ - All CSS classes namespaced with `fountain-` prefix to prevent framework collisions
39
+ - Screenplay-formatted CSS: Courier font, proper margins, centered dialogue, hidden boneyard
40
+ - Dual dialogue side-by-side layout via flexbox
41
+ - Title page rendering with all standard and custom metadata fields
42
+
43
+ #### Document Analysis
44
+ - `FountainDocument` container with element access and metadata
45
+ - `get_characters()` — extract unique character names
46
+ - `get_scenes()` — list scene heading elements
47
+ - `get_statistics()` — element counts by type, character count, scene count
48
+ - `to_html()` — convenience method for standalone HTML output
49
+
50
+ #### Type System
51
+ - Full type hints throughout, strict mypy compliance
52
+ - `FormatType` literal type (`"bold"`, `"italic"`, `"underline"`, `"bold_italic"`)
53
+ - `MetadataValue` union type for element metadata documentation
54
+ - PEP 561 `py.typed` marker for downstream type checking
55
+
56
+ #### Quality
57
+ - 314 tests with 99% code coverage
58
+ - 38 module-level doctests + 447 Sphinx doctests
59
+ - Supports Python 3.10, 3.11, 3.12, 3.13, 3.14
60
+ - Zero runtime dependencies
61
+ - CI with GitHub Actions across all supported Python versions
@@ -0,0 +1,84 @@
1
+ # Contributing to Fountain-Py
2
+
3
+ We love your input! We want to make contributing to this project as easy and transparent as possible.
4
+
5
+ ## Development Process
6
+
7
+ 1. Fork the repo and create your branch from `main`
8
+ 2. If you've added code that should be tested, add tests
9
+ 3. Ensure the test suite passes
10
+ 4. Make sure your code follows the style guidelines
11
+ 5. Issue that pull request!
12
+
13
+ ## Development Setup
14
+
15
+ ```bash
16
+ # Clone your fork
17
+ git clone https://github.com/your-username/fountain-py.git
18
+ cd fountain-py
19
+
20
+ # Install development dependencies
21
+ uv sync --dev
22
+ ```
23
+
24
+ ## Running Tests
25
+
26
+ ```bash
27
+ # Run all tests
28
+ uv run pytest
29
+
30
+ # Run tests with coverage
31
+ uv run pytest --cov=fountain --cov-report=html
32
+
33
+ # Run specific test file
34
+ uv run pytest tests/test_parser.py
35
+ ```
36
+
37
+ ## Code Style
38
+
39
+ We use:
40
+ - `ruff` for linting and formatting
41
+ - `mypy` for type checking
42
+ - All code must have type hints
43
+ - Follow PEP8 conventions
44
+
45
+ Run these checks locally:
46
+ ```bash
47
+ # Format code
48
+ uv run ruff format src/ tests/
49
+
50
+ # Check linting
51
+ uv run ruff check src/ tests/
52
+
53
+ # Type checking
54
+ uv run mypy src/
55
+ ```
56
+
57
+ ## Pull Request Process
58
+
59
+ 1. Update the README.md with details of changes if needed
60
+ 2. Update the CHANGELOG.md with your changes
61
+ 3. The PR will be merged once you have the sign-off of at least one maintainer
62
+
63
+ ## Reporting Bugs
64
+
65
+ 1. Use the GitHub Issues tracker
66
+ 2. Include a clear title and description
67
+ 3. Provide example code if possible
68
+ 4. Include error messages and stack traces
69
+ 5. Mention your Python version and OS
70
+
71
+ ## Suggesting Features
72
+
73
+ 1. Open an issue with the "enhancement" label
74
+ 2. Clearly describe the feature and its use case
75
+ 3. Provide examples of how it would work
76
+ 4. Be open to discussion and feedback
77
+
78
+ ## Code of Conduct
79
+
80
+ Please note we have a code of conduct. Follow it in all your interactions with the project.
81
+
82
+ ## License
83
+
84
+ By contributing, you agree that your contributions will be licensed under the MIT License.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mason Egger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.4
2
+ Name: fountain-py
3
+ Version: 0.1.0
4
+ Summary: A Python library for parsing Fountain markup, the screenwriting format
5
+ Project-URL: Homepage, https://github.com/MasonEgger/fountain-py
6
+ Project-URL: Repository, https://github.com/MasonEgger/fountain-py
7
+ Project-URL: Documentation, https://masonegger.github.io/fountain-py/
8
+ Project-URL: Issues, https://github.com/MasonEgger/fountain-py/issues
9
+ Author-email: Mason Egger <mason@masonegger.com>
10
+ License-File: LICENSE
11
+ Keywords: fountain,parser,screenplay,screenwriting,script,theater
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Text Processing :: Markup
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Fountain-Py
27
+
28
+ [![CI](https://github.com/MasonEgger/fountain-py/workflows/CI/badge.svg)](https://github.com/MasonEgger/fountain-py/actions?query=workflow%3ACI)
29
+ [![Python versions](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
31
+ [![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
32
+
33
+ A Python library for parsing [Fountain markup](https://fountain.io/), the screenwriting format. Fountain-Py converts Fountain scripts into structured Python objects and can render them as HTML.
34
+
35
+ ## Features
36
+
37
+ - **Full Fountain Support**: Parses all Fountain elements including scenes, dialogue, action, transitions, notes, dual dialogue, lyrics, and inline emphasis
38
+ - **Validation**: Reports structural problems (unclosed comments and notes, orphaned character cues) through a validation API
39
+ - **Multiple Render Modes**: HTML fragments for embedding, full pages with CSS, or raw CSS for custom styling
40
+ - **Round-Trip and Export**: Write a parsed script back to clean Fountain, or export it to JSON
41
+ - **Type-Safe**: Built with full type hints and strict mypy compliance
42
+ - **Zero Dependencies**: Pure Python with no runtime dependencies
43
+ - **Well-Tested**: Unit tests and doctests across every module, with high coverage enforced in CI
44
+ - **Modern Python**: Supports Python 3.10 through 3.14
45
+
46
+ ## Quick Start
47
+
48
+ ### Installation
49
+
50
+ Fountain-Py is not on PyPI yet (the 0.1.0 release is pending), so install it from source:
51
+
52
+ ```bash
53
+ pip install git+https://github.com/MasonEgger/fountain-py.git
54
+ ```
55
+
56
+ Once it is published, `pip install fountain-py` will work.
57
+
58
+ ### Basic Usage
59
+
60
+ ```python
61
+ from fountain import FountainParser
62
+ from fountain.renderer import HTMLRenderer
63
+
64
+ # Parse a Fountain script
65
+ parser = FountainParser()
66
+ document = parser.parse("""Title: My Screenplay
67
+ Author: Jane Writer
68
+
69
+ INT. COFFEE SHOP - DAY
70
+
71
+ SARAH enters, looking tired.
72
+
73
+ SARAH
74
+ One large cappuccino, please!
75
+ """)
76
+
77
+ # Access parsed data
78
+ print(document.metadata["title"]) # "My Screenplay"
79
+ print(document.get_characters()) # ["SARAH"]
80
+ print(len(document.elements)) # 3
81
+
82
+ # Render as HTML fragment (for embedding in web pages)
83
+ renderer = HTMLRenderer()
84
+ html_fragment = renderer.render(document)
85
+
86
+ # Render as standalone HTML file with embedded CSS
87
+ html_page = renderer.render_page(document)
88
+
89
+ # Get raw CSS for external stylesheets
90
+ css = renderer.get_css()
91
+ ```
92
+
93
+ ### Rendering Modes
94
+
95
+ ```python
96
+ renderer = HTMLRenderer()
97
+
98
+ # Fragment — no <style> tags, just the screenplay markup
99
+ # Use this for embedding in web pages, docs, or CMS systems
100
+ fragment = renderer.render(document)
101
+
102
+ # Full page — self-contained HTML with embedded CSS
103
+ # Use this for saving as .html files or previewing
104
+ page = renderer.render_page(document)
105
+
106
+ # Raw CSS — for custom stylesheet integration
107
+ # Use this with mkdocs, static site generators, or your own build pipeline
108
+ css = renderer.get_css()
109
+ ```
110
+
111
+ ### Round-Trip Conversion
112
+
113
+ ```python
114
+ from fountain.renderer import FountainRenderer
115
+
116
+ # Convert back to Fountain markup
117
+ fountain_renderer = FountainRenderer()
118
+ fountain_text = fountain_renderer.render(document)
119
+ ```
120
+
121
+ The round trip preserves element structure and inline emphasis.
122
+ Scene headings, action, character cues, parentheticals, dialogue, transitions, dual dialogue, lyrics, sections, synopses, and notes all keep their element types through `parse(render(parse(text)))`, and the blank lines that separate structural blocks survive so blocks are not merged on re-parse.
123
+
124
+ Inline emphasis is re-emitted too.
125
+ The parser records the bold (`**`), italic (`*`), and underline (`_`) delimiters as formatting spans, and `FountainRenderer` restores them, so a `**bold**` word round-trips as `**bold**`, including nested emphasis and backslash-escaped literals.
126
+
127
+ ## Documentation
128
+
129
+ Full documentation is available at [masonegger.github.io/fountain-py](https://masonegger.github.io/fountain-py/).
130
+
131
+ - [Installation Guide](https://masonegger.github.io/fountain-py/installation.html)
132
+ - [Quick Start Tutorial](https://masonegger.github.io/fountain-py/quickstart.html)
133
+ - [API Reference](https://masonegger.github.io/fountain-py/api/index.html)
134
+
135
+ ## Development
136
+
137
+ ### Setup
138
+
139
+ ```bash
140
+ git clone https://github.com/MasonEgger/fountain-py.git
141
+ cd fountain-py
142
+
143
+ # Install with development and docs dependencies
144
+ just dev && uv sync --group docs
145
+ ```
146
+
147
+ ### Running Tests
148
+
149
+ ```bash
150
+ # Run comprehensive quality checks (tests, coverage, doctests, lint, type check)
151
+ just test
152
+
153
+ # Run only unit tests
154
+ just unit-test
155
+
156
+ # Run tests with coverage
157
+ just unit-test-cov
158
+
159
+ # Run specific tests
160
+ uv run pytest tests/test_parser.py
161
+ ```
162
+
163
+ ### Code Quality
164
+
165
+ ```bash
166
+ just lint # Lint check (ruff)
167
+ just format # Format code (ruff)
168
+ just type-check # Type checking (mypy strict)
169
+ ```
170
+
171
+ ## Contributing
172
+
173
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
174
+
175
+ ## Fountain Format
176
+
177
+ Fountain is a simple markup syntax for writing, editing and sharing screenplays in plain text. Learn more at [fountain.io](https://fountain.io/).
178
+
179
+ ## License
180
+
181
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
182
+
183
+ ## Acknowledgments
184
+
185
+ - The [Fountain](https://fountain.io/) format creators
186
+ - The screenwriting community for feedback and testing