Repository: Delgan/loguru

Issue:
Add unit tests for traceback formatting of RecursionError
For example, the following snippet:

```python
from loguru import logger

def rec():
    rec()

try:
    rec()
except Exception:
    logger.exception("Oups")
```

Should produce the following logs:

```txt
2024-02-17 12:06:00.577 | ERROR    | __main__:<module>:9 - Oups
Traceback (most recent call last):

> File "/home/delgan/Code/loguru/script.py", line 7, in <module>
    rec()
    └ <function rec at 0x7a13f1314720>

  File "/home/delgan/Code/loguru/script.py", line 4, in rec
    rec()
    └ <function rec at 0x7a13f1314720>

  File "/home/delgan/Code/loguru/script.py", line 4, in rec
    rec()
    └ <function rec at 0x7a13f1314720>

  File "/home/delgan/Code/loguru/script.py", line 4, in rec
    rec()
    └ <function rec at 0x7a13f1314720>
  [Previous line repeated 996 more times]

RecursionError: maximum recursion depth exceeded
```

Note the "[Previous line repeated 996 more times]".


Discussion:

Patch:
diff --git a/loguru/_better_exceptions.py b/loguru/_better_exceptions.py
index e9ee112..17d36d6 100644
--- a/loguru/_better_exceptions.py
+++ b/loguru/_better_exceptions.py
@@ -534,13 +534,39 @@ class ExceptionFormatter:
                 yield from self._indent("-" * 35, group_nesting + 1, prefix="+-")
 
     def _format_list(self, frames):
-        result = []
-        for filename, lineno, name, line in frames:
-            row = []
-            row.append('  File "{}", line {}, in {}\n'.format(filename, lineno, name))
+
+        def source_message(filename, lineno, name, line):
+            message = '  File "%s", line %d, in %s\n' % (filename, lineno, name)
             if line:
-                row.append("    {}\n".format(line.strip()))
-            result.append("".join(row))
+                message += "    %s\n" % line.strip()
+            return message
+
+        def skip_message(count):
+            plural = "s" if count > 1 else ""
+            return "  [Previous line repeated %d more time%s]\n" % (count, plural)
+
+        result = []
+        count = 0
+        last_source = None
+
+        for *source, line in frames:
+            if source != last_source and count > 3:
+                result.append(skip_message(count - 3))
+
+            if source == last_source:
+                count += 1
+                if count > 3:
+                    continue
+            else:
+                count = 1
+
+            result.append(source_message(*source, line))
+            last_source = source
+
+        # Add a final skip message if the iteration of frames ended mid-repetition.
+        if count > 3:
+            result.append(skip_message(count - 3))
+
         return result
 
     def format_exception(self, type_, value, tb, *, from_decorator=False):


