diff --git a/pycgtool/parsers/cfg.py b/pycgtool/parsers/cfg.py index 20b723259969a52dcb0fb367c29ca9eba1bd0e2b..081fa697b415408003c40ee5063e35189553de06 100644 --- a/pycgtool/parsers/cfg.py +++ b/pycgtool/parsers/cfg.py @@ -8,6 +8,8 @@ import contextlib import pathlib import typing +PathLike = typing.Union[str, pathlib.Path] + class DuplicateSectionError(KeyError): """Exception used to indicate that a section has appeared twice in a file.""" @@ -28,53 +30,44 @@ class CFG(collections.OrderedDict, contextlib.AbstractContextManager): Contains a dictionary of Sections. """ - def __init__(self, - filename: typing.Optional[typing.Union[str, - pathlib.Path]] = None): - """Parse a config file and extract Sections. - - :param filename: Path of file to read - """ + def __init__(self, filepath: typing.Optional[PathLike] = None): + """Parse a config file and extract Sections.""" super().__init__() - self.filename = None + self.filepath = None - if filename is not None: - self.filename = pathlib.Path(filename) - self._read_file() + if filepath is not None: + self.filepath = pathlib.Path(filepath) + self._read_file(self.filepath) - def _read_line(self, line: str) -> typing.Optional[str]: + def _read_line(self, line: str, filepath: pathlib.Path) -> str: # Strip comments line = line.split(';')[0].strip() - if not line: - return None - # Handle include directive if line.startswith('#include'): include_file = line.split()[1].strip('"') - other = type(self)(self.filename.parent.joinpath(include_file)) + other = type(self)(filepath.parent.joinpath(include_file)) self.update(other) - return None + return '' # Handle include then treat as empty line return line - def _read_file(self) -> None: - with open(self.filename) as cfg_file: + def _read_file(self, filepath: pathlib.Path) -> None: + with open(filepath) as cfg_file: curr_section = None for line in cfg_file: - line = self._read_line(line) + line = self._read_line(line, filepath) - if line is None: + if not line: continue if line.startswith("["): curr_section = line.strip("[ ]") if curr_section in self: - raise DuplicateSectionError(curr_section, - self.filename) + raise DuplicateSectionError(curr_section, filepath) self[curr_section] = [] @@ -86,7 +79,7 @@ class CFG(collections.OrderedDict, contextlib.AbstractContextManager): self[curr_section].append(toks) except KeyError as exc: - raise NoSectionError(self.filename) from exc + raise NoSectionError(filepath) from exc def __exit__(self, exc_type, exc_value, traceback): pass diff --git a/pycgtool/parsers/itp.py b/pycgtool/parsers/itp.py index 974a96594f3e7904eafdba06278cdbad7dfbd0c3..6e19e7ddfea710783d6c4a3c165c1d1f1f053a2f 100644 --- a/pycgtool/parsers/itp.py +++ b/pycgtool/parsers/itp.py @@ -2,6 +2,7 @@ import collections import logging +import pathlib from .cfg import CFG, NoSectionError, DuplicateSectionError @@ -9,21 +10,21 @@ logger = logging.getLogger(__name__) class ITP(CFG): - """Class representing an .itp file + """Class representing an .itp file. - Contains a dictionary for every molecule definition + Contains a dictionary of sections for every molecule definition. """ - def _read_file(self) -> None: + def _read_file(self, filepath: pathlib.Path) -> None: mol_sections = ["atoms", "bonds", "angles", "dihedrals"] - with open(self.filename) as itp_file: + with open(filepath) as itp_file: curr_section = None curr_mol = None for line in itp_file: - line = self._read_line(line) + line = self._read_line(line, filepath) - if line is None: + if not line: continue if line.startswith("["): @@ -42,7 +43,7 @@ class ITP(CFG): curr_mol = toks[0] if curr_mol in self: - raise DuplicateSectionError(curr_mol, self.filename) + raise DuplicateSectionError(curr_mol, filepath) self[curr_mol] = collections.OrderedDict() @@ -50,8 +51,8 @@ class ITP(CFG): self[curr_mol][curr_section].append(toks) elif curr_section is None: - raise NoSectionError(self.filename) + raise NoSectionError(filepath) else: logger.info("File '%s' contains unexpected section '%s'", - self.filename, curr_section) + filepath, curr_section)