dis.dis question

R

Ron Adam

Can anyone show me an example of of using dis() with a traceback?

Examples of using disassemble_string() and distb() separately if
possible would be nice also.


I'm experimenting with modifying the dis module so that it returns it's
results instead of using 'print' it as it goes. I want to make sure it
works for all the current use cases (or as many as possible), but I
haven't been able to find any examples of using dis with tracebacks
using google. I keep getting various copies of the current and older
Python doc pages when I search, and not much else.

How much other python code depends on the dis() and disassembly()
functions? Is it used by other modules or is it meant to be a stand
alone tool?

The changes I've made (for my own use so far) is to have disassembly()
return a bare unformatted table, (list of list), that can easily be
examined with python, and then to use a dis2str() function to return a
nice formatted output-string from the table. In order to have dis()
display properly in an interactive shell as well as printing, I have
dis() return a disassembly list object with a __repr__() method to call
dis2str().

class disobj(list):
""" A disassembly list object """
def __init__(self, dislist, name=None, lasti=-1):
self[:] = dislist
self.name = name
self.lasti = lasti
def __repr__(self):
return dis2str(self, self.name, self.lasti)

That seems to work well in both the shell and with 'print'. And it
still allows direct table introspection without having to parse the
output. ;-)

For example the get_labels() function used was reduced to ...

def getlabels(dislist):
""" Get labels from disassembly list table. """
return [x[4] for x in dislist if type(x[4]) is str]

Another benefit, is to be able to get the results without having to
redirect, capture, and then reset sys.stdout.

But I still need to rewrite disassemble_string() and need to test it
with tracebacks.

Cheers,
Ron
 
R

Ron Adam

Ron said:
Can anyone show me an example of of using dis() with a traceback?

Examples of using disassemble_string() and distb() separately if
possible would be nice also.

[cliped]
But I still need to rewrite disassemble_string() and need to test it
with tracebacks.

Cheers,
Ron

It seems I've found a bug in dis.py, or maybe a expected non feature.
When running dis from a program it fails to find the last traceback
because sys.last_traceback doesn't get set. (a bug in sys?) It works
ok from the shell, but not from the program.

Changing it to to get sys.exc_info()[2], fix's it in a program, but then
it doesn't work in the shell. So I replaced it with the following which
works in both.

try:
if hasattr(sys,'last_traceback'):
tb = sys.last_traceback
else:
tb = sys.exc_info()[2]
except AttributeError:
raise RuntimeError, "no last traceback to disassemble"

I'm still looking for info on how to use disassemble_string().

Cheers,
Ron
 
B

Bengt Richter

Ron said:
Can anyone show me an example of of using dis() with a traceback?

Examples of using disassemble_string() and distb() separately if
possible would be nice also.
[cliped]

But I still need to rewrite disassemble_string() and need to test it
with tracebacks.

Cheers,
Ron

It seems I've found a bug in dis.py, or maybe a expected non feature.
When running dis from a program it fails to find the last traceback
because sys.last_traceback doesn't get set. (a bug in sys?) It works
ok from the shell, but not from the program.

Changing it to to get sys.exc_info()[2], fix's it in a program, but then
it doesn't work in the shell. So I replaced it with the following which
works in both.

try:
if hasattr(sys,'last_traceback'):
tb = sys.last_traceback
else:
tb = sys.exc_info()[2]
except AttributeError:
raise RuntimeError, "no last traceback to disassemble"

I'm still looking for info on how to use disassemble_string().

One way to get dis output without modufying dis is to capture stdout:
(ancient thing I cobbled together, no guarantees ;-)
... """class to capture stdout between calls to start & end methods, q.v."""
... import sys
... def __init__(self):
... self.so = self.sys.stdout
... self.text = []
... def start(self, starttext=None):
... """Overrides sys.stdout to capture writes.
... Optional starttext is immediately appended as if written to stdout."""
... self.sys.stdout = self
... if starttext is None: return
... self.text.append(starttext)
... def end(self, endtext=None):
... """Restores stdout to value seen at contruction time.
... Optional endtext is appended as if written to stdout before that."""
... self.sys.stdout = self.so
... if endtext is None: return
... self.text.append(endtext)
... def gettext(self):
... """Returns captured text as single string."""
... return ''.join(self.text)
... def clear(self):
... """Clears captured text list."""
... self.text = []
... def write(self, s):
... """Appends written string to captured text list.
... This method is what allows an instance to stand in for stdout."""
... self.text.append(s)
... 1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 LOAD_CONST 2 (2)
10 BINARY_POWER
11 RETURN_VALUE

