diff --git a/IPython/parallel/client/client.py b/IPython/parallel/client/client.py index 6281df9..27e5d45 100644 --- a/IPython/parallel/client/client.py +++ b/IPython/parallel/client/client.py @@ -37,7 +37,7 @@ from IPython.core.profiledir import ProfileDir, ProfileDirError from IPython.utils.capture import RichOutput from IPython.utils.coloransi import TermColors -from IPython.utils.jsonutil import rekey, extract_dates +from IPython.utils.jsonutil import rekey, extract_dates, parse_date from IPython.utils.localinterfaces import localhost, is_local_ip from IPython.utils.path import get_ipython_dir from IPython.utils.py3compat import cast_bytes, string_types, xrange, iteritems @@ -675,7 +675,7 @@ class Client(HasTraits): if 'date' in parent: md['submitted'] = parent['date'] if 'started' in msg_meta: - md['started'] = extract_dates(msg_meta['started']) + md['started'] = parse_date(msg_meta['started']) if 'date' in header: md['completed'] = header['date'] return md @@ -1580,7 +1580,7 @@ class Client(HasTraits): ) md.update(self._extract_metadata(md_msg)) if rec.get('received'): - md['received'] = extract_dates(rec['received']) + md['received'] = parse_date(rec['received']) md.update(iodict) if rcontent['status'] == 'ok': @@ -1843,12 +1843,12 @@ class Client(HasTraits): has_rbufs = result_buffer_lens is not None for i,rec in enumerate(records): # unpack datetime objects - for dtkey in ('header', 'result_header', - 'submitted', 'started', - 'completed', 'received', - ): + for hkey in ('header', 'result_header'): + if hkey in rec: + rec[hkey] = extract_dates(rec[hkey]) + for dtkey in ('submitted', 'started', 'completed', 'received'): if dtkey in rec: - rec[dtkey] = extract_dates(rec[dtkey]) + rec[dtkey] = parse_date(rec[dtkey]) # relink buffers if has_bufs: blen = buffer_lens[i] diff --git a/IPython/utils/jsonutil.py b/IPython/utils/jsonutil.py index ee93a06..565b1bc 100644 --- a/IPython/utils/jsonutil.py +++ b/IPython/utils/jsonutil.py @@ -62,22 +62,34 @@ def rekey(dikt): dikt[nk] = dikt.pop(k) return dikt +def parse_date(s): + """parse an ISO8601 date string + + If it is None or not a valid ISO8601 timestamp, + it will be returned unmodified. + Otherwise, it will return a datetime object. + """ + if s is None: + return s + m = ISO8601_PAT.match(s) + if m: + # FIXME: add actual timezone support + # this just drops the timezone info + notz = m.groups()[0] + return datetime.strptime(notz, ISO8601) + return s def extract_dates(obj): """extract ISO8601 dates from unpacked JSON""" if isinstance(obj, dict): - obj = dict(obj) # don't clobber + new_obj = {} # don't clobber for k,v in iteritems(obj): - obj[k] = extract_dates(v) + new_obj[k] = extract_dates(v) + obj = new_obj elif isinstance(obj, (list, tuple)): obj = [ extract_dates(o) for o in obj ] elif isinstance(obj, string_types): - m = ISO8601_PAT.match(obj) - if m: - # FIXME: add actual timezone support - # this just drops the timezone info - notz = m.groups()[0] - obj = datetime.strptime(notz, ISO8601) + obj = parse_date(obj) return obj def squash_dates(obj):