]> Devi Nivas Git - chevron.git/commitdiff
Allow field access for namedtuple in Python 3
authorThomas Hebb <tommyhebb@gmail.com>
Sat, 23 May 2020 03:24:22 +0000 (23:24 -0400)
committerThomas Hebb <tommyhebb@gmail.com>
Sat, 23 May 2020 03:35:27 +0000 (23:35 -0400)
`namedtuple` in Python 3 does not provide a `__dict__` attribute. See
https://bugs.python.org/issue24931 for rationale why. As such, if we
want to render keys in `namedtuple`s, we need to use its [`_asdict`][1]
method.

[1]: https://docs.python.org/3/library/collections.html#collections.somenamedtuple._asdict

chevron/renderer.py
test_spec.py

index 99415da97fbea56901e1fc7900d16b77c2e24680..dfc2a40f73e1007cf37d09396302464c215f3cbd 100644 (file)
@@ -66,11 +66,16 @@ def _get_key(key, scopes):
                     scope = scope[child]
                 except (TypeError, AttributeError):
                     try:
-                        # Try the dictionary (Complex types)
-                        scope = scope.__dict__[child]
+                        # Try namedtuple (which does not have __dict__ in
+                        # Python 3: https://bugs.python.org/issue24931)
+                        scope = scope._asdict()[child]
                     except (TypeError, AttributeError):
-                        # Try as a list
-                        scope = scope[int(child)]
+                        try:
+                            # Try the dictionary (Complex types)
+                            scope = scope.__dict__[child]
+                        except (TypeError, AttributeError):
+                            # Try as a list
+                            scope = scope[int(child)]
 
             # Return an empty string if falsy, with two exceptions
             # 0 should return 0, and False should return False
index 56bdea6bc4b8a5abb6b38cd41098cf2ef54c5576..d064ffe367552c581b88982d4b857b1a5cc117f0 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
+import collections
 import unittest
 import os
 import json
@@ -435,6 +436,18 @@ class ExpandedCoverage(unittest.TestCase):
 
         self.assertEqual(result, expected)
 
+    def test_namedtuple_data(self):
+        NT = collections.namedtuple('NT', ['foo', 'bar'])
+        args = {
+            'template': '{{foo}} {{bar}}',
+            'data': NT('hello', 'world')
+        }
+
+        result = chevron.render(**args)
+        expected = 'hello world'
+
+        self.assertEqual(result, expected)
+
 
 # Run unit tests from command line
 if __name__ == "__main__":