Skip to content

Commit

Permalink
Implement JSONWriter to write files of records as an array of MARC-in…
Browse files Browse the repository at this point in the history
…-JSON objects.
  • Loading branch information
jimnicholls committed Sep 6, 2015
1 parent 780ff5a commit 699e63a
Show file tree
Hide file tree
Showing 2 changed files with 313 additions and 1 deletion.
72 changes: 72 additions & 0 deletions pymarc/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
except ImportError:
import elementtree.ElementTree as ET

try:
# the json module was included in the stdlib in python 2.6
# http://docs.python.org/library/json.html
import json
except ImportError:
# simplejson 2.0.9 is available for python 2.4+
# http://pypi.python.org/pypi/simplejson/2.0.9
# simplejson 1.7.3 is available for python 2.3+
# http://pypi.python.org/pypi/simplejson/1.7.3
import simplejson as json


class Writer(object):

Expand All @@ -16,6 +27,67 @@ def close(self):
pass


class JSONWriter(Writer):
"""
A class for writing records as an array of MARC-in-JSON objects.
IMPORTANT: You must the close a JSONWriter,
otherwise you will not get valid JSON.
Simple usage:
from pymarc import JSONWriter
## pass in a file
writer = JSONWriter(open('file.xml','wt'))
writer.write(record)
writer.close()
## use StringIO if you want to write to a string
string = StringIO()
writer = JSONWriter(string, own_file_handle = False)
writer.write(record)
writer.close()
print string
"""

def __init__(self, file_handle, own_file_handle = True):
"""
You need to pass in a text file like object.
If own_file_handle is True (the default) then the file handle will be
closed when the writer is closed. Otherwise the file handle will be
left open.
"""
super(JSONWriter, self).__init__()
self.file_handle = file_handle
self.own_file_handle = own_file_handle
self.write_count = 0
self.file_handle.write('[')

def write(self, record):
"""
Writes a record.
"""
if not isinstance(record, Record):
raise WriteNeedsRecord
if self.write_count > 0:
self.file_handle.write(',')
json.dump(record.as_dict(), self.file_handle, separators=(',', ':'))
self.write_count += 1

def close(self):
"""
Closes the file.
If own_file_handle is True, also closes the file handle.
"""
self.file_handle.write(']')
if self.own_file_handle:
self.file_handle.close()
self.file_handle = None


