"""
EDS-JSON serialization and deserialization.
"""
import json
from pathlib import Path
from delphin.eds import EDS, Node
from delphin.lnk import Lnk
CODEC_INFO = {
'representation': 'eds',
}
HEADER = '['
JOINER = ','
FOOTER = ']'
[docs]
def load(source):
"""
Deserialize a EDS-JSON file (handle or filename) to EDS objects
Args:
source: filename or file object
Returns:
a list of EDS objects
"""
if hasattr(source, 'read'):
data = json.load(source)
else:
source = Path(source).expanduser()
with source.open() as fh:
data = json.load(fh)
return [from_dict(d) for d in data]
[docs]
def loads(s):
"""
Deserialize a EDS-JSON string to EDS objects
Args:
s (str): a EDS-JSON string
Returns:
a list of EDS objects
"""
data = json.loads(s)
return [from_dict(d) for d in data]
[docs]
def dump(es, destination, properties=True, lnk=True,
indent=False, encoding='utf-8'):
"""
Serialize EDS objects to a EDS-JSON file.
Args:
destination: filename or file object
es: iterator of :class:`~delphin.eds.EDS` objects to
serialize
properties: if `True`, encode variable properties
lnk: if `False`, suppress surface alignments and strings
indent: if `True`, adaptively indent; if `False` or `None`,
don't indent; if a non-negative integer N, indent N spaces
per level
encoding (str): if *destination* is a filename, write to the
file with the given encoding; otherwise it is ignored
"""
if indent is False:
indent = None
elif indent is True:
indent = 2
data = [to_dict(e, properties=properties, lnk=lnk)
for e in es]
if hasattr(destination, 'write'):
json.dump(data, destination, indent=indent)
else:
destination = Path(destination).expanduser()
with open(destination, 'w', encoding=encoding) as fh:
json.dump(data, fh)
[docs]
def dumps(es, properties=True, lnk=True, indent=False):
"""
Serialize EDS objects to a EDS-JSON string.
Args:
es: iterator of :class:`~delphin.eds.EDS` objects to
serialize
properties: if `True`, encode variable properties
lnk: if `False`, suppress surface alignments and strings
indent: if `True`, adaptively indent; if `False` or `None`,
don't indent; if a non-negative integer N, indent N spaces
per level
Returns:
a EDS-JSON-serialization of the EDS objects
"""
if indent is False:
indent = None
elif indent is True:
indent = 2
data = [to_dict(e, properties=properties, lnk=lnk)
for e in es]
return json.dumps(data, indent=indent)
[docs]
def decode(s):
"""
Deserialize a EDS object from a EDS-JSON string.
"""
return from_dict(json.loads(s))
[docs]
def encode(eds, properties=True, lnk=True, indent=False):
"""
Serialize a EDS object to a EDS-JSON string.
Args:
e: a EDS object
properties (bool): if `False`, suppress variable properties
lnk: if `False`, suppress surface alignments and strings
indent (bool, int): if `True` or an integer value, add
newlines and indentation
Returns:
a EDS-JSON-serialization of the EDS object
"""
if indent is False:
indent = None
elif indent is True:
indent = 2
d = to_dict(eds, properties=properties, lnk=lnk)
return json.dumps(d, indent=indent)
[docs]
def to_dict(eds, properties=True, lnk=True):
"""
Encode the EDS as a dictionary suitable for JSON serialization.
"""
nodes = {}
for node in eds.nodes:
nd = {
'label': node.predicate,
'edges': node.edges
}
if lnk and node.lnk is not None:
nd['lnk'] = {'from': node.cfrom, 'to': node.cto}
if node.type is not None:
nd['type'] = node.type
if properties:
props = node.properties
if props:
nd['properties'] = props
if node.carg is not None:
nd['carg'] = node.carg
nodes[node.id] = nd
return {'top': eds.top, 'nodes': nodes}
[docs]
def from_dict(d):
"""
Decode a dictionary, as from :func:`to_dict`, into an EDS object.
"""
top = d.get('top')
nodes = []
for nodeid, node in d.get('nodes', {}).items():
props = node.get('properties', None)
nodetype = node.get('type')
lnk = None
if 'lnk' in node:
lnk = Lnk.charspan(node['lnk']['from'], node['lnk']['to'])
nodes.append(
Node(id=nodeid,
predicate=node['label'],
type=nodetype,
edges=node.get('edges', {}),
properties=props,
carg=node.get('carg'),
lnk=lnk))
nodes.sort(key=lambda n: (n.cfrom, -n.cto))
return EDS(top, nodes=nodes)