Write F#, run Python - a practical guide to Fable.Python
This blog-post is a guide to Fable.Python, written as literate F# that transpiles to Python and generates its own documentation.
- Introduction - What is Fable.Python and why use it
- For Python Developers - F# concepts explained for Pythonistas
- Getting Started - Setup, your first project, hello world
- Interop - Using existing Python libraries and Fable.Python bindings
- Bindings - Creating your own type-safe bindings for Python libraries
- Compatibility - Supported F# features and limitations
- Async Programming - F# async and Python asyncio
- Testing - Testing F# code with Python test runners
- Fable v5 - What's new in Fable v5 for Python
- Pydantic - Pydantic interop with Decorate and ClassAttributes
- FastAPI - Building type-safe web APIs with F#
- Units of Measure - Compile-time dimensional analysis
- Fable.Literate - The self-documenting converter
- Summary - Wrap-up, resources, and contributing
This guide is self-documenting: each chapter is an .fs file with embedded Markdown comments. Fable.Literate (the final chapter) processes these files to generate the documentation you're reading - including itself.
The chain:
- Write F# with embedded Markdown (
chapters/*.fs) - Compile to Python with Fable
- Run Fabletext (F# compiled to Python) to extract documentation
- Output: the Markdown you're reading
The blog post is its own proof of concept.
# Install dependencies
just setup
just restore
# Build everything (F# → Python → Markdown)
just all
# Or generate just the blogpost
just blogpostjust setup # Install Fable and Python dependencies (uv)
just restore # Restore NuGet packages
just build # Compile F# to Python with Fable
just generate # Convert chapters to individual markdown files
just blogpost # Generate concatenated blogpost.md for publishing
just format # Format F# (fantomas) and Python (ruff) files
just lint # Lint Python (ruff) and Markdown (markdownlint)
just all # Full pipeline: restore, build, generate, format, lint
just clean # Remove generated fileschapters/
├── Introduction.fs # What is Fable.Python
├── Python.fs # F# for Python developers
├── GettingStarted.fs # Setup and first project
├── Interop.fs # Using Python libraries
├── Bindings.fs # Creating bindings
├── Compatibility.fs # F# feature support
├── AsyncProgramming.fs # Async workflows
├── Testing.fs # Testing with Python
├── FableV5.fs # What's new in Fable v5
├── Pydantic.fs # Pydantic interop
├── UnitsOfMeasure.fs # Dimensional analysis
├── FableLiterate.fs # Symlink → ../Fable.Literate/App.fs
└── Summary.fs # Wrap-up and resources
Fable.Literate/
├── App.fs # Fable.Literate converter (F#)
└── Fable.Literate.fsproj
output/
├── chapters/ # Generated Python from chapters
└── Fable.Literate/
└── app.py # Generated converter (Python)
docs/
├── Introduction.md # Individual chapter docs
├── Python.md
├── ...
└── blogpost.md # Concatenated for Hashnode
Defined in justfile:
chapters := "Introduction Python GettingStarted Interop Bindings Compatibility AsyncProgramming Testing FableV5 Pydantic UnitsOfMeasure FableLiterate Summary"To add a new chapter, just add the file and update this list.
- Fable 5 (alpha) - F# to Python compiler
- uv - Python dependency management
- just - Command runner
- ruff - Python formatter/linter
- fantomas - F# formatter
- markdownlint - Markdown linter
- Thoth.Json.Python - Type-safe JSON
- AsyncRx - Reactive extensions
- Fable.Giraffe - Web framework
- Feliz.ViewEngine - HTML DSL
- Siren - Mermaid diagrams
- Fable.Pyxpecto - Testing
- ARCtrl - Real-world multi-target library
- Fable
- Fable.Python Documentation
- Fable.Python GitHub
- BINDINGS_GUIDE.md - Comprehensive binding patterns
Part of F# Advent 2025