diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 538106e..8ad9b57 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -60,6 +60,8 @@ jobs:
name: Publish to PyPI
needs: build
runs-on: [ubuntu-latest]
+ permissions:
+ id-token: write
if: github.event_name != 'pull_request'
steps:
- uses: actions/download-artifact@v3
@@ -73,11 +75,8 @@ jobs:
- name: Test Publish package
uses: pypa/gh-action-pypi-publish@release/v1
with:
- password: ${{ secrets.SHARED_PYPI_TEST_TOKEN }}
- repository_url: https://test.pypi.org/legacy/
+ repository-url: https://test.pypi.org/legacy/
- name: Publish package
uses: pypa/gh-action-pypi-publish@release/v1
if: startsWith(github.event.ref, 'refs/tags/v')
- with:
- password: ${{ secrets.SHARED_PYPI_TOKEN }}
diff --git a/llsd/serde_xml.py b/llsd/serde_xml.py
index 99d39b8..7dfeaa2 100644
--- a/llsd/serde_xml.py
+++ b/llsd/serde_xml.py
@@ -44,17 +44,13 @@ def _elt(self, name, contents=None):
If 'contents' is omitted, write .
If 'contents' is bytes, write contents.
If 'contents' is str, write contents.encode('utf8').
- If 'contents' is callable, write , call contents(), write .
"""
if not contents:
self.stream.writelines([b"<", name, b" />"])
else:
- self.stream.writelines([b"<", name, b">"])
- if callable(contents):
- contents()
- else:
- self.stream.write(_str_to_bytes(contents))
- self.stream.writelines([b"", name, b">"])
+ self.stream.writelines([b"<", name, b">",
+ _str_to_bytes(contents),
+ b"", name, b">"])
def xml_esc(self, v):
"Escape string or unicode object v for xml output"
@@ -100,15 +96,16 @@ def _URI(self, v):
def _DATE(self, v):
return self._elt(b'date', _format_datestr(v))
def _ARRAY(self, v):
- return self._elt(
- b'array',
- lambda: [self._generate(item) for item in v])
+ self.stream.write(b'')
+ for item in v:
+ self._generate(item)
+ self.stream.write(b'')
def _MAP(self, v):
- return self._elt(
- b'map',
- lambda: [(self._elt(b'key', self.xml_esc(UnicodeType(key))),
- self._generate(value))
- for key, value in v.items()])
+ self.stream.write(b'')
def _generate(self, something):
"Generate xml from a single python object."
@@ -127,8 +124,10 @@ def _write(self, something):
:param something: A python object (typically a dict) to be serialized.
"""
- self.stream.write(b'')
- self._elt(b"llsd", lambda: self._generate(something))
+ self.stream.write(b''
+ b'')
+ self._generate(something)
+ self.stream.write(b'')
class LLSDXMLPrettyFormatter(LLSDXMLFormatter):
diff --git a/tests/llsd_test.py b/tests/llsd_test.py
index 6691c1c..46f64fe 100644
--- a/tests/llsd_test.py
+++ b/tests/llsd_test.py
@@ -1345,6 +1345,20 @@ def testMap(self):
map_within_map_xml)
self.assertXMLRoundtrip({}, blank_map_xml)
+ def testDeepMap(self):
+ """
+ Test that formatting a deeply nested map does not cause a RecursionError
+ """
+
+ test_map = {"foo":"bar", "depth":0, "next":None}
+ max_depth = 200
+ for depth in range(max_depth):
+ test_map = {"foo":"bar", "depth":depth, "next":test_map}
+
+ # this should not throw an exception.
+ test_xml = self.llsd.as_xml(test_map)
+
+
def testBinary(self):
"""
Test the parse and serialization of input type : binary.