Repository: saulpw/visidata

Issue:
[sheets] cursorDisplay for the sheet's own cursorDisplay crashes in Python 3.8.0 through 3.9.9
**Small description**
In SheetsSheet, viewing the cursorDisplay cell for the SheetsSheet leads to infinite recursion, which crashes on versions of Python >= 3.8.0 and <= 3.9.9

**Expected result**
The cursorDisplay should be blank or show a null.

**Actual result with screenshot**
```
Fatal Python error:
_Py_CheckRecursiveCall: Cannot recover from stack overflow.
Python runtime state: initialized

Current thread 0x00007f5f79c5fb80 (most recent call first):
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 308 in getValue
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/wrappers.py", line 108 in wrapply
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 327 in getCell
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 388 in getDisplayValue
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/sheets.py", line 453 in cursorDisplay
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 460 in getattrdeep
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 497 in <lambda>
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 270 in calcValue
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/column.py", line 308 in getValue
  File "/home/midichef/.pyenv/versions/3.9.9/lib/python3.9/site-packages/visidata/wrappers.py", line 108 in wrapply
...
```


**Steps to reproduce with sample data and a .vd**
Open the SheetsSheet and move to the cursorDisplay column, or run:
`vd -p cursordisplay.vdj`
[cursordisplay.vdj.txt](https://github.com/saulpw/visidata/files/10484256/cursordisplay.vdj.txt)



**Additional context**
saul.pw/VisiData v2.11

I tested the behavior in different versions of Python:
3.7:  no crashes in any version tested: 3.7.0, 3.7.4, 3.7.8, 3.7.12 or 3.7.16.
3.8:  crashes in all versions tested: 3.8.0, 3.8.4, 3.8.8, 3.8.10, 3.8.16
3.9:  crashes all minor versions from 3.9.0 through 3.9.9 (except 3.9.3 which I did not test), does not crash any from 3.9.10 through 3.9.16
3.10:  no crash in any version tested:  3.10.0, 3.10.9
3.11:  no crash in 3.11.0


Judging by the [Python 3.9.10 changelog](https://docs.python.org/release/3.9.10/whatsnew/changelog.html#changelog) the change in behavior for 3.9.10 is is likely related to [a Python bugfix allowing recovery from stack overflow](https://bugs.python.org/issue45806).

This bug will affect people running the 20.04 Ubuntu LTS release, where the default Python version is 3.8.10.


Discussion:
Thanks for your diligence on this, @midichef!  This is related to #1029, which we closed because we didn't have a solid repro.

To be honest, though, I'm not really sure what we should do about it.  I agree that VisiData shouldn't crash in this case, but what should we do to prevent it for Python versions 3.8 through 3.9.10?
Oh, I do see that it is the same issue as 1029.

What if we just prevent the recursive call in SheetsSheet for just that one cell? Something like https://github.com/saulpw/visidata/commit/ffdb8c0a44c8c889b3ad55f3f0b432749751c750
But I'm not sure what is the stylistically correct way to access the current cursor column and row. Should it be vd.sheet.cursorCol instead of r.cursorCol?
Well, the SheetsSheet is a cute demonstration of VisiData's architecture, but it's honestly not very useful, and often confusing for people.  We already have some hacks in there so that you can e.g. sort the sheets without moving away from the SheetsSheet (which is surprising), but I'd rather not add more hacks to it.  I think we can fix the whole SheetsSheet concept all around, so that it doesn't have a reference to itself on it.

>  what is the stylistically correct way to access the current cursor column and row

You have the right idea; better to use the local variables than `vd.sheet`, even if the result is the same.  But, beware that in Python, you should use `isinstance(r, SheetsSheet)` so that it catches subclasses; and also `c is r.cursorCol` and `r is r.cursorRow` to check for object identity, rather than equality (possibly the columns and rows could compare identically, without being the same exact object).
Does `sys.setrecursionlimit(500)` or similar have any effect?

Resolving patch:
diff --git a/visidata/column.py b/visidata/column.py
--- a/visidata/column.py
+++ b/visidata/column.py
@@ -451,6 +451,8 @@ def getattrdeep(obj, attr, *default, getter=getattr):
         try:  # if attribute exists, return toplevel value, even if dotted
             if attr in obj:
                 return getter(obj, attr)
+        except RecursionError:  #1696
+            raise
         except Exception as e:
             pass
 


Test patch: