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'):"
class py.code.Code(rawcode)[source]

wrapper around Python code objects

path

return a path object pointing to source code (note that it might not point to an actually existing file).

fullsource

return a py.code.Source object for the full source file of the code

source()[source]

return a py.code.Source object for the code object’s source only

getargs(var=False)[source]

return a tuple with the argument names for the code object

if ‘var’ is set True also return the names of the variable and keyword arguments when present

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"'
class py.code.Source(*parts, **kwargs)[source]

a immutable object holding a source code fragment, possibly deindenting it.

strip()[source]

return new source object with trailing and leading blank lines removed.

putaround(before='', after='', indent=' ')[source]

return a copy of the source object with ‘before’ and ‘after’ wrapped around it.

indent(indent=' ')[source]

return a copy of the source object with all lines indented by the given indent-string.

getstatement(lineno, assertion=False)[source]

return Source statement which contains the given linenumber (counted from 0).

getstatementrange(lineno, assertion=False)[source]

return (start, end) tuple which spans the minimal statement region which containing the given lineno.

deindent(offset=None)[source]

return a new source object deindented by offset. If offset is None then guess an indentation offset from the first non-blank line. Subsequent lines which have a lower indentation offset will be copied verbatim as they are assumed to be part of multilines.

isparseable(deindent=True)[source]

return True if source is parseable, heuristically deindenting it by default.

compile(filename=None, mode='exec', flag=0, dont_inherit=0, _genframe=None)[source]

return compiled code object. if filename is None invent an artificial filename which displays the source/line position of the caller frame.

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
class py.code.Traceback(tb)[source]

Traceback objects encapsulate and offer higher level access to Traceback entries.

Entry

alias of TracebackEntry

cut(path=None, lineno=None, firstlineno=None, excludepath=None)[source]

return a Traceback instance wrapping part of this Traceback

by provding any combination of path, lineno and firstlineno, the first frame to start the to-be-returned traceback is determined

this allows cutting the first part of a Traceback instance e.g. for formatting reasons (removing some uninteresting bits that deal with handling of the exception/traceback)

filter(fn=<function <lambda>>)[source]

return a Traceback instance with certain items removed

fn is a function that gets a single argument, a TracebackItem instance, and should return True when the item should be added to the Traceback, False when not

by default this removes all the TracebackItems which are hidden (see ishidden() above)

getcrashentry()[source]

return last non-hidden traceback entry that lead to the exception of a traceback.

recursionindex()[source]

return the index of the frame/TracebackItem where recursion originates if appropriate, None if no recursion occurred

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']
class py.code.Frame(frame)[source]

Wrapper around a Python frame holding f_locals and f_globals in which expressions can be evaluated.

statement

statement this frame is at

eval(code, **vars)[source]

evaluate ‘code’ in the frame

‘vars’ are optional additional local variables

returns the result of the evaluation

exec_(code, **vars)[source]

exec ‘code’ in the frame

‘vars’ are optiona; additional local variables

repr(object)[source]

return a ‘safe’ (non-recursive, one-line) string repr for ‘object’

getargs(var=False)[source]

return a list of tuples (name, value) for all arguments

if ‘var’ is set True also include the variable and keyword arguments when present

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"
class py.code.ExceptionInfo(tup=None, exprinfo=None)[source]

wraps sys.exc_info() objects and offers help for navigating the traceback.

type = None

the exception class

value = None

the exception instance

tb = None

the exception raw traceback

typename = None

the exception type name

traceback = None

the exception traceback (py.code.Traceback instance)

exconly(tryshort=False)[source]

return the exception as a string

when ‘tryshort’ resolves to True, and the exception is a py.code._AssertionError, only the actual exception part of the exception representation is returned (so ‘AssertionError: ‘ is removed from the beginning)

errisinstance(exc)[source]

return True if the exception is an instance of exc

getrepr(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=False)[source]

return str()able representation of this exception info. showlocals: show locals per traceback entry style: long|short|no|native traceback style tbfilter: hide entries (where __tracebackhide__ is true)

in case of style==native, tbfilter and showlocals is ignored.

class py.code.Traceback(tb)[source]

Traceback objects encapsulate and offer higher level access to Traceback entries.

Entry

alias of TracebackEntry

cut(path=None, lineno=None, firstlineno=None, excludepath=None)[source]

return a Traceback instance wrapping part of this Traceback

by provding any combination of path, lineno and firstlineno, the first frame to start the to-be-returned traceback is determined

this allows cutting the first part of a Traceback instance e.g. for formatting reasons (removing some uninteresting bits that deal with handling of the exception/traceback)

filter(fn=<function <lambda>>)[source]

return a Traceback instance with certain items removed

fn is a function that gets a single argument, a TracebackItem instance, and should return True when the item should be added to the Traceback, False when not

by default this removes all the TracebackItems which are hidden (see ishidden() above)

getcrashentry()[source]

return last non-hidden traceback entry that lead to the exception of a traceback.

recursionindex()[source]

return the index of the frame/TracebackItem where recursion originates if appropriate, None if no recursion occurred