浏览代码

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 年之前
父节点
当前提交
6f4be1cffc
共有 2 个文件被更改,包括 28 次插入1 次删除
  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 hashlib
 import json
 import json
 import json.decoder
 import json.decoder
+import logging
 
 
 import six
 import six
 
 
 
 
 json_decoder = json.JSONDecoder()
 json_decoder = json.JSONDecoder()
+log = logging.getLogger(__name__)
 
 
 
 
 def get_output_stream(stream):
 def get_output_stream(stream):
@@ -60,13 +62,21 @@ def split_buffer(stream, splitter=None, decoder=lambda a: a):
             yield item
             yield item
 
 
     if buffered:
     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):
 def json_splitter(buffer):
     """Attempt to parse a json object from a buffer. If there is at least one
     """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.
     object, return it and the rest of the buffer, otherwise return None.
     """
     """
+    buffer = buffer.strip()
     try:
     try:
         obj, index = json_decoder.raw_decode(buffer)
         obj, index = json_decoder.raw_decode(buffer)
         rest = buffer[json.decoder.WHITESPACE.match(buffer, index).end():]
         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"}'
         data = '{"foo": "bar"}\n  \n{"next": "obj"}'
         assert utils.json_splitter(data) == ({'foo': 'bar'}, '{"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):
 class TestStreamAsText(object):
 
 
@@ -43,3 +47,16 @@ class TestJsonStream(object):
             [1, 2, 3],
             [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}
+        ]