@@ -53,6 +53,76 @@ def safe_extract_row(result: Any, index: int = 0) -> Dict:
5353 return {}
5454 return result
5555
56+ def sanitize_for_json (obj : Any ) -> Any :
57+ """
58+ Recursively sanitize any data structure to make it JSON serializable.
59+ Converts numpy types, pandas types, and other non-serializable types to native Python types.
60+
61+ :param obj: Object to sanitize
62+ :return: JSON-serializable version of the object
63+ """
64+ if isinstance (obj , dict ):
65+ return {key : sanitize_for_json (value ) for key , value in obj .items ()}
66+ elif isinstance (obj , (list , tuple )):
67+ return [sanitize_for_json (item ) for item in obj ]
68+ elif isinstance (obj , np .integer ):
69+ return int (obj )
70+ elif isinstance (obj , np .floating ):
71+ return float (obj )
72+ elif isinstance (obj , np .ndarray ):
73+ return obj .tolist ()
74+ elif isinstance (obj , np .bool_ ):
75+ return bool (obj )
76+ elif hasattr (obj , 'item' ): # Handle pandas scalar types
77+ return obj .item ()
78+ elif isinstance (obj , pd .DataFrame ):
79+ return safe_to_dict (obj )
80+ elif hasattr (obj , '__dict__' ): # Handle custom objects
81+ return sanitize_for_json (obj .__dict__ )
82+ else :
83+ return obj
84+
85+ def safe_json_dumps (obj : Any , ** kwargs ) -> str :
86+ """
87+ Safely serialize any object to JSON string, handling numpy and pandas types.
88+
89+ :param obj: Object to serialize
90+ :param kwargs: Additional arguments to pass to json.dumps
91+ :return: JSON string
92+ """
93+ # Set default arguments
94+ default_kwargs = {'indent' : 2 , 'ensure_ascii' : False , 'cls' : NumpyEncoder }
95+ default_kwargs .update (kwargs )
96+
97+ try :
98+ # First try with the NumpyEncoder
99+ return json .dumps (obj , ** default_kwargs )
100+ except (TypeError , ValueError ):
101+ # If that fails, sanitize the object first
102+ sanitized_obj = sanitize_for_json (obj )
103+ return json .dumps (sanitized_obj , ** default_kwargs )
104+
105+ def pretty_print_vfb_result (result : Any , max_length : int = 1000 ) -> None :
106+ """
107+ Pretty print any VFB query result in a safe, readable format.
108+
109+ :param result: Result from any VFB query function
110+ :param max_length: Maximum length of output (truncates if longer)
111+ """
112+ try :
113+ json_str = safe_json_dumps (result )
114+ if len (json_str ) > max_length :
115+ print (json_str [:max_length ] + f'\n ... (truncated, full length: { len (json_str )} characters)' )
116+ else :
117+ print (json_str )
118+ except Exception as e :
119+ print (f'Error printing result: { e } ' )
120+ print (f'Result type: { type (result )} ' )
121+ if hasattr (result , '__dict__' ):
122+ print (f'Result attributes: { list (result .__dict__ .keys ())} ' )
123+ else :
124+ print (f'Result: { str (result )[:max_length ]} ...' )
125+
56126def patch_vfb_connect_query_wrapper ():
57127 """
58128 Apply monkey patches to VfbConnect.neo_query_wrapper to make it handle DataFrame results safely.
0 commit comments