@@ -501,7 +501,7 @@ type PydanticUserWithValidator(Name: string) =
501501 inherit BaseModel()
502502 member val Name : string = Name with get, set
503503
504- [<Py.Decorate( " pydantic. field_validator" , " 'Name'" ) >]
504+ [<Py.Decorate( " field_validator" , importFrom = " pydantic " , parameters = " 'Name'" ) >]
505505 [<Py.ClassMethod>]
506506 static member validate_name ( cls : obj , v : string ) : string =
507507 v.ToUpper()
@@ -513,7 +513,7 @@ let ``test Pydantic field_validator with classmethod`` () =
513513 let user = emitPyExpr< PydanticUserWithValidator> [] " PydanticUserWithValidator(Name='john')"
514514 user.Name |> equal " JOHN"
515515
516- [<Py.Decorate( " dataclasses. dataclass" ) >]
516+ [<Py.Decorate( " dataclass" , importFrom = " dataclasses " ) >]
517517[<Py.ClassAttributes( style= Py.ClassAttributeStyle.Attributes, init= false ) >]
518518type DecoratedUser () =
519519 member val Name : string = " " with get, set
@@ -529,19 +529,20 @@ let ``test simple decorator without parameters`` () =
529529 user.Name |> equal " Test User"
530530 user.Age |> equal 25
531531
532- [<Py.Decorate( " functools.lru_cache" , " maxsize=128" ) >]
533- [<Py.ClassAttributes( style= Py.ClassAttributeStyle.Attributes, init= false ) >]
534- type DecoratedCache () =
535- member val Value : string = " cached" with get, set
532+ [<AttachMembers>]
533+ type DecoratedCacheClass () =
534+ [<Py.Decorate( " lru_cache" , importFrom= " functools" , parameters= " maxsize=128" ) >]
535+ static member expensive_computation ( x : int ) : int =
536+ x * x // Simulated expensive computation
536537
537538[<Fact>]
538539let ``test decorator with parameters`` () =
539- // Test that decorator with parameters is applied correctly
540- let cache = DecoratedCache ( )
541- cache.Value |> equal " cached "
540+ // Test that decorator with parameters is applied correctly to a method
541+ let result = DecoratedCacheClass.expensive _ computation ( 5 )
542+ result |> equal 25
542543
543- [<Py.Decorate( " dataclasses. dataclass" ) >]
544- [<Py.Decorate( " functools. total_ordering" ) >]
544+ [<Py.Decorate( " dataclass" , importFrom = " dataclasses " ) >]
545+ [<Py.Decorate( " total_ordering" , importFrom = " functools " ) >]
545546[<Py.ClassAttributes( style= Py.ClassAttributeStyle.Attributes, init= false ) >]
546547type MultiDecoratedClass () =
547548 member val Priority : int = 0 with get, set
@@ -560,7 +561,7 @@ let ``test multiple decorators applied in correct order`` () =
560561 obj.Priority |> equal 1
561562 obj.Name |> equal " test"
562563
563- [<Py.Decorate( " attrs. define" , " auto_attribs=True, slots=True" ) >]
564+ [<Py.Decorate( " define" , importFrom = " attrs " , parameters = " auto_attribs=True, slots=True" ) >]
564565[<Py.ClassAttributes( style= Py.ClassAttributeStyle.Attributes, init= false ) >]
565566type AttrsDecoratedClass () =
566567 member val Data : string = " attrs_data" with get, set
@@ -575,7 +576,7 @@ let ``test complex decorator parameters`` () =
575576
576577// Test combining Decorate with existing F# features
577578
578- [<Py.Decorate( " dataclasses. dataclass" ) >]
579+ [<Py.Decorate( " dataclass" , " dataclasses " ) >]
579580[<Py.ClassAttributes( style= Py.ClassAttributeStyle.Attributes, init= false ) >]
580581type InheritedDecoratedClass () =
581582 inherit DecoratedUser()
@@ -608,13 +609,32 @@ let ``test PropertiesUserWithInit`` () =
608609 user.Email
|> equal
( Some
" [email protected] " ) 609610 user.Enabled |> equal true
610611
612+ // Test Py.Decorate without import (local variable decorator like FastAPI app.get)
613+
614+ // Simulate a decorator factory (like FastAPI's app instance)
615+ let my_decorator ( path : string ) : ( obj -> obj ) = import " my_decorator" " ./native_code.py"
616+
617+ [<AttachMembers>]
618+ type ClassWithLocalDecorator () =
619+ // Use full decorator expression since my_decorator is a local variable (no import)
620+ [<Py.Decorate( " my_decorator(\" /test\" )" ) >]
621+ static member decorated_method () : string =
622+ " result"
623+
624+ [<Fact>]
625+ let ``test Py.Decorate without import ( local variable ) `` () =
626+ // Test that decorator is emitted verbatim without auto-import
627+ // This pattern is used for FastAPI: @app.get("/")
628+ let result = ClassWithLocalDecorator.decorated_ method()
629+ result |> equal " decorated: result"
630+
611631// Test Py.Decorate on static methods
612632
613633[<AttachMembers>]
614634type ClassWithDecoratedStaticMethod () =
615635 member val Value : int = 0 with get, set
616636
617- [<Py.Decorate( " functools. lru_cache" ) >]
637+ [<Py.Decorate( " lru_cache" , importFrom = " functools " ) >]
618638 static member cached_function ( x : int ) : int =
619639 x * 2
620640
@@ -628,7 +648,7 @@ let ``test Py.Decorate on static method`` () =
628648
629649[<AttachMembers>]
630650type ClassWithDecoratedStaticMethodWithParams () =
631- [<Py.Decorate( " functools. lru_cache" , " maxsize=32" ) >]
651+ [<Py.Decorate( " lru_cache" , importFrom = " functools " , parameters = " maxsize=32" ) >]
632652 static member cached_with_params ( x : int ) : int =
633653 x * 3
634654
@@ -661,10 +681,10 @@ let ``test Py.ClassMethod attribute`` () =
661681
662682[<AttachMembers>]
663683type ClassWithMultipleDecoratedMethods () =
664- [<Py.Decorate( " functools. lru_cache" , " maxsize=16" ) >]
684+ [<Py.Decorate( " lru_cache" , importFrom = " functools " , parameters = " maxsize=16" ) >]
665685 static member method_a ( x : int ) : int = x * 2
666686
667- [<Py.Decorate( " functools. lru_cache" , " maxsize=32" ) >]
687+ [<Py.Decorate( " lru_cache" , importFrom = " functools " , parameters = " maxsize=32" ) >]
668688 static member method_b ( x : int ) : int = x * 3
669689
670690[<Fact>]
@@ -679,7 +699,7 @@ let ``test multiple static methods with decorators`` () =
679699type ClassWithDecoratedInstanceMethod () =
680700 member val CallCount : int = 0 with get, set
681701
682- [<Py.Decorate( " functools. lru_cache" , " maxsize=16" ) >]
702+ [<Py.Decorate( " lru_cache" , importFrom = " functools " , parameters = " maxsize=16" ) >]
683703 member this.cached_instance_method ( x : int ) : int =
684704 x * 4
685705
0 commit comments