From 7f45788235cf00ea7e1793a640ce5224f58d0475 Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Sun, 12 Apr 2020 22:27:52 -0400 Subject: [PATCH] config: Start configuration file with books path. Ultimately I would like to make it possible to configure the software entirely through this file, rather than the hodgepodge system we have now. But that can come later. --- conservancy_beancount/config.py | 19 +++++++++++++++++++ tests/test_config.py | 25 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/conservancy_beancount/config.py b/conservancy_beancount/config.py index d03ea59..6d1157a 100644 --- a/conservancy_beancount/config.py +++ b/conservancy_beancount/config.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import configparser import decimal import functools import os @@ -74,6 +75,15 @@ class Config: 'XDG_CONFIG_HOME': Path('.config'), } + def __init__(self) -> None: + self.file_config = configparser.ConfigParser() + + def load_file(self, config_path: Optional[Path]=None) -> None: + if config_path is None: + config_path = self.config_file_path() + with config_path.open() as config_file: + self.file_config.read_file(config_file) + def _dir_or_none(self, path: Path) -> Optional[Path]: try: path.mkdir(exist_ok=True) @@ -94,6 +104,15 @@ class Config: retval = default or (Path.home() / self._ENVIRON_DEFAULT_PATHS[key]) return retval + def books_path(self) -> Optional[Path]: + try: + retval = Path(self.file_config['Beancount'].get('books dir')) + except (KeyError, ValueError): + ok = False + else: + ok = retval.is_absolute() + return retval if ok else None + def cache_dir_path(self, name: str='conservancy_beancount') -> Optional[Path]: cache_root = self._path_from_environ('XDG_CACHE_HOME') return ( diff --git a/tests/test_config.py b/tests/test_config.py index 44742b1..65743b3 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -16,6 +16,7 @@ import contextlib import decimal +import operator import os import re @@ -317,3 +318,27 @@ def test_config_file_path_with_subdir(): expected = testutil.test_path('userconfig/conftest/config.ini') config = config_mod.Config() assert config.config_file_path('conftest') == expected + +@pytest.mark.parametrize('path', [ + None, + testutil.test_path('userconfig/conservancy_beancount/config.ini'), +]) +def test_load_file(path): + config = config_mod.Config() + config.load_file(path) + assert config.books_path() == Path('/test/conservancy_beancount') + +@pytest.mark.parametrize('path_func', [ + lambda path: None, + operator.methodcaller('touch', 0o200), +]) +def test_load_file_error(tmp_path, path_func): + config_path = tmp_path / 'nonexistent.ini' + path_func(config_path) + config = config_mod.Config() + with pytest.raises(OSError): + config.load_file(config_path) + +def test_no_books_path(): + config = config_mod.Config() + assert config.books_path() is None