Fixed #28324 -- Made feedgenerators write feeds with deterministically ordered attributes.

This commit is contained in:
Georg Sauthoff 2017-02-10 15:29:34 +01:00 committed by Tim Graham
parent 335a8d7895
commit d0f59054d0
3 changed files with 21 additions and 11 deletions

View File

@ -2,7 +2,6 @@
XML serializer.
"""
from collections import OrderedDict
from xml.dom import pulldom
from xml.sax import handler
from xml.sax.expatreader import ExpatParser as _ExpatParser
@ -47,7 +46,7 @@ class Serializer(base.Serializer):
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
self.indent(1)
attrs = OrderedDict([("model", str(obj._meta))])
attrs = {'model': str(obj._meta)}
if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
obj_pk = obj.pk
if obj_pk is not None:
@ -68,10 +67,10 @@ class Serializer(base.Serializer):
ManyToManyFields).
"""
self.indent(2)
self.xml.startElement("field", OrderedDict([
("name", field.name),
("type", field.get_internal_type()),
]))
self.xml.startElement('field', {
'name': field.name,
'type': field.get_internal_type(),
})
# Get a "string version" of the object's data.
if getattr(obj, field.name) is not None:
@ -140,11 +139,11 @@ class Serializer(base.Serializer):
def _start_relational_field(self, field):
"""Output the <field> element for relational fields."""
self.indent(2)
self.xml.startElement("field", OrderedDict([
("name", field.name),
("rel", field.remote_field.__class__.__name__),
("to", str(field.remote_field.model._meta)),
]))
self.xml.startElement('field', {
'name': field.name,
'rel': field.remote_field.__class__.__name__,
'to': str(field.remote_field.model._meta),
})
class Deserializer(base.Deserializer):

View File

@ -3,6 +3,7 @@ Utilities for XML generation/parsing.
"""
import re
from collections import OrderedDict
from xml.sax.saxutils import XMLGenerator
@ -26,3 +27,8 @@ class SimplerXMLGenerator(XMLGenerator):
# See http://www.w3.org/International/questions/qa-controls
raise UnserializableContentError("Control characters are not supported in XML 1.0")
XMLGenerator.characters(self, content)
def startElement(self, name, attrs):
# Sort attrs for a deterministic output.
sorted_attrs = OrderedDict(sorted(attrs.items())) if attrs else attrs
super().startElement(name, sorted_attrs)

View File

@ -126,6 +126,11 @@ class FeedgeneratorTest(unittest.TestCase):
feed.add_item('item_title', 'item_link', 'item_description')
feed.writeString('utf-8')
def test_deterministic_attribute_order(self):
feed = feedgenerator.Atom1Feed('title', '/link/', 'desc')
feed_content = feed.writeString('utf-8')
self.assertIn('href="/link/" rel="alternate"', feed_content)
class FeedgeneratorDBTest(TestCase):