# HG changeset patch # User cmlenz # Date 1232063409 0 # Node ID c690de5abafd1a6c0ff929568e518ad6830beb3f # Parent 890dc65c3e756abc492294fdd02704e0a54dd960 Ported [914], [970], and [971] to 0.5.x branch. diff --git a/genshi/core.py b/genshi/core.py --- a/genshi/core.py +++ b/genshi/core.py @@ -13,6 +13,10 @@ """Core classes for markup processing.""" +try: + from functools import reduce +except ImportError: + pass # builtin in Python <= 2.5 from itertools import chain import operator @@ -640,6 +644,9 @@ return QName(self.uri + u'}' + name) __getattr__ = __getitem__ + def __hash__(self): + return hash(self.uri) + def __repr__(self): return '' % self.uri diff --git a/genshi/filters/transform.py b/genshi/filters/transform.py --- a/genshi/filters/transform.py +++ b/genshi/filters/transform.py @@ -1037,7 +1037,7 @@ def _inject(self): content = self.content - if callable(content): + if hasattr(content, '__call__'): content = content() for event in _ensure(content): yield None, event @@ -1170,7 +1170,7 @@ :param stream: The marked event stream to filter """ - callable_value = callable(self.value) + callable_value = hasattr(self.value, '__call__') for mark, (kind, data, pos) in stream: if mark is ENTER: if callable_value: diff --git a/genshi/path.py b/genshi/path.py --- a/genshi/path.py +++ b/genshi/path.py @@ -38,6 +38,10 @@ structures), it only implements a subset of the full XPath 1.0 language. """ +try: + from functools import reduce +except ImportError: + pass # builtin in Python <= 2.5 from math import ceil, floor import operator import re diff --git a/genshi/template/eval.py b/genshi/template/eval.py --- a/genshi/template/eval.py +++ b/genshi/template/eval.py @@ -23,6 +23,7 @@ from sets import ImmutableSet as frozenset from sets import Set as set from textwrap import dedent +from types import CodeType from genshi.core import Markup from genshi.template.base import TemplateRuntimeError @@ -453,7 +454,7 @@ # We'd like to just set co_firstlineno, but it's readonly. So we need to # clone the code object while adjusting the line number - return new.code(0, code.co_nlocals, code.co_stacksize, + return CodeType(0, code.co_nlocals, code.co_stacksize, code.co_flags | 0x0040, code.co_code, code.co_consts, code.co_names, code.co_varnames, filename, name, lineno, code.co_lnotab, (), ()) diff --git a/genshi/template/interpolation.py b/genshi/template/interpolation.py --- a/genshi/template/interpolation.py +++ b/genshi/template/interpolation.py @@ -44,7 +44,7 @@ string. >>> for kind, data, pos in interpolate("hey ${foo}bar"): - ... print kind, `data` + ... print kind, repr(data) TEXT u'hey ' EXPR Expression('foo') TEXT u'bar' diff --git a/genshi/template/loader.py b/genshi/template/loader.py --- a/genshi/template/loader.py +++ b/genshi/template/loader.py @@ -124,7 +124,7 @@ self.default_class = default_class or MarkupTemplate self.variable_lookup = variable_lookup self.allow_exec = allow_exec - if callback is not None and not callable(callback): + if callback is not None and not hasattr(callback, '__call__'): raise TypeError('The "callback" parameter needs to be callable') self.callback = callback self._cache = LRUCache(max_cache_size) diff --git a/genshi/template/markup.py b/genshi/template/markup.py --- a/genshi/template/markup.py +++ b/genshi/template/markup.py @@ -244,10 +244,9 @@ for event in stream: - # We (currently) only care about start and end events for matching + # We (currently) only care about start events for matching # We might care about namespace events in the future, though - if not match_templates or (event[0] is not START and - event[0] is not END): + if not match_templates or event[0] is not START: yield event continue diff --git a/genshi/template/plugin.py b/genshi/template/plugin.py --- a/genshi/template/plugin.py +++ b/genshi/template/plugin.py @@ -57,7 +57,7 @@ options.get('genshi.max_cache_size')) loader_callback = options.get('genshi.loader_callback', None) - if loader_callback and not callable(loader_callback): + if loader_callback and not hasattr(loader_callback, '__call__'): raise ConfigurationError('loader callback must be a function') lookup_errors = options.get('genshi.lookup_errors', 'strict') diff --git a/genshi/template/tests/eval.py b/genshi/template/tests/eval.py --- a/genshi/template/tests/eval.py +++ b/genshi/template/tests/eval.py @@ -195,8 +195,9 @@ def test_compare_ne(self): self.assertEqual(False, Expression("1 != 1").evaluate({})) self.assertEqual(False, Expression("x != y").evaluate({'x': 1, 'y': 1})) - self.assertEqual(False, Expression("1 <> 1").evaluate({})) - self.assertEqual(False, Expression("x <> y").evaluate({'x': 1, 'y': 1})) + if sys.version < '3': + self.assertEqual(False, Expression("1 <> 1").evaluate({})) + self.assertEqual(False, Expression("x <> y").evaluate({'x': 1, 'y': 1})) def test_compare_lt(self): self.assertEqual(True, Expression("1 < 2").evaluate({})) @@ -241,16 +242,9 @@ self.assertEqual(42, expr.evaluate({'foo': foo, 'bar': {"x": 42}})) def test_lambda(self): - # Define a custom `sorted` function cause the builtin isn't available - # on Python 2.3 - def sorted(items, compfunc): - items.sort(compfunc) - return items - data = {'items': [{'name': 'b', 'value': 0}, {'name': 'a', 'value': 1}], - 'sorted': sorted} - expr = Expression("sorted(items, lambda a, b: cmp(a.name, b.name))") - self.assertEqual([{'name': 'a', 'value': 1}, {'name': 'b', 'value': 0}], - expr.evaluate(data)) + data = {'items': range(5)} + expr = Expression("filter(lambda x: x > 2, items)") + self.assertEqual([3, 4], expr.evaluate(data)) def test_list_comprehension(self): expr = Expression("[n for n in numbers if n < 2]") @@ -703,7 +697,7 @@ def test_delitem(self): d = {'k': 'foo'} Suite("del d['k']").execute({'d': d}) - self.failIf('k' in d, `d`) + self.failIf('k' in d, repr(d)) def suite():