@@ -16,11 +16,48 @@ module Py =
1616 [<Emit " $0" >]
1717 abstract Instance: obj
1818
19+ /// <summary>
20+ /// Base class for creating F#-side decorator attributes that transform functions at compile time.
21+ /// This is similar to Python decorators but operates during Fable compilation, not at Python runtime.
22+ /// </summary>
23+ /// <remarks>
24+ /// <para>Inherit from this class and implement the Decorate method to wrap or transform functions.</para>
25+ /// <para>The decorated function is passed to Decorate, and the returned Callable replaces it.</para>
26+ /// <para>Example:</para>
27+ /// <code>
28+ /// type LogAttribute() =
29+ /// inherit Py.DecoratorAttribute()
30+ /// override _.Decorate(fn) =
31+ /// Py.argsFunc (fun args ->
32+ /// printfn "Calling function"
33+ /// fn.Invoke(args))
34+ /// </code>
35+ /// <para>Note: This does NOT emit Python @decorator syntax. For emitting Python decorators,
36+ /// use DecorateAttribute or DecorateTemplateAttribute instead.</para>
37+ /// </remarks>
1938 [<AbstractClass>]
2039 type DecoratorAttribute () =
2140 inherit Attribute()
2241 abstract Decorate: fn : Callable -> Callable
2342
43+ /// <summary>
44+ /// Base class for creating F#-side decorator attributes with access to reflection metadata.
45+ /// Like DecoratorAttribute, but the Decorate method also receives MethodInfo for the decorated member.
46+ /// </summary>
47+ /// <remarks>
48+ /// <para>Use this when your decorator needs information about the decorated method (name, parameters, etc.).</para>
49+ /// <para>Example:</para>
50+ /// <code>
51+ /// type LogWithNameAttribute() =
52+ /// inherit Py.ReflectedDecoratorAttribute()
53+ /// override _.Decorate(fn, info) =
54+ /// Py.argsFunc (fun args ->
55+ /// printfn "Calling %s" info.Name
56+ /// fn.Invoke(args))
57+ /// </code>
58+ /// <para>Note: This does NOT emit Python @decorator syntax. For emitting Python decorators,
59+ /// use DecorateAttribute or DecorateTemplateAttribute instead.</para>
60+ /// </remarks>
2461 [<AbstractClass>]
2562 type ReflectedDecoratorAttribute () =
2663 inherit Attribute()
@@ -49,7 +86,32 @@ module Py =
4986 /// Decorator with import but no parameters
5087 new ( decorator: string, importFrom: string) = DecorateAttribute( decorator, importFrom, " " )
5188
52- /// Decorator with all parameters
89+ /// <summary>
90+ /// Marks a custom attribute class as a decorator template, enabling library authors to create
91+ /// ergonomic decorator attributes that users can apply without knowing the underlying Python syntax.
92+ /// </summary>
93+ /// <remarks>
94+ /// <para>Place this attribute on a custom attribute class. The template string uses {0}, {1}, etc.
95+ /// as placeholders for the custom attribute's constructor arguments.</para>
96+ /// <para>Example - defining a custom decorator attribute:</para>
97+ /// <code>
98+ /// [<Erase; Py.DecorateTemplate("app.get('{0}')")>]
99+ /// type GetAttribute(path: string) = inherit Attribute()
100+ /// </code>
101+ /// <para>Example - using the custom decorator:</para>
102+ /// <code>
103+ /// [<Get("/users")>]
104+ /// static member get_users() = ...
105+ /// // Generates: @app.get('/users')
106+ /// </code>
107+ /// <para>Use [<Erase>] to prevent the attribute type from being emitted to Python.</para>
108+ /// </remarks>
109+ [<AttributeUsage( AttributeTargets.Class) >]
110+ type DecorateTemplateAttribute ( template : string ) =
111+ inherit Attribute()
112+ /// Template with import specification
113+ new ( template: string, importFrom: string) = DecorateTemplateAttribute( template)
114+
53115 /// <summary>
54116 /// Marks a static member to be emitted as a Python @classmethod instead of @staticmethod.
55117 /// </summary>
@@ -72,6 +134,7 @@ module Py =
72134 // Translates to class attributes
73135 | Attributes = 1
74136
137+ /// <summary>
75138 /// Used on a class to provide Python-specific control over how F# types are transpiled to Python classes.
76139 /// This attribute implies member attachment (similar to AttachMembers) while offering Python-specific parameters.
77140 /// </summary>
@@ -80,12 +143,58 @@ module Py =
80143 /// <para>Additional Python-specific parameters control the generated Python class style and features.</para>
81144 /// </remarks>
82145 [<AttributeUsage( AttributeTargets.Class) >]
83- type ClassAttributes () =
146+ type ClassAttributesAttribute () =
84147 inherit Attribute()
85148
86- new ( style: ClassAttributeStyle) = ClassAttributes()
149+ new ( style: ClassAttributeStyle) = ClassAttributesAttribute()
150+
151+ new ( style: ClassAttributeStyle, init: bool) = ClassAttributesAttribute()
152+
153+ /// <summary>
154+ /// Marks a custom attribute class as a class attributes template, enabling library authors
155+ /// to create ergonomic class attributes that users can apply without knowing the underlying parameters.
156+ /// </summary>
157+ /// <remarks>
158+ /// <para>Place this attribute on a custom attribute class to define the class generation style.</para>
159+ /// <para>Example - defining a custom class attribute:</para>
160+ /// <code>
161+ /// [<Erase; Py.ClassAttributesTemplate(Py.ClassAttributeStyle.Attributes, init = false)>]
162+ /// type BaseModelAttribute() = inherit Attribute()
163+ /// </code>
164+ /// <para>Example - using the custom attribute:</para>
165+ /// <code>
166+ /// [<BaseModel>]
167+ /// type User(name: string, age: int) = ...
168+ /// // Generates class with class-level attributes, no __init__
169+ /// </code>
170+ /// <para>Use [<Erase>] to prevent the attribute type from being emitted to Python.</para>
171+ /// </remarks>
172+ [<AttributeUsage( AttributeTargets.Class) >]
173+ type ClassAttributesTemplateAttribute ( style : ClassAttributeStyle , init : bool ) =
174+ inherit Attribute()
175+ /// Template with Attributes style and init = false (common for Pydantic/dataclasses)
176+ new ( style: ClassAttributeStyle) = ClassAttributesTemplateAttribute( style, false )
87177
88- new ( style: ClassAttributeStyle, init: bool) = ClassAttributes()
178+ /// <summary>
179+ /// Shorthand for [<Py.ClassAttributes(style = Attributes, init = false)>].
180+ /// Use this for Python dataclasses, Pydantic models, attrs classes, or any class
181+ /// that needs class-level type annotations without a generated __init__.
182+ /// </summary>
183+ /// <remarks>
184+ /// <para>Example:</para>
185+ /// <code>
186+ /// [<Py.DataClass>]
187+ /// type User(name: string, age: int) = ...
188+ /// // Generates:
189+ /// // class User:
190+ /// // name: str
191+ /// // age: int
192+ /// </code>
193+ /// </remarks>
194+ [<Erase>]
195+ [<ClassAttributesTemplate( ClassAttributeStyle.Attributes, false ) >]
196+ type DataClassAttribute () =
197+ inherit Attribute()
89198
90199 // Hack because currently Fable doesn't keep information about spread for anonymous functions
91200 [<Emit( " lambda *args: $0(args)" ) >]
0 commit comments