Mercurial > genshi > mirror
changeset 304:b2fdaff8c385 trunk
Return an `Undefined` instance from failed item or attribute lookups.
author | cmlenz |
---|---|
date | Mon, 16 Oct 2006 12:16:33 +0000 |
parents | 53d502c7c874 |
children | 60111a041e7c |
files | genshi/eval.py genshi/tests/eval.py |
diffstat | 2 files changed, 58 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/genshi/eval.py +++ b/genshi/eval.py @@ -65,6 +65,14 @@ __slots__ = ['source', 'code'] def __init__(self, source, filename=None, lineno=-1): + """Create the expression, either from a string, or from an AST node. + + @param source: either a string containing the source code of the + expression, or an AST node + @param filename: the (preferably absolute) name of the file containing + the expression + @param lineno: the number of the line on which the expression was found + """ if isinstance(source, basestring): self.source = source if isinstance(source, unicode): @@ -128,10 +136,10 @@ ... NameError: Variable "foo" is not defined """ - __slots__ = ['name'] + __slots__ = ['_name'] def __init__(self, name): - self.name = name + self._name = name def __call__(self, *args, **kwargs): self.throw() @@ -149,7 +157,7 @@ return 'undefined' def throw(self): - raise NameError('Variable "%s" is not defined' % self.name) + raise NameError('Variable "%s" is not defined' % self._name) def _compile(node, source=None, filename=None, lineno=-1): @@ -202,7 +210,7 @@ try: return obj[key] except (KeyError, TypeError): - return None + return Undefined(key) def _lookup_item(data, obj, key): if type(obj) is Undefined: @@ -213,10 +221,11 @@ return obj[key] except (KeyError, IndexError, TypeError), e: if isinstance(key, basestring): - try: - return getattr(obj, key) - except (AttributeError, TypeError), e: - pass + val = getattr(obj, key, Undefined) + if val is Undefined: + val = Undefined(key) + return val + raise class ASTTransformer(object):
--- a/genshi/tests/eval.py +++ b/genshi/tests/eval.py @@ -281,7 +281,8 @@ def test_slice_with_vars(self): expr = Expression("numbers[start:end]") - self.assertEqual([0, 1], expr.evaluate({'numbers': range(5), 'start': 0, 'end': 2})) + self.assertEqual([0, 1], expr.evaluate({'numbers': range(5), 'start': 0, + 'end': 2})) def test_slice_copy(self): expr = Expression("numbers[:]") @@ -289,7 +290,8 @@ def test_slice_stride(self): expr = Expression("numbers[::stride]") - self.assertEqual([0, 2, 4], expr.evaluate({'numbers': range(5), 'stride': 2})) + self.assertEqual([0, 2, 4], expr.evaluate({'numbers': range(5), + 'stride': 2})) def test_slice_negative_start(self): expr = Expression("numbers[-1:]") @@ -315,6 +317,7 @@ while frame.tb_next: frame = frame.tb_next frames.append(frame) + self.assertEqual('Variable "nothing" is not defined', str(e)) self.assertEqual('<Expression "nothing()">', frames[-3].tb_frame.f_code.co_name) self.assertEqual('index.html', @@ -333,12 +336,48 @@ while frame.tb_next: frame = frame.tb_next frames.append(frame) + self.assertEqual('Variable "nothing" is not defined', str(e)) self.assertEqual('<Expression "nothing.nil">', frames[-3].tb_frame.f_code.co_name) self.assertEqual('index.html', frames[-3].tb_frame.f_code.co_filename) self.assertEqual(50, frames[-3].tb_lineno) + def test_error_getitem_undefined(self): + expr = Expression("nothing[0]", filename='index.html', lineno=50) + try: + expr.evaluate({}) + self.fail('Expected NameError') + except NameError, e: + exc_type, exc_value, exc_traceback = sys.exc_info() + frame = exc_traceback.tb_next + frames = [] + while frame.tb_next: + frame = frame.tb_next + frames.append(frame) + self.assertEqual('Variable "nothing" is not defined', str(e)) + self.assertEqual('<Expression "nothing[0]">', + frames[-3].tb_frame.f_code.co_name) + self.assertEqual('index.html', + frames[-3].tb_frame.f_code.co_filename) + self.assertEqual(50, frames[-3].tb_lineno) + + def test_error_getattr_nested_undefined(self): + expr = Expression("nothing.nil", filename='index.html', lineno=50) + val = expr.evaluate({'nothing': object()}) + assert isinstance(val, Undefined) + self.assertEqual("nil", val._name) + + def test_error_getitem_nested_undefined_string(self): + expr = Expression("nothing['bla']", filename='index.html', lineno=50) + val = expr.evaluate({'nothing': object()}) + assert isinstance(val, Undefined) + self.assertEqual("bla", val._name) + + def test_error_getitem_nested_undefined_int(self): + expr = Expression("nothing[0]", filename='index.html', lineno=50) + self.assertRaises(TypeError, expr.evaluate, {'nothing': object()}) + def suite(): suite = unittest.TestSuite()