def get_active_years(entries: Entries, fye: str) -> List[str]: """Returns active years, with support for fiscal years. Args: entries: Beancount entries fye: fiscal year end Returns: A reverse sorted list of years or fiscal years that occur in the entries. """ if fye == "12-31": return sorted( map(str, getters.get_active_years(entries)), reverse=True ) seen = set() month, day = map(int, fye.split("-")) for entry in entries: date = entry.date if date.month > month or date.month == month and date.day > day: seen.add(entry.date.year + 1) else: seen.add(entry.date.year) return [f"FY{year}" for year in sorted(seen, reverse=True)]
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" self.all_entries, self.errors, self.options = \ loader.load_file(self.beancount_file_path) self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] if self.options['render_commas']: self.format_string = '{:,f}' self.default_format_string = '{:,.2f}' else: self.format_string = '{:f}' self.default_format_string = '{:.2f}' self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.queries = _filter_entries_by_type(self.all_entries, Query) self.all_root_account = realization.realize(self.all_entries, self.account_types) self.all_accounts = _list_accounts(self.all_root_account) self.all_accounts_leaf_only = _list_accounts( self.all_root_account, leaf_only=True) self.sidebar_links = _sidebar_links(self.all_entries) self._apply_filters() self.budgets = Budgets(self.entries) self.errors.extend(self.budgets.errors)
def load_file(self, beancount_file_path=None): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" if beancount_file_path: self.beancount_file_path = beancount_file_path self.all_entries, self.errors, self.options = \ loader.load_file(self.beancount_file_path) self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] if self.options['render_commas']: self.format_string = '{:,f}' self.default_format_string = '{:,.2f}' else: self.format_string = '{:f}' self.default_format_string = '{:.2f}' self.dcontext = self.options['dcontext'] self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.queries = self._entries_filter_type(self.all_entries, Query) self.all_root_account = realization.realize(self.all_entries, self.account_types) self.all_accounts = self._all_accounts() self.all_accounts_leaf_only = self._all_accounts(leaf_only=True) self._apply_filters()
def load_file(self): all_entries = self.ledger.all_entries self.links = getters.get_all_links(all_entries) self.tags = getters.get_all_tags(all_entries) self.years = list(getters.get_active_years(all_entries))[::-1] account_ranker = ExponentialDecayRanker( sorted(self.ledger.accounts.keys())) currency_ranker = ExponentialDecayRanker( self.ledger.options['commodities']) payee_ranker = ExponentialDecayRanker() transactions = self.ledger.all_entries_by_type[Transaction] for txn in transactions: if txn.payee: payee_ranker.update(txn.payee, txn.date) for posting in txn.postings: account_ranker.update(posting.account, txn.date) currency_ranker.update(posting.units.currency, txn.date) if posting.cost: currency_ranker.update(posting.cost.currency, txn.date) self.accounts = account_ranker.sort() self.currencies = currency_ranker.sort() self.payees = payee_ranker.sort()
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" with open(self.beancount_file_path, encoding='utf8') as f: self.source = f.read() self.entries, self._errors, self.options = loader.load_file(self.beancount_file_path) self.all_entries = self.entries self.price_map = prices.build_price_map(self.all_entries) self.title = self.options['title'] self.errors = [] for error in self._errors: self.errors.append({ 'file': error.source['filename'], 'line': error.source['lineno'], 'error': error.message, 'entry': error.entry # TODO render entry }) self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.account_types = options.get_account_types(self.options) self.real_accounts = realization.realize(self.entries, self.account_types) self.all_accounts = self._account_components()
def load_file(self) -> None: all_entries = self.ledger.all_entries self.links = getters.get_all_links(all_entries) self.tags = getters.get_all_tags(all_entries) self.years = list(getters.get_active_years(all_entries))[::-1] account_ranker = ExponentialDecayRanker( sorted(self.ledger.accounts.keys())) currency_ranker = ExponentialDecayRanker( self.ledger.options["commodities"]) payee_ranker = ExponentialDecayRanker() transactions = self.ledger.all_entries_by_type[Transaction] for txn in transactions: if txn.payee: payee_ranker.update(txn.payee, txn.date) for posting in txn.postings: account_ranker.update(posting.account, txn.date) currency_ranker.update(posting.units.currency, txn.date) if posting.cost: currency_ranker.update(posting.cost.currency, txn.date) self.accounts = account_ranker.sort() self.currencies = currency_ranker.sort() self.payees = payee_ranker.sort()
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" self.all_entries, self.errors, self.options = \ loader.load_file(self.beancount_file_path) self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] if self.options['render_commas']: self.format_string = '{:,f}' self.default_format_string = '{:,.2f}' else: self.format_string = '{:f}' self.default_format_string = '{:.2f}' self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.queries = _filter_entries_by_type(self.all_entries, Query) self.all_root_account = realization.realize(self.all_entries, self.account_types) self.all_accounts = _list_accounts(self.all_root_account) self.all_accounts_leaf_only = _list_accounts(self.all_root_account, leaf_only=True) self.sidebar_links = _sidebar_links(self.all_entries) self._apply_filters() self.budgets = Budgets(self.entries) self.errors.extend(self.budgets.errors)
def load_file(self): all_entries = self.ledger.all_entries self.payees = getters.get_all_payees(all_entries) self.tags = getters.get_all_tags(all_entries) self.years = list(getters.get_active_years(all_entries)) self.accounts = _list_accounts(self.ledger.all_root_account, active_only=True)
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" # use the internal function to disable cache if not self.is_encrypted: self.all_entries, self.errors, self.options = \ loader._load([(self.beancount_file_path, True)], None, None, None) include_path = os.path.dirname(self.beancount_file_path) self.watcher.update(self.options['include'], [ os.path.join(include_path, path) for path in self.options['documents']]) else: self.all_entries, self.errors, self.options = \ loader.load_file(self.beancount_file_path) self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] if self.options['render_commas']: self._format_string = '{:,f}' self._default_format_string = '{:,.2f}' else: self._format_string = '{:f}' self._default_format_string = '{:.2f}' self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.queries = _filter_entries_by_type(self.all_entries, Query) self.custom_entries = _filter_entries_by_type(self.all_entries, Custom) self.all_root_account = realization.realize(self.all_entries, self.account_types) self.all_accounts = _list_accounts(self.all_root_account) self.all_accounts_active = _list_accounts( self.all_root_account, active_only=True) self.fava_options, errors = parse_options(self.custom_entries) self.errors.extend(errors) self.sidebar_links = _sidebar_links(self.custom_entries) self.upcoming_events = _upcoming_events( self.all_entries, self.fava_options['upcoming-events']) self.budgets, errors = parse_budgets(self.custom_entries) self.errors.extend(errors) self._apply_filters()
def wrapper(*posargs, **kwargs): filename = app.args.filename if loader.needs_refresh(app.options): logging.info('Reloading...') # Save the source for later, to render. with open(filename, encoding='utf8') as f: app.source = f.read() # Parse the beancount file. entries, errors, options_map = loader.load_file(filename) # Print out the list of errors. if errors: # pylint: disable=unsupported-assignment-operation request.params['render_overlay'] = True print( ',----------------------------------------------------------------' ) printer.print_errors(errors, file=sys.stdout) print( '`----------------------------------------------------------------' ) # Save globals in the global app. app.entries = entries app.errors = errors app.options = options_map app.account_types = options.get_account_types(options_map) # Pre-compute the price database. app.price_map = prices.build_price_map(entries) # Pre-compute the list of active years. app.active_years = list(getters.get_active_years(entries)) # Reset the view cache. app.views.clear() else: # For now, the overlay is a link to the errors page. Always render # it on the right when there are errors. if app.errors: # pylint: disable=unsupported-assignment-operation request.params['render_overlay'] = True return callback(*posargs, **kwargs)
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" # use the internal function to disable cache if not self.is_encrypted: self.all_entries, self.errors, self.options = loader._load( [(self.beancount_file_path, True)], None, None, None ) include_path = os.path.dirname(self.beancount_file_path) self.watcher.update( self.options["include"], [os.path.join(include_path, path) for path in self.options["documents"]] ) else: self.all_entries, self.errors, self.options = loader.load_file(self.beancount_file_path) self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options["title"] if self.options["render_commas"]: self._format_string = "{:,f}" self._default_format_string = "{:,.2f}" else: self._format_string = "{:f}" self._default_format_string = "{:.2f}" self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.queries = _filter_entries_by_type(self.all_entries, Query) self.custom_entries = _filter_entries_by_type(self.all_entries, Custom) self.all_root_account = realization.realize(self.all_entries, self.account_types) self.all_accounts = _list_accounts(self.all_root_account) self.all_accounts_active = _list_accounts(self.all_root_account, active_only=True) self.fava_options, errors = parse_options(self.custom_entries) self.errors.extend(errors) self.sidebar_links = _sidebar_links(self.custom_entries) self.upcoming_events = _upcoming_events(self.all_entries, self.fava_options["upcoming-events"]) self.budgets, errors = parse_budgets(self.custom_entries) self.errors.extend(errors) self._apply_filters()
def load_file(self, beancount_file_path=None): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" if beancount_file_path: self.beancount_file_path = beancount_file_path self.all_entries, self.errors, self.options = \ loader.load_file(self.beancount_file_path) self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] if self.options['render_commas']: self.format_string = '{:,f}' self.default_format_string = '{:,.2f}' else: self.format_string = '{:f}' self.default_format_string = '{:.2f}' self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.queries = self._entries_filter_type(self.all_entries, Query) self.all_root_account = realization.realize(self.all_entries, self.account_types) self.all_accounts = self._all_accounts() self.all_accounts_leaf_only = self._all_accounts(leaf_only=True) self.sidebar_link_entries = [entry for entry in self.all_entries if isinstance(entry, Custom) and entry.type == 'fava-sidebar-link'] self._apply_filters() self.budgets = Budgets(self.entries) self.errors.extend(self.budgets.errors)
def load_file(self): all_entries = self.ledger.all_entries self.tags = getters.get_all_tags(all_entries) self.years = list(getters.get_active_years(all_entries))[::-1] account_ranker = ExponentialDecayRanker( self.list_accounts(active_only=True)) currency_ranker = ExponentialDecayRanker( self.ledger.options['commodities']) payee_ranker = ExponentialDecayRanker() for txn in filter_type(all_entries, Transaction): if txn.payee: payee_ranker.update(txn.payee, txn.date) for posting in txn.postings: account_ranker.update(posting.account, txn.date) currency_ranker.update(posting.units.currency, txn.date) if posting.cost: currency_ranker.update(posting.cost.currency, txn.date) self.accounts = account_ranker.sort() self.currencies = currency_ranker.sort() self.payees = payee_ranker.sort()
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" self.entries, self._errors, self.options = loader.load_file(self.beancount_file_path) self.all_entries = self.entries self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] self.errors = [] for error in self._errors: self.errors.append({ 'file': error.source['filename'], 'line': error.source['lineno'], 'error': error.message }) self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.apply_filters()
def load_file(self): """Load self.beancount_file_path and compute things that are independent of how the entries might be filtered later""" self.entries, self._errors, self.options = loader.load_file( self.beancount_file_path) self.all_entries = self.entries self.price_map = prices.build_price_map(self.all_entries) self.account_types = options.get_account_types(self.options) self.title = self.options['title'] self.errors = [] for error in self._errors: self.errors.append({ 'file': error.source['filename'], 'line': error.source['lineno'], 'error': error.message }) self.active_years = list(getters.get_active_years(self.all_entries)) self.active_tags = list(getters.get_all_tags(self.all_entries)) self.active_payees = list(getters.get_all_payees(self.all_entries)) self.apply_filters()
def toc(): entries_no_open_close = [ entry for entry in app.entries if not isinstance(entry, (data.Open, data.Close)) ] if entries_no_open_close: mindate, maxdate = None, None else: mindate, maxdate = getters.get_min_max_dates(entries_no_open_close) def view_url(name, **kw): return app.router.build(name, path=DEFAULT_VIEW_REDIRECT, **kw) viewboxes = [] if app.args.view: # Render a single link to a view, the view selected from --view. viewboxes.append(('selected', None, [('/', 'Selected View')])) else: # Render a menu of various views. # Global views. viewboxes.append( ('global', None, [(view_url('all'), 'All Transactions')])) # By year views. viewboxes.append(('year', 'By Year', [ (view_url('year', year=year), 'Year {}'.format(year)) for year in reversed(list(getters.get_active_years(app.entries))) ])) # By tag views. viewboxes.append( ('tag', 'Tags', [(view_url('tag', tag=tag), '#{}'.format(tag)) for tag in getters.get_all_tags(app.entries)])) # By component. components = getters.get_account_components(app.entries) viewboxes.append( ('component', 'Component', [(view_url('component', component=component), '{}'.format(component)) for component in components])) # Note: With the filtering language, payees will be added and much many more # options. Don't worry. oss = io.StringIO() oss.write('<div id="viewboxes">\n') for cssid, title, viewbox in viewboxes: view_items = [ '<li><a href="{}">{}</a></li>'.format(url, title) for url, title in viewbox ] oss.write(""" <div id="{cssid}" class="viewbox"> {title} <ul> {view_items} </ul> </div> <hr/> """.format(cssid=cssid, title='<h2>{}</h2>'.format(title) if title else '', view_items='\n'.join(view_items))) oss.write('</div> <!-- viewboxes -->\n') return render_global(pagetitle="Table of Contents", contents=oss.getvalue())
def test_get_active_years(self): entries = loader.load_string(TEST_INPUT)[0] years = list(getters.get_active_years(entries)) self.assertEqual([2012, 2013, 2014], years)
def active_years(self): return list(getters.get_active_years(self.all_entries))