Leo should call the checkers (the
g.check* functions in leoGlobals.py) based on the
apparent, static context of each checked argument. In most cases, the argument's
name gives apparent context. As an exception, the StringTextWrapper
annotation means (at present, it's merely a temporary stand-in) that the argument should have an annotation indicating one of the wrapper classes that comprise the high-level text interface. Let's look at some examples.
First, the checkers in Leo's core should be distinct from the checkers in Leo's qt gui files. Why? Because those checkers have separate static environments.
An argument's name usually suffices to indicate context, so,
regardless of the initial annotation, an arg called
frame or
parentFrame should be checked with
g.checkFrame (in Leo's core) or
g.checkQtFrame (in any Qt-related plugin).
As I said, StringTextWrapper is a special case. It should be checked with
g.checkText (in Leo's core) or
g.checkQtText (in any Qt-related plugin). In other words, we provisionally trust that StringTextWrapper is a stand-in for an arg that conforms to Leo's high-level text interface. However, the reports from these two text checkers may show that we need to call another (possibly new) checker.
Do you see why this scheme is clever? We know,
from the static context alone, what checker to call! We don't need to know beforehand what the correct annotation should be! This scheme cuts the Gordian knot of type inference by unifying static and dynamic inference.
This scheme is resilient and flexible. We can add new checkers if necessary. It's trivial to change our minds about what the ground truth of annotated objects should be.
The virtual user will be my guide
A previous ENB discussed running a virtual user in a unit test running in the Qt gui. The goals of this unit test will be:
- To call each instance of each g.checker method throughout Leo's code base.
The test should fail otherwise.
- At first, to report the cumulative set of classes that each individual checker receives.
- Eventually, to verify that each individual checker receives objects of all and only classes of the expected kinds.
In this way, the unit test will guide both the annotations and the definitions of checkers.
Summary
The PR should insert calls to g.checkers based on the apparent context of arguments. The args name usually provides the context, but the StringTextWrapper annotation is an exception.
The virtual user, running in a Qt-based unit test, will suggest improvements to checkers and annotations.
For now, this scheme applies only to Leo. Eventually, I might try to generalize it to other Python programs, but that's a distant possibility.
I welcome all comments, questions, and suggestions.
Edward