On Monday, March 24, 2014 11:37:05 AM UTC-5, Edward K. Ream wrote:

> I am using the g.SherlockTracing class to do the executing.  This is, in 
essence, and alternate version of pdb, with many cool features.

The present Sherlock code only handles Python calls and returns, but 
Python's sys.settrace mechanism allows the trapping of *any* kind of Python 
statement.  sys.settrace is a great window into the workings of Python 
interp--I am surprised that only a few interesting applications have been 
developed. 

sys.setttrace allows the execution of *any* code whatever, not just 
pdb-like code.  Rather than stopping, which is *way* too slow, Sherlock 
runs something like full machine speed (say 10x slower).  Rather than 
relying on human data-gathering capabilities, which is *way* too limited, 
Sherlock allows data gathering driving by computer code.  By manipulating 
the present (and future) Sherlock args, the human can do what we do best, 
which is find patterns and meaning.

There are several extensions to the Sherlock idea I would like to explore:

1. Simulating backward execution.

The idea is simple:  store Sherlock traces in a list instead of printing 
them immediately.  Then, when something "interesting" happens, say the use 
of an object at **a particular** address/id, filter the list so that only 
traces pertaining to that id are shown.  This allows "backward" filtering.  
If we simply reverse the list before printing it we show the execution "in 
reverse".

2. Tracing the flow of data rather than (or in addition to) tracing 
execution flow.

Again, the idea is simple: save lists or dicts of information about objects 
and show/filter them to make them maximally convenient to understand.

Points 1 and 2 above are intimately related, and I'll be exploring various 
combinations of them soon.  

This will be driven by real exploration of pylint. Here is the test code I 
am presently using to explore how pylint works::

    # Test this file by running pylint --tt
    class aClass:
        def __init__ (self):
            self.a = 2
            self.b()
        def b(self):
            return self.a.c

We expect pylint to give an error.

Here is the output of pylint --tt.  Note that most of the opening lines 
were produced by print statements within Sherlock or pylint-leo.py or 
pylint itself, not by the enabled Sherlock patterns::

<module 'pylint.lint' from 
'c:\python26\lib\site-packages\pylint-0.25.1-py2.6.egg\pylint\lint.pyc'>
pylint-leo.py: c:\leo.repo\static-type-checking\test\pylint\pylint_test.py
pylint-leo.py: enabling Sherlock traces
patterns contained in plyint-leo.py
Sherlock patterns:
+PyLinter::add_message
+:.*typecheck.py
typecheck.py        .....+<module>()
typecheck.py        ......+TypeChecker()
typecheck.py        ......-TypeChecker -> dict
typecheck.py        .....-<module>
typecheck.py        .....+register(linter=<pylint.lint.PyLinter object at 
0x02AA5EF0>)
typecheck.py        .....-register
typecheck.py        ...+TypeChecker::open()
typecheck.py        ...-TypeChecker::open
utils.py            
........+PyLinter::add_message(msgid='C0111',node=<Module(pylint_test)>)
utils.py            ........-PyLinter::add_message
utils.py            
.........+PyLinter::add_message(msgid='C0111',node=<Class(aClass)>)
utils.py            .........-PyLinter::add_message
typecheck.py        ........+TypeChecker::visit_assign(node=<Assign>)
typecheck.py        ........-TypeChecker::visit_assign
typecheck.py        .........+TypeChecker::visit_assattr(node=<AssAttr(a)>)
typecheck.py        .........-TypeChecker::visit_assattr
typecheck.py        .........+TypeChecker::visit_callfunc(node=<CallFunc>)
typecheck.py        .........-TypeChecker::visit_callfunc
typecheck.py        ..........+TypeChecker::visit_getattr(node=<Getattr(b)>)
typecheck.py        ..........-TypeChecker::visit_getattr
utils.py            
..........+PyLinter::add_message(msgid='C0111',node=<Function(b)>)
utils.py            ..........-PyLinter::add_message
typecheck.py        .........+TypeChecker::visit_getattr(node=<Getattr(c)>)
utils.py            
...........+PyLinter::add_message(msgid='E1101',node=<Getattr(c)>,args=['Instance
 
of','int','c'])
************* Module pylint_test
E1101:  9,0:aClass.b: Instance of 'int' has no 'c' member
utils.py            ...........-PyLinter::add_message
typecheck.py        .........-TypeChecker::visit_getattr
typecheck.py        ..........+TypeChecker::visit_getattr(node=<Getattr(a)>)
typecheck.py        ..........-TypeChecker::visit_getattr
EKR: time: 0.12 sec, exit status: 2

Note 1: The following lines are the actual pylint error message:

************* Module pylint_test
E1101:  9,0:aClass.b: Instance of 'int' has no 'c' member

Note 2: The data part of this trace is produced by one of pylint's __repr__ 
methods, modified by me to make them more readable.  For example, the 
<Getattr(a)> in::

TypeChecker::visit_getattr(node=<Getattr(a)>

Otoh, Sherlock produces everything else, including the list of arguments to 
visit_getattr.  (Sherlock discovers that "node" is the name of the formal 
argument). It's a nifty division of responsibilities.

I ran the test above (with many different traces) to answer two question:

1. How the actual message gets printed (answer PyLinter.add_message)

2. The order in which nodes of the ast (abstract syntax tree) are visited 
in order to check the tree.  The answer: the order shown by the various 
visit_ methods.

An unanswered question: why aren't visit_ClassDef and visit_FunctionDef 
called?  Something truly clever is going on.

The part that isn't shown by this trace is the entire "inference" 
machinery.  I'll be exploring that next.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to leo-editor+unsubscr...@googlegroups.com.
To post to this group, send email to leo-editor@googlegroups.com.
Visit this group at http://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to