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. ## `[]`