[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