[PATCH] formatter: allow json to handle more levels of depth

Kostia Balytskyi ikostia at fb.com
Fri Mar 4 14:14:24 UTC 2016


# HG changeset patch
# User Kostia Balytskyi <ikostia at fb.com>
# Date 1457099048 28800
#      Fri Mar 04 05:44:08 2016 -0800
# Node ID 0d64a8a89cb33fb677047e3b9357389b52015294
# Parent  4f7a5e4f2daff0a65aa470d9f70365ad55aaa100
formatter: allow json to handle more levels of depth

Only the topmost level gets pretty-printed, further ones
are printed on the same line. I feel this is good since
humans reading json output will have better separation
between items.

Sample output looks somewhat like this:
```
$ ./hg tf
[
 {
  "l1": {"l2": [1, 2]}
 }
]
```

achieved through the following formatter use
```
@command('tf', [] + formatteropts)
def tf(ui, repo, **opts):
    obj = {'l1': {'l2': [1,2]}}
    fm = ui.formatter('tf', {'template': 'json'})
    fm.startitem()
    fm.data(l1=obj['l1'])
    fm.end()
```

diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -109,8 +109,22 @@ class pickleformatter(baseformatter):
         baseformatter.end(self)
         self._ui.write(cPickle.dumps(self._data))
 
+def _getjsonbody(obj, sep=',', indent=''):
+    r = []
+    first = True
+    for key, val in sorted(obj.items()):
+        if first:
+            first = False
+        else:
+            r.append(sep)
+        r.append(indent)
+        r.append('"%s": %s' % (key, _jsonifyobj(val)))
+    return ''.join(r)
+
 def _jsonifyobj(v):
-    if isinstance(v, tuple):
+    if isinstance(v, dict):
+        return '{' + _getjsonbody(v) + '}'
+    elif isinstance(v, tuple) or isinstance(v, list):
         return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']'
     elif v is None:
         return 'null'
@@ -133,16 +147,8 @@ class jsonformatter(baseformatter):
             self._ui._first = False
         else:
             self._ui.write(",")
-
-        self._ui.write("\n {\n")
-        first = True
-        for k, v in sorted(self._item.items()):
-            if first:
-                first = False
-            else:
-                self._ui.write(",\n")
-            self._ui.write('  "%s": %s' % (k, _jsonifyobj(v)))
-        self._ui.write("\n }")
+        body = _getjsonbody(self._item, sep=",\n", indent='  ')
+        self._ui.write("\n {\n" + body + "\n }")
     def end(self):
         baseformatter.end(self)
         self._ui.write("\n]\n")


More information about the Mercurial-devel mailing list