# HG changeset patch
# Parent ceae545e662b5f8e1d7146de255c6e31bce3a30b
output: refactor code relative to the token serialization cache (introduced in [1038]).
In preparation for fixing #429.
diff -r ceae545e662b genshi/output.py
|
a
|
b
|
def get_serializer(method='xml', **kwarg |
| 79 | 79 | return method(**kwargs) |
| 80 | 80 | |
| 81 | 81 | |
| | 82 | def _prepare_cache(use_cache=True): |
| | 83 | """Prepare a private token serialization cache. |
| | 84 | |
| | 85 | :param use_cache: boolean indicating whether a real cache should |
| | 86 | be used or not. If not, the returned functions |
| | 87 | are no-ops. |
| | 88 | |
| | 89 | :return: emit and get functions, for storing and retrieving |
| | 90 | serialized values from the cache. |
| | 91 | """ |
| | 92 | cache = {} |
| | 93 | if use_cache: |
| | 94 | def _emit(kind, input, output): |
| | 95 | cache[kind, input] = output |
| | 96 | return output |
| | 97 | _get = cache.get |
| | 98 | else: |
| | 99 | def _emit(kind, input, output): |
| | 100 | return output |
| | 101 | def _get(key): |
| | 102 | pass |
| | 103 | return _emit, _get, cache |
| | 104 | |
| | 105 | |
| 82 | 106 | class DocType(object): |
| 83 | 107 | """Defines a number of commonly used DOCTYPE declarations as constants.""" |
| 84 | 108 | |
| … |
… |
class XMLSerializer(object): |
| 204 | 228 | self.filters.append(DocTypeInserter(doctype)) |
| 205 | 229 | self.cache = cache |
| 206 | 230 | |
| | 231 | def _prepare_cache(self): |
| | 232 | return _prepare_cache(self.cache)[:2] |
| | 233 | |
| 207 | 234 | def __call__(self, stream): |
| 208 | 235 | have_decl = have_doctype = False |
| 209 | 236 | in_cdata = False |
| 210 | | |
| 211 | | cache = {} |
| 212 | | cache_get = cache.get |
| 213 | | if self.cache: |
| 214 | | def _emit(kind, input, output): |
| 215 | | cache[kind, input] = output |
| 216 | | return output |
| 217 | | else: |
| 218 | | def _emit(kind, input, output): |
| 219 | | return output |
| | 237 | _emit, _get = self._prepare_cache() |
| 220 | 238 | |
| 221 | 239 | for filter_ in self.filters: |
| 222 | 240 | stream = filter_(stream) |
| 223 | 241 | for kind, data, pos in stream: |
| 224 | | cached = cache_get((kind, data)) |
| | 242 | cached = _get((kind, data)) |
| 225 | 243 | if cached is not None: |
| 226 | 244 | yield cached |
| 227 | | |
| 228 | 245 | elif kind is START or kind is EMPTY: |
| 229 | 246 | tag, attrib = data |
| 230 | 247 | buf = ['<', tag] |
| … |
… |
class XHTMLSerializer(XMLSerializer): |
| 323 | 340 | drop_xml_decl = self.drop_xml_decl |
| 324 | 341 | have_decl = have_doctype = False |
| 325 | 342 | in_cdata = False |
| 326 | | |
| 327 | | cache = {} |
| 328 | | cache_get = cache.get |
| 329 | | if self.cache: |
| 330 | | def _emit(kind, input, output): |
| 331 | | cache[kind, input] = output |
| 332 | | return output |
| 333 | | else: |
| 334 | | def _emit(kind, input, output): |
| 335 | | return output |
| | 343 | _emit, _get = self._prepare_cache() |
| 336 | 344 | |
| 337 | 345 | for filter_ in self.filters: |
| 338 | 346 | stream = filter_(stream) |
| 339 | 347 | for kind, data, pos in stream: |
| 340 | | cached = cache_get((kind, data)) |
| | 348 | cached = _get((kind, data)) |
| 341 | 349 | if cached is not None: |
| 342 | 350 | yield cached |
| 343 | 351 | |
| … |
… |
class HTMLSerializer(XHTMLSerializer): |
| 454 | 462 | noescape_elems = self._NOESCAPE_ELEMS |
| 455 | 463 | have_doctype = False |
| 456 | 464 | noescape = False |
| 457 | | |
| 458 | | cache = {} |
| 459 | | cache_get = cache.get |
| 460 | | if self.cache: |
| 461 | | def _emit(kind, input, output): |
| 462 | | cache[kind, input] = output |
| 463 | | return output |
| 464 | | else: |
| 465 | | def _emit(kind, input, output): |
| 466 | | return output |
| | 465 | _emit, _get = self._prepare_cache() |
| 467 | 466 | |
| 468 | 467 | for filter_ in self.filters: |
| 469 | 468 | stream = filter_(stream) |
| 470 | 469 | for kind, data, _ in stream: |
| 471 | | output = cache_get((kind, data)) |
| | 470 | output = _get((kind, data)) |
| 472 | 471 | if output is not None: |
| 473 | 472 | yield output |
| 474 | 473 | if (kind is START or kind is EMPTY) \ |
| … |
… |
class NamespaceFlattener(object): |
| 626 | 625 | self.cache = cache |
| 627 | 626 | |
| 628 | 627 | def __call__(self, stream): |
| 629 | | cache = {} |
| 630 | | cache_get = cache.get |
| 631 | | if self.cache: |
| 632 | | def _emit(kind, input, output, pos): |
| 633 | | cache[kind, input] = output |
| 634 | | return kind, output, pos |
| 635 | | else: |
| 636 | | def _emit(kind, input, output, pos): |
| 637 | | return output |
| 638 | | |
| 639 | 628 | prefixes = dict([(v, [k]) for k, v in self.prefixes.items()]) |
| 640 | 629 | namespaces = {XML_NAMESPACE.uri: ['xml']} |
| | 630 | _emit, _get, cache = _prepare_cache(self.cache) |
| 641 | 631 | def _push_ns(prefix, uri): |
| 642 | 632 | namespaces.setdefault(uri, []).append(prefix) |
| 643 | 633 | prefixes.setdefault(prefix, []).append(uri) |
| … |
… |
class NamespaceFlattener(object): |
| 668 | 658 | _gen_prefix = _gen_prefix().next |
| 669 | 659 | |
| 670 | 660 | for kind, data, pos in stream: |
| 671 | | output = cache_get((kind, data)) |
| | 661 | output = _get((kind, data)) |
| 672 | 662 | if output is not None: |
| 673 | 663 | yield kind, output, pos |
| 674 | 664 | |
| … |
… |
class NamespaceFlattener(object): |
| 701 | 691 | attrname = '%s:%s' % (prefix, attrname) |
| 702 | 692 | new_attrs.append((attrname, value)) |
| 703 | 693 | |
| 704 | | yield _emit(kind, data, (tagname, Attrs(ns_attrs + new_attrs)), pos) |
| | 694 | data = _emit(kind, data, (tagname, Attrs(ns_attrs + new_attrs))) |
| | 695 | yield kind, data, pos |
| 705 | 696 | del ns_attrs[:] |
| 706 | 697 | |
| 707 | 698 | elif kind is END: |
| … |
… |
class NamespaceFlattener(object): |
| 711 | 702 | prefix = namespaces[tagns][-1] |
| 712 | 703 | if prefix: |
| 713 | 704 | tagname = '%s:%s' % (prefix, tagname) |
| 714 | | yield _emit(kind, data, tagname, pos) |
| | 705 | yield kind, _emit(kind, data, tagname), pos |
| 715 | 706 | |
| 716 | 707 | elif kind is START_NS: |
| 717 | 708 | prefix, uri = data |