Exemple #1
0
 def test_nested_bound_namespaces(self):
     stream = Stream([
         (Stream.START_NS, ('x', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}div'), Attrs()),
          (None, -1, -1)), (Stream.TEXT, '\n          ', (None, -1, -1)),
         (Stream.START_NS, ('x', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}p'), Attrs()),
          (None, -1, -1)),
         (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
         (Stream.END_NS, 'x', (None, -1, -1)),
         (Stream.TEXT, '\n          ', (None, -1, -1)),
         (Stream.START_NS, ('x', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}p'), Attrs()),
          (None, -1, -1)),
         (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
         (Stream.END_NS, 'x', (None, -1, -1)),
         (Stream.TEXT, '\n        ', (None, -1, -1)),
         (Stream.END, QName('http://example.org/}div'), (None, -1, -1)),
         (Stream.END_NS, 'x', (None, -1, -1))
     ])
     output = stream.render(XMLSerializer)
     self.assertEqual(
         """<x:div xmlns:x="http://example.org/">
       <x:p/>
       <x:p/>
     </x:div>""", output)
Exemple #2
0
 def test_nested_default_namespaces(self):
     stream = Stream([
         (Stream.START_NS, ('', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}div'), Attrs()),
          (None, -1, -1)), (Stream.TEXT, '\n          ', (None, -1, -1)),
         (Stream.START_NS, ('', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}p'), Attrs()),
          (None, -1, -1)),
         (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
         (Stream.END_NS, '', (None, -1, -1)),
         (Stream.TEXT, '\n          ', (None, -1, -1)),
         (Stream.START_NS, ('', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}p'), Attrs()),
          (None, -1, -1)),
         (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
         (Stream.END_NS, '', (None, -1, -1)),
         (Stream.TEXT, '\n        ', (None, -1, -1)),
         (Stream.END, QName('http://example.org/}div'), (None, -1, -1)),
         (Stream.END_NS, '', (None, -1, -1))
     ])
     output = stream.render(XMLSerializer, encoding=None)
     self.assertEqual(
         """<div xmlns="http://example.org/">
       <p/>
       <p/>
     </div>""", output)
Exemple #3
0
 def test_cache_markup(self):
     loc = (None, -1, -1)
     stream = Stream([(Stream.START, (QName('foo'), Attrs()), loc),
                      (Stream.TEXT, u'&hellip;', loc),
                      (Stream.END, QName('foo'), loc),
                      (Stream.START, (QName('bar'), Attrs()), loc),
                      (Stream.TEXT, Markup('&hellip;'), loc),
                      (Stream.END, QName('bar'), loc)])
     output = stream.render(XMLSerializer, encoding=None, 
                            strip_whitespace=False)
     self.assertEqual('<foo>&amp;hellip;</foo><bar>&hellip;</bar>', output)
Exemple #4
0
 def test_convert_ElementTree_to_markup_stream(self):
     tree = ElementTree.fromstring(
         u'<div class="test_div">text<span>some more text</span></div>'
     )
     events = list(ET(tree))
     self.assertEqual(6, len(events))
     self.assertEqual(
         (Stream.START, (QName("div"), Attrs([(QName("class"), "test_div")]))),
         events[0][:2],
     )
     self.assertEqual((Stream.TEXT, "text"), events[1][:2])
     self.assertEqual((Stream.START, (QName("span"), Attrs())), events[2][:2])
     self.assertEqual((Stream.TEXT, "some more text"), events[3][:2])
     self.assertEqual((Stream.END, QName("span")), events[4][:2])
     self.assertEqual((Stream.END, QName("div")), events[5][:2])
Exemple #5
0
 def _format_fragment(self, text, fragment):
     START, TEXT, END, Attrs = self.START, self.TEXT, self.END, self.Attrs
     qname = self.qname
     output = []
     
     index = fragment.startchar
     lastmatched = False
     for t in fragment.matches:
         if t.startchar > index:
             if lastmatched:
                 output.append((END, qname, (None, -1, -1)))
                 lastmatched = False
             self._add_text(text[index:t.startchar], output)
         
         ttxt = text[t.startchar:t.endchar]
         if not lastmatched:
             output.append((START, (qname, Attrs()), (None, -1, -1)))
             lastmatched = True
         output.append((TEXT, ttxt, (None, -1, -1)))
                                 
         index = t.endchar
     
     if lastmatched:
         output.append((END, qname, (None, -1, -1)))
     
     return output
Exemple #6
0
        def __call__(self, stream):
            """Apply the filter to the given stream.

            :deprecated: the ability to behave as a Genshi filter will be
                         removed in Trac 1.5.1.

            :param stream: the markup event stream to filter
            """
            waiting_for = None

            for kind, data, pos in stream:
                if kind is START:
                    if waiting_for:
                        continue
                    tag, attrs = data
                    if not self.is_safe_elem(tag, attrs):
                        waiting_for = tag
                        continue
                    new_attrs = self.sanitize_attrs(tag, dict(attrs))
                    yield kind, (tag, Attrs(new_attrs.iteritems())), pos

                elif kind is END:
                    tag = data
                    if waiting_for:
                        if waiting_for == tag:
                            waiting_for = None
                    else:
                        yield kind, data, pos

                elif kind is not COMMENT:
                    if not waiting_for:
                        yield kind, data, pos
Exemple #7
0
    def post_process_request(self, req, template, data, content_type):
        """post process request filter"""
        # update the nav item links
        root = req.href()
        rootproducts = req.href.products()
        pid = req.args.get('productid')
        if pid:
            for navkey, section in req.chrome['nav'].iteritems():
                for item in section:
                    try:
                        href = item['label'].attrib.get('href')
                    except AttributeError:
                        continue
                    if href.startswith(rootproducts):
                        continue
                    if href.startswith(root):
                        tail = href[len(root):]
                        if tail not in self.NAVITEM_DO_NOT_TRANSFORM:
                            attrs = [
                                attr for attr in item['label'].attrib
                                if attr[0] != 'href'
                            ]
                            newhref = req.href.products(pid, tail)
                            item['label'].attrib = Attrs([(QName('href'),
                                                           newhref)] + attrs)

        return (template, data, content_type)
Exemple #8
0
 def test_attr_selection_with_namespace(self):
     xml = XML('<root xmlns:ns1="http://example.com">'
               '<foo ns1:bar="abc"></foo>'
               '</root>')
     path = Path('foo/@ns1:bar')
     result = path.select(xml, namespaces={'ns1': 'http://example.com'})
     self.assertEqual(list(result),
                      [Attrs([(QName('http://example.com}bar'), 'abc')])])
Exemple #9
0
 def test_pickle(self):
     attrs = Attrs([("attr1", "foo"), ("attr2", "bar")])
     buf = BytesIO()
     pickle.dump(attrs, buf, 2)
     buf.seek(0)
     unpickled = pickle.load(buf)
     self.assertEquals("Attrs([('attr1', 'foo'), ('attr2', 'bar')])",
                       repr(unpickled))
 def test_map_element(self):
     self.assertEqual(
         self._map('foo'),
         [(QName('foo'), Attrs([(QName('name'), 'foo'),
                                (QName('size'), '100')])),
          'FOO',
          QName('foo')]
     )
Exemple #11
0
 def handle_starttag(self, tag, attrib):
     fixed_attrib = [(QName(name), name if value is None else value)
                     for name, value in attrib]
     self._enqueue(START, (QName(tag), Attrs(fixed_attrib)))
     if tag in self._EMPTY_ELEMS:
         self._enqueue(END, QName(tag))
     else:
         self._open_tags.append(tag)
Exemple #12
0
 def mark_text(self, pos, text, tag):
     ws, text = self.cut_leading_space(text)
     tag = QName(tag)
     if ws:
         self.append(TEXT, ws, pos)
     self.append(START, (tag, Attrs()), pos)
     self.append(TEXT, text, pos)
     self.append(END, tag, pos)
 def test_duplicate_attributes(self):
     link = tag.a(href='#1', href_='#1')('Bar')
     events = list(link.generate())
     self.assertEqual(
         (Stream.START, ('a', Attrs([('href', "#1")])), (None, -1, -1)),
         events[0])
     self.assertEqual((Stream.TEXT, 'Bar', (None, -1, -1)), events[1])
     self.assertEqual((Stream.END, 'a', (None, -1, -1)), events[2])
 def test_link(self):
     link = tag.a(href='#', accesskey=None)('Bar')
     events = list(link.generate())
     self.assertEqual(
         (Stream.START, ('a', Attrs([('href', "#")])), (None, -1, -1)),
         events[0])
     self.assertEqual((Stream.TEXT, 'Bar', (None, -1, -1)), events[1])
     self.assertEqual((Stream.END, 'a', (None, -1, -1)), events[2])
Exemple #15
0
 def test_duplicate_attributes(self):
     link = tag.a(href='#1', href_='#2')('Bar')
     bits = iter(link.generate())
     self.assertEqual(
         (Stream.START, ('a', Attrs([('href', "#1")])), (None, -1, -1)),
         bits.next())
     self.assertEqual((Stream.TEXT, u'Bar', (None, -1, -1)), bits.next())
     self.assertEqual((Stream.END, 'a', (None, -1, -1)), bits.next())
Exemple #16
0
def _kwargs_to_attrs(kwargs):
    attrs = []
    names = set()
    for name, value in kwargs.items():
        name = name.rstrip('_').replace('_', '-')
        if value is not None and name not in names:
            attrs.append((QName(name), unicode(value)))
            names.add(name)
    return Attrs(attrs)
Exemple #17
0
 def __call__(self, *args, **kwargs):
     """Append any positional arguments as child nodes, and keyword arguments
     as attributes.
     
     :see: `Fragment.append`
     """
     self.attrib |= Attrs(_kwargs_to_attrs(kwargs))
     Fragment.__call__(self, *args)
     return self
Exemple #18
0
 def test_link(self):
     link = tag.a(href='#', title='Foo', accesskey=None)('Bar')
     bits = iter(link.generate())
     self.assertEqual(
         (Stream.START, ('a', Attrs([('href', "#"),
                                     ('title', "Foo")])), (None, -1, -1)),
         bits.next())
     self.assertEqual((Stream.TEXT, u'Bar', (None, -1, -1)), bits.next())
     self.assertEqual((Stream.END, 'a', (None, -1, -1)), bits.next())
Exemple #19
0
 def _generate():
     for c, text in self._chunk(tokens):
         if c:
             attrs = Attrs([(class_, c)])
             yield START, (span, attrs), pos
             yield TEXT, text, pos
             yield END, span, pos
         else:
             yield TEXT, text, pos
 def test_nonstring_attributes(self):
     """
     Verify that if an attribute value is given as an int (or some other
     non-string type), it is coverted to a string when the stream is
     generated.
     """
     events = list(tag.foo(id=3))
     self.assertEqual(
         (Stream.START, ('foo', Attrs([('id', '3')])), (None, -1, -1)),
         events[0])
Exemple #21
0
def to_genshi(walker):
    """Convert a tree to a genshi tree

    :arg walker: the treewalker to use to walk the tree to convert it

    :returns: generator of genshi nodes

    """
    text = []
    for token in walker:
        type = token["type"]
        if type in ("Characters", "SpaceCharacters"):
            text.append(token["data"])
        elif text:
            yield TEXT, "".join(text), (None, -1, -1)
            text = []

        if type in ("StartTag", "EmptyTag"):
            if token["namespace"]:
                name = "{%s}%s" % (token["namespace"], token["name"])
            else:
                name = token["name"]
            attrs = Attrs(
                [
                    (QName("{%s}%s" % attr if attr[0] is not None else attr[1]), value)
                    for attr, value in token["data"].items()
                ]
            )
            yield (START, (QName(name), attrs), (None, -1, -1))
            if type == "EmptyTag":
                type = "EndTag"

        if type == "EndTag":
            if token["namespace"]:
                name = "{%s}%s" % (token["namespace"], token["name"])
            else:
                name = token["name"]

            yield END, QName(name), (None, -1, -1)

        elif type == "Comment":
            yield COMMENT, token["data"], (None, -1, -1)

        elif type == "Doctype":
            yield DOCTYPE, (token["name"], token["publicId"], token["systemId"]), (
                None,
                -1,
                -1,
            )

        else:
            pass  # FIXME: What to do?

    if text:
        yield TEXT, "".join(text), (None, -1, -1)
Exemple #22
0
 def test_empty_text_in_span(self):
     """
     http://trac.edgewall.org/ticket/4336
     """
     ns = Namespace('http://www.w3.org/1999/xhtml')
     input = [(START, (ns.span, Attrs([])), (None, -1, -1)),
              (TEXT, "", (None, -1, -1)),
              (END, ns.span, (None, -1, -1)),
             ]
     lines = list(_group_lines(input))
     self.assertEqual(len(lines), 0)
    def handle_starttag(self, tag, attrib):
        fixed_attrib = []
        for name, value in attrib:  # Fixup minimized attributes
            if value is None:
                value = name
            fixed_attrib.append((QName(name), stripentities(value)))

        self._enqueue(START, (QName(tag), Attrs(fixed_attrib)))
        if tag in self._EMPTY_ELEMS:
            self._enqueue(END, QName(tag))
        else:
            self._open_tags.append(tag)
Exemple #24
0
 def test_out_of_order_tags2(self):
     text = '<span class="baz"><b><i>Foobar</span></b></i>'
     events = list(HTMLParser(StringIO(text)))
     self.assertEqual(7, len(events))
     self.assertEqual((Stream.START, ('span', Attrs([('class', 'baz')]))),
                      events[0][:2])
     self.assertEqual((Stream.START, ('b', ())), events[1][:2])
     self.assertEqual((Stream.START, ('i', ())), events[2][:2])
     self.assertEqual((Stream.TEXT, 'Foobar'), events[3][:2])
     self.assertEqual((Stream.END, 'i'), events[4][:2])
     self.assertEqual((Stream.END, 'b'), events[5][:2])
     self.assertEqual((Stream.END, 'span'), events[6][:2])
Exemple #25
0
 def test_multiple_bound_namespaces(self):
     stream = Stream([
         (Stream.START, (QName('div'), Attrs()), (None, -1, -1)),
         (Stream.TEXT, '\n          ', (None, -1, -1)),
         (Stream.START_NS, ('x', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}p'), Attrs()), (None, -1, -1)),
         (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
         (Stream.END_NS, 'x', (None, -1, -1)),
         (Stream.TEXT, '\n          ', (None, -1, -1)),
         (Stream.START_NS, ('x', 'http://example.org/'), (None, -1, -1)),
         (Stream.START, (QName('http://example.org/}p'), Attrs()), (None, -1, -1)),
         (Stream.END, QName('http://example.org/}p'), (None, -1, -1)),
         (Stream.END_NS, 'x', (None, -1, -1)),
         (Stream.TEXT, '\n        ', (None, -1, -1)),
         (Stream.END, QName('div'), (None, -1, -1)),
     ])
     output = stream.render(XMLSerializer, encoding=None)
     self.assertEqual("""<div>
       <x:p xmlns:x="http://example.org/"/>
       <x:p xmlns:x="http://example.org/"/>
     </div>""", output)
Exemple #26
0
    def _eval(self, stream, ctxt, **vars):
        """Internal stream filter that evaluates any expressions in `START` and
        `TEXT` events.
        """
        filters = (self._flatten, self._eval)
        number_conv = self._number_conv

        for kind, data, pos in stream:

            if kind is START and data[1]:
                # Attributes may still contain expressions in start tags at
                # this point, so do some evaluation
                tag, attrs = data
                new_attrs = []
                for name, substream in attrs:
                    if isinstance(substream, basestring):
                        value = substream
                    else:
                        values = []
                        for subkind, subdata, subpos in self._eval(substream,
                                                                   ctxt,
                                                                   **vars):
                            if subkind is TEXT:
                                values.append(subdata)
                        value = [x for x in values if x is not None]
                        if not value:
                            continue
                    new_attrs.append((name, u''.join(value)))
                yield kind, (tag, Attrs(new_attrs)), pos

            elif kind is EXPR:
                result = _eval_expr(data, ctxt, **vars)
                if result is not None:
                    # First check for a string, otherwise the iterable test
                    # below succeeds, and the string will be chopped up into
                    # individual characters
                    if isinstance(result, basestring):
                        yield TEXT, result, pos
                    elif isinstance(result, (int, float, long)):
                        yield TEXT, number_conv(result), pos
                    elif hasattr(result, '__iter__'):
                        substream = _ensure(result)
                        for filter_ in filters:
                            substream = filter_(substream, ctxt, **vars)
                        for event in substream:
                            yield event
                    else:
                        yield TEXT, unicode(result), pos

            else:
                yield kind, data, pos
Exemple #27
0
    def handle_starttag(self, tag, attrib):
        fixed_attrib = []
        for name, value in attrib: # Fixup minimized attributes
            if value is None:
                value = str(name)
            elif not isinstance(value, str):
                value = value.decode(self.encoding, 'replace')
            fixed_attrib.append((QName(name), stripentities(value)))

        self._enqueue(START, (QName(tag), Attrs(fixed_attrib)))
        if tag in self._EMPTY_ELEMS:
            self._enqueue(END, QName(tag))
        else:
            self._open_tags.append(tag)
Exemple #28
0
    def GenshiAdapter(tree):
        text = None
        for token in treewalkers.getTreeWalker('dom')(tree):
            type = token['type']
            if type in ('Characters', 'SpaceCharacters'):
                if text is None:
                    text = token['data']
                else:
                    text += token['data']
            elif text is not None:
                yield TEXT, text, (None, -1, -1)
                text = None

            if type in ('StartTag', 'EmptyTag'):
                if token['namespace']:
                    name = '{%s}%s' % (token['namespace'], token['name'])
                else:
                    name = token['name']
                attrs = Attrs([
                    (QName('{%s}%s' %
                           attr if attr[0] is not None else attr[1]), value)
                    for attr, value in token['data'].items()
                ])
                yield (START, (QName(name), attrs), (None, -1, -1))
                if type == 'EmptyTag':
                    type = 'EndTag'

            if type == 'EndTag':
                if token['namespace']:
                    name = '{%s}%s' % (token['namespace'], token['name'])
                else:
                    name = token['name']

                yield END, QName(name), (None, -1, -1)

            elif type == 'Comment':
                yield COMMENT, token['data'], (None, -1, -1)

            elif type == 'Doctype':
                yield DOCTYPE, (token['name'], token['publicId'],
                                token['systemId']), (None, -1, -1)

            else:
                pass  # FIXME: What to do?

        if text is not None:
            yield TEXT, text, (None, -1, -1)
    def GenshiAdapter(tree):
        text = None
        for token in treewalkers.getTreeWalker("dom")(tree):
            type = token["type"]
            if type in ("Characters", "SpaceCharacters"):
                if text is None:
                    text = token["data"]
                else:
                    text += token["data"]
            elif text is not None:
                yield TEXT, text, (None, -1, -1)
                text = None

            if type in ("StartTag", "EmptyTag"):
                if token["namespace"]:
                    name = "{%s}%s" % (token["namespace"], token["name"])
                else:
                    name = token["name"]
                attrs = Attrs([
                    (QName("{%s}%s" %
                           attr if attr[0] is not None else attr[1]), value)
                    for attr, value in token["data"].items()
                ])
                yield (START, (QName(name), attrs), (None, -1, -1))
                if type == "EmptyTag":
                    type = "EndTag"

            if type == "EndTag":
                if token["namespace"]:
                    name = "{%s}%s" % (token["namespace"], token["name"])
                else:
                    name = token["name"]

                yield END, QName(name), (None, -1, -1)

            elif type == "Comment":
                yield COMMENT, token["data"], (None, -1, -1)

            elif type == "Doctype":
                yield DOCTYPE, (token["name"], token["publicId"],
                                token["systemId"]), (None, -1, -1)

            else:
                pass  # FIXME: What to do?

        if text is not None:
            yield TEXT, text, (None, -1, -1)
Exemple #30
0
    def __call__(self, stream):
        """Apply the filter to the given stream.
        
        :param stream: the markup event stream to filter
        """
        waiting_for = None

        for kind, data, pos in stream:
            if kind is START:
                if waiting_for:
                    continue
                tag, attrs = data
                if not self.is_safe_elem(tag, attrs):
                    waiting_for = tag
                    continue

                new_attrs = []
                for attr, value in attrs:
                    value = stripentities(value)
                    if attr not in self.safe_attrs:
                        continue
                    elif attr in self.uri_attrs:
                        # Don't allow URI schemes such as "javascript:"
                        if not self.is_safe_uri(value):
                            continue
                    elif attr == 'style':
                        # Remove dangerous CSS declarations from inline styles
                        decls = self.sanitize_css(value)
                        if not decls:
                            continue
                        value = '; '.join(decls)
                    new_attrs.append((attr, value))

                yield kind, (tag, Attrs(new_attrs)), pos

            elif kind is END:
                tag = data
                if waiting_for:
                    if waiting_for == tag:
                        waiting_for = None
                else:
                    yield kind, data, pos

            elif kind is not COMMENT:
                if not waiting_for:
                    yield kind, data, pos
    def _parse(self, source, encoding):
        streams = [[]]  # stacked lists of events of the "compiled" template
        dirmap = {}  # temporary mapping of directives to elements
        ns_prefix = {}
        depth = 0
        fallbacks = []
        includes = []

        if not isinstance(source, Stream):
            source = XMLParser(source, filename=self.filename, encoding=encoding)

        for kind, data, pos in source:
            stream = streams[-1]

            if kind is START_NS:
                # Strip out the namespace declaration for template directives
                prefix, uri = data
                ns_prefix[prefix] = uri
                if uri not in (self.DIRECTIVE_NAMESPACE, self.XINCLUDE_NAMESPACE):
                    stream.append((kind, data, pos))

            elif kind is END_NS:
                uri = ns_prefix.pop(data, None)
                if uri and uri not in (self.DIRECTIVE_NAMESPACE, self.XINCLUDE_NAMESPACE):
                    stream.append((kind, data, pos))

            elif kind is START:
                # Record any directive attributes in start tags
                tag, attrs = data
                directives = []
                strip = False

                if tag in self.DIRECTIVE_NAMESPACE:
                    cls = self._dir_by_name.get(tag.localname)
                    if cls is None:
                        raise BadDirectiveError(tag.localname, self.filepath, pos[1])
                    args = dict([(name.localname, value) for name, value in attrs if not name.namespace])
                    directives.append((cls, args, ns_prefix.copy(), pos))
                    strip = True

                new_attrs = []
                for name, value in attrs:
                    if name in self.DIRECTIVE_NAMESPACE:
                        cls = self._dir_by_name.get(name.localname)
                        if cls is None:
                            raise BadDirectiveError(name.localname, self.filepath, pos[1])
                        directives.append((cls, value, ns_prefix.copy(), pos))
                    else:
                        if value:
                            value = list(interpolate(value, self.filepath, pos[1], pos[2], lookup=self.lookup))
                            if len(value) == 1 and value[0][0] is TEXT:
                                value = value[0][1]
                        else:
                            value = [(TEXT, u"", pos)]
                        new_attrs.append((name, value))
                new_attrs = Attrs(new_attrs)

                if directives:
                    index = self._dir_order.index
                    directives.sort(lambda a, b: cmp(index(a[0]), index(b[0])))
                    dirmap[(depth, tag)] = (directives, len(stream), strip)

                if tag in self.XINCLUDE_NAMESPACE:
                    if tag.localname == "include":
                        include_href = new_attrs.get("href")
                        if not include_href:
                            raise TemplateSyntaxError(
                                "Include misses required " 'attribute "href"', self.filepath, *pos[1:]
                            )
                        includes.append((include_href, new_attrs.get("parse")))
                        streams.append([])
                    elif tag.localname == "fallback":
                        streams.append([])
                        fallbacks.append(streams[-1])

                else:
                    stream.append((kind, (tag, new_attrs), pos))

                depth += 1

            elif kind is END:
                depth -= 1

                if fallbacks and data == self.XINCLUDE_NAMESPACE["fallback"]:
                    assert streams.pop() is fallbacks[-1]
                elif data == self.XINCLUDE_NAMESPACE["include"]:
                    fallback = None
                    if len(fallbacks) == len(includes):
                        fallback = fallbacks.pop()
                    streams.pop()  # discard anything between the include tags
                    # and the fallback element
                    stream = streams[-1]
                    href, parse = includes.pop()
                    try:
                        cls = {"xml": MarkupTemplate, "text": NewTextTemplate}[parse or "xml"]
                    except KeyError:
                        raise TemplateSyntaxError(
                            'Invalid value for "parse" ' "attribute of include", self.filepath, *pos[1:]
                        )
                    stream.append((INCLUDE, (href, cls, fallback), pos))
                else:
                    stream.append((kind, data, pos))

                # If there have have directive attributes with the corresponding
                # start tag, move the events inbetween into a "subprogram"
                if (depth, data) in dirmap:
                    directives, start_offset, strip = dirmap.pop((depth, data))
                    substream = stream[start_offset:]
                    if strip:
                        substream = substream[1:-1]
                    stream[start_offset:] = [(SUB, (directives, substream), pos)]

            elif kind is PI and data[0] == "python":
                if not self.allow_exec:
                    raise TemplateSyntaxError("Python code blocks not allowed", self.filepath, *pos[1:])
                try:
                    suite = Suite(data[1], self.filepath, pos[1], lookup=self.lookup)
                except SyntaxError, err:
                    raise TemplateSyntaxError(
                        err, self.filepath, pos[1] + (err.lineno or 1) - 1, pos[2] + (err.offset or 0)
                    )
                stream.append((EXEC, suite, pos))

            elif kind is TEXT:
                for kind, data, pos in interpolate(data, self.filepath, pos[1], pos[2], lookup=self.lookup):
                    stream.append((kind, data, pos))
Exemple #32
0
    def __call__(self, stream, ctxt=None, search_text=True, msgbuf=None):
        """Translate any localizable strings in the given stream.
        
        This function shouldn't be called directly. Instead, an instance of
        the `Translator` class should be registered as a filter with the
        `Template` or the `TemplateLoader`, or applied as a regular stream
        filter. If used as a template filter, it should be inserted in front of
        all the default filters.
        
        :param stream: the markup event stream
        :param ctxt: the template context (not used)
        :param search_text: whether text nodes should be translated (used
                            internally)
        :param msgbuf: a `MessageBuffer` object or `None` (used internally)
        :return: the localized stream
        """
        ignore_tags = self.ignore_tags
        include_attrs = self.include_attrs
        translate = self.translate
        if not self.extract_text:
            search_text = False
        skip = 0
        i18n_msg = I18N_NAMESPACE['msg']
        ns_prefixes = []
        xml_lang = XML_NAMESPACE['lang']

        for kind, data, pos in stream:

            # skip chunks that should not be localized
            if skip:
                if kind is START:
                    skip += 1
                elif kind is END:
                    skip -= 1
                yield kind, data, pos
                continue

            # handle different events that can be localized
            if kind is START:
                tag, attrs = data
                if tag in self.ignore_tags or \
                        isinstance(attrs.get(xml_lang), basestring):
                    skip += 1
                    yield kind, data, pos
                    continue

                new_attrs = []
                changed = False
                for name, value in attrs:
                    newval = value
                    if search_text and isinstance(value, basestring):
                        if name in include_attrs:
                            newval = self.translate(value)
                    else:
                        newval = list(self(_ensure(value), ctxt,
                            search_text=False, msgbuf=msgbuf)
                        )
                    if newval != value:
                        value = newval
                        changed = True
                    new_attrs.append((name, value))
                if changed:
                    attrs = Attrs(new_attrs)

                if msgbuf:
                    msgbuf.append(kind, data, pos)
                    continue
                elif i18n_msg in attrs:
                    params = attrs.get(i18n_msg)
                    if params and type(params) is list: # event tuple
                        params = params[0][1]
                    msgbuf = MessageBuffer(params)
                    attrs -= i18n_msg

                yield kind, (tag, attrs), pos

            elif search_text and kind is TEXT:
                if not msgbuf:
                    text = data.strip()
                    if text:
                        data = data.replace(text, unicode(translate(text)))
                    yield kind, data, pos
                else:
                    msgbuf.append(kind, data, pos)

            elif msgbuf and kind is EXPR:
                msgbuf.append(kind, data, pos)

            elif not skip and msgbuf and kind is END:
                msgbuf.append(kind, data, pos)
                if not msgbuf.depth:
                    for event in msgbuf.translate(translate(msgbuf.format())):
                        yield event
                    msgbuf = None
                    yield kind, data, pos

            elif kind is SUB:
                subkind, substream = data
                new_substream = list(self(substream, ctxt, msgbuf=msgbuf))
                yield kind, (subkind, new_substream), pos

            elif kind is START_NS and data[1] == I18N_NAMESPACE:
                ns_prefixes.append(data[0])

            elif kind is END_NS and data in ns_prefixes:
                ns_prefixes.remove(data)

            else:
                yield kind, data, pos