def Transaction(self, entry, oss): # Compute the string for the payee and narration line. strings = [] if entry.payee: strings.append('"{}"'.format(misc_utils.escape_string( entry.payee))) if entry.narration: strings.append('"{}"'.format( misc_utils.escape_string(entry.narration))) elif entry.payee: # Ensure we append an empty string for narration if we have a payee. strings.append('""') if entry.tags: for tag in sorted(entry.tags): strings.append('#{}'.format(tag)) if entry.links: for link in sorted(entry.links): strings.append('^{}'.format(link)) oss.write('{e.date} {flag} {}\n'.format(' '.join(strings), e=entry, flag=render_flag(entry.flag))) self.write_metadata(entry.meta, oss) rows = [ self.render_posting_strings(posting) for posting in entry.postings ] strs_account = [row[0] for row in rows] width_account = (max( len(flag_account) for flag_account in strs_account) if strs_account else 1) strs_position, width_position = align_position_strings(row[1] for row in rows) strs_weight, width_weight = align_position_strings(row[2] for row in rows) if self.min_width_account and self.min_width_account > width_account: width_account = self.min_width_account non_trivial_balance = (any( map(interpolate.has_nontrivial_balance, entry.postings)) if self.render_weight else False) if non_trivial_balance: for posting, account, position, weight in zip( entry.postings, strs_account, strs_position, strs_weight): oss.write(f"{self.prefix}{account:{width_account}} " f"{position:{width_position}} " f"; {weight:{max(1, width_weight)}}".rstrip() + '\n') if posting.meta: self.write_metadata(posting.meta, oss, ' ') else: for posting, account, position in zip(entry.postings, strs_account, strs_position): oss.write(f"{self.prefix}{account:{width_account}} " f"{position:{max(1, width_position)}}".rstrip() + '\n') if posting.meta: self.write_metadata(posting.meta, oss, ' ')
def Transaction(self, entry, oss): # Compute the string for the payee and narration line. strings = [] if entry.payee: strings.append('"{}"'.format(misc_utils.escape_string(entry.payee))) if entry.narration: strings.append('"{}"'.format(misc_utils.escape_string(entry.narration))) elif entry.payee: # Ensure we append an empty string for narration if we have a payee. strings.append('""') if entry.tags: for tag in sorted(entry.tags): strings.append('#{}'.format(tag)) if entry.links: for link in sorted(entry.links): strings.append('^{}'.format(link)) oss.write('{e.date} {e.flag} {}\n'.format(' '.join(strings), e=entry)) self.write_metadata(entry.meta, oss) rows = [self.render_posting_strings(posting) for posting in entry.postings] strs_account = [row[0] for row in rows] width_account = (max(len(flag_account) for flag_account in strs_account) if strs_account else 1) strs_position, width_position = align_position_strings(row[1] for row in rows) strs_weight, width_weight = align_position_strings(row[2] for row in rows) if self.min_width_account and self.min_width_account > width_account: width_account = self.min_width_account non_trivial_balance = (any(map(interpolate.has_nontrivial_balance, entry.postings)) if self.render_weight else False) if non_trivial_balance: fmt = " {{:{0}}} {{:{1}}} ; {{:{2}}}\n".format( width_account, width_position, width_weight).format for posting, account, position_str, weight_str in zip(entry.postings, strs_account, strs_position, strs_weight): oss.write(fmt(account, position_str, weight_str if non_trivial_balance else '')) if posting.meta: self.write_metadata(posting.meta, oss, ' ') else: fmt_str = " {{:{0}}} {{:{1}}}\n".format(width_account, max(1, width_position)) fmt = fmt_str.format for posting, account, position_str in zip(entry.postings, strs_account, strs_position): # pylint: disable=too-many-format-args oss.write(fmt(account, position_str)) if posting.meta: self.write_metadata(posting.meta, oss, ' ')
def write_metadata(self, meta, oss, prefix=None): """Write metadata to the file object, excluding filename and line number. Args: meta: A dict that contains the metadata for this directive. oss: A file object to write to. """ if meta is None: return if prefix is None: prefix = self.prefix for key, value in sorted(meta.items()): if key not in self.META_IGNORE: value_str = None if isinstance(value, str): value_str = '"{}"'.format(misc_utils.escape_string(value)) elif isinstance(value, (Decimal, datetime.date, amount.Amount, enum.Enum)): value_str = str(value) elif isinstance(value, bool): value_str = 'TRUE' if value else 'FALSE' elif isinstance(value, (dict, inventory.Inventory)): pass # Ignore dicts, don't print them out. elif value is None: value_str = '' # Render null metadata as empty, on purpose. else: if self.stringify_invalid_types: # This is only intended to be used during development, # when debugging for custom values of data types # attached directly and not coming from the parser. value_str = str(value) else: raise ValueError("Unexpected value: '{!r}'".format(value)) if value_str is not None: oss.write("{}{}: {}\n".format(prefix, key, value_str))
def write_metadata(self, meta, oss, prefix=' '): """Write metadata to the file object, excluding filename and line number. Args: meta: A dict that contains the metadata for this directive. oss: A file object to write to. """ if meta is None: return for key, value in sorted(meta.items()): if key not in self.META_IGNORE: value_str = None if isinstance(value, str): value_str = '"{}"'.format(misc_utils.escape_string(value)) elif isinstance(value, (Decimal, datetime.date, amount.Amount)): value_str = str(value) elif isinstance(value, bool): value_str = 'TRUE' if value else 'FALSE' elif isinstance(value, (dict, inventory.Inventory)): pass # Ignore dicts, don't print them out. else: raise ValueError("Unexpected value: '{!r}'".format(value)) if value_str is not None: oss.write("{}{}: {}\n".format(prefix, key, value_str))
def test_escape_string(self): assert misc_utils.escape_string("Entry with escaped \"symbols\" \\ \r \n") == \ 'Entry with escaped \\"symbols\\" \\\\ \r \n'