135 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| ================================================================================
 | |
| py.code: higher level python code and introspection objects
 | |
| ================================================================================
 | |
| 
 | |
| The ``py.code`` part of the pylib 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 ``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"
 | |
| 
 |