Skip to content

Conversation

@dbrattli
Copy link
Collaborator

@dbrattli dbrattli commented Dec 4, 2025

This PR improves the Py.Decorate attribute to emit decorator strings verbatim and adds explicit import control via the importFrom parameter. This fixes issues with decorator patterns since the previous auto-import logic could not be used for FastAPI endpoint decorators.

Key changes:

  • Decorator strings are now emitted exactly as written (e.g., app.get("/") stays as @app.get("/"))
  • Added importFrom parameter to explicitly specify the module to import from

New API:

// Simple decorator with import
[<Py.Decorate("dataclass", "dataclasses")>]

// Decorator with import and parameters
[<Py.Decorate("lru_cache", importFrom="functools", parameters="maxsize=128")>]

// Local variable decorator (no import) - FastAPI pattern
[<Py.Decorate("app.get(\"/\")")>]

// .. same as, but we need both when we use importFrom
[<Py.Decorate("app.get", parameters="\"/\"")>]

This enables proper integration with FastAPI, Pydantic, and other Python frameworks that use local variable decorators or decorator factories.

Note: We need to use importFrom parameter instead of using [<Import(..)>]´ since the Import` attribute is not allowed to have multiple imports on the same element. We need to be able to add multiple decorators to the same element

Alternative would be to change the Fable AST. Named Attribute Parameters in Fable AST. Currently, Fable.Attribute only exposes ConstructorArgs: obj list, which means we rely on constructor overloads and positional arguments. This works but can be awkward for attributes with multiple optional parameters.

For example, we'd ideally write:
[<Py.Decorate("lru_cache", importFrom="functools", parameters="maxsize=128")>]

And have the compiler recognize importFrom and parameters as named arguments rather than relying on constructor position matching.

Proposed change to Fable.Attribute:

type Attribute =
    abstract Entity: EntityRef
    abstract ConstructorArgs: obj list
    abstract NamedArgs: (string * obj) list  // New!

This would require changes to:

  • src/Fable.AST/Fable.fs - Add NamedArgs to the interface
  • src/Fable.Transforms/FSharp2Fable.Util.fs - Extract named args from FSharpAttribute

@dbrattli dbrattli merged commit 33c9095 into main Dec 4, 2025
22 checks passed
@dbrattli dbrattli deleted the python-decorate-fixes branch December 4, 2025 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants