Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/hsd/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@
"""


class HsdException(Exception):
class HsdError(Exception):
"""Base class for exceptions in the HSD package."""


class HsdParserError(HsdException):
"""Base class for parser related errors."""


def unquote(txt):
"""Giving string without quotes if enclosed in those."""
if len(txt) >= 2 and (txt[0] in "\"'") and txt[-1] == txt[0]:
Expand Down
61 changes: 39 additions & 22 deletions src/hsd/dictbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Contains an event-driven builder for dictionary based (JSON-like) structure
"""
import re
from .common import ATTRIB_SUFFIX, HSD_ATTRIB_SUFFIX
from .common import ATTRIB_SUFFIX, HSD_ATTRIB_SUFFIX, HsdError
from .eventhandler import HsdEventHandler


Expand Down Expand Up @@ -40,9 +40,9 @@ def __init__(self, flatten_data: bool = False,
include_hsd_attribs: bool = False):
super().__init__()
self._hsddict = {}
self._curblock = self._hsddict
self._content = self._hsddict # Content obtained for the current node
self._parentblocks = []
self._data = None
self._attribs = []
self._flatten_data = flatten_data
self._include_hsd_attribs = include_hsd_attribs

Expand All @@ -54,34 +54,51 @@ def hsddict(self):


def open_tag(self, tagname, attrib, hsdattrib):
if attrib is not None:
self._curblock[tagname + ATTRIB_SUFFIX] = attrib
if self._include_hsd_attribs and hsdattrib is not None:
self._curblock[tagname + HSD_ATTRIB_SUFFIX] = hsdattrib
self._parentblocks.append(self._curblock)
self._curblock = {}
self._attribs.append((attrib, hsdattrib))
content = {} if self._content is None else self._content
self._parentblocks.append(content)
self._content = None


def close_tag(self, tagname):
attrib, hsdattrib = self._attribs.pop(-1)
parentblock = self._parentblocks.pop(-1)
prevcontent = parentblock.get(tagname)
if prevcontent is not None and not isinstance(prevcontent, list):
prevcontent = [prevcontent]
parentblock[tagname] = prevcontent
if self._data is None:
content = self._curblock
else:
content = self._data
self._data = None
if prevcontent is None:
prevcont = parentblock.get(tagname)
if prevcont is not None:
if isinstance(prevcont, dict) and isinstance(self._content, dict):
prevcont = [prevcont]
parentblock[tagname] = prevcont
elif not (isinstance(prevcont, list)
and isinstance(prevcont[0], dict)):
msg = f"Invalid duplicate occurance of node '{tagname}'"
raise HsdError(msg)
content = {} if self._content is None else self._content
if prevcont is None:
parentblock[tagname] = content
if attrib:
parentblock[tagname + ATTRIB_SUFFIX] = attrib
if self._include_hsd_attribs:
parentblock[tagname + HSD_ATTRIB_SUFFIX] = hsdattrib
else:
prevcontent.append(content)
self._curblock = parentblock
prevcont.append(content)
prevattrib = parentblock.get(tagname + ATTRIB_SUFFIX)
if not (prevattrib is None and attrib is None):
msg = f"Duplicate node '{tagname}' should not carry attributes"
if self._include_hsd_attribs:
prevhsdattrib = parentblock.get(tagname + HSD_ATTRIB_SUFFIX)
if isinstance(prevhsdattrib, list):
prevhsdattrib.append(hsdattrib)
else:
parentblock[tagname + HSD_ATTRIB_SUFFIX] = [prevhsdattrib,
hsdattrib]
self._content = parentblock


def add_text(self, text):
self._data = self._text_to_data(text)
if self._content is not None:
msg = f"Data appeared in an invalid context"
raise HsdError(msg)
self._content = self._text_to_data(text)


def _text_to_data(self, txt):
Expand Down
11 changes: 7 additions & 4 deletions src/hsd/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,11 @@ def _dump_dict(obj, fobj, indentstr, use_hsd_attribs):
else:
attribstr = " [" + attrib + "]"
if use_hsd_attribs:
hsdattribs = obj.get(key + HSD_ATTRIB_SUFFIX)
if hsdattribs is not None:
key = hsdattribs.get("tag", key)
hsdattrib = obj.get(key + HSD_ATTRIB_SUFFIX)
else:
hsdattrib = None
if isinstance(value, dict):
key = hsdattrib.get("tag", key) if hsdattrib else key
if value:
fobj.write("{}{}{} {{\n".format(indentstr, key, attribstr))
_dump_dict(
Expand All @@ -235,12 +236,14 @@ def _dump_dict(obj, fobj, indentstr, use_hsd_attribs):
else:
fobj.write("{}{}{} {{}}\n".format(indentstr, key, attribstr))
elif isinstance(value, list) and value and isinstance(value[0], dict):
for item in value:
for ind, item in enumerate(value):
key = hsdattrib[ind].get("tag", key) if hsdattrib else key
fobj.write("{}{}{} {{\n".format(indentstr, key, attribstr))
_dump_dict(
item, fobj, indentstr + _INDENT_STR, use_hsd_attribs)
fobj.write("{}}}\n".format(indentstr))
else:
key = hsdattrib.get("tag", key) if hsdattrib else key
valstr = _get_hsd_rhs(value, indentstr)
fobj.write("{}{}{} {}\n"\
.format(indentstr, key, attribstr, valstr))
Expand Down
2 changes: 1 addition & 1 deletion src/hsd/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def _error(self, errorcode, lines):
error_msg = (
"Parsing error ({}) between lines {} - {} in file '{}'.".format(
errorcode, lines[0] + 1, lines[1] + 1, self._fname))
raise common.HsdParserError(error_msg)
raise common.HsdError(error_msg)



Expand Down
2 changes: 1 addition & 1 deletion test/test.hsd
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Analysis {
Atoms = 1 2 3
Label = "region1"
}
Region {
REgion {
Atoms = 1 2 3
Label = "region2"
}
Expand Down
6 changes: 3 additions & 3 deletions test/test_dictbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ def test_dictbuilder():


def test_dictbuilder_flat():
dictbuilder = hsd.HsdDictBuilder(flatten_data=True)
parser = hsd.HsdParser(eventhandler=dictbuilder)
dictbuilder = hsd.HsdDictBuilder(flatten_data=True, include_hsd_attribs=True)
parser = hsd.HsdParser(eventhandler=dictbuilder, lower_tag_names=True)
with open(op.join(op.dirname(__file__), "test.hsd"), "r") as fobj:
parser.feed(fobj)
pyrep = dictbuilder.hsddict
print("** Python structure with data flattening:\n")
print(pyrep)
print("\n** Turning back to HSD:\n")
print(hsd.dump_string(pyrep))
print(hsd.dump_string(pyrep, use_hsd_attribs=True))


if __name__ == '__main__':
Expand Down