Skip to content
Snippets Groups Projects
Commit edcc2975 authored by James Graham's avatar James Graham
Browse files

Refactor CFG parser - slight API change, now inherits from OrderedDict

parent 65765f94
Branches
Tags
No related merge requests found
......@@ -135,12 +135,12 @@ class BondSet:
pass
with CFG(filename) as cfg:
for mol in cfg:
self._molecules[mol.name] = []
mol_bonds = self._molecules[mol.name]
for mol_name, mol_section in cfg.items():
self._molecules[mol_name] = []
mol_bonds = self._molecules[mol_name]
angles_defined = False
for atomlist in mol:
for atomlist in mol_section:
try:
# TODO consider best way to override default func form
# On per bond, or per type basis
......
......@@ -7,7 +7,7 @@ import shutil
import functools
from .util import dir_up
from .parsers.cfg import CFG
from .parsers import ITP
class ForceField:
......@@ -29,8 +29,8 @@ class ForceField:
dist_dat_dir = os.path.join(dir_up(os.path.realpath(__file__), 2), "data")
# Copy main MARTINI itp
shutil.copyfile(os.path.join(dist_dat_dir, "martini_v2.2.itp"),
os.path.join(self.dirname, "martini_v2.2.itp"))
martini_itp = os.path.join(dist_dat_dir, "martini_v2.2.itp")
shutil.copyfile(martini_itp, os.path.join(self.dirname, "martini_v2.2.itp"))
# Copy water models
shutil.copyfile(os.path.join(dist_dat_dir, "watermodels.dat"),
os.path.join(self.dirname, "watermodels.dat"))
......@@ -38,9 +38,9 @@ class ForceField:
os.path.join(self.dirname, "w.itp"))
# Create atomtypes.atp required for correct masses with pdb2gmx
with CFG(os.path.join(dist_dat_dir, "martini_v2.2.itp"), allow_duplicate=True) as cfg,\
open(os.path.join(self.dirname, "atomtypes.atp"), 'w') as atomtypes:
for toks in cfg["atomtypes"]:
atomtypes_atp = os.path.join(self.dirname, "atomtypes.atp")
with ITP(martini_itp) as itp, open(atomtypes_atp, 'w') as atomtypes:
for toks in itp["atomtypes"]:
print(" ".join(toks), file=atomtypes)
with open(os.path.join(self.dirname, "forcefield.doc"), "w") as doc:
......
......@@ -88,16 +88,16 @@ class Mapping:
with CFG(filename) as cfg:
self._manual_charges = {}
for mol in cfg:
self._mappings[mol.name] = []
self._manual_charges[mol.name] = False
molmap = self._mappings[mol.name]
for name, typ, first, *atoms in mol:
for mol_name, mol_section in cfg.items():
self._mappings[mol_name] = []
self._manual_charges[mol_name] = False
molmap = self._mappings[mol_name]
for name, typ, first, *atoms in mol_section:
charge = 0
try:
# Allow optional charge in mapping file
charge = float(first)
self._manual_charges[mol.name] = True
self._manual_charges[mol_name] = True
except ValueError:
atoms.insert(0, first)
assert atoms, "Bead {0} specification contains no atoms".format(name)
......
from .cfg import CFG
ITP = CFG
\ No newline at end of file
......@@ -5,35 +5,7 @@ Format is based upon GROMACS .itp files but does not support nesting of sections
"""
import os
from collections import OrderedDict
class Section:
"""
Class representing a single section of the config file.
"""
__slots__ = ["name", "_lines"]
def __init__(self, name=None):
"""
Create a section and storage for the lines it contains.
:param name: Name of section
"""
self.name = name
self._lines = []
def __len__(self):
return len(self._lines)
def __iter__(self):
return iter(self._lines)
def __getitem__(self, item):
return self._lines[item]
def add_line(self, line):
self._lines.append(line)
import collections
class DuplicateSectionError(Exception):
......@@ -44,24 +16,23 @@ class DuplicateSectionError(Exception):
return "Section {0} appears twice in file {1}.".format(*self.args)
class CFG:
class CFG(collections.OrderedDict):
"""
Class representing a CFG file.
Contains a dictionary of Sections.
"""
__slots__ = ["filename", "_sections"]
__slots__ = ["filename"]
def __init__(self, filename=None, allow_duplicate=False):
def __init__(self, filename=None):
"""
Parse a config file and extract Sections.
:param filename: Name of file to read
:param allow_duplicate: Allow sections to appear more than once in a file
:return: Instance of CFG
"""
super(CFG, self).__init__()
self.filename = filename
self._sections = OrderedDict()
with open(self.filename) as f:
curr_section = None
......@@ -73,33 +44,21 @@ class CFG:
elif line.startswith("#include"):
cfg2 = CFG(os.path.join(os.path.dirname(self.filename),
line.split()[1]))
self._sections.update(cfg2._sections)
self.update(cfg2)
continue
elif line.startswith("["):
curr_section = line.strip("[ ]")
if curr_section in self._sections and not allow_duplicate:
if curr_section in self:
raise DuplicateSectionError(curr_section, self.filename)
self._sections[curr_section] = Section(name=curr_section)
self[curr_section] = []
continue
toks = tuple(line.split())
self._sections[curr_section].add_line(toks)
self[curr_section].append(toks)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
pass
def __len__(self):
return len(self._sections)
def __iter__(self):
return iter(self._sections.values())
def __contains__(self, item):
return item in self._sections
def __getitem__(self, item):
return self._sections[item]
import unittest
from pycgtool.parsers.cfg import CFG, DuplicateSectionError
from pycgtool.parsers.cfg import DuplicateSectionError
from pycgtool.parsers import CFG
class TestParsersCFG(unittest.TestCase):
......@@ -12,13 +13,13 @@ class TestParsersCFG(unittest.TestCase):
def test_cfg_iterate_sections(self):
with CFG("test/data/water.map") as cfg:
for section in cfg:
self.assertEqual("SOL", section.name)
for name in cfg:
self.assertEqual("SOL", name)
def test_cfg_iterate_lines(self):
with CFG("test/data/water.map") as cfg:
for section in cfg:
self.assertEqual("SOL", section.name)
for name, section in cfg.items():
self.assertEqual("SOL", name)
for line in section:
self.assertEqual(self.watline, line)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment