diff --git a/doc/source/pycgtool.parsers.json.rst b/doc/source/pycgtool.parsers.json.rst new file mode 100644 index 0000000000000000000000000000000000000000..f761daeea7be5ac827e8cc2a49b65b5c4ca09fca --- /dev/null +++ b/doc/source/pycgtool.parsers.json.rst @@ -0,0 +1,7 @@ +pycgtool.parsers.json module +============================ + +.. automodule:: pycgtool.parsers.json + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/pycgtool.parsers.rst b/doc/source/pycgtool.parsers.rst index e1fea8bc63eac01873b1086edc5c340901688454..1bf99ceac6b2b731a7cf3eef1ae3f0d9a336821d 100644 --- a/doc/source/pycgtool.parsers.rst +++ b/doc/source/pycgtool.parsers.rst @@ -7,6 +7,7 @@ Submodules .. toctree:: pycgtool.parsers.cfg + pycgtool.parsers.json Module contents --------------- diff --git a/pycgtool/parsers/json.py b/pycgtool/parsers/json.py index bbfe9aefac4a0a837e54943ef770bc92355b254a..9fc342fb09e8bb5061e57a1afad858048c36b987 100644 --- a/pycgtool/parsers/json.py +++ b/pycgtool/parsers/json.py @@ -2,23 +2,34 @@ import json import os -class Record(dict): - def __setattr__(self, key, value): - self[key] = value - - def __getattr__(self, item): - return self[item] +class AttrDict(dict): + """ + Class allowing dictionary entries to be accessed as attributes as well as keys. + """ + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self class CFG: + """ + Class to read data from JSON files. Supports including other files and filtering a single section. + """ def __init__(self, filename, from_section=None): + """ + Create a new CFG JSON parser. + + :param filename: JSON file to read + :param from_section: Optional section to select from file + """ with open(filename) as f: - self._json = json.load(f, object_hook=Record) + self._json = json.load(f, object_hook=AttrDict) + # Recurse through include lists and add to self._json while self._json.include: include_file = os.path.join(os.path.dirname(filename), self._json.include.pop()) with open(include_file) as include_file: - include_json = json.load(include_file, object_hook=Record) + include_json = json.load(include_file, object_hook=AttrDict) for curr, incl in zip(self._json.values(), include_json.values()): try: @@ -26,10 +37,13 @@ class CFG: except TypeError: curr.update(incl) + self._records = self._json if from_section is not None: - self._records = self._json[from_section] - else: - self._records = self._json + try: + self._records = self._json[from_section] + except KeyError as e: + e.args = ("Section '{0}' not in file '{1}'".format(from_section, filename),) + raise def __getitem__(self, item): return self._records[item] diff --git a/test/test_parsers_json.py b/test/test_parsers_json.py index c6f6c057461f31749fc281d8e8657e9d55c2c979..5878d96d71f4ef2cb464baba5b2cc2547c15b8b8 100644 --- a/test/test_parsers_json.py +++ b/test/test_parsers_json.py @@ -49,6 +49,10 @@ class TestParsersJson(unittest.TestCase): self.assertTrue("DOPC" in cfg) self.assertTrue("GLY" in cfg) + def test_missing_section(self): + with self.assertRaises(KeyError): + cfg = CFG("test/data/water.json", "potato") + if __name__ == '__main__': unittest.main()