Repository: numba/numba

Issue:
Typed List causes IPython console to hang when gets printed
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x] I have tried using the latest released version of Numba (most recent is
 visible in the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
- [x] I have included below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).

<!--

-->

All elements of `numba`'s typed `List` get printed to `IPython` console, causing it to crash if the list is long. This doesn't happen with Python's native lists, as they get shortened when printed.

```python
In [1]: x = [1] * 1_000_000
In [2]: y = numba.typed.List(x)
In [3]: y
```


Discussion:
Thanks for the report. Unfortunately I can't reproduce, though it'd probably make sense to fix this anyway. Are you using windows, I wonder if it's terminal/stdout/buffer related? Also, when you say "crash" what actually happens, does the terminal hang/segfault (access violation)/do nothing? Thanks in advance!
I'm using Spyder IDE on Windows. Sorry, I misspoke, I didn't mean "crash", but it gets stuck until it succeeds in printing the entire list in the `IPython` console. I also realized that 1 million elements is not large enough for it to hang, but 10 million elements keeps my PC hanging for 10-20 sec.
@ma-sadeghi thanks for confirming, I think you are just experiencing the effect of buffering a large amount of output. I think this should be reasonable to fix, just by restricting the amount of printing done for the `List` type.
This is a good first issue. The task is to:
1. Add a limit to the amount of items printed if a `numba.typed.List`'s `__str__` method is called from within an `ipython` shell.
2. Add a test for the above to `numba.tests.test_typedlist`.

Location of code involved:
https://github.com/numba/numba/blob/0db8a2bcd0f53c0d0ad8a798432fb3f37f14af27/numba/typed/typedlist.py#L393-L397

Developer guide:
https://numba.readthedocs.io/en/stable/developer/contributing.html#getting-set-up

@stuartarchibald I'd be more than happy to contribute to `numba`! I'll take a crack at it.
> @stuartarchibald I'd be more than happy to contribute to `numba`! I'll take a crack at it.

Great, thanks for taking it on!
@stuartarchibald @ma-sadeghi is this issue open for work? If so I would be happy to try and make my first contribution to numba!
@caljrobe since no progress has been made so far, I would guess the issue is open for work if you don't hear back from @ma-sadeghi within a day or two.

Resolving patch:
diff --git a/numba/typed/typedlist.py b/numba/typed/typedlist.py
--- a/numba/typed/typedlist.py
+++ b/numba/typed/typedlist.py
@@ -394,7 +394,12 @@ def __str__(self):
         buf = []
         for x in self:
             buf.append("{}".format(x))
-        return '[{0}]'.format(', '.join(buf))
+        # Check whether the code was invoked from IPython shell
+        try:
+            get_ipython
+            return '[{0}, ...]'.format(', '.join(buf[:1000]))
+        except (NameError, IndexError):
+            return '[{0}]'.format(', '.join(buf))
 
     def __repr__(self):
         body = str(self)


Test patch:
diff --git a/numba/tests/test_typedlist.py b/numba/tests/test_typedlist.py
--- a/numba/tests/test_typedlist.py
+++ b/numba/tests/test_typedlist.py
@@ -1,3 +1,5 @@
+import sys
+import subprocess
 from itertools import product
 from textwrap import dedent
 
@@ -12,7 +14,6 @@
 from numba.core.errors import TypingError
 from numba.tests.support import (TestCase, MemoryLeakMixin, override_config,
                                  forbid_codegen, skip_parfors_unsupported)
-
 from numba.core.unsafe.refcount import get_refcount
 from numba.experimental import jitclass
 
@@ -530,6 +531,37 @@ def test_repr(self):
         expected = "ListType[int32]([1, 2, 3])"
         self.assertEqual(expected, repr(l))
 
+    def test_repr_long_list_ipython(self):
+        # Test repr of long typed Lists in an IPython session
+        args = ["-m", "IPython", "--quiet", "--quick", "--no-banner",
+                "--colors=NoColor", "-c"]
+        base_cmd = [sys.executable] + args
+        try:
+            subprocess.check_output(base_cmd + ["--version"])
+        except subprocess.CalledProcessError as e:
+            self.skipTest("ipython not found: return code %d" % e.returncode)
+        repr_cmd = [" ".join(
+            [
+                "import sys;",
+                "from numba.typed import List;",
+                "res = repr(List(range(1005)));",
+                "sys.stderr.write(res);"
+            ]
+        )]
+        cmd = base_cmd + repr_cmd
+        p = subprocess.Popen(
+            cmd,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            universal_newlines=True,
+        )
+        out, err = p.communicate()
+
+        l = List(range(1005))
+        # Assert that the long list is truncated
+        expected = f"{typeof(l)}([{', '.join(map(str, l[:1000]))}, ...])"
+        self.assertEqual(expected, err)
+
     def test_iter_mutates_self(self):
         self.disable_leak_check()