Mailing List Archive

Controlling Python
Hi all,

in my application (written in C++) I want to use Python as the
scripting language. The application comunicates with the hardware and
when a specific event occurres, a thread is started, in which a python
interpreter is created to execute a certain script. The thread should
have a finer control over the Python-Interpreter as is possible with
PyRun_SimpleFile().
(E.g. I want to be able to stop the thread independent of the
interpreter) I would like to have some kind of "hook" after, say, every
line of python-code.
I thought something like (pseudocode):
while(getline(f, s) {
PyRun_SimpleString(s);
my_hook(s, lineno++,...);
}
should work but it fails, whenever the python-code becomes a little
more difficult. E.g. PyRunSimpleString() failes, whenever the simple
string continues in the following line:
if bla:
pass

Is this the way to go? If yes: how? If no: why not and in which
direction should I turn?

Any hints are most welcom.

TIA

Norbert Riedlin


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
Controlling Python [ In reply to ]
nriedlin@my-deja.com wrote:
>
> Hi all,
>
> in my application (written in C++) I want to use Python as the
> scripting language. The application comunicates with the hardware and
> when a specific event occurres, a thread is started, in which a python
> interpreter is created to execute a certain script. The thread should
> have a finer control over the Python-Interpreter as is possible with
> PyRun_SimpleFile().
> (E.g. I want to be able to stop the thread independent of the
> interpreter) I would like to have some kind of "hook" after, say, every
> line of python-code.
> I thought something like (pseudocode):
> while(getline(f, s) {
> PyRun_SimpleString(s);
> my_hook(s, lineno++,...);
> }
> should work but it fails, whenever the python-code becomes a little
> more difficult. E.g. PyRunSimpleString() failes, whenever the simple
> string continues in the following line:
> if bla:
> pass
>
> Is this the way to go? If yes: how? If no: why not and in which
> direction should I turn?

You can use a callback which you can register with the
sys.settrace() function. A less fine-grained hook is available
through sys.setprofile(). See the docs for more infos.

--
Marc-Andre Lemburg
______________________________________________________________________
Y2000: 138 days left
Business: http://www.lemburg.com/
Python Pages: http://www.lemburg.com/python/
Controlling Python [ In reply to ]
> You can use a callback which you can register with the
> sys.settrace() function. A less fine-grained hook is available
> through sys.setprofile(). See the docs for more infos.
>

You are correct, but isn't it true, that the callback is only called
every function call? I would like to interfere every line (and so being
able to trace my scripts). Please correct me if I'm wrong.

TIA

Norbert Riedlin


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
Controlling Python [ In reply to ]
nriedlin@my-deja.com wrote:
>
> > You can use a callback which you can register with the
> > sys.settrace() function. A less fine-grained hook is available
> > through sys.setprofile(). See the docs for more infos.
> >
>
> You are correct, but isn't it true, that the callback is only called
> every function call? I would like to interfere every line (and so being
> able to trace my scripts). Please correct me if I'm wrong.

Please read the docs or simply try the hints I gave you...
sys.settrace() is what you want, BTW.

--
Marc-Andre Lemburg
______________________________________________________________________
Y2000: 135 days left
Business: http://www.lemburg.com/
Python Pages: http://www.lemburg.com/python/
Controlling Python [ In reply to ]
nriedlin@my-deja.com wrote:

:> You can use a callback which you can register with the
:> sys.settrace() function. A less fine-grained hook is available
:> through sys.setprofile(). See the docs for more infos.
:>

: You are correct, but isn't it true, that the callback is only called
: every function call? I would like to interfere every line (and so being
: able to trace my scripts). Please correct me if I'm wrong.

: TIA

The settrace callback is envoked under four events: call, line, return,
and exception. Below is a subsystem I wrote to help debugging. Note that
there is a known "bug" in that call events do not return the arguments as
documented.

For more info, read:
Python 1.5.2 Library Reference Manual 9.2 "How It Works"
http://www.python.org/doc/current/lib/node201.html

-Arcege

#!/usr/local/bin/python

import sys, traceback
import linecache

class Tracer:
output = sys.stderr
linecache = {}
indent_value = 0

def __init__(self, file=None):
if file is None:
pass
elif type(file) is type(''):
self.output = open(file, 'w')
else:
self.output = file

def write(self, *args):
apply(self.output.write, args)
self.output.flush()

def load_file(self, filename):
if not self.linecache.has_key(filename):
try:
self.linecache[filename] = open(filename).readlines()
except:
self.linecache[filename] = []
def lineno(self, filename, line):
return linecache.getline(filename, line)
self.load_file(filename)
if line < len(self.linecache[filename]):
return self.linecache[filename][line]
return None

def indent(self):
self.indent_value = self.indent_value + 1
def outdent(self):
self.indent_value = self.indent_value - 1
def output_indent(self):
self.write(' ' * self.indent_value)

def __call__(self, frame, event, arg):
method_name = 'type_%s' % event
getattr(self, method_name)(frame, arg)
return self

def type_call(self, frame, arg):
self.output_indent()
self.indent()
self.write('Function call: %s' % frame.f_code.co_name)
self.write('(')
l = arg and len(arg) or 0
for i in range(l):
self.write(repr(arg))
if i < l-1:
self.write(', ')
self.write(')')
self.write('\n')
return self

def type_line(self, frame, arg):
code = frame.f_code
file = code.co_filename
line = frame.f_lineno
self.output_indent()
self.write('Line number %d in %s (%s)\n ->%s' %
(line, file, code.co_name, self.lineno(file, line)))
return self

def type_return(self, frame, arg):
self.outdent()
self.output_indent()
self.write('Function %s returning %s\n' %
(frame.f_code.co_name, repr(arg)))

def type_exception(self, frame, arg):
code = frame.f_code
funcname = code.co_name
exc, value, traceback = arg
t = type(exc)
if t is type(''):
name = exc
elif t is type(self):
name = exc.__class__.__name__
elif t is type(self.__class__):
name = exc.__name__
else:
name = repr(exc)
self.output_indent()
self.write('Exception %s raised in %s\n' % (name, funcname))
self.outdent()
return self.inside_exception

def inside_exception(self, frame, event, arg):
self.write('Exception: %s\n' % event)
return self.inside_exception

def settrace(tracer):
# Start debugging from here
try:
raise SystemError
except:
if hasattr(sys, 'exc_info'):
frame = sys.exc_info()[2].tb_frame.f_back
else:
frame = sys.exc_traceback.tb_frame.f_back
while frame:
frame.f_trace = tracer
frame = frame.f_back
sys.settrace(tracer)

def unsettrace():
settrace(None)

class _Num:
def __init__(self, value=None):
if value is None:
self.value = self.start
else:
self.value = value
def __str__(self):
return str(self.value)

class _Sigma(_Num):
start = 0
def __add__(self, other):
self.value = self.value + other
return self

class _Pi(_Num):
start = long(1)
def __mul__(self, other):
self.value = self.value * other
return self

def _test(count):
sum = _Sigma(); aggr = _Pi()
for i in xrange(count):
j = i + 1
sum = sum + j
aggr = aggr * j
print 'Sigma(%d)' % count, sum
print 'Pi(%d)' % count, aggr

if __name__ == '__main__':
tracer = Tracer()
settrace(tracer)
_test(100)