From 323521344ae54756171dcf3b68734c8c74ce6706 2021-04-29 15:35:47 From: Brett Smith Date: 2021-04-29 15:35:47 Subject: [PATCH] books: Add docstrings throughout. --- diff --git a/conservancy_beancount/books.py b/conservancy_beancount/books.py index 3ed11c81d69698cc7077a02d79138bf79e82a5ab..d77c16eb4c96ae128bea01bea4f52b21ee48a31b 100644 --- a/conservancy_beancount/books.py +++ b/conservancy_beancount/books.py @@ -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: