diff --git a/docs/docs/python/features.md b/docs/docs/python/features.md
index a39c159..ea73eb8 100644
--- a/docs/docs/python/features.md
+++ b/docs/docs/python/features.md
@@ -458,73 +458,111 @@ def add(a: int32, b: int32) -> Any:
`Py.python` executes as statements, so use `return` keyword to return values.
-## Python Decorators
+## Class Attributes
Added in v5.0.0-alpha
-`Py.Decorator` allows you to apply Python decorators to classes and functions.
+`Py.ClassAttributes` controls how class members are generated in Python.
```fs
open Fable.Core
-[]
-type User =
- { Name: string
- Age: int }
+[]
+type Config() =
+ member val Name = "default" with get, set
+ member val Port = 8080 with get, set
```
generates:
```py
-@dataclasses.dataclass
-class User:
- name: str
- age: int32
+class Config:
+ name: str = "default"
+ port: int = 8080
```
-You can also pass parameters to decorators:
+Without `ClassAttributes`, members would be generated as properties with instance backing.
-```fs
-[]
-let expensiveFunction x = x * 2
-```
+| Parameter | Effect |
+| -------------------- | ---------------------------------------------------------- |
+| `style = Attributes` | Generate class-level type annotations |
+| `style = Properties` | Generate properties with instance attribute backing |
+| `init = false` | Don't generate `__init__` (Pydantic/dataclass provides it) |
+| `init = true` | Generate `__init__` with attribute assignments |
-generates:
+`Py.DataClass` is shorthand for `Py.ClassAttributes(style = Attributes, init = false)`.
+This is useful when working with frameworks like Pydantic, dataclasses, and attrs that
+expect class-level type annotations:
-```py
-@functools.lru_cache(maxsize=128)
-def expensive_function(x):
- return x * 2
+```fs
+[]
+type User() =
+ inherit BaseModel()
+ member val Name: string = "" with get, set
+ member val Age: int = 0 with get, set
```
-## Class Attributes
+## Python Decorators
Added in v5.0.0-alpha
-`Py.ClassAttributes` controls how class members are generated in Python.
+`Py.Decorate` allows you to apply Python decorators to types.
```fs
open Fable.Core
-[]
-type Config() =
- member val Name = "default" with get, set
- member val Port = 8080 with get, set
+[]
+[]
+type DecoratedUser() =
+ member val Name: string = "" with get, set
+ member val Age: int = 0 with get, set
```
generates:
```py
-class Config:
- name: str = "default"
- port: int = 8080
+@dataclass
+class DecoratedUser:
+ Age: int32 = int32.ZERO
+ Name: str = ""
```
-Without `ClassAttributes`, members would be generated as properties with instance backing.
+The single argument form can be used for local decorators where you don't need to import anything:
+
+```fs
+[]
+type MyClass() =
+ member val Value: int = 0 with get, set
+```
+
+### DecorateTemplate for Library Authors
+
+When building a library, you can create custom decorator attributes that users
+can apply without knowing the underlying Python syntax. Use `Py.DecorateTemplate`:
+
+```fs
+/// Custom route decorator for a web framework
+[]
+[]
+type GetRouteAttribute(path: string) =
+ inherit System.Attribute()
+```
+
+Now users of your library can simply write:
+
+```fs
+[]
+static member get_users() = ...
+// Generates: @app.get('/users')
+```
+
+The template string uses `{0}`, `{1}`, etc. as placeholders for the attribute's
+constructor arguments. The `[]` attribute prevents the attribute type
+from being emitted to Python.
## `[]`