Test patch:
diff --git a/tests/exceptions/output/others/one_liner_recursion.txt b/tests/exceptions/output/others/one_liner_recursion.txt
new file mode 100644
index 0000000..635d3a2
--- /dev/null
+++ b/tests/exceptions/output/others/one_liner_recursion.txt
@@ -0,0 +1,79 @@
+
+Traceback (most recent call last):
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <module>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  [Previous line repeated 8 more times]
+ZeroDivisionError: division by zero
+
+Traceback (most recent call last):
+> File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <module>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+  [Previous line repeated 8 more times]
+ZeroDivisionError: division by zero
+
+[33m[1mTraceback (most recent call last):[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mone_liner_recursion.py[0m", line [33m14[0m, in [35m<module>[0m
+    [1mrec[0m [35m[1m=[0m [35m[1mlambda[0m [1mr[0m[1m,[0m [1mi[0m[1m:[0m [34m[1m1[0m [35m[1m/[0m [34m[1m0[0m [35m[1mif[0m [1mi[0m [35m[1m==[0m [34m[1m0[0m [35m[1melse[0m [1mr[0m[1m([0m[1mr[0m[1m,[0m [1mi[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m[1m;[0m [1mrec[0m[1m([0m[1mrec[0m[1m,[0m [34m[1m10[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mone_liner_recursion.py[0m", line [33m14[0m, in [35m<lambda>[0m
+    [1mrec[0m [35m[1m=[0m [35m[1mlambda[0m [1mr[0m[1m,[0m [1mi[0m[1m:[0m [34m[1m1[0m [35m[1m/[0m [34m[1m0[0m [35m[1mif[0m [1mi[0m [35m[1m==[0m [34m[1m0[0m [35m[1melse[0m [1mr[0m[1m([0m[1mr[0m[1m,[0m [1mi[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m[1m;[0m [1mrec[0m[1m([0m[1mrec[0m[1m,[0m [34m[1m10[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mone_liner_recursion.py[0m", line [33m14[0m, in [35m<lambda>[0m
+    [1mrec[0m [35m[1m=[0m [35m[1mlambda[0m [1mr[0m[1m,[0m [1mi[0m[1m:[0m [34m[1m1[0m [35m[1m/[0m [34m[1m0[0m [35m[1mif[0m [1mi[0m [35m[1m==[0m [34m[1m0[0m [35m[1melse[0m [1mr[0m[1m([0m[1mr[0m[1m,[0m [1mi[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m[1m;[0m [1mrec[0m[1m([0m[1mrec[0m[1m,[0m [34m[1m10[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mone_liner_recursion.py[0m", line [33m14[0m, in [35m<lambda>[0m
+    [1mrec[0m [35m[1m=[0m [35m[1mlambda[0m [1mr[0m[1m,[0m [1mi[0m[1m:[0m [34m[1m1[0m [35m[1m/[0m [34m[1m0[0m [35m[1mif[0m [1mi[0m [35m[1m==[0m [34m[1m0[0m [35m[1melse[0m [1mr[0m[1m([0m[1mr[0m[1m,[0m [1mi[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m[1m;[0m [1mrec[0m[1m([0m[1mrec[0m[1m,[0m [34m[1m10[0m[1m)[0m
+  [Previous line repeated 8 more times]
+[31m[1mZeroDivisionError[0m:[1m division by zero[0m
+
+Traceback (most recent call last):
+
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <module>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+                                                         │   └ <function <lambda> at 0xDEADBEEF>
+                                                         └ <function <lambda> at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+                 │  │           │           │ │  │       │   └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           │ │  │       └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           │ │  └ 10
+                 │  │           │           │ └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           └ <function <lambda> at 0xDEADBEEF>
+                 │  │           └ 10
+                 │  └ 10
+                 └ <function <lambda> at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+                 │  │           │           │ │  │       │   └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           │ │  │       └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           │ │  └ 9
+                 │  │           │           │ └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           └ <function <lambda> at 0xDEADBEEF>
+                 │  │           └ 9
+                 │  └ 9
+                 └ <function <lambda> at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/one_liner_recursion.py", line 14, in <lambda>
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+                 │  │           │           │ │  │       │   └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           │ │  │       └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           │ │  └ 8
+                 │  │           │           │ └ <function <lambda> at 0xDEADBEEF>
+                 │  │           │           └ <function <lambda> at 0xDEADBEEF>
+                 │  │           └ 8
+                 │  └ 8
+                 └ <function <lambda> at 0xDEADBEEF>
+  [Previous line repeated 8 more times]
+
+ZeroDivisionError: division by zero
diff --git a/tests/exceptions/output/others/recursion_error.txt b/tests/exceptions/output/others/recursion_error.txt
new file mode 100644
index 0000000..56219c1
--- /dev/null
+++ b/tests/exceptions/output/others/recursion_error.txt
@@ -0,0 +1,57 @@
+
+Traceback (most recent call last):
+  File "tests/exceptions/source/others/recursion_error.py", line 19, in <module>
+    recursive()
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+  [Previous line repeated 996 more times]
+RecursionError: maximum recursion depth exceeded
+
+Traceback (most recent call last):
+> File "tests/exceptions/source/others/recursion_error.py", line 19, in <module>
+    recursive()
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+  [Previous line repeated 996 more times]
+RecursionError: maximum recursion depth exceeded
+
+[33m[1mTraceback (most recent call last):[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrecursion_error.py[0m", line [33m19[0m, in [35m<module>[0m
+    [1mrecursive[0m[1m([0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrecursion_error.py[0m", line [33m15[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrecursion_error.py[0m", line [33m15[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrecursion_error.py[0m", line [33m15[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1m)[0m
+  [Previous line repeated 996 more times]
+[31m[1mRecursionError[0m:[1m maximum recursion depth exceeded[0m
+
+Traceback (most recent call last):
+
+  File "tests/exceptions/source/others/recursion_error.py", line 19, in <module>
+    recursive()
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/recursion_error.py", line 15, in recursive
+    recursive()
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 996 more times]
+
+RecursionError: maximum recursion depth exceeded
diff --git a/tests/exceptions/output/others/repeated_lines.txt b/tests/exceptions/output/others/repeated_lines.txt
new file mode 100644
index 0000000..57ed102
--- /dev/null
+++ b/tests/exceptions/output/others/repeated_lines.txt
@@ -0,0 +1,504 @@
+
+Traceback (most recent call last):
+  File "tests/exceptions/source/others/repeated_lines.py", line 22, in <module>
+    recursive(10, 10)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 7 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 6 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 5 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 4 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 3 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 2 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 1 more time]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 15, in recursive
+    raise ValueError("End of recursion")
+ValueError: End of recursion
+
+Traceback (most recent call last):
+> File "tests/exceptions/source/others/repeated_lines.py", line 22, in <module>
+    recursive(10, 10)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 7 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 6 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 5 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 4 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 3 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 2 more times]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  [Previous line repeated 1 more time]
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+  File "tests/exceptions/source/others/repeated_lines.py", line 15, in recursive
+    raise ValueError("End of recursion")
+ValueError: End of recursion
+
+[33m[1mTraceback (most recent call last):[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m22[0m, in [35m<module>[0m
+    [1mrecursive[0m[1m([0m[34m[1m10[0m[1m,[0m [34m[1m10[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 7 more times]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 6 more times]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 5 more times]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 4 more times]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 3 more times]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 2 more times]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  [Previous line repeated 1 more time]
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m18[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m[1m,[0m [1minner[0m[35m[1m=[0m[1minner[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m17[0m, in [35mrecursive[0m
+    [1mrecursive[0m[1m([0m[1mouter[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m,[0m [1minner[0m[35m[1m=[0m[1mouter[0m [35m[1m-[0m [34m[1m1[0m[1m)[0m
+  File "[32mtests/exceptions/source/others/[0m[32m[1mrepeated_lines.py[0m", line [33m15[0m, in [35mrecursive[0m
+    [35m[1mraise[0m [1mValueError[0m[1m([0m[36m"End of recursion"[0m[1m)[0m
+[31m[1mValueError[0m:[1m End of recursion[0m
+
+Traceback (most recent call last):
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 22, in <module>
+    recursive(10, 10)
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 10
+    │               └ 10
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 9
+    │               └ 10
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 8
+    │               └ 10
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 7 more times]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 10
+    │               └ 10
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 9
+    │               └ 9
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 8
+    │               └ 9
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 7
+    │               └ 9
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 6 more times]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 9
+    │               └ 9
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 8
+    │               └ 8
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 7
+    │               └ 8
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 6
+    │               └ 8
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 5 more times]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 8
+    │               └ 8
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 7
+    │               └ 7
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 6
+    │               └ 7
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 5
+    │               └ 7
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 4 more times]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 7
+    │               └ 7
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 6
+    │               └ 6
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 5
+    │               └ 6
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 4
+    │               └ 6
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 3 more times]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 6
+    │               └ 6
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 5
+    │               └ 5
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 4
+    │               └ 5
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 3
+    │               └ 5
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 2 more times]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 5
+    │               └ 5
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 4
+    │               └ 4
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 3
+    │               └ 4
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 2
+    │               └ 4
+    └ <function recursive at 0xDEADBEEF>
+  [Previous line repeated 1 more time]
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 4
+    │               └ 4
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 3
+    │               └ 3
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 2
+    │               └ 3
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 1
+    │               └ 3
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 3
+    │               └ 3
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 2
+    │               └ 2
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 1
+    │               └ 2
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 2
+    │               └ 2
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 18, in recursive
+    recursive(outer=outer, inner=inner - 1)
+    │               │            └ 1
+    │               └ 1
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 17, in recursive
+    recursive(outer=outer - 1, inner=outer - 1)
+    │               │                └ 1
+    │               └ 1
+    └ <function recursive at 0xDEADBEEF>
+
+  File "tests/exceptions/source/others/repeated_lines.py", line 15, in recursive
+    raise ValueError("End of recursion")
+
+ValueError: End of recursion
diff --git a/tests/exceptions/source/others/one_liner_recursion.py b/tests/exceptions/source/others/one_liner_recursion.py
new file mode 100644
index 0000000..91f29c0
--- /dev/null
+++ b/tests/exceptions/source/others/one_liner_recursion.py
@@ -0,0 +1,16 @@
+# fmt: off
+from loguru import logger
+
+import sys
+
+
+logger.remove()
+logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=False)
+logger.add(sys.stderr, format="", diagnose=False, backtrace=True, colorize=False)
+logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=True)
+logger.add(sys.stderr, format="", diagnose=True, backtrace=False, colorize=False)
+
+try:
+    rec = lambda r, i: 1 / 0 if i == 0 else r(r, i - 1); rec(rec, 10)
+except Exception:
+    logger.exception("Error")
diff --git a/tests/exceptions/source/others/recursion_error.py b/tests/exceptions/source/others/recursion_error.py
new file mode 100644
index 0000000..15e0fea
--- /dev/null
+++ b/tests/exceptions/source/others/recursion_error.py
@@ -0,0 +1,21 @@
+from loguru import logger
+
+import sys
+
+sys.setrecursionlimit(1000)
+
+logger.remove()
+logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=False)
+logger.add(sys.stderr, format="", diagnose=False, backtrace=True, colorize=False)
+logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=True)
+logger.add(sys.stderr, format="", diagnose=True, backtrace=False, colorize=False)
+
+
+def recursive():
+    recursive()
+
+
+try:
+    recursive()
+except Exception:
+    logger.exception("Oups")
diff --git a/tests/exceptions/source/others/repeated_lines.py b/tests/exceptions/source/others/repeated_lines.py
new file mode 100644
index 0000000..404ecf6
--- /dev/null
+++ b/tests/exceptions/source/others/repeated_lines.py
@@ -0,0 +1,24 @@
+from loguru import logger
+
+import sys
+
+
+logger.remove()
+logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=False)
+logger.add(sys.stderr, format="", diagnose=False, backtrace=True, colorize=False)
+logger.add(sys.stderr, format="", diagnose=False, backtrace=False, colorize=True)
+logger.add(sys.stderr, format="", diagnose=True, backtrace=False, colorize=False)
+
+
+def recursive(outer, inner):
+    if outer == 0:
+        raise ValueError("End of recursion")
+    if inner == 0:
+        recursive(outer=outer - 1, inner=outer - 1)
+    recursive(outer=outer, inner=inner - 1)
+
+
+try:
+    recursive(10, 10)
+except Exception:
+    logger.exception("Oups")
diff --git a/tests/test_exceptions_formatting.py b/tests/test_exceptions_formatting.py
index 802cabb..47e05cf 100644
--- a/tests/test_exceptions_formatting.py
+++ b/tests/test_exceptions_formatting.py
@@ -219,6 +219,9 @@ def test_exception_ownership(filename):
         "message_formatting_with_context_manager",
         "message_formatting_with_decorator",
         "nested_with_reraise",
+        "one_liner_recursion",
+        "recursion_error",
+        "repeated_lines",
         "syntaxerror_without_traceback",
         "sys_tracebacklimit",
         "sys_tracebacklimit_negative",
@@ -228,6 +231,9 @@ def test_exception_ownership(filename):
     ],
 )
 def test_exception_others(filename):
+    if filename == "recursion_error" and platform.python_implementation() == "PyPy":
+        pytest.skip("RecursionError is not reliable on PyPy")
+
     compare_exception("others", filename)