Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,6 @@ The converter follows a compiler-like architecture with three phases:
| `(*** include-python: symbol ***)` | Include generated Python for symbol |
| Regular F# code | Wrapped in ```fsharp fenced blocks |

### Escaping F# in Headings

Use `` F`#` `` (backticks around `#`) in markdown headings to prevent markdownlint from interpreting it as ATX closed style:

```fsharp
(**
## F`#` Async Workflows
*)
```

### File Structure

```text
Expand All @@ -68,6 +58,7 @@ chapters/
├── Testing.fs # Testing F# code with Python test runners
├── FableV5.fs # Fable v5 features, Rust core, PyPI
├── Pydantic.fs # Pydantic models, DTOs, validation
├── FastAPI.fs # Type-safe web APIs with FastAPI
├── UnitsOfMeasure.fs # Compile-time dimensional analysis
├── FableLiterate.fs # Symlink → ../Fable.Literate/App.fs
└── Summary.fs # Wrap-up, resources, repo link
Expand Down
2 changes: 1 addition & 1 deletion Fable.Literate/App.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Fable.Python isn't just a toy: you're looking at a real project that works.

## How It Works

The converter follows a compiler-like architecture with three phases:
The converter follows a compiler-like architecture with three phases (just like Fable itself):

1. **Parse**: Convert source lines into a Block AST
2. **Transform**: Filter hidden blocks, resolve Python includes
Expand Down
4 changes: 2 additions & 2 deletions chapters/AsyncProgramming.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Asynchronous programming is essential for modern applications - from web APIs to
processing pipelines. F# offers two models for async code: `async` workflows and `task`
expressions. Understanding when to use each is key to effective Fable.Python development.

## Comparing Python and F`#` Async Models
## Comparing Python and F# Async Models

Python's async model is built on `asyncio`. Python coroutines are **cold** - calling an
`async def` function returns a coroutine object that doesn't execute until awaited:
Expand Down Expand Up @@ -110,7 +110,7 @@ let catchExample () =
}

(**
## F`#` Tasks
## F# Tasks

The `task` computation expression in .NET creates *hot* tasks that start immediately.
However, when compiled to Python via Fable, tasks become Python coroutines - which are
Expand Down
4 changes: 3 additions & 1 deletion chapters/Compatibility.fs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Most FSharp.Core operators are supported, including formatting with `sprintf`,
| F# Type | Python |
| ----------------- | -------------------------- |
| `Tuple` | `tuple` |
| `Option<T>` | erased to `T \| None` |
| `Option<T>` | `Optional[T]` (*) |
| `string` | `str` |
| `List<T>` | `List.fs` (immutable list) |
| `Map<K,V>` | `Map.fs` (immutable map) |
Expand All @@ -56,6 +56,8 @@ Most FSharp.Core operators are supported, including formatting with `sprintf`,
| Record types | `@dataclass` |
| Anonymous Records | `dict` |

(*) Generated as `T | None` in Python 3.12+

## Interfaces and Protocols

.NET interfaces map to Python protocols and special methods:
Expand Down
2 changes: 1 addition & 1 deletion chapters/FableV5.fs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ dotnet tool install fable --version 5.0.0-alpha.21
dotnet add package Fable.Core --version 5.0.0-beta.4

# Install the Python runtime
uv add fable-library==5.0.0a17
uv add fable-library==5.0.0a21
```

Then compile your F# to Python:
Expand Down
6 changes: 3 additions & 3 deletions chapters/FastAPI.fs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ let app = FastAPI(title = "My API", version = "1.0.0")

(**
This generates:
*)

```python
app = FastAPI(title="My API", version="1.0.0")
```
(*** include-python: app ***)

(**
The `app` variable name is important - the route decorators reference it.

## Defining Models
Expand Down
9 changes: 4 additions & 5 deletions chapters/Introduction.fs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Fable.Python is a great choice when:
Let's start with F# code that compiles to Python:
*)

let greet name = $"Hello, {name}!"
let greet (name: string) = $"Hello, {name}!"

let message = greet "Fable.Python"

Expand All @@ -88,10 +88,9 @@ When compiled with Fable, this generates the following Python:
(*** include-python: greet, message ***)

(**
The `name: Any | None = None` signature may look odd at first. This happens because F# infers the type from usage -
since we only call `greet` with a string, the compiler doesn't know if it might also be called with unit `()` (no
argument). If it were, Python would call it as `greet()` instead of `greet("Fable.Python")`. Adding an explicit type
annotation `let greet (name: string) = ...` would generate a cleaner `name: str` parameter.
Notice how the explicit type annotation `(name: string)` generates clean Python with `name: str`.
Without it, F# infers from usage and Fable generates `name: Any | None = None` to handle cases
where the function might be called with no argument. Type annotations give you cleaner output.

## The Power of Types

Expand Down
24 changes: 13 additions & 11 deletions chapters/Pydantic.fs
Original file line number Diff line number Diff line change
Expand Up @@ -178,17 +178,19 @@ This pattern is useful when you want to:

F# types map naturally to Python/Pydantic types:

| F# Type | Python Type | Notes |
| ----------- | ------------ | ------------------------------ |
| `string` | `str` | |
| `int` | `int` | |
| `float` | `float` | |
| `bool` | `bool` | |
| `'T option` | `T \| None` | Modern union syntax |
| `'T list` | `list[T]` | |
| `'T array` | `list[T]` | |
| Record | `class` | With `@dataclass` or BaseModel |
| DU | Tagged class | See below |
| F# Type | Python Type | Notes |
| ----------- | ----------------- | ------------------------------ |
| `string` | `str` | |
| `int` | `int` | |
| `float` | `float` | |
| `bool` | `bool` | |
| `'T option` | `Optional[T]` (*) | Modern union syntax |
| `'T list` | `list[T]` | |
| `'T array` | `list[T]` | |
| Record | `class` | With `@dataclass` or BaseModel |
| DU | Tagged class | See below |

(*) Generated as `T | None` in Python 3.12+

### F# Option to Python Union

Expand Down
2 changes: 1 addition & 1 deletion chapters/Python.fs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ unwrap the option first.
| Dictionary | `{"a": 1}` | `Map.ofList [("a", 1)]` |
| None check | `if x is None:` | `match x with None ->` |
| String format | `f"Hello {name}"` | `$"Hello {name}"` |
| Type annotation | `x: int` | `x: int32`. |
| Type annotation | `x: int` | `x: int32` |
| Comments | `# comment` | `// comment` |
| Multiline string | `"""text"""` | `"""text"""` (same!) |

Expand Down
2 changes: 1 addition & 1 deletion chapters/Testing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ same API to Fable, supporting JavaScript, Python, and .NET.

- **Composable**: Tests are values you can combine and transform
- **No magic**: No reflection, no attributes - just functions
- **Familiar F# idioms**: Uses computation expressions and pipelines
- **Familiar F# idioms**: Uses lists and pipelines

### Setting Up Pyxpecto

Expand Down