@@ -153,6 +153,8 @@ def test_set_uuid():
153153
154154
155155def test_schema ():
156+ from functools import cached_property
157+
156158 from pydantic import BaseModel
157159
158160 from jobflow import OutputReference
@@ -173,6 +175,17 @@ class MySchema(BaseModel):
173175 name : str
174176 nested : MediumSchema
175177
178+ @property
179+ def b (self ) -> int :
180+ return self .number
181+
182+ @cached_property
183+ def c (self ) -> int :
184+ return self .number
185+
186+ def some_method (self ) -> int :
187+ return self .number
188+
176189 ref = OutputReference ("123" , output_schema = MySchema )
177190 assert ref .attributes == ()
178191
@@ -185,15 +198,26 @@ class MySchema(BaseModel):
185198 assert new_ref .uuid == "123"
186199 assert new_ref .output_schema is None
187200
188- with pytest .raises (AttributeError ):
201+ with pytest .raises (AttributeError , match = "does not have attribute 'a'" ):
189202 _ = ref .a .uuid
190203
191- with pytest .raises (AttributeError ):
204+ with pytest .raises (AttributeError , match = "does not have attribute 'a'" ):
192205 _ = ref ["a" ].uuid
193206
194207 with pytest .raises (AttributeError ):
195208 _ = ref [1 ].uuid
196209
210+ assert ref .b
211+ assert ref ["b" ]
212+ assert ref .c
213+ assert ref ["c" ]
214+
215+ with pytest .raises (AttributeError , match = "does not have attribute 'some_method'" ):
216+ _ = ref .some_method
217+
218+ with pytest .raises (AttributeError , match = "does not have attribute 'some_method'" ):
219+ _ = ref ["some_method" ]
220+
197221 # check valid nested schemas
198222 assert ref .nested .s .uuid == "123"
199223 with pytest .raises (AttributeError ):
@@ -518,3 +542,49 @@ def test_not_iterable():
518542 with pytest .raises (TypeError ):
519543 for _ in ref :
520544 pass
545+
546+
547+ def test_has_property_like ():
548+ from functools import cached_property
549+
550+ from monty .functools import lazy_property
551+ from pydantic import BaseModel , ConfigDict
552+
553+ from jobflow .core .reference import has_property_like
554+
555+ class TestModel (BaseModel ):
556+ model_config = ConfigDict (ignored_types = (lazy_property ,))
557+
558+ x : str = "x"
559+ y : int = 1
560+
561+ def method (self ):
562+ return self .x
563+
564+ @staticmethod
565+ def static_method ():
566+ return 1
567+
568+ @classmethod
569+ def class_method (cls ):
570+ return cls .y
571+
572+ @property
573+ def standard_property (self ):
574+ return self .x
575+
576+ @lazy_property
577+ def monty_lazy_property (self ):
578+ return self .x
579+
580+ @cached_property
581+ def functools_cached_property (self ):
582+ return self .x
583+
584+ assert not has_property_like (TestModel , "method" )
585+ assert not has_property_like (TestModel , "static_method" )
586+ assert not has_property_like (TestModel , "class_method" )
587+ assert has_property_like (TestModel , "standard_property" )
588+ assert has_property_like (TestModel , "monty_lazy_property" )
589+ assert has_property_like (TestModel , "functools_cached_property" )
590+ assert not has_property_like (TestModel , "not_existing_prop" )
0 commit comments