Kaydet (Commit) d0f59054 authored tarafından Georg Sauthoff's avatar Georg Sauthoff Kaydeden (comit) Tim Graham

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

üst 335a8d78
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
XML serializer. XML serializer.
""" """
from collections import OrderedDict
from xml.dom import pulldom from xml.dom import pulldom
from xml.sax import handler from xml.sax import handler
from xml.sax.expatreader import ExpatParser as _ExpatParser from xml.sax.expatreader import ExpatParser as _ExpatParser
...@@ -47,7 +46,7 @@ class Serializer(base.Serializer): ...@@ -47,7 +46,7 @@ class Serializer(base.Serializer):
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj)) raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
self.indent(1) 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'): if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
obj_pk = obj.pk obj_pk = obj.pk
if obj_pk is not None: if obj_pk is not None:
...@@ -68,10 +67,10 @@ class Serializer(base.Serializer): ...@@ -68,10 +67,10 @@ class Serializer(base.Serializer):
ManyToManyFields). ManyToManyFields).
""" """
self.indent(2) self.indent(2)
self.xml.startElement("field", OrderedDict([ self.xml.startElement('field', {
("name", field.name), 'name': field.name,
("type", field.get_internal_type()), 'type': field.get_internal_type(),
])) })
# Get a "string version" of the object's data. # Get a "string version" of the object's data.
if getattr(obj, field.name) is not None: if getattr(obj, field.name) is not None:
...@@ -140,11 +139,11 @@ class Serializer(base.Serializer): ...@@ -140,11 +139,11 @@ class Serializer(base.Serializer):
def _start_relational_field(self, field): def _start_relational_field(self, field):
"""Output the <field> element for relational fields.""" """Output the <field> element for relational fields."""
self.indent(2) self.indent(2)
self.xml.startElement("field", OrderedDict([ self.xml.startElement('field', {
("name", field.name), 'name': field.name,
("rel", field.remote_field.__class__.__name__), 'rel': field.remote_field.__class__.__name__,
("to", str(field.remote_field.model._meta)), 'to': str(field.remote_field.model._meta),
])) })
class Deserializer(base.Deserializer): class Deserializer(base.Deserializer):
......
...@@ -3,6 +3,7 @@ Utilities for XML generation/parsing. ...@@ -3,6 +3,7 @@ Utilities for XML generation/parsing.
""" """
import re import re
from collections import OrderedDict
from xml.sax.saxutils import XMLGenerator from xml.sax.saxutils import XMLGenerator
...@@ -26,3 +27,8 @@ class SimplerXMLGenerator(XMLGenerator): ...@@ -26,3 +27,8 @@ class SimplerXMLGenerator(XMLGenerator):
# See http://www.w3.org/International/questions/qa-controls # See http://www.w3.org/International/questions/qa-controls
raise UnserializableContentError("Control characters are not supported in XML 1.0") raise UnserializableContentError("Control characters are not supported in XML 1.0")
XMLGenerator.characters(self, content) 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)
...@@ -126,6 +126,11 @@ class FeedgeneratorTest(unittest.TestCase): ...@@ -126,6 +126,11 @@ class FeedgeneratorTest(unittest.TestCase):
feed.add_item('item_title', 'item_link', 'item_description') feed.add_item('item_title', 'item_link', 'item_description')
feed.writeString('utf-8') 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): class FeedgeneratorDBTest(TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment