Skip to content

Commit c2dc0fc

Browse files
dbrattliclaude
andcommitted
fix: add missing models.py for pydantic example and update README
- Add handwritten Pydantic models.py file for the pydantic example - Update justfile to copy models.py to build directory - Update .gitignore to track models.py but ignore generated files - Rewrite README with clearer documentation and examples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 0a3c477 commit c2dc0fc

File tree

4 files changed

+226
-139
lines changed

4 files changed

+226
-139
lines changed

README.md

Lines changed: 182 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -3,199 +3,244 @@
33
![Build and Test](https://github.com/dbrattli/Fable.Python/workflows/Build%20and%20Test/badge.svg)
44
[![Nuget](https://img.shields.io/nuget/vpre/Fable.Python)](https://www.nuget.org/packages/Fable.Python/)
55

6-
[Fable](https://github.com/fable-compiler/Fable/tree/beyond) is a
7-
compiler that translates F# source files to JavaScript and Python.
6+
[Fable](https://github.com/fable-compiler/Fable) is a compiler that translates F# source files to JavaScript and Python.
87

9-
This Fable Python repository is a community driven project that contains
10-
the Python type bindings for Fable. The library will eventually contain
11-
Python (stdlib) bindings for Fable based on Python
12-
[typeshed](https://github.com/python/typeshed). It will also contain
13-
type binding for many other 3rd party libraries such as Flask, MicroBit
14-
and many more. Some bindings have already been added:
8+
**Fable.Python** provides Python type bindings for Fable, enabling you to write type-safe F# code that compiles to Python. This community-driven library includes bindings for the Python standard library and popular frameworks like Flask, FastAPI, and Pydantic.
159

16-
- Python Standard Libray
17-
- Jupyter
18-
- Flask
19-
- CogniteSdk
10+
## Requirements
2011

21-
## Version
22-
23-
This library currently targets Python 3.10 or greater. Types bindings
24-
for other versions of Python should not be added to this library until
25-
we decide how to deal with Python version handling.
12+
- Python 3.12 or greater
13+
- .NET 8.0 or greater
14+
- [Fable](https://fable.io/) compiler
2615

2716
## Installation
2817

29-
Prerequisite for compiling F# to Python using Fable:
18+
Install the Fable compiler:
3019

3120
```sh
32-
> dotnet tool install --global fable --prerelease
33-
> dotnet add package Fable.Core --prerelease
21+
dotnet tool install --global fable --prerelease
22+
dotnet add package Fable.Core --prerelease
3423
```
3524

36-
To use the `Fable.Python` library in your Fable project:
25+
Add Fable.Python to your project:
3726

3827
```sh
39-
> dotnet add package Fable.Python
28+
dotnet add package Fable.Python
4029
```
4130

42-
## Usage
31+
## Quick Start
4332

44-
```fs
33+
```fsharp
4534
open Fable.Python.Json
4635
47-
let object = {| A=10n; B=20n |}
48-
let result = json.dumps object
36+
let data = {| name = "Alice"; age = 30 |}
37+
let jsonStr = dumps data
4938
```
5039

51-
To compile an F# Fable project to Python run e.g:
40+
Compile to Python:
5241

5342
```sh
54-
> fable --lang Python MyProject.fsproj
43+
fable --lang Python MyProject.fsproj
5544
```
5645

57-
For more examples see the
58-
[examples](https://github.com/dbrattli/Fable.Python/tree/main/examples) folder.
59-
It contains example code for using Fable Python with:
60-
61-
- [Flask](https://github.com/dbrattli/Fable.Python/tree/main/examples/flask).
62-
References [Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine)
63-
as a nuget package.
64-
- [Timeflies](https://github.com/dbrattli/Fable.Python/tree/main/examples/timeflies),
65-
Cool demo using Tkinter and references
66-
[FSharp.Control.AsyncRx](https://github.com/dbrattli/AsyncRx) as a nuget
67-
package.
68-
69-
## Libraries that uses or works with Fable Python
70-
71-
- [Femto](https://github.com/Zaid-Ajaj/Femto)
72-
- [AsyncRx](https://github.com/dbrattli/AsyncRx)
73-
- [Fable.Aether](https://xyncro.tech/aether/)
74-
- [Fable.Giraffe](https://github.com/dbrattli/Fable.Giraffe), port of Giraffe to Fable.Python
75-
- [Fable.Logging](https://github.com/dbrattli/Fable.logging), logging for Fable.Python
76-
- [Fable.Requests](https://github.com/Zaid-Ajaj/Fable.Requests)
77-
- [Fable.Jupyter](https://github.com/fable-compiler/Fable.Jupyter), Jupyter Notebook using Fable.Python
78-
- [Fable.Pyexpecto](https://github.com/Freymaurer/Fable.Pyxpecto), Fable-python equivalent for Fable.Mocha
79-
- [Fable.SimpleJson.Python](https://github.com/Zaid-Ajaj/Fable.SimpleJson.Python)
80-
- [Fable.Sedlex](https://github.com/thautwarm/Fable.Sedlex)
81-
- [Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine)
82-
- [FsToolkit.ErrorHandling](https://demystifyfp.gitbook.io/fstoolkit-errorhandling/)
83-
- [TypedCssClasses](https://github.com/zanaptak/TypedCssClasses)
84-
- [Typed-BNF](https://github.com/thautwarm/Typed-BNF#readme)
85-
- [Zanaptak.TypedCssClasses](https://github.com/zanaptak/TypedCssClasses)
86-
87-
## Uv
88-
89-
Fable.Python uses [Uv](https://docs.astral.sh/uv/) for package and
90-
dependency management. To handle dependencies when adding Fable Python
91-
compatible NuGet packages, you should use
92-
[Femto](https://github.com/Zaid-Ajaj/Femto).
93-
94-
## Development
46+
## Available Bindings
9547

96-
This project uses [just](https://github.com/casey/just) as a command runner.
48+
### Python Standard Library
9749

98-
```sh
99-
# Install just (macOS)
100-
> brew install just
50+
| Module | Description |
51+
| ----------------------- | ------------------------------------------- |
52+
| `Fable.Python.Builtins` | Built-in functions (open, print, len, etc.) |
53+
| `Fable.Python.Json` | JSON serialization with Fable type support |
54+
| `Fable.Python.Os` | Operating system interfaces |
55+
| `Fable.Python.Sys` | System-specific parameters |
56+
| `Fable.Python.Math` | Mathematical functions |
57+
| `Fable.Python.Random` | Random number generation |
58+
| `Fable.Python.Logging` | Logging facilities |
59+
| `Fable.Python.Time` | Time-related functions |
60+
| `Fable.Python.String` | String operations |
61+
| `Fable.Python.Base64` | Base64 encoding/decoding |
62+
| `Fable.Python.Queue` | Queue data structures |
63+
| `Fable.Python.Ast` | Abstract Syntax Tree |
64+
| `Fable.Python.AsyncIO` | Async programming (Events, Futures, Tasks) |
65+
| `Fable.Python.TkInter` | GUI toolkit |
10166

102-
# Show available commands
103-
> just
67+
### Web Frameworks
10468

105-
# Full setup (restore .NET and Python dependencies)
106-
> just setup
69+
| Package | Description |
70+
| ----------------------- | ----------------------------------- |
71+
| `Fable.Python.Flask` | Flask web framework |
72+
| `Fable.Python.FastAPI` | FastAPI with automatic OpenAPI docs |
73+
| `Fable.Python.Pydantic` | Data validation and settings |
10774

108-
# Build F# to Python
109-
> just build
75+
## JSON Serialization
11076

111-
# Run all tests (native .NET and Python)
112-
> just test
77+
Fable types (like `Int32`, F# records, unions) need special handling for JSON serialization. Use `Fable.Python.Json.dumps`:
11378

114-
# Format code
115-
> just format
79+
```fsharp
80+
open Fable.Python.Json
11681
117-
# Create NuGet package
118-
> just pack
82+
type User = { Id: int; Name: string }
83+
let user = { Id = 1; Name = "Bob" }
84+
let json = dumps user // {"Id": 1, "Name": "Bob"}
11985
```
12086

121-
## Contributing
87+
See [JSON.md](JSON.md) for detailed documentation on serialization patterns.
12288

123-
This project is community driven. If the type binding you are looking
124-
for is currently missing, then you need to add them to the relevant
125-
files (or add new ones). Open a
126-
[PR](https://github.com/dbrattli/Fable.Python/pull/3/files) to get them
127-
included.
89+
## Web Framework Examples
12890

129-
### Commit Convention
91+
### FastAPI
13092

131-
This project uses [Conventional Commits](https://www.conventionalcommits.org/)
132-
and [release-please](https://github.com/googleapis/release-please) for automated
133-
releases. PR titles must follow the format:
93+
```fsharp
94+
open Fable.Python.FastAPI
95+
open Fable.Python.Pydantic
13496
97+
[<Py.ClassAttributes(style = Py.ClassAttributeStyle.Attributes, init = false)>]
98+
type UserResponse(Id: int, Name: string) =
99+
inherit BaseModel()
100+
member val Id: int = Id with get, set
101+
member val Name: string = Name with get, set
102+
103+
[<APIClass>]
104+
type API() =
105+
[<Get("/users/{user_id}")>]
106+
static member get_user(user_id: int) : UserResponse =
107+
UserResponse(Id = user_id, Name = "Alice")
135108
```
136-
type: description
109+
110+
### Flask
111+
112+
```fsharp
113+
open Fable.Python.Flask
114+
open Fable.Python.Json
115+
116+
[<APIClass>]
117+
type Routes() =
118+
[<Get("/api/hello")>]
119+
static member hello() : string =
120+
dumps {| message = "Hello, World!" |}
137121
```
138122

139-
Where `type` is one of:
140-
- `feat` - New features (bumps minor version)
141-
- `fix` - Bug fixes (bumps patch version)
142-
- `docs` - Documentation changes
143-
- `chore` - Maintenance tasks
144-
- `refactor` - Code refactoring
145-
- `test` - Adding or updating tests
146-
- `ci` - CI/CD changes
147-
- `build` - Build system changes
148-
- `perf` - Performance improvements
123+
## Examples
149124

150-
Breaking changes should include `!` after the type (e.g., `feat!: breaking change`)
151-
and will bump the major version.
125+
The [examples](examples/) directory contains working applications:
152126

153-
The `src/stdlib` directory contains type bindings for modules in the
154-
Python 3 standard library. We also accept type bindings for 3rd party
155-
libraries as long as:
127+
| Example | Description |
128+
| ------------------------------------------ | ---------------------------------------------- |
129+
| [fastapi](examples/fastapi/) | REST API with Pydantic models and Swagger docs |
130+
| [flask](examples/flask/) | Web app with Feliz.ViewEngine HTML rendering |
131+
| [django](examples/django/) | Full Django project |
132+
| [django-minimal](examples/django-minimal/) | Single-file Django app |
133+
| [pydantic](examples/pydantic/) | Pydantic model examples |
134+
| [timeflies](examples/timeflies/) | Tkinter GUI with AsyncRx |
156135

157-
- the package is publicly available on the [Python Package Index](https://pypi.org/);
158-
- the package supports any Python version supported by Fable Python; and
159-
- the package does not ship with its own stubs or type annotations
136+
Run an example:
160137

161-
There's not much Python specific documentation yet, but the process of
162-
adding type bindings for Python is similar to JS:
138+
```sh
139+
just example-fastapi # FastAPI with auto-reload
140+
just example-flask # Flask web app
141+
just example-timeflies # Tkinter desktop app
142+
```
163143

164-
- <https://fable.io/docs/communicate/js-from-fable.html>
165-
- <https://medium.com/@zaid.naom/f-interop-with-javascript-in-fable-the-complete-guide-ccc5b896a59f>
144+
## Development
166145

167-
## Differences from JS
146+
This project uses [just](https://github.com/casey/just) as a command runner and [uv](https://docs.astral.sh/uv/) for Python package management.
168147

169-
Note that import all is different from JS. E.g:
148+
### Setup
170149

171-
```fs
172-
[<ImportAll("flask")>]
173-
let flask: IExports = nativeOnly
150+
```sh
151+
# Install just (macOS)
152+
brew install just
153+
154+
# Full setup (restore .NET and Python dependencies)
155+
just setup
156+
```
157+
158+
### Commands
159+
160+
```sh
161+
just # Show all available commands
162+
just build # Build F# to Python
163+
just test # Run all tests (native .NET and Python)
164+
just test-python # Run only Python tests
165+
just format # Format code with Fantomas
166+
just pack # Create NuGet package
167+
just clean # Clean build artifacts
174168
```
175169

176-
This will generate `import flask` and not a wildcard import `from flask import
177-
*`. The latter version is discoraged anyways.
170+
### Project Structure
171+
172+
```txt
173+
src/
174+
├── stdlib/ # Python standard library bindings
175+
├── flask/ # Flask bindings
176+
├── fastapi/ # FastAPI bindings
177+
├── pydantic/ # Pydantic bindings
178+
└── jupyter/ # Jupyter bindings
179+
test/ # Test suite
180+
examples/ # Example applications
181+
build/ # Generated Python output (gitignored)
182+
```
183+
184+
## Compatible Libraries
185+
186+
These libraries work with Fable.Python:
187+
188+
- [AsyncRx](https://github.com/dbrattli/AsyncRx) - Reactive programming
189+
- [Fable.Giraffe](https://github.com/dbrattli/Fable.Giraffe) - Giraffe port
190+
- [Fable.Logging](https://github.com/dbrattli/Fable.logging) - Logging
191+
- [Fable.Requests](https://github.com/Zaid-Ajaj/Fable.Requests) - HTTP requests
192+
- [Fable.Jupyter](https://github.com/fable-compiler/Fable.Jupyter) - Jupyter notebooks
193+
- [Fable.Pyexpecto](https://github.com/Freymaurer/Fable.Pyxpecto) - Testing
194+
- [Fable.SimpleJson.Python](https://github.com/Zaid-Ajaj/Fable.SimpleJson.Python) - JSON parsing
195+
- [Fable.Sedlex](https://github.com/thautwarm/Fable.Sedlex) - Lexer generator
196+
- [Feliz.ViewEngine](https://github.com/dbrattli/Feliz.ViewEngine) - HTML rendering
197+
- [Femto](https://github.com/Zaid-Ajaj/Femto) - Package management
198+
- [FsToolkit.ErrorHandling](https://demystifyfp.gitbook.io/fstoolkit-errorhandling/) - Error handling
199+
- [TypedCssClasses](https://github.com/zanaptak/TypedCssClasses) - Type-safe CSS
200+
201+
## Contributing
202+
203+
Contributions are welcome! If a type binding you need is missing, open a [PR](https://github.com/dbrattli/Fable.Python/pulls) to add it.
204+
205+
### Commit Convention
206+
207+
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for automated releases:
208+
209+
| Type | Description |
210+
| ---------- | ---------------------------------- |
211+
| `feat` | New features (bumps minor version) |
212+
| `fix` | Bug fixes (bumps patch version) |
213+
| `docs` | Documentation changes |
214+
| `chore` | Maintenance tasks |
215+
| `refactor` | Code refactoring |
216+
| `test` | Tests |
217+
218+
Breaking changes use `!` (e.g., `feat!: breaking change`).
178219

179-
## Auto-generation
220+
### Adding Bindings
180221

181-
Parts of this library could benefit from code-generation based on the type
182-
annotations in Python [typeshed](https://github.com/python/typeshed) similar to
183-
[ts2fable](https://github.com/fable-compiler/ts2fable). Even so we should keep
184-
this library manually updated based on PRs to ensure the quality of the code.
222+
The `src/stdlib/` directory contains Python standard library bindings. Third-party library bindings are accepted if:
185223

186-
Current plan:
224+
- The package is publicly available on [PyPI](https://pypi.org/)
225+
- The package supports Python 3.12+
226+
- The package doesn't ship with its own type stubs
187227

188-
1. Add bindings for Python `ast` module (in progress)
189-
2. Use `ast` module to parse Python typeshed annotations
190-
3. Generate F# bindings
228+
For guidance on creating bindings, see:
191229

192-
## Road-map
230+
- [Fable JS Interop](https://fable.io/docs/communicate/js-from-fable.html) (patterns apply to Python)
231+
- [F# Interop Guide](https://medium.com/@zaid.naom/f-interop-with-javascript-in-fable-the-complete-guide-ccc5b896a59f)
193232

194-
- Use a dedicated List.fs for Python. List.fs currently depends on
195-
Array.fs that is not an efficient list implementation for Python.
233+
### Import Pattern
234+
235+
Note that `ImportAll` generates a module import:
236+
237+
```fsharp
238+
[<ImportAll("flask")>]
239+
let flask: IExports = nativeOnly
240+
```
196241

197-
- Compile Fable.Library as a published library (done)
242+
This generates `import flask`, not `from flask import *`.
198243

199-
- Use uv for Python references to Fable modules (done)
244+
## License
200245

201-
- Update docs
246+
MIT

examples/pydantic/.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ obj/
1515
fable_modules/
1616

1717
# Generated Fable code
18-
src
19-
*.py
18+
build/
19+
20+
# Generated Python files (but not models.py which is handwritten)
21+
app.py
22+
!models.py

0 commit comments

Comments
 (0)