Skip to content

Commit

Permalink
deprecate extracting dates in message headers
Browse files Browse the repository at this point in the history
adds Session.extract_header_dates config
and JUPYTER_SESSION_EXTRACT_HEADER_DATES env

default unchanged, but deprecated
  • Loading branch information
minrk committed Mar 10, 2024
1 parent a66bd11 commit bbc9559
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 7 deletions.
39 changes: 37 additions & 2 deletions jupyter_client/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
Set,
TraitError,
Unicode,
default,
observe,
)
from traitlets.config.configurable import Configurable, LoggingConfigurable
Expand Down Expand Up @@ -420,6 +421,36 @@ def _session_changed(self, change: t.Any) -> None:
"message.",
)

extract_header_dates = Bool(
True,
config=True,
help="""
Parse timestamps in message headers to datetime objects.
If True, `date` and other timestamp fields
will be `datetime.datetime` objects.
If False, they will be ISO8601 strings.
Parsing has a performance cost and is deprecated,
but kept as default for backward compatibility.
""",
)

@default("extract_header_dates")
def _extract_header_dates_default(self):
msg = """Session.extract_header_dates = True is deprecated in jupyter-client 8.6
set cfg.Session.extract_header_dates = False
or JUPYTER_SESSION_EXTRACT_HEADER_DATES=0
to avoid this message.
"""
env_value = os.environ.get("JUPYTER_SESSION_EXTRACT_HEADER_DATES", "") != "0"
if env_value:
warnings.warn(msg, DeprecationWarning, stacklevel=2)
return True
else:
return False

# if 0, no adapting to do.
adapt_version = Integer(0)

Expand Down Expand Up @@ -1076,10 +1107,14 @@ def deserialize(
msg = "malformed message, must have at least %i elements" % minlen
raise TypeError(msg)
header = self.unpack(msg_list[1])
message["header"] = extract_dates(header)
parent_header = self.unpack(msg_list[2])
if self.extract_header_dates:
header = extract_dates(header)
parent_header = extract_dates(parent_header)
message["header"] = header
message["msg_id"] = header["msg_id"]
message["msg_type"] = header["msg_type"]
message["parent_header"] = extract_dates(self.unpack(msg_list[2]))
message["parent_header"] = parent_header
message["metadata"] = self.unpack(msg_list[3])
if content:
message["content"] = self.unpack(msg_list[4])
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ filterwarnings= [
# from python-dateutil
"ignore:datetime.datetime.utcfromtimestamp:DeprecationWarning",
"ignore:datetime.datetime.utcnow:DeprecationWarning",
# ignore header dates warning
"ignore:.*extract_header_dates.*:DeprecationWarning",
]

[tool.coverage.report]
Expand Down
16 changes: 11 additions & 5 deletions tests/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,18 +411,24 @@ def _datetime_test(self, session):
msg = session.msg("msg", content=content, metadata=metadata, parent=p["header"])
smsg = session.serialize(msg)
msg2 = session.deserialize(session.feed_identities(smsg)[1])
assert isinstance(msg2["header"]["date"], datetime)
self.assertEqual(msg["header"], msg2["header"])
self.assertEqual(msg["parent_header"], msg2["parent_header"])
self.assertEqual(msg["parent_header"], msg2["parent_header"])
if session.extract_header_dates:
date_type = datetime
else:
date_type = str
assert isinstance(msg2["header"]["date"], date_type)
assert isinstance(msg2["parent_header"]["date"], date_type)
self.assertEqual(msg["header"], jsonutil.extract_dates(msg2["header"]))
self.assertEqual(msg["parent_header"], jsonutil.extract_dates(msg2["parent_header"]))
assert isinstance(msg["content"]["t"], datetime)
assert isinstance(msg["metadata"]["t"], datetime)
assert isinstance(msg2["content"]["t"], str)
assert isinstance(msg2["metadata"]["t"], str)
self.assertEqual(msg["content"], jsonutil.extract_dates(msg2["content"]))
self.assertEqual(msg["content"], jsonutil.extract_dates(msg2["content"]))

def test_datetimes(self, session):
@pytest.mark.parametrize("extract_header_dates", [True, False])
def test_datetimes(self, session, extract_header_dates):
session.extract_header_dates = extract_header_dates
self._datetime_test(session)

def test_datetimes_pickle(self):
Expand Down

0 comments on commit bbc9559

Please sign in to comment.