2323import os
2424import socketserver
2525import threading
26- from typing import Optional , TypeAlias
26+ from typing import Any , Optional , TypeAlias
2727
2828import networkx as nx
2929from traits .trait_base import Undefined
@@ -124,6 +124,23 @@ def __str__(self) -> str:
124124 return super ().__str__ ()
125125
126126
127+ class DatetimeJSONEncoder (json .JSONEncoder ):
128+ """JSON encoder that handles DatetimeWithSafeNone instances."""
129+
130+ def default (self , o : Any ) -> str :
131+ """Convert datetime objects to ISO format."""
132+ if isinstance (o , datetime ):
133+ return o .isoformat ()
134+ if o is None or o is NoTime :
135+ return ""
136+ return super ().default (o )
137+
138+
139+ def json_dumps (obj : Any , ** kwargs ) -> str :
140+ """Convert an object to a JSON string."""
141+ return json .dumps (obj , cls = DatetimeJSONEncoder , ** kwargs )
142+
143+
127144OptionalDatetime : TypeAlias = Optional [datetime | str | DatetimeWithSafeNone | _NoTime ]
128145"""Type alias for a datetime, ISO-format string or None."""
129146
@@ -144,7 +161,7 @@ def recurse_nodes(workflow, prefix=""):
144161def log_nodes_initial (workflow ):
145162 logger = getLogger ("callback" )
146163 for node in recurse_nodes (workflow ):
147- logger .debug (json . dumps (node ))
164+ logger .debug (json_dumps (node ))
148165
149166
150167def log_nodes_cb (node , status ):
@@ -242,7 +259,7 @@ def log_nodes_cb(node, status):
242259 ):
243260 status_dict ["error" ] = True
244261
245- logger .debug (json . dumps (status_dict ))
262+ logger .debug (json_dumps (status_dict ))
246263
247264
248265log_nodes_cb .__doc__ = f"""{ _nipype_log_nodes_cb .__doc__ }
@@ -299,7 +316,7 @@ def handle(self):
299316 tree = {s : t for s , t in tree .items () if t }
300317
301318 headers = "HTTP/1.1 200 OK\n Connection: close\n \n "
302- self .request .sendall (headers + json . dumps (tree ) + "\n " )
319+ self .request .sendall (headers + json_dumps (tree ) + "\n " )
303320
304321
305322class LoggingHTTPServer (socketserver .ThreadingTCPServer , object ):
0 commit comments