
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 class py.code.Code(rawcode)

   wrapper around Python code objects

   path

      path of this code object

   fullsource

      full source containing this code object

   source()

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

   getargs(var=False)

      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 class py.code.Source(*parts, **kwargs)

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

   strip()

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

   putaround(before='', after='', indent='    ')

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

   indent(indent='    ')

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

   getstatement(lineno, assertion=False)

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

   getstatementrange(lineno, assertion=False)

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

   deindent(offset=None)

      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)

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

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

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

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

   Entry

      alias of "TracebackEntry"

   cut(path=None, lineno=None, firstlineno=None, excludepath=None)

      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> at 0x312d9b88>)

      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()

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

   recursionindex()

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

   append()

      L.append(object) -- append object to end

   count(value) -> integer -- return number of occurrences of value

   extend()

      L.extend(iterable) -- extend list by appending elements from the
      iterable

   index(value[, start[, stop]]) -> integer -- return first index of value.

      Raises ValueError if the value is not present.

   insert()

      L.insert(index, object) -- insert object before index

   pop([index]) -> item -- remove and return item at index (default last).

      Raises IndexError if list is empty or index is out of range.

   remove()

      L.remove(value) -- remove first occurrence of value. Raises
      ValueError if the value is not present.

   reverse()

      L.reverse() -- reverse *IN PLACE*

   sort()

      L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN
      PLACE*; cmp(x, y) -> -1, 0, 1


"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 class py.code.Frame(frame)

   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)

      evaluate 'code' in the frame

      'vars' are optional additional local variables

      returns the result of the evaluation

   exec_(code, **vars)

      exec 'code' in the frame

      'vars' are optiona; additional local variables

   repr(object)

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

   getargs(var=False)

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

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

   exconly(tryshort=False)

      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)

      return True if the exception is an instance of exc

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

      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.
