dis.dis question

Ron Adam rrr at ronadam.com
Sun Oct 16 11:33:49 CEST 2005


Bengt Richter wrote:
> On Sun, 09 Oct 2005 12:10:46 GMT, Ron Adam <rrr at ronadam.com> wrote:

>>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 SOCapture:
>  ...     """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.


>  >>> diss(foo)
>  '  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'
>  >>> print diss(foo)
>    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






More information about the Python-list mailing list