Or safer:
... try:
... so = SOCapture()
... so.start()
... dis.dis(code)
... finally:
... so.end()
... return so.gettext()
... ' 1 0 LOAD_FAST 0 (x)\n 3 LOAD_CONST 1 (1)\
n 6 BINARY_ADD \n 7 LOAD_CONST 2 (2)\n
10 BINARY_POWER \n 11 RETURN_VALUE \n' 1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 LOAD_CONST 2 (2)
10 BINARY_POWER
11 RETURN_VALUE


Regards,
Bengt Richter
 
S

skip

How about this?
... print "hello world"
... 0 LOAD_CONST 1 (1)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (0)
8 RETURN_VALUE

Skip
 
R

Ron Adam

Bengt said:
Ron Adam wrote:
It seems I've found a bug in dis.py, or maybe a expected non feature.
When running dis from a program it fails to find the last traceback
because sys.last_traceback doesn't get set. (a bug in sys?) It works
ok from the shell, but not from the program.

Changing it to to get sys.exc_info()[2], fix's it in a program, but then
it doesn't work in the shell. So I replaced it with the following which
works in both.

try:
if hasattr(sys,'last_traceback'):
tb = sys.last_traceback
else:
tb = sys.exc_info()[2]
except AttributeError:
raise RuntimeError, "no last traceback to disassemble"

I guess I should do a bug report on this part so you can do the
following in a program.

try:
(something that fails)
except:
dis.dis() # print a dissasembled traceback.

I'm still looking for info on how to use disassemble_string().


One way to get dis output without modufying dis is to capture stdout:
(ancient thing I cobbled together, no guarantees ;-)
... """class to capture stdout between calls to start & end methods, q.v."""
... import sys
... def __init__(self):
... self.so = self.sys.stdout
... self.text = []
... def start(self, starttext=None):
... """Overrides sys.stdout to capture writes.
... Optional starttext is immediately appended as if written to stdout."""
... self.sys.stdout = self
... if starttext is None: return
... self.text.append(starttext)
... def end(self, endtext=None):
... """Restores stdout to value seen at contruction time.
... Optional endtext is appended as if written to stdout before that."""
... self.sys.stdout = self.so
... if endtext is None: return
... self.text.append(endtext)
... def gettext(self):
... """Returns captured text as single string."""
... return ''.join(self.text)
... def clear(self):
... """Clears captured text list."""
... self.text = []
... def write(self, s):
... """Appends written string to captured text list.
... This method is what allows an instance to stand in for stdout."""
... self.text.append(s)

This is useful. But I've already rewritten it. ;-)

I tried to keep it's output as close to the original as possible. For
example replacing the the call "dis.dis(func)" in test_dis.py with
"print dis.dis(func)" is all that's needed to get it to pass the test.

s = StringIO.StringIO()
save_stdout = sys.stdout
sys.stdout = s
dis.dis(func) #<- "print dis.dis(func)" passes
sys.stdout = save_stdout
got = s.getvalue()

The above could be replaced with...

got = dis.dis(func)

The same minor change needs to be made in test_peepholer.py. It uses
dis to check the bytecodes. I havn't found any other dependancies yet.

' 1 0 LOAD_FAST 0 (x)\n 3 LOAD_CONST 1 (1)\
n 6 BINARY_ADD \n 7 LOAD_CONST 2 (2)\n
10 BINARY_POWER \n 11 RETURN_VALUE \n'
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 LOAD_CONST 2 (2)
10 BINARY_POWER
11 RETURN_VALUE

This is something I fixed (or added) so it displays the same from print,
the terminal, and the command line.

I'm not sure if it can replace dis module. It may be different enough
that it can't. I suspect some might not like the table class. I'm
thinking of making a bug report for the traceback not being found when
distb() is used inline, and attach the altered file for consideration
and feedback.

One possibility is to dispense with keeping it like dis and rename it to
something different and then additional functions and capabilities can
be added to it without worrying about breaking anything. ;-)

BTW do you know how to read the time and version stamp of the beginning
of .pyo and .pyc files? I added that (just too easy not to) and would
like to put the time and version stamp at the top of the output for
those. It's easy to take stuff out if needed. ;-)

I can send it to you as an attached file if you'd like to take a look.

Cheers,
Ron
 
R

Ron Adam

How about this?

... print "hello world"
...
0 LOAD_CONST 1 (1)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (0)
8 RETURN_VALUE

Skip

Thanks Skip, I had figured it out, but I like your example.
0 LOAD_CONST 1 (1)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (0)
8 RETURN_VALUE

It works! :)

Cheers,
Ron
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Python battle game help 2
Oddity using sorted with key 6
Issues with writing pytest 0
Pythen question 0
Question about weakref 0
Finding the variables (read or write) 4
Method chaining 16
Math python question 10

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top