# HG changeset patch
# Parent f5c2e2ec50f4b254f456b2a9447acc88e2805fdd
#429: don't cache `(TEXT, Markup)` in serializers.
Not only this is not needed, but this can also lead to wrong retrievals.
For example, if the `u'…'` input is seen first, the `Markup('…')` output is cached. If later `Markup('…')` is seen, the retrieved value would have been `Markup('&…')`!
Added a regression test for this example, `genshi.tests.output.cache_markup`.
diff -r f5c2e2ec50f4 genshi/output.py
|
a
|
b
|
class XMLSerializer(object): |
| 239 | 239 | for filter_ in self.filters: |
| 240 | 240 | stream = filter_(stream) |
| 241 | 241 | for kind, data, pos in stream: |
| | 242 | if kind is TEXT and isinstance(data, Markup): |
| | 243 | yield data |
| | 244 | continue |
| 242 | 245 | cached = _get((kind, data)) |
| 243 | 246 | if cached is not None: |
| 244 | 247 | yield cached |
| … |
… |
class XHTMLSerializer(XMLSerializer): |
| 345 | 348 | for filter_ in self.filters: |
| 346 | 349 | stream = filter_(stream) |
| 347 | 350 | for kind, data, pos in stream: |
| | 351 | if kind is TEXT and isinstance(data, Markup): |
| | 352 | yield data |
| | 353 | continue |
| 348 | 354 | cached = _get((kind, data)) |
| 349 | 355 | if cached is not None: |
| 350 | 356 | yield cached |
| … |
… |
class HTMLSerializer(XHTMLSerializer): |
| 467 | 473 | for filter_ in self.filters: |
| 468 | 474 | stream = filter_(stream) |
| 469 | 475 | for kind, data, _ in stream: |
| | 476 | if kind is TEXT and isinstance(data, Markup): |
| | 477 | yield data |
| | 478 | continue |
| 470 | 479 | output = _get((kind, data)) |
| 471 | 480 | if output is not None: |
| 472 | 481 | yield output |
| … |
… |
class NamespaceFlattener(object): |
| 658 | 667 | _gen_prefix = _gen_prefix().next |
| 659 | 668 | |
| 660 | 669 | for kind, data, pos in stream: |
| | 670 | if kind is TEXT and isinstance(data, Markup): |
| | 671 | yield kind, data, pos |
| | 672 | continue |
| 661 | 673 | output = _get((kind, data)) |
| 662 | 674 | if output is not None: |
| 663 | 675 | yield kind, output, pos |
diff -r f5c2e2ec50f4 genshi/tests/output.py
|
a
|
b
|
import doctest |
| 15 | 15 | import unittest |
| 16 | 16 | import sys |
| 17 | 17 | |
| 18 | | from genshi.core import Attrs, Stream, QName |
| | 18 | from genshi.core import Attrs, Markup, QName, Stream |
| 19 | 19 | from genshi.input import HTML, XML |
| 20 | 20 | from genshi.output import DocType, XMLSerializer, XHTMLSerializer, \ |
| 21 | 21 | HTMLSerializer, EmptyTagFilter |
| … |
… |
class XHTMLSerializerTestCase(unittest.T |
| 390 | 390 | encoding=None) |
| 391 | 391 | self.assertEqual('<!DOCTYPE html>\n<html></html>', output) |
| 392 | 392 | |
| | 393 | def test_ignorable_space(self): |
| | 394 | text = '<foo> Mess \n\n\n with me! </foo>' |
| | 395 | output = XML(text).render(XMLSerializer, encoding=None) |
| | 396 | self.assertEqual('<foo> Mess\n with me! </foo>', output) |
| | 397 | |
| | 398 | def test_cache_markup(self): |
| | 399 | loc = (None, -1, -1) |
| | 400 | stream = Stream([(Stream.START, (QName('foo'), Attrs()), loc), |
| | 401 | (Stream.TEXT, u'…', loc), |
| | 402 | (Stream.END, QName('foo'), loc), |
| | 403 | (Stream.START, (QName('bar'), Attrs()), loc), |
| | 404 | (Stream.TEXT, Markup('…'), loc), |
| | 405 | (Stream.END, QName('bar'), loc)]) |
| | 406 | output = stream.render(XMLSerializer, encoding=None, |
| | 407 | strip_whitespace=False) |
| | 408 | self.assertEqual('<foo>&hellip;</foo><bar>…</bar>', output) |
| | 409 | |
| 393 | 410 | |
| 394 | 411 | class HTMLSerializerTestCase(unittest.TestCase): |
| 395 | 412 | |