config: Add Config.fiscal_year_begin() method.

This commit is contained in:
Brett Smith 2020-04-20 14:31:22 -04:00
parent 7f45788235
commit 894f044093
2 changed files with 61 additions and 0 deletions

View file

@ -15,9 +15,11 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import configparser import configparser
import datetime
import decimal import decimal
import functools import functools
import os import os
import re
import urllib.parse as urlparse import urllib.parse as urlparse
import requests.auth import requests.auth
@ -27,6 +29,7 @@ from pathlib import Path
from typing import ( from typing import (
NamedTuple, NamedTuple,
Optional, Optional,
Tuple,
Type, Type,
) )
@ -84,6 +87,9 @@ class Config:
with config_path.open() as config_file: with config_path.open() as config_file:
self.file_config.read_file(config_file) self.file_config.read_file(config_file)
def load_string(self, config_str: str) -> None:
self.file_config.read_string(config_str)
def _dir_or_none(self, path: Path) -> Optional[Path]: def _dir_or_none(self, path: Path) -> Optional[Path]:
try: try:
path.mkdir(exist_ok=True) path.mkdir(exist_ok=True)
@ -124,6 +130,24 @@ class Config:
config_root = self._path_from_environ('XDG_CONFIG_HOME') config_root = self._path_from_environ('XDG_CONFIG_HOME')
return Path(config_root, name, 'config.ini') return Path(config_root, name, 'config.ini')
def fiscal_year_begin(self) -> Tuple[int, int]:
s = self.file_config.get('Beancount', 'fiscal year begin', fallback='3 1')
match = re.match(r'([01]?[0-9])(?:\s*[-./ ]\s*([0-3]?[0-9]))?$', s.strip())
if match is None:
raise ValueError(f"fiscal year begin {s!r} has unknown format")
try:
month = int(match.group(1))
day = int(match.group(2) or 1)
# To check date validity we use an arbitrary year that's
# 1. definitely using the modern calendar
# 2. far enough in the past to not have books (pre-Unix epoch)
# 3. not a leap year
datetime.date(1959, month, day)
except ValueError as e:
raise ValueError(f"fiscal year begin {s!r} is invalid date: {e.args[0]}")
else:
return (month, day)
def payment_threshold(self) -> decimal.Decimal: def payment_threshold(self) -> decimal.Decimal:
return decimal.Decimal(0) return decimal.Decimal(0)

View file

@ -342,3 +342,40 @@ def test_load_file_error(tmp_path, path_func):
def test_no_books_path(): def test_no_books_path():
config = config_mod.Config() config = config_mod.Config()
assert config.books_path() is None assert config.books_path() is None
@pytest.mark.parametrize('value,month,day', [
('2', 2, 1),
('3 ', 3, 1),
(' 4', 4, 1),
(' 5 ', 5, 1),
('6 1', 6, 1),
(' 06 03 ', 6, 3),
('6-05', 6, 5),
('06 - 10', 6, 10),
('6/15', 6, 15),
('06 / 20', 6, 20),
('10.25', 10, 25),
(' 10 . 30 ', 10, 30),
])
def test_fiscal_year_begin(value, month, day):
config = config_mod.Config()
config.load_string(f'[Beancount]\nfiscal year begin = {value}\n')
assert config.fiscal_year_begin() == (month, day)
@pytest.mark.parametrize('value', [
'text',
'1900',
'13',
'010',
'2 30',
'4-31',
])
def test_bad_fiscal_year_begin(value):
config = config_mod.Config()
config.load_string(f'[Beancount]\nfiscal year begin = {value}\n')
with pytest.raises(ValueError):
config.fiscal_year_begin()
def test_default_fiscal_year_begin():
config = config_mod.Config()
assert config.fiscal_year_begin() == (3, 1)