Przeglądaj źródła

json_splitter: Don't break when buffer contains leading whitespace.

Add error logging with detailed output for decode errors

Signed-off-by: Joffrey F <[email protected]>
Joffrey F 9 lat temu
rodzic
commit
6f4be1cffc
2 zmienionych plików z 28 dodań i 1 usunięć
  1. 11 1
      compose/utils.py
  2. 17 0
      tests/unit/utils_test.py

+ 11 - 1
compose/utils.py

@@ -5,11 +5,13 @@ import codecs
 import hashlib
 import json
 import json.decoder
+import logging
 
 import six
 
 
 json_decoder = json.JSONDecoder()
+log = logging.getLogger(__name__)
 
 
 def get_output_stream(stream):
@@ -60,13 +62,21 @@ def split_buffer(stream, splitter=None, decoder=lambda a: a):
             yield item
 
     if buffered:
-        yield decoder(buffered)
+        try:
+            yield decoder(buffered)
+        except ValueError:
+            log.error(
+                'Compose tried parsing the following chunk as a JSON object, '
+                'but failed:\n%s' % repr(buffered)
+            )
+            raise
 
 
 def json_splitter(buffer):
     """Attempt to parse a json object from a buffer. If there is at least one
     object, return it and the rest of the buffer, otherwise return None.
     """
+    buffer = buffer.strip()
     try:
         obj, index = json_decoder.raw_decode(buffer)
         rest = buffer[json.decoder.WHITESPACE.match(buffer, index).end():]

+ 17 - 0
tests/unit/utils_test.py

@@ -15,6 +15,10 @@ class TestJsonSplitter(object):
         data = '{"foo": "bar"}\n  \n{"next": "obj"}'
         assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
 
+    def test_json_splitter_leading_whitespace(self):
+        data = '\n   \r{"foo": "bar"}\n\n   {"next": "obj"}'
+        assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
+
 
 class TestStreamAsText(object):
 
@@ -43,3 +47,16 @@ class TestJsonStream(object):
             [1, 2, 3],
             [],
         ]
+
+    def test_with_leading_whitespace(self):
+        stream = [
+            '\n  \r\n  {"one": "two"}{"x": 1}',
+            '  {"three": "four"}\t\t{"x": 2}'
+        ]
+        output = list(utils.json_stream(stream))
+        assert output == [
+            {'one': 'two'},
+            {'x': 1},
+            {'three': 'four'},
+            {'x': 2}
+        ]