Skip to content

Commit eb3b416

Browse files
committed
SL-18330: In XML formatter, avoid adding call stack depth.
Making LLSDXMLFormatter._elt() accept a lambda was a tricky way to minimize source changes to existing _elt() calls in _ARRAY() and _MAP(). The trouble is that that added function entries for each level of a deeply-nested LLSD structure -- and with our users, we unfortunately do encounter deeply-nested large inventories. Log observed RecursionError failures in AIS. Explicitly write out the individual sequence of calls in _ARRAY(), _MAP() and the top-level _write(), the only callers to pass lambdas to _elt().
1 parent 8245728 commit eb3b416

File tree

1 file changed

+16
-17
lines changed

1 file changed

+16
-17
lines changed

llsd/serde_xml.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,13 @@ def _elt(self, name, contents=None):
4444
If 'contents' is omitted, write <name/>.
4545
If 'contents' is bytes, write <name>contents</name>.
4646
If 'contents' is str, write <name>contents.encode('utf8')</name>.
47-
If 'contents' is callable, write <name>, call contents(), write </name>.
4847
"""
4948
if not contents:
5049
self.stream.writelines([b"<", name, b" />"])
5150
else:
52-
self.stream.writelines([b"<", name, b">"])
53-
if callable(contents):
54-
contents()
55-
else:
56-
self.stream.write(_str_to_bytes(contents))
57-
self.stream.writelines([b"</", name, b">"])
51+
self.stream.writelines([b"<", name, b">",
52+
_str_to_bytes(contents),
53+
b"</", name, b">"])
5854

5955
def xml_esc(self, v):
6056
"Escape string or unicode object v for xml output"
@@ -100,15 +96,16 @@ def _URI(self, v):
10096
def _DATE(self, v):
10197
return self._elt(b'date', _format_datestr(v))
10298
def _ARRAY(self, v):
103-
return self._elt(
104-
b'array',
105-
lambda: [self._generate(item) for item in v])
99+
self.stream.write(b'<array>')
100+
for item in v:
101+
self._generate(item)
102+
self.stream.write(b'</array>')
106103
def _MAP(self, v):
107-
return self._elt(
108-
b'map',
109-
lambda: [(self._elt(b'key', self.xml_esc(UnicodeType(key))),
110-
self._generate(value))
111-
for key, value in v.items()])
104+
self.stream.write(b'<map>')
105+
for key, value in v.items():
106+
self._elt(b'key', self.xml_esc(UnicodeType(key)))
107+
self._generate(value)
108+
self.stream.write(b'</map>')
112109

113110
def _generate(self, something):
114111
"Generate xml from a single python object."
@@ -127,8 +124,10 @@ def _write(self, something):
127124
128125
:param something: A python object (typically a dict) to be serialized.
129126
"""
130-
self.stream.write(b'<?xml version="1.0" ?>')
131-
self._elt(b"llsd", lambda: self._generate(something))
127+
self.stream.write(b'<?xml version="1.0" ?>'
128+
b'<llsd>')
129+
self._generate(something)
130+
self.stream.write(b'</llsd>')
132131

133132

134133
class LLSDXMLPrettyFormatter(LLSDXMLFormatter):

0 commit comments

Comments
 (0)