class MARCWriter(Writer):
"""
A class for writing MARC21 records in transmission format.
Expand Down
242 changes: 241 additions & 1 deletion test/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,245 @@
import textwrap
from six import BytesIO, StringIO, u, binary_type

try:
# the json module was included in the stdlib in python 2.6
# http://docs.python.org/library/json.html
import json
except ImportError:
# simplejson 2.0.9 is available for python 2.4+
# http://pypi.python.org/pypi/simplejson/2.0.9
# simplejson 1.7.3 is available for python 2.3+
# http://pypi.python.org/pypi/simplejson/1.7.3
import simplejson as json


class JSONWriterTest(unittest.TestCase):

def test_own_file_handle_true(self):
"""
If a JSONWriter is created with own_file_handle = True, then when the
JSONWriter is closed the file handle is also closed.
"""
file_handle = StringIO()
self.assertFalse(
file_handle.closed,
'The file handle should be open')
writer = pymarc.JSONWriter(file_handle, own_file_handle = True)
self.assertFalse(
file_handle.closed,
'The file handle should still be open')
writer.close()
self.assertTrue(
file_handle.closed,
'The file handle should close when the writer closes')

def test_own_file_handle_false(self):
"""
If a JSONWriter is created with own_file_handle = False, then when the
JSONWriter is closed the file handle is NOT also closed.
"""
file_handle = StringIO()
self.assertFalse(
file_handle.closed,
'The file handle should be open')
writer = pymarc.JSONWriter(file_handle, own_file_handle = False)
self.assertFalse(
file_handle.closed,
'The file handle should still be open')
writer.close()
self.assertFalse(
file_handle.closed,
'The file handle should NOT close when the writer closes')

def test_writing_0_records(self):
expected = json.loads(r"""
[]
""")
file_handle = StringIO()
try:
writer = pymarc.JSONWriter(file_handle, own_file_handle = False)
writer.close()
actual = json.loads(file_handle.getvalue())
self.assertEquals(actual, expected)
finally:
file_handle.close()

def test_writing_empty_record(self):
expected = json.loads(r"""
[
{
"leader" : " 22 4500",
"fields" : []
}
]
""")
file_handle = StringIO()
try:
writer = pymarc.JSONWriter(file_handle, own_file_handle = False)
record = pymarc.Record()
writer.write(record)
writer.close()
actual = json.loads(file_handle.getvalue())
self.assertEquals(actual, expected)
finally:
file_handle.close()

def test_writing_1_record(self):
expected = json.loads(r"""
[
{
"leader" : " 22 4500",
"fields" : [
{
"100": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "me" }
]
}
},
{
"245": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "Foo /" },
{ "c": "by me." }
]
}
}
]
}
]
""")
file_handle = StringIO()
try:
writer = pymarc.JSONWriter(file_handle, own_file_handle = False)
record = pymarc.Record()
record.add_field(
pymarc.Field('100', ['0', '0'], ['a', u('me')]))
record.add_field(
pymarc.Field(
'245',
['0', '0'],
['a', u('Foo /'), 'c', u('by me.')]))
writer.write(record)
writer.close()
actual = json.loads(file_handle.getvalue())
self.assertEquals(actual, expected)
finally:
file_handle.close()

def test_writing_3_records(self):
expected = json.loads(r"""
[
{
"leader" : " 22 4500",
"fields" : [
{
"008": "090227s2009 mau chi d"
},
{
"100": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "me" }
]
}
},
{
"245": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "Foo /" },
{ "c": "by me." }
]
}
}
]
},
{
"leader" : " 22 4500",
"fields" : [
{
"100": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "me" }
]
}
},
{
"245": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "Foo /" },
{ "c": "by me." }
]
}
}
]
},
{
"leader" : " 22 4500",
"fields" : [
{
"245": {
"ind1": "0",
"ind2": "0",
"subfields": [
{ "a": "Foo /" },
{ "c": "by me." }
]
}
}
]
}
]
""")
file_handle = StringIO()
try:
writer = pymarc.JSONWriter(file_handle, own_file_handle = False)
record = pymarc.Record()
record.add_field(
pymarc.Field(
'008',
data=u('090227s2009 mau chi d')))
record.add_field(
pymarc.Field('100', ['0', '0'], ['a', u('me')]))
record.add_field(
pymarc.Field(
'245',
['0', '0'],
['a', u('Foo /'), 'c', u('by me.')]))
writer.write(record)
record = pymarc.Record()
record.add_field(
pymarc.Field('100', ['0', '0'], ['a', u('me')]))
record.add_field(
pymarc.Field(
'245',
['0', '0'],
['a', u('Foo /'), 'c', u('by me.')]))
writer.write(record)
record = pymarc.Record()
record.add_field(
pymarc.Field(
'245',
['0', '0'],
['a', u('Foo /'), 'c', u('by me.')]))
writer.write(record)
writer.close()
actual = json.loads(file_handle.getvalue())
self.assertEquals(actual, expected)
finally:
file_handle.close()


class MARCWriterTest(unittest.TestCase):

Expand Down Expand Up @@ -396,10 +635,11 @@ def test_own_file_handle_false(self):


def suite():
json_suite = unittest.makeSuite(JSONWriterTest, 'test')
marc_suite = unittest.makeSuite(MARCWriterTest, 'test')
text_suite = unittest.makeSuite(TextWriterTest, 'test')
xml_suite = unittest.makeSuite(XMLWriterTest, 'test')
test_suite = unittest.TestSuite((marc_suite, text_suite, xml_suite))
test_suite = unittest.TestSuite((json_suite, marc_suite, text_suite, xml_suite))
return test_suite

if __name__ == '__main__':
Expand Down

0 comments on commit 699e63a

Please sign in to comment.