I spent most of this weekend working on the `script: report missing docstrings in Leo itself` script in scripts.leo. You can open scripts.leo with <Alt-x>leo-sc<tab><return>.
This was going to be the basis of a new find-missing-docstrings command. That won't happen, as I'll now explain. This is an Engineering Notebook post, full of geeky details. Feel free to ignore.
g.getRepresentativeLiveObjects
This new function is the highlight of the prototype. It's in devel, and it's going to stay. Here it is:
def getRepresentativeLiveObjects():
'''
Return a dict. Keys classes.
Values are the first (representative) live object for each type.
'''
d = {} # Keys are types, values are the *first* instance.
for obj in gc.get_objects():
t = type(obj)
if t not in d and hasattr(obj, '__class__'):
d [t] = obj
return d
This function is astoundingly fast. g.get_objects returns all the live objects in Leo. Nevertheless, this function runs in about 1/20 sec on my machine. This was the happy surprise of the prototype.
The plan
I thought to myself. Gee. It's really easy to get a representative live object for any (instantiated) class in Leo. Why not use that live object to detect missing docstrings? Well, the "report missing docstrings" script does that. As shown in
#1187, its output is:
7 missing docstrings in AbbrevCommandsClass
1 missing docstring in AtButtonCallback
30 missing docstrings in AtFile
19 missing docstrings in AutoCompleterClass
2 missing docstrings in BindingInfo
6 missing docstrings in Bunch
2 missing docstrings in Chapter
10 missing docstrings in ChapterController
3 missing docstrings in CommanderCacher
2 missing docstrings in CommanderWrapper
113 missing docstrings in Commands
4 missing docstrings in ControlCommandsClass
3 missing docstrings in ConvertCommandsClass
3 missing docstrings in DebugCommandsClass
2 missing docstrings in DefaultDict
5 missing docstrings in DefaultWrapper
28 missing docstrings in DynamicWindow
39 missing docstrings in EditCommandsClass
11 missing docstrings in EditFileCommandsClass
7 missing docstrings in EvalController
3 missing docstrings in EventWrapper
3 missing docstrings in FastRead
39 missing docstrings in FileCommands
7 missing docstrings in FindTabManager
4 missing docstrings in FreeLayoutController
1 missing docstring in GeneralSetting
1 missing docstring in GetArg
1 missing docstring in GlobalCacher
4 missing docstrings in GlobalConfigManager
1 missing docstring in GoToCommands
6 missing docstrings in HelpCommandsClass
37 missing docstrings in JEditColorizer
49 missing docstrings in KeyHandlerClass
3 missing docstrings in KeyHandlerCommandsClass
9 missing docstrings in KeyStroke
6 missing docstrings in KillBufferCommandsClass
1 missing docstring in KillBufferIterClass
13 missing docstrings in LeoApp
52 missing docstrings in LeoFind
49 missing docstrings in LeoImportCommands
1 missing docstring in LeoKeyEvent
11 missing docstrings in LeoPluginsController
1 missing docstring in LeoQComboBox
3 missing docstrings in LeoQTextBrowser
7 missing docstrings in LeoQTreeWidget
19 missing docstrings in LeoQtBody
3 missing docstrings in LeoQtEventFilter
68 missing docstrings in LeoQtFrame
23 missing docstrings in LeoQtGui
17 missing docstrings in LeoQtLog
27 missing docstrings in LeoQtMenu
1 missing docstring in LeoQtSpellTab
50 missing docstrings in LeoQtTree
1 missing docstring in LeoQtTreeTab
2 missing docstrings in LeoTabbedTopLevel
28 missing docstrings in LoadManager
2 missing docstrings in LocalConfigManager
23 missing docstrings in NullBody
1 missing docstring in NullColorizer
64 missing docstrings in NullFrame
38 missing docstrings in NullGui
10 missing docstrings in NullIconBarClass
22 missing docstrings in NullLog
40 missing docstrings in NullMenu
15 missing docstrings in NullTree
1 missing docstring in PersistenceDataController
97 missing docstrings in Position
1 missing docstring in PrintingController
13 missing docstrings in Py_Importer
10 missing docstrings in QMinibufferWrapper
10 missing docstrings in QTextEditWrapper
6 missing docstrings in QtIconBarClass
31 missing docstrings in QtMenuWrapper
7 missing docstrings in QtStatusLineClass
1 missing docstring in QtTabBarWrapper
6 missing docstrings in RecentFilesManager
4 missing docstrings in RectangleCommandsClass
6 missing docstrings in RedirectClass
12 missing docstrings in RstCommands
2 missing docstrings in ScriptingController
9 missing docstrings in SearchWidget
6 missing docstrings in ShadowController
3 missing docstrings in SpellCommandsClass
1 missing docstring in SpellTabHandler
7 missing docstrings in SqlitePickleShare
12 missing docstrings in StringTextWrapper
1 missing docstring in StyleSheetManager
7 missing docstrings in TabbedFrameFactory
61 missing docstrings in TangleCommands
26 missing docstrings in TestManager
13 missing docstrings in TypedDict
14 missing docstrings in TypedDictOfLists
70 missing docstrings in Undoer
73 missing docstrings in VNode
17 missing docstrings in VimCommands
4 missing docstrings in VisLineEdit
1 missing docstring in leoIconBarButton
129 leo classes. methods 4370, w/o docstrings 1595 in 0.10 sec
Note the time: 1/10 second!
report-missing-docstrings is doomed
I thought it would be straightforward, if a bit tricky, to use the representative live objects to create clickable links to the offending routines. But no. The task is impossible, for two fundamental reasons:
1. The code runs within Leo, so it can only report problems in Leo's own code. There is no way to "recreate" the desired program under test from a Leo outline!
End of story! We aren't going to do AI to discover apps, and no way would we want to run those apps. It would be so naive and dangerous.
In contrast, pylint takes uses the AST: it doesn't actually run anything. A huge difference.
2. Lives objects are useful, because we can use python's inspect module to get data on them. The script does this. Alas, inspect knows nothing of Leo's outlines, positions, nodes, etc. And even Leo can't recreate that data with any reasonable amount of work. Yes, one could imagine heroic measures, but problem one isn't going away, so it's useless to solve problem two.
Looking back, the code was destined to drown, not in an inch of water, but more like 20 feet :-)
Summary
I spent almost two days on this script. I think the time was well worth the effort. The prototype was useful because it:
- failed quickly,
- it showed why my original plan was hopeless,
- it produced g.getRepresentativeLiveObjects.
We'll end up revisiting similar issues when integrating pyzo's Shell into Leo.
Edward