Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

json_stream.py 2.1KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import json
  2. import json.decoder
  3. from ..errors import StreamParseError
  4. json_decoder = json.JSONDecoder()
  5. def stream_as_text(stream):
  6. """
  7. Given a stream of bytes or text, if any of the items in the stream
  8. are bytes convert them to text.
  9. This function can be removed once we return text streams
  10. instead of byte streams.
  11. """
  12. for data in stream:
  13. if not isinstance(data, str):
  14. data = data.decode('utf-8', 'replace')
  15. yield data
  16. def json_splitter(buffer):
  17. """Attempt to parse a json object from a buffer. If there is at least one
  18. object, return it and the rest of the buffer, otherwise return None.
  19. """
  20. buffer = buffer.strip()
  21. try:
  22. obj, index = json_decoder.raw_decode(buffer)
  23. rest = buffer[json.decoder.WHITESPACE.match(buffer, index).end():]
  24. return obj, rest
  25. except ValueError:
  26. return None
  27. def json_stream(stream):
  28. """Given a stream of text, return a stream of json objects.
  29. This handles streams which are inconsistently buffered (some entries may
  30. be newline delimited, and others are not).
  31. """
  32. return split_buffer(stream, json_splitter, json_decoder.decode)
  33. def line_splitter(buffer, separator='\n'):
  34. index = buffer.find(str(separator))
  35. if index == -1:
  36. return None
  37. return buffer[:index + 1], buffer[index + 1:]
  38. def split_buffer(stream, splitter=None, decoder=lambda a: a):
  39. """Given a generator which yields strings and a splitter function,
  40. joins all input, splits on the separator and yields each chunk.
  41. Unlike string.split(), each chunk includes the trailing
  42. separator, except for the last one if none was found on the end
  43. of the input.
  44. """
  45. splitter = splitter or line_splitter
  46. buffered = ''
  47. for data in stream_as_text(stream):
  48. buffered += data
  49. while True:
  50. buffer_split = splitter(buffered)
  51. if buffer_split is None:
  52. break
  53. item, buffered = buffer_split
  54. yield item
  55. if buffered:
  56. try:
  57. yield decoder(buffered)
  58. except Exception as e:
  59. raise StreamParseError(e)