[py-svn] r37674 - in py/trunk/py: code doc
guido at codespeak.net
guido at codespeak.net
Wed Jan 31 16:29:21 CET 2007
Author: guido
Date: Wed Jan 31 16:29:18 2007
New Revision: 37674
Added:
py/trunk/py/doc/code.txt
Modified:
py/trunk/py/code/code.py
py/trunk/py/code/excinfo.py
py/trunk/py/code/frame.py
py/trunk/py/code/traceback2.py
Log:
Added document 'code.txt' that describes py.code, added docstrings to py.code
public items.
Modified: py/trunk/py/code/code.py
==============================================================================
--- py/trunk/py/code/code.py (original)
+++ py/trunk/py/code/code.py Wed Jan 31 16:29:18 2007
@@ -1,6 +1,7 @@
import py
class Code(object):
+ """ wrapper around Python code objects """
def __init__(self, rawcode):
rawcode = getattr(rawcode, 'im_func', rawcode)
rawcode = getattr(rawcode, 'func_code', rawcode)
@@ -57,6 +58,7 @@
)
def path(self):
+ """ return a py.path.local object wrapping the source of the code """
try:
return self.raw.co_filename.__path__
except AttributeError:
@@ -64,6 +66,8 @@
path = property(path, None, None, "path of this code object")
def fullsource(self):
+ """ return a py.code.Source object for the full source file of the code
+ """
fn = self.raw.co_filename
try:
return fn.__source__
@@ -73,11 +77,16 @@
"full source containing this code object")
def source(self):
+ """ return a py.code.Source object for the code object's source only
+ """
# return source only for that part of code
import inspect
return py.code.Source(inspect.getsource(self.raw))
def getargs(self):
+ """ return a tuple with the argument names for the code object
+ """
# handfull shortcut for getting args
raw = self.raw
return raw.co_varnames[:raw.co_argcount]
+
Modified: py/trunk/py/code/excinfo.py
==============================================================================
--- py/trunk/py/code/excinfo.py (original)
+++ py/trunk/py/code/excinfo.py Wed Jan 31 16:29:18 2007
@@ -22,6 +22,13 @@
self.traceback = py.code.Traceback(tb)
def exconly(self, tryshort=False):
+ """ return the exception as a string
+
+ when 'tryshort' resolves to True, and the exception is a
+ py.magic.AssertionError, only the actual exception part of
+ the exception representation is returned (so 'AssertionError: ' is
+ removed from the beginning)
+ """
lines = py.std.traceback.format_exception_only(self.type, self.value)
text = ''.join(lines)
if text.endswith('\n'):
@@ -32,6 +39,7 @@
return text
def errisinstance(self, exc):
+ """ return True if the exception is an instance of exc """
return isinstance(self.value, exc)
def __str__(self):
Modified: py/trunk/py/code/frame.py
==============================================================================
--- py/trunk/py/code/frame.py (original)
+++ py/trunk/py/code/frame.py Wed Jan 31 16:29:18 2007
@@ -18,23 +18,38 @@
"statement this frame is at")
def eval(self, code, **vars):
+ """ evaluate 'code' in the frame
+
+ 'vars' are optional additional local variables
+
+ returns the result of the evaluation
+ """
f_locals = self.f_locals.copy()
f_locals.update(vars)
return eval(code, self.f_globals, f_locals)
def exec_(self, code, **vars):
+ """ exec 'code' in the frame
+
+ 'vars' are optiona; additional local variables
+ """
f_locals = self.f_locals.copy()
f_locals.update(vars)
exec code in self.f_globals, f_locals
def repr(self, object):
+ """ return a 'safe' (non-recursive, one-line) string repr for 'object'
+ """
return py.__.code.safe_repr._repr(object)
def is_true(self, object):
return object
def getargs(self):
+ """ return a list of tuples (name, value) for all arguments
+ """
retval = []
for arg in self.code.getargs():
retval.append((arg, self.f_locals[arg]))
return retval
+
Modified: py/trunk/py/code/traceback2.py
==============================================================================
--- py/trunk/py/code/traceback2.py (original)
+++ py/trunk/py/code/traceback2.py Wed Jan 31 16:29:18 2007
@@ -2,6 +2,8 @@
import py
class TracebackEntry(object):
+ """ a single entry in a traceback """
+
exprinfo = None
def __init__(self, rawentry):
@@ -14,6 +16,7 @@
return "<TracebackEntry %s:%d>" %(self.frame.code.path, self.lineno+1)
def statement(self):
+ """ return a py.code.Source object for the current statement """
source = self.frame.code.fullsource
return source.getstatement(self.lineno)
statement = property(statement, None, None,
@@ -63,6 +66,11 @@
source = property(getsource)
def ishidden(self):
+ """ return True if the current frame has a var __tracebackhide__
+ resolving to True
+
+ mostly for internal use
+ """
try:
return self.frame.eval("__tracebackhide__")
except (SystemExit, KeyboardInterrupt):
@@ -103,6 +111,15 @@
list.__init__(self, tb)
def cut(self, path=None, lineno=None, firstlineno=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)
+ """
for x in self:
if ((path is None or x.frame.code.path == path) and
(lineno is None or x.lineno == lineno) and
@@ -114,9 +131,18 @@
val = super(Traceback, self).__getitem__(key)
if isinstance(key, type(slice(0))):
val = self.__class__(val)
- return val
+ return val
def filter(self, fn=lambda x: not x.ishidden()):
+ """ 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)
+ """
return Traceback(filter(fn, self))
def getcrashentry(self):
@@ -129,6 +155,9 @@
return tb[-1]
def recursionindex(self):
+ """ return the index of the frame/TracebackItem where recursion
+ originates if appropriate, None if no recursion occurred
+ """
cache = {}
for i, entry in py.builtin.enumerate(self):
key = entry.frame.code.path, entry.lineno
@@ -155,3 +184,4 @@
co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2',
'?', 'eval')
+
Added: py/trunk/py/doc/code.txt
==============================================================================
--- (empty file)
+++ py/trunk/py/doc/code.txt Wed Jan 31 16:29:18 2007
@@ -0,0 +1,141 @@
+==============
+:api:`py.code`
+==============
+
+The :api:`py.code` part of the 'py lib' contains some functionality to help
+dealing with Python code objects. Even though working with Python's internal
+code objects (as found on frames and callables) can be very powerful, it's
+usually also quite cumbersome, because the API provided by core Python is
+relatively low level and not very accessible.
+
+The :api:`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.
+
+source: :source:`py/code/`
+
+Contents of the library
+=======================
+
+Every object in the :api:`py.code` library wraps a code Python object related
+to code objects, source code, frames and tracebacks: the :api:`py.code.Code`
+class wraps code objects, :api:`py.code.Source` source snippets,
+:api:`py.code.Traceback` exception tracebacks, :api:`py.code.Frame` frame
+objects (as found in e.g. tracebacks) and :api:`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
+:api:`py.code.compile()` that provides the same functionality as Python's
+built-in 'compile()' function, but returns a wrapped code object.
+
+The wrappers
+============
+
+:api:`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='rb'):"
+
+source: :source:`py/code/code.py`
+
+:api:`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"'
+
+source: :source:`py/code/source.py`
+
+:api:`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
+
+source: :source:`py/code/traceback2.py`
+
+:api:`py.code.Frame`
+--------------------
+
+Frame wrappers are used in :api:`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 :api:`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.local.LocalPath)
+ True
+ >>> [namevalue[0] for namevalue in frame.getargs()]
+ ['cls', 'path']
+
+:api:`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
+ 'exceptions.NameError'
+ >>> isinstance(excinfo.traceback, py.code.Traceback)
+ True
+ >>> excinfo.exconly()
+ "NameError: name 'foobar' is not defined"
+
More information about the pytest-commit
mailing list