# HG changeset patch
# User cmlenz
# Date 1212269656 0
# Node ID a424b2443e11175441843306a65c877c403a7f5e
# Parent 1447d40df660dca2123b1dd833394589c5131951
Fix for potential duplicate attributes making it through the builder API. Closes #216.
diff --git a/genshi/builder.py b/genshi/builder.py
--- a/genshi/builder.py
+++ b/genshi/builder.py
@@ -68,6 +68,11 @@
Hello, world!
"""
+try:
+ set
+except NameError:
+ from sets import Set as set
+
from genshi.core import Attrs, Namespace, QName, Stream, START, END, TEXT
__all__ = ['Fragment', 'Element', 'ElementFactory', 'tag']
@@ -146,14 +151,13 @@
return Stream(self._generate())
-def _value_to_unicode(value):
- if isinstance(value, unicode):
- return value
- return unicode(value)
-
def _kwargs_to_attrs(kwargs):
- return [(QName(k.rstrip('_').replace('_', '-')), _value_to_unicode(v))
- for k, v in kwargs.items() if v is not None]
+ retval = {}
+ for name, value in kwargs.items():
+ name = name.rstrip('_').replace('_', '-')
+ if value is not None and name not in retval:
+ retval[QName(name)] = unicode(value)
+ return Attrs(retval.items())
class Element(Fragment):
@@ -240,7 +244,7 @@
def __init__(self, tag_, **attrib):
Fragment.__init__(self)
self.tag = QName(tag_)
- self.attrib = Attrs(_kwargs_to_attrs(attrib))
+ self.attrib = _kwargs_to_attrs(attrib)
def __call__(self, *args, **kwargs):
"""Append any positional arguments as child nodes, and keyword arguments
@@ -250,7 +254,7 @@
:rtype: `Element`
:see: `Fragment.append`
"""
- self.attrib |= Attrs(_kwargs_to_attrs(kwargs))
+ self.attrib |= _kwargs_to_attrs(kwargs)
Fragment.__call__(self, *args)
return self
diff --git a/genshi/tests/builder.py b/genshi/tests/builder.py
--- a/genshi/tests/builder.py
+++ b/genshi/tests/builder.py
@@ -42,6 +42,15 @@
(None, -1, -1)),
event)
+ 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())
+
def test_stream_as_child(self):
xml = list(tag.span(XML('Foo')).generate())
self.assertEqual(5, len(xml))