First, the commas.
The nicest solution would be to wrap JsonLinesItemExporter
so that it adds a comma at the end of each item.
If the appropriate method isn't exposed in a way that you can override it, super
it, and add the comma, you may have to reimplement the method in your subclass, or even monkeypatch the exporter class. Less nice.
Alternatively, you can hook the file you pass into the exporter to make writes do a replace('\n', ',\n')
. This is hacky, so I wouldn't do it if you can hook the exporter instead, but it does have the virtue of being simple.
Now, the brackets at start and end of file. Without knowing the library you're using or the way you're using it, this will be pretty vague.
If you're using a single "session" of the exporter per file—that is, you open it at startup, write a bunch of items to it, then close it, and never re-open it and append to it, this is pretty easy. Let's assume you solved the first problem by subclassing the exporter class to hook its writes, something like this:
class JsonArrayExporter(JsonLinesItemExporter):
def _write_bytes(self, encoded_bytes):
encoded_bytes = _encoded_bytes.replace(b'\n', b',\n')
returns super()._write_bytes(encoded_bytes)
I'm guessing at what the implementation looks like, but you've already discovered the right thing to do, so you should be able to translate from my guess to reality. Now, you need to add two methods like this:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._writebytes(b'[\n')
def close(self):
if not self.closed():
self._writebytes(b']\n')
super().close()
You may need a flush
somewhere before the _writebytes
if the exporter class has its own buffer inside it, but that's the only extra complexity I'd expect to see.
If you're reopening files and appending to them in each session, this obviously won't work. You could do something like this pseudocode in __init__
:
if file is empty:
write('[\n')
else:
seek to end of file
if last two bytes are ']\n':
seek back 2 bytes
That has the advantage of being transparent to your client code, but it's a bit hacky. If your client code knows when it's opening a new file rather than appending to an old one, and knows when it's finishing off a file for good, it's probably cleaner to add addStartMarker
and addEndMarker
methods and call those, or just have the client manually write the brackets to the file before initializing/after closing the exporter.