@@ -875,6 +875,50 @@ def test_jsanitize(self):
875875 clean = jsanitize (d , strict = True )
876876 assert "@class" in clean ["c" ]
877877
878+ def test_unserializable_composite (self ):
879+ class Unserializable :
880+ def __init__ (self , a ):
881+ self ._a = a
882+
883+ def __str__ (self ):
884+ return "Unserializable"
885+
886+ class Composite (MSONable ):
887+ def __init__ (self , name , unserializable , msonable ):
888+ self .name = name
889+ self .unserializable = unserializable
890+ self .msonable = msonable
891+
892+ composite_dictionary = {
893+ "name" : "test" ,
894+ "unserializable" : Unserializable (1 ),
895+ "msonable" : GoodMSONClass (1 , 2 , 3 ),
896+ }
897+
898+ with pytest .raises (AttributeError ):
899+ jsanitize (composite_dictionary , strict = True )
900+
901+ composite_obj = Composite .from_dict (composite_dictionary )
902+
903+ with pytest .raises (AttributeError ):
904+ jsanitize (composite_obj , strict = True )
905+
906+ # Test that skip mode preserves unserializable objects
907+ skipped_dict = jsanitize (composite_obj , strict = "skip" , recursive_msonable = True )
908+ assert skipped_dict ["name" ] == "test" , "String values should remain unchanged"
909+ assert (
910+ skipped_dict ["unserializable" ]._a == 1
911+ ), "Unserializable object should be preserved in skip mode"
912+ assert (
913+ skipped_dict ["msonable" ]["a" ] == 1
914+ ), "MSONable object should be properly serialized"
915+
916+ # Test non-strict mode converts unserializable to string
917+ dict_with_str = jsanitize (composite_obj , strict = False , recursive_msonable = True )
918+ assert isinstance (
919+ dict_with_str ["unserializable" ], str
920+ ), "Unserializable object should be converted to string in non-strict mode"
921+
878922 @pytest .mark .skipif (pd is None , reason = "pandas not present" )
879923 def test_jsanitize_pandas (self ):
880924 s = pd .Series ({"a" : [1 , 2 , 3 ], "b" : [4 , 5 , 6 ]})
0 commit comments