args attribute of Exception objects

Bengt Richter bokr at oz.net
Mon Apr 11 18:20:31 EDT 2005


On 11 Apr 2005 03:31:23 -0700, sdementen at hotmail.com (Sebastien de Menten) wrote:

>Jeremy Bowers <jerf at jerf.org> wrote in message news:<pan.2005.04.08.16.07.30.85408 at jerf.org>...
>> On Fri, 08 Apr 2005 09:32:37 +0000, Sébastien de Menten wrote:
>> 
>> > Hi,
>> > 
>> > When I need to make sense of a python exception, I often need to parse the 
>> > string exception in order to retrieve the data.
>> 
>> What exactly are you doing with this info? (Every time I started to do
>> this, I found a better way. Perhaps one of them will apply for you.)
>> 
>> (As a general comment, I'd point out that you don't have to check the
>> entire error message; checking for a descriptive substring, while still
>> not "safe", is at least safe*r*.)
>
>I have symbolic expressions in a dictionnary like:
>
>dct = dict( a = "b**2 + c", b = "cos(2.3) + sin(v)", v = "4", c =
>"some_very_expensive_function(v)")
>
>I want to build a function that finds the links between all those
>expressions (think about computing dependencies between cells in a
>spreadsheet).
>
Here's a way of finding the symbols being used in the expressions, and dependencies:
(no guarantees, I haven't explored any special corner cases or caught syntax errors etc ;-)

And note that eval is not safe even for expressions, if you don't know what's in the string.
A safer approach would be to use compiler.parse and a visitor to extract names from the ast.

 >>> dct = dict(
 ...     a = "b**2 + c",
 ...     b = "cos(2.3) + sin(v)",
 ...     v = "4",
 ...     c = "some_very_expensive_function(v)")
 >>>
 >>> symdep = dict((sym, sorted(eval('lambda:'+expr).func_code.co_names)) for sym, expr in dct.items())
 >>>
 >>> def tree(startsym, depdict):
 ...     seen = set()
 ...     def _tree(sym, level=0):
 ...         print '%s%s'%('    '*level, sym)
 ...         seen.add(sym)
 ...         for dep in depdict.get(sym, []): _tree(dep, level+1)
 ...     for sym in sorted(depdict.keys()):
 ...         if sym in seen: continue
 ...         _tree(sym)
 ...
 >>> tree(sorted(symdep.keys())[0], symdep)
 a
     b
         cos
         sin
         v
     c
         some_very_expensive_function
         v

Skipping fancy visitor stuff ;-), getting names brute force from the ast, should be safer
than eval('lambda:'+expr).func_code.co_names):
(not tested beyond what you see ;-)

 >>> def getnames(expr):
 ...     ast = compiler.parse(expr, 'eval')
 ...     names = []
 ...     def descend(node):
 ...         if isinstance(node, compiler.ast.Name): names.append(node.name)
 ...         if not hasattr(node, 'getChildren'): return
 ...         for child in node.getChildren(): descend(child)
 ...     descend(ast)
 ...     return sorted(names)
 ...
 >>> getnames('a*b+c**foo(x)')
 ['a', 'b', 'c', 'foo', 'x']
 >>> for v,x in sorted(dct.items()):
 ...     print '%5s: %s'%(v, getnames(x))
 ...
     a: ['b', 'c']
     b: ['cos', 'sin', 'v']
     c: ['some_very_expensive_function', 'v']
     v: []

>All I do is:
>def link(name):
>   dependencies = {}
>   while True:
>      try:
>         eval(dct[name], globals(), dependencies)
>      except NameError,e:
>         dependencies[e.args[0][6:-16]] = 1
>      else:
>         return dependencies
>
>globals() can be replaced by a custom dictionnary for security
>purposes.
I would use something  getnames above, and put getnames(expr)
in the expression for symdep = dict(...) in place of
sorted(eval('lambda:'+expr).func_code.co_names))

>variation on the theme can:
>  - check SyntaxError and give interlligent feedback to user (BTW,
>SyntaxError args are much smarter)
compiler.parse will raise SyntaxError in getnames, so you could make your own message, e.g.,

 >>> try: getnames('a*b+c***foo(x)') # *** is syntax error
 ... except SyntaxError, e:
 ...     print 'SyntaxError: %s<<--BROKE HERE-->>%s' % (e.text[:e.offset], e.text[e.offset:])
 ...
 SyntaxError: a*b+c***<<--BROKE HERE-->>foo(x)


>  - find or/and eval recursively the whole tree and keep in cache
>values,...
>
HTH

Regards,
Bengt Richter



More information about the Python-list mailing list