books: Add docstrings throughout.

This commit is contained in:
Brett Smith 2021-04-29 11:35:47 -04:00
parent e2dda7ae0c
commit 323521344a

View file

@ -1,4 +1,8 @@
"""books - Tools for loading the books"""
"""books - Tools for loading the books
This module provides common functionality for loading books split by fiscal
year and doing common operations on the results.
"""
# Copyright © 2020 Brett Smith
# License: AGPLv3-or-later WITH Beancount-Plugin-Additional-Permission-1.0
#
@ -39,10 +43,25 @@ PathLike = Union[str, Path]
Year = Union[int, datetime.date]
class FiscalYear(NamedTuple):
"""Convert to and from fiscal years and calendar dates
Given a month and date that a fiscal year starts, this class provides
methods to calculate the fiscal year of a given calendar date; to return
important calendar dates associated with the fiscal year; and iterate
fiscal years.
Most methods can accept either an int, representing a fiscal year;
or a date. When you pass a date, the method will calculate that date's
corresponding fiscal year, and use it as the argument.
"""
month: int = 3
day: int = 1
def for_date(self, date: Optional[datetime.date]=None) -> int:
"""Return the fiscal year of a given calendar date
The default date is today's date.
"""
if date is None:
date = datetime.date.today()
if (date.month, date.day) < self:
@ -51,14 +70,17 @@ class FiscalYear(NamedTuple):
return date.year
def first_date(self, year: Year) -> datetime.date:
"""Return the first calendar date of a fiscal year"""
if isinstance(year, datetime.date):
year = self.for_date(year)
return datetime.date(year, self.month, self.day)
def last_date(self, year: Year) -> datetime.date:
"""Return the last calendar date of a fiscal year"""
return self.next_fy_date(year) - datetime.timedelta(days=1)
def next_fy_date(self, year: Year) -> datetime.date:
"""Return the last calendar date of a fiscal year"""
if isinstance(year, datetime.date):
year = self.for_date(year)
return datetime.date(year + 1, self.month, self.day)
@ -100,12 +122,25 @@ class FiscalYear(NamedTuple):
class LoadResult(NamedTuple):
"""Common functionality for loaded books
This class is type-compatible with the return value of the loader
functions in ``beancount.loader``. This provides named access to the
results, as well as common functionality methods.
"""
entries: Entries
errors: Errors
options_map: OptionsMap
@classmethod
def empty(cls, error: Optional[Error]=None) -> 'LoadResult':
"""Create a return result that represents nothing loaded
If an error is provided, it will be the sole error reported.
This method is useful to create a LoadResult when one can't be
created normally; e.g., because a books path is not properly configured.
"""
errors: Errors = []
if error is not None:
errors.append(error)
@ -116,6 +151,14 @@ class LoadResult(NamedTuple):
rewrites: Iterable[Union[Path, rewrite.RewriteRuleset]]=(),
search_terms: Iterable[cliutil.SearchTerm]=(),
) -> Iterator[data.Posting]:
"""Iterate all the postings in this LoadResult
If ``rewrites`` are provided, postings will be passed through them all.
See the ``reports.rewrite`` pydoc for details.
If ``search_terms`` are provided, postings will be filtered through
them all. See the ``cliutil.SearchTerm`` pydoc for details.
"""
postings = data.Posting.from_entries(self.entries)
for ruleset in rewrites:
if isinstance(ruleset, Path):
@ -126,9 +169,14 @@ class LoadResult(NamedTuple):
return postings
def load_account_metadata(self) -> None:
"""Load account metadata from this LoadResult"""
return data.Account.load_from_books(self.entries, self.options_map)
def print_errors(self, out_file: TextIO) -> bool:
"""Report errors from this LoadResult to ``out_file``
Returns True if errors were reported, False otherwise.
"""
for error in self.errors:
bc_printer.print_error(error, file=out_file)
try:
@ -139,6 +187,11 @@ class LoadResult(NamedTuple):
return True
def returncode(self) -> int:
"""Return an appropriate Unix exit code for this LoadResult
If this LoadResult has errors, or no entries, return an exit code that
best represents that. Otherwise, return the standard OK exit code 0.
"""
if self.errors:
if self.entries:
return cliutil.ExitCode.BeancountErrors
@ -265,6 +318,11 @@ class Loader:
from_fy: Optional[Year]=None,
to_fy: Optional[Year]=None,
) -> LoadResult:
"""High-level, "do-what-I-mean"-ish books loader
Most tools can call this with a books loader from configuration, plus
one or two fiscal year arguments, to get the LoadResult they want.
"""
if loader is None:
return cls.load_none()
elif to_fy is None: