ipython / ipykernel

IPython Kernel for Jupyter
https://ipykernel.readthedocs.io/en/stable/
BSD 3-Clause "New" or "Revised" License
646 stars 365 forks source link

Kernel crashes after setting decimal precision #1259

Closed JasonWeill closed 1 month ago

JasonWeill commented 3 months ago

Originally reported by @eendebakpt in https://github.com/jupyterlab/jupyterlab/issues/16268, and clarified by @williamstein on the same issue.

Using JupyterLab 4.3.0 alpha or Jupyter Console 6.6.3, with IPyKernel 6.29.5, run this cell:

import decimal
d = decimal.Decimal('1001')
con = decimal.getcontext()
con.prec = 1
print('first cell')

… which should print first cell. Then, run the second cell:

print('second cell')

At this point, the following message appears, and the kernel becomes unresponsive:

[IPKernelApp] ERROR | Invalid Message
Traceback (most recent call last):
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 395, in dispatch_shell
    msg = self.session.deserialize(msg, content=True, copy=False)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/session.py", line 1079, in deserialize
    message["header"] = extract_dates(header)
                        ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/jsonutil.py", line 75, in extract_dates
    new_obj[k] = extract_dates(v)
                 ^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/jsonutil.py", line 80, in extract_dates
    obj = parse_date(obj)
          ^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/jsonutil.py", line 65, in parse_date
    dt = _dateutil_parse(s)
         ^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 1368, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 640, in parse
    res, skipped_tokens = self._parse(timestr, **kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 740, in _parse
    i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 942, in _parse_numeric_token
    (res.minute, res.second) = self._parse_min_sec(value)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 1106, in _parse_min_sec
    sec_remainder = value % 1
                    ~~~~~~^~~
decimal.InvalidOperation: [<class 'decimal.DivisionImpossible'>]
/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_console/ptshell.py:787: UserWarning: The kernel did not respond to an is_complete_request. Setting `use_kernel_is_complete` to False.
  warn('The kernel did not respond to an is_complete_request. '
In [3]: print('second cell')
[IPKernelApp] ERROR | Invalid Message
Traceback (most recent call last):
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/ipykernel/kernelbase.py", line 395, in dispatch_shell
    msg = self.session.deserialize(msg, content=True, copy=False)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/session.py", line 1079, in deserialize
    message["header"] = extract_dates(header)
                        ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/jsonutil.py", line 75, in extract_dates
    new_obj[k] = extract_dates(v)
                 ^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/jsonutil.py", line 80, in extract_dates
    obj = parse_date(obj)
          ^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/jupyter_client/jsonutil.py", line 65, in parse_date
    dt = _dateutil_parse(s)
         ^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 1368, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 640, in parse
    res, skipped_tokens = self._parse(timestr, **kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 740, in _parse
    i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 942, in _parse_numeric_token
    (res.minute, res.second) = self._parse_min_sec(value)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/jupyterlab-20240325/lib/python3.12/site-packages/dateutil/parser/_parser.py", line 1106, in _parse_min_sec
    sec_remainder = value % 1
                    ~~~~~~^~~
decimal.InvalidOperation: [<class 'decimal.DivisionImpossible'>]

I can reproduce this on macOS 13.6.7 (22G720) on Apple Silicon. Output of jupyter --version:

Selected Jupyter core packages...
IPython          : 8.24.0
ipykernel        : 6.29.5
ipywidgets       : 8.1.2
jupyter_client   : 8.6.1
jupyter_core     : 5.7.2
jupyter_server   : 2.14.0
jupyterlab       : 4.3.0a2
nbclient         : 0.10.0
nbconvert        : 7.16.4
nbformat         : 5.10.3
notebook         : not installed
qtconsole        : not installed
traitlets        : 5.14.3
minrk commented 2 months ago

Perhaps this should be reported to dateutil? Or Python itself?

A simple reproducer script without IPython at all:

import decimal
from datetime import datetime
from dateutil.parser import parse as parse_date

parse_date(datetime.now().isoformat())  # ok
con = decimal.getcontext()
con.prec = 1
parse_date(datetime.now().isoformat())  # error
minrk commented 2 months ago

Already reported in dateutil: https://github.com/dateutil/dateutil/issues/1366

minrk commented 2 months ago

I believe this is fixed by https://github.com/jupyter/jupyter_client/pull/1032