# -*- coding: utf-8 -*-
"""A singleton to ensure the ~.seammrc file is always up-to-date."""
import configparser
from pathlib import Path
# Used in parser getters to indicate the default behaviour when a specific
# option is not found it to raise an exception. Created to enable `None' as
# a valid fallback value.
_UNSET = object()
[docs]
class Singleton(object):
_instances = {}
def __new__(class_, *args, **kwargs):
if class_ not in class_._instances:
class_._instances[class_] = super(Singleton, class_).__new__(
class_, *args, **kwargs
)
return class_._instances[class_]
[docs]
class SEAMMrc(Singleton):
def __init__(self, path="~/.seamm.d/seammrc"):
self._config = configparser.ConfigParser()
self.path = Path(path).expanduser()
# Create the file if it doesn't exist
if self.path.exists():
self._config.read(self.path)
else:
# Initially used ~/.seammrc but this doesn't play well with Docker
# containers, so moved to ~/seamm.d/seammrc Check for the old file and move
# to new
tmp = Path("~/.seammrc").expanduser()
if tmp.exists():
self.path.parent.mkdir(parents=True, exist_ok=True)
self.path.write_text(tmp.read_text())
self._config.read(self.path)
tmp.unlink()
else:
self.path.parent.mkdir(parents=True, exist_ok=True)
self._save()
# Check the version and upgrade if necessary
if "VERSION" not in self._config:
# Rename all sections as Dashboards
for section in self._config.sections():
tmp = {}
for key, value in self._config[section].items():
tmp[key] = value
self._config.remove_section(section)
self._config[f"Dashboard: {section}"] = tmp
self._config["VERSION"] = {"file": "1.0"}
self._save()
def __getitem__(self, key):
raise NotImplementedError("Please use get/set")
def __setitem__(self, key, value):
raise NotImplementedError("Please use get/set")
def __delitem__(self, key):
del self._config[key]
self._save()
def __contains__(self, key):
return key in self._config
def __len__(self):
return len(self._config)
def __iter__(self):
return self._config.__iter__()
[docs]
def defaults(self):
return self._config.defaults()
[docs]
def sections(self):
return self._config.sections()
[docs]
def add_section(self, section):
self._config.add_section(section)
self._save()
[docs]
def has_section(self, section):
return self._config.has_section(section)
[docs]
def options(self, section):
return self._config.options(section)
[docs]
def has_option(self, section, option):
return self._config.has_option(section, option)
[docs]
def get(self, section, option, raw=False, vars=None, fallback=_UNSET):
return self._config.get(section, option, raw=raw, vars=vars, fallback=fallback)
[docs]
def getint(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
return self._config.getint(
section, option, raw=raw, vars=vars, fallback=fallback
)
[docs]
def getfloat(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
return self._config.getfloat(
section, option, raw=raw, vars=vars, fallback=fallback
)
[docs]
def getboolean(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
return self._config.getboolean(
section, option, raw=raw, vars=vars, fallback=fallback
)
[docs]
def items(self, section=_UNSET, raw=False, vars=None):
return self._config.items(section=section, raw=raw, vars=vars)
[docs]
def set(self, section, option, value):
self._config.set(section, option, value)
self._save()
[docs]
def remove_option(self, section, option):
self._config.remove_option(section, option)
self._save()
[docs]
def remove_section(self, section):
self._config.remove_section(section)
self._save()
def _save(self):
with open(self.path, "w") as fd:
# Added commented sections if they don't exist
if "USER" not in self:
fd.write(
"""
# [USER]
# Default user and grant information for flowcharts
# name = Last, First
# ORCID = xxxx-xxxx-xxxx-xxxx
# affiliation = Your instititution
# grants = <as DOIs like Zenodo uses, e.g 10.13039/100000001::2136142 10.13...>
"""
)
if "ZENODO" not in self:
fd.write(
"""
# [ZENODO]
# API token for Zenodo
# token = xxxx....
"""
)
if "SANDBOX" not in self:
fd.write(
"""
# [SANDBOX]
# API token for Zenodo's sandbox
# token = xxxxx....
"""
)
# And write the config file data
self._config.write(fd)
[docs]
def re_read(self):
self._config.read(self.path)