Changeset - 323521344ae5
[Not reviewed]
0 1 0
Brett Smith - 3 years ago 2021-04-29 15:35:47
brettcsmith@brettcsmith.org
books: Add docstrings throughout.
1 file changed with 59 insertions and 1 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/books.py
Show inline comments
 
"""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:
0 comments (0 inline, 0 general)