py.code: higher level python code and introspection objects

py.code provides higher level APIs and objects for Code, Frame, Traceback, ExceptionInfo and source code construction. The py.code library tries to simplify accessing the code objects as well as creating them. There is a small set of interfaces a user needs to deal with, all nicely bundled together, and with a rich set of ‘Pythonic’ functionality.

Contents of the library

Every object in the py.code library wraps a code Python object related to code objects, source code, frames and tracebacks: the py.code.Code class wraps code objects, py.code.Source source snippets, py.code.Traceback` exception tracebacks, ``py.code.Frame frame objects (as found in e.g. tracebacks) and py.code.ExceptionInfo the tuple provided by sys.exc_info() (containing exception and traceback information when an exception occurs). Also in the library is a helper function py.code.compile() that provides the same functionality as Python’s built-in ‘compile()’ function, but returns a wrapped code object.

The wrappers

py.code.Code

Code objects are instantiated with a code object or a callable as argument, and provide functionality to compare themselves with other Code objects, get to the source file or its contents, create new Code objects from scratch, etc.

A quick example:

>>> import py
>>> c = py.code.Code(py.path.local.read)
>>> c.path.basename
'common.py'
>>> isinstance(c.source(), py.code.Source)
True
>>> str(c.source()).split('\n')[0]
"def read(self, mode='r'):"

py.code.Source

Source objects wrap snippets of Python source code, providing a simple yet powerful interface to read, deindent, slice, compare, compile and manipulate them, things that are not so easy in core Python.

Example:

>>> s = py.code.Source("""\
...   def foo():
...     print "foo"
... """)
>>> str(s).startswith('def') # automatic de-indentation!
True
>>> s.isparseable()
True
>>> sub = s.getstatement(1) # get the statement starting at line 1
>>> str(sub).strip() # XXX why is the strip() required?!?
'print "foo"'

py.code.Traceback

Tracebacks are usually not very easy to examine, you need to access certain somewhat hidden attributes of the traceback’s items (resulting in expressions such as ‘fname = tb.tb_next.tb_frame.f_code.co_filename’). The Traceback interface (and its TracebackItem children) tries to improve this.

Example:

>>> import sys
>>> try:
...   py.path.local(100) # illegal argument
... except:
...   exc, e, tb = sys.exc_info()
>>> t = py.code.Traceback(tb)
>>> first = t[1] # get the second entry (first is in this doc)
>>> first.path.basename # second is in py/path/local.py
'local.py'
>>> isinstance(first.statement, py.code.Source)
True
>>> str(first.statement).strip().startswith('raise ValueError')
True

py.code.Frame

Frame wrappers are used in py.code.Traceback items, and will usually not directly be instantiated. They provide some nice methods to evaluate code ‘inside’ the frame (using the frame’s local variables), get to the underlying code (frames have a code attribute that points to a py.code.Code object) and examine the arguments.

Example (using the ‘first’ TracebackItem instance created above):

>>> frame = first.frame
>>> isinstance(frame.code, py.code.Code)
True
>>> isinstance(frame.eval('self'), py.path.local)
True
>>> [namevalue[0] for namevalue in frame.getargs()]
['cls', 'path']

py.code.ExceptionInfo

A wrapper around the tuple returned by sys.exc_info() (will call sys.exc_info() itself if the tuple is not provided as an argument), provides some handy attributes to easily access the traceback and exception string.

Example:

>>> import sys
>>> try:
...   foobar()
... except:
...   excinfo = py.code.ExceptionInfo()
>>> excinfo.typename
'NameError'
>>> isinstance(excinfo.traceback, py.code.Traceback)
True
>>> excinfo.exconly()
"NameError: name 'foobar' is not defined"

Project Versions

Table Of Contents

Previous topic

py.path

Next topic

py.io

This Page