beancount.core
用于表示条目列表的核心基本对象和数据结构。
beancount.core.account
操作账户字符串的函数。
这些账户对象非常简单且无智能;它们不包含与其关联的分录列表。这通过构建实现来完成;详情请参见 realization.py。
beancount.core.account.AccountTransformer
账户名称转换器。
此功能用于支持 Windows... 嗯,不支持冒号字符的文件系统和平台。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
rsep |
一个字符字符串,用于链接名称中的新分隔符。 |
beancount.core.account.AccountTransformer.parse(self, transformed_name)
将转换后的账户名称转换为原始账户名称。
源代码位于 beancount/core/account.py
def parse(self, transformed_name: str) -> Account:
"Convert the transform account name to an account name."
return (transformed_name
if self.rsep is None
else transformed_name.replace(self.rsep, sep))
beancount.core.account.AccountTransformer.render(self, account_name)
将账户名称转换为转换后的账户名称。
源代码位于 beancount/core/account.py
def render(self, account_name: Account) -> str:
"Convert the account name to a transformed account name."
return (account_name
if self.rsep is None
else account_name.replace(sep, self.rsep))
beancount.core.account.commonprefix(accounts)
返回一组账户名称的公共前缀。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def commonprefix(accounts: Iterable[Account]) -> Account:
"""Return the common prefix of a list of account names.
Args:
accounts: A sequence of account name strings.
Returns:
A string, the common parent account. If none, returns an empty string.
"""
accounts_lists = [account_.split(sep)
for account_ in accounts]
# Note: the os.path.commonprefix() function just happens to work here.
# Inspect its code, and even the special case of no common prefix
# works well with str.join() below.
common_list = path.commonprefix(accounts_lists)
return sep.join(common_list)
beancount.core.account.has_component(account_name, component)
如果账户名称中包含指定的组件,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def has_component(account_name: Account, component: str) -> bool:
"""Return true if one of the account contains a given component.
Args:
account_name: A string, an account name.
component: A string, a component of an account name. For instance,
``Food`` in ``Expenses:Food:Restaurant``. All components are considered.
Returns:
Boolean: true if the component is in the account. Note that a component
name must be whole, that is ``NY`` is not in ``Expenses:Taxes:StateNY``.
"""
return bool(re.search('(^|:){}(:|$)'.format(component), account_name))
beancount.core.account.is_valid(string)
如果给定字符串是有效的账户名称,则返回 True。此函数仅检查一般语法,不验证根账户类型。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def is_valid(string: Account) -> bool:
"""Return true if the given string is a valid account name.
This does not check for the root account types, just the general syntax.
Args:
string: A string, to be checked for account name pattern.
Returns:
A boolean, true if the string has the form of an account's name.
"""
return (isinstance(string, str) and
bool(regex.match('{}$'.format(ACCOUNT_RE), string)))
beancount.core.account.join(*components)
使用账户分隔符连接各部分名称。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def join(*components: Tuple[str]) -> Account:
"""Join the names with the account separator.
Args:
*components: Strings, the components of an account name.
Returns:
A string, joined in a single account name.
"""
return sep.join(components)
beancount.core.account.leaf(account_name)
获取此账户的叶子名称。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def leaf(account_name: Account) -> Account:
"""Get the name of the leaf of this account.
Args:
account_name: A string, the name of the account whose leaf name to return.
Returns:
A string, the name of the leaf of the account.
"""
assert isinstance(account_name, str)
return account_name.split(sep)[-1] if account_name else None
beancount.core.account.parent(account_name)
返回给定账户的父账户名称。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def parent(account_name: Account) -> Account:
"""Return the name of the parent account of the given account.
Args:
account_name: A string, the name of the account whose parent to return.
Returns:
A string, the name of the parent account of this account.
"""
assert isinstance(account_name, str), account_name
if not account_name:
return None
components = account_name.split(sep)
components.pop(-1)
return sep.join(components)
beancount.core.account.parent_matcher(account_name)
构建一个谓词,用于判断某个账户是否位于给定账户之下。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def parent_matcher(account_name: Account) -> Callable[[str], Any]:
"""Build a predicate that returns whether an account is under the given one.
Args:
account_name: The name of the parent account we want to check for.
Returns:
A callable, which, when called, will return true if the given account is a
child of ``account_name``.
"""
return re.compile(r'{}($|{})'.format(re.escape(account_name), sep)).match
beancount.core.account.parents(account_name)
一个生成器,生成此账户的所有父账户名称(包括自身)。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def parents(account_name: Account) -> Iterator[Account]:
"""A generator of the names of the parents of this account, including this account.
Args:
account_name: The name of the account we want to start iterating from.
Returns:
A generator of account name strings.
"""
while account_name:
yield account_name
account_name = parent(account_name)
beancount.core.account.root(num_components, account_name)
返回账户名称的前若干个组成部分。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def root(num_components: int, account_name: Account) -> str:
"""Return the first few components of an account's name.
Args:
num_components: An integer, the number of components to return.
account_name: A string, an account name.
Returns:
A string, the account root up to 'num_components' components.
"""
return join(*(split(account_name)[:num_components]))
beancount.core.account.sans_root(account_name)
获取不包含根部分的账户名称。
例如,输入 'Assets:BofA:Checking' 将返回 'BofA:Checking'。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def sans_root(account_name: Account)-> Account:
"""Get the name of the account without the root.
For example, an input of 'Assets:BofA:Checking' will produce 'BofA:Checking'.
Args:
account_name: A string, the name of the account whose leaf name to return.
Returns:
A string, the name of the non-root portion of this account name.
"""
assert isinstance(account_name, str)
components = account_name.split(sep)[1:]
return join(*components) if account_name else None
beancount.core.account.split(account_name)
将账户名称拆分为其各个组成部分。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account.py
def split(account_name: Account) -> List[str]:
"""Split an account's name into its components.
Args:
account_name: A string, an account name.
Returns:
A list of strings, the components of the account name (without the separators).
"""
return account_name.split(sep)
beancount.core.account.walk(root_directory)
一个 os.walk() 的变体,仅生成有效的账户名称目录。
此函数仅生成符合账户规范的目录……其他目录会被跳过。为方便起见,它还会返回账户的名称。
| 参数: |
|
|---|
返回:类似于 os.walk() 的元组 (root, account-name, dirs, files)。
源代码位于 beancount/core/account.py
def walk(root_directory: Account) -> Iterator[Tuple[str, Account, List[str], List[str]]]:
"""A version of os.walk() which yields directories that are valid account names.
This only yields directories that are accounts... it skips the other ones.
For convenience, it also yields you the account's name.
Args:
root_directory: A string, the name of the root of the hierarchy to be walked.
Yields:
Tuples of (root, account-name, dirs, files), similar to os.walk().
"""
for root, dirs, files in os.walk(root_directory):
dirs.sort()
files.sort()
relroot = root[len(root_directory)+1:]
account_name = relroot.replace(os.sep, sep)
# The regex module does not handle Unicode characters in decomposed
# form. Python uses the normal form for representing string. However,
# some filesystems use the canonical decomposition form.
# See https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize
account_name = unicodedata.normalize('NFKC', account_name)
if is_valid(account_name):
yield (root, account_name, dirs, files)
beancount.core.account_types
全局账户类型的定义。
此处保存全局账户类型的值和定义。
需要注意的是,我们在这里使用了全局变量和副作用,这并不理想,但这是短期的最佳解决方案,因为账户类型在太多地方被使用,无法在各处传递该状态。也许以后我们会改进这一点。
beancount.core.account_types.AccountTypes (tuple)
AccountTypes(assets, liabilities, equity, income, expenses)
beancount.core.account_types.AccountTypes.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/account_types.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.account_types.AccountTypes.__new__(_cls, assets, liabilities, equity, income, expenses)
特殊
静态方法
创建一个新的 AccountTypes 实例,包含 assets、liabilities、equity、income 和 expenses。
beancount.core.account_types.AccountTypes.__replace__(/, self, **kwds)
特殊
返回一个新的 AccountTypes 对象,用指定的新值替换相应字段。
源代码位于 beancount/core/account_types.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.account_types.AccountTypes.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/account_types.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.account_types.get_account_sign(account_name, account_types=None)
返回特定账户的正常余额符号。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def get_account_sign(account_name: Account, account_types: AccountTypes=None) -> int:
"""Return the sign of the normal balance of a particular account.
Args:
account_name: A string, the name of the account whose sign is to return.
account_types: An optional instance of the current account_types.
Returns:
+1 or -1, depending on the account's type.
"""
if account_types is None:
account_types = DEFAULT_ACCOUNT_TYPES
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
account_type = get_account_type(account_name)
return (+1
if account_type in (account_types.assets,
account_types.expenses)
else -1)
beancount.core.account_types.get_account_sort_key(account_types, account_name)
返回一个可用于对账户名称进行排序的元组。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def get_account_sort_key(account_types: AccountTypes,
account_name: Account) -> Tuple[str, Account]:
"""Return a tuple that can be used to order/sort account names.
Args:
account_types: An instance of AccountTypes, a tuple of account type names.
Returns:
An object to use as the 'key' argument to the sort function.
"""
return (account_types.index(get_account_type(account_name)), account_name)
beancount.core.account_types.get_account_type(account_name)
返回该账户名称的类型。
警告:不会检查账户类型的有效性。此函数仅返回对应账户名称的根账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def get_account_type(account_name: Account):
"""Return the type of this account's name.
Warning: No check is made on the validity of the account type. This merely
returns the root account of the corresponding account name.
Args:
account_name: A string, the name of the account whose type is to return.
Returns:
A string, the type of the account in 'account_name'.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
return account.split(account_name)[0]
beancount.core.account_types.is_account_type(account_type, account_name)
返回该账户名称的类型。
警告:不会检查账户类型的有效性。此函数仅返回对应账户名称的根账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def is_account_type(account_type: str, account_name: Account) -> bool:
"""Return the type of this account's name.
Warning: No check is made on the validity of the account type. This merely
returns the root account of the corresponding account name.
Args:
account_type: A string, the prefix type of the account.
account_name: A string, the name of the account whose type is to return.
Returns:
A boolean, true if the account is of the given type.
"""
return bool(re.match('^{}{}'.format(account_type, account.sep), account_name))
beancount.core.account_types.is_balance_sheet_account(account_name, account_types)
如果给定账户是资产负债表账户,则返回真。资产、负债和权益账户均为资产负债表账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def is_balance_sheet_account(account_name: Account, account_types: AccountTypes) -> bool:
"""Return true if the given account is a balance sheet account.
Assets, liabilities and equity accounts are balance sheet accounts.
Args:
account_name: A string, an account name.
account_types: An instance of AccountTypes.
Returns:
A boolean, true if the account is a balance sheet account.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
assert isinstance(account_types, AccountTypes), (
"Account types has invalid type: {}".format(account_types))
account_type = get_account_type(account_name)
return account_type in (account_types.assets,
account_types.liabilities,
account_types.equity)
beancount.core.account_types.is_equity_account(account_name, account_types)
如果给定账户是权益账户,则返回真。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def is_equity_account(account_name: Account, account_types: AccountTypes) -> bool:
"""Return true if the given account is an equity account.
Args:
account_name: A string, an account name.
account_types: An instance of AccountTypes.
Returns:
A boolean, true if the account is an equity account.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
assert isinstance(account_types, AccountTypes), (
"Account types has invalid type: {}".format(account_types))
account_type = get_account_type(account_name)
return account_type == account_types.equity
beancount.core.account_types.is_income_statement_account(account_name, account_types)
如果给定账户是利润表账户,则返回真。收入和费用账户均为利润表账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def is_income_statement_account(account_name: Account, account_types: AccountTypes) -> bool:
"""Return true if the given account is an income statement account.
Income and expense accounts are income statement accounts.
Args:
account_name: A string, an account name.
account_types: An instance of AccountTypes.
Returns:
A boolean, true if the account is an income statement account.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
assert isinstance(account_types, AccountTypes), (
"Account types has invalid type: {}".format(account_types))
account_type = get_account_type(account_name)
return account_type in (account_types.income,
account_types.expenses)
beancount.core.account_types.is_inverted_account(account_name, account_types)
如果给定账户具有反向符号,则返回真。
反向符号是指与外部报表中预期相反的符号,即所有符号均按正数预期处理。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def is_inverted_account(account_name: Account, account_types: AccountTypes) -> bool:
"""Return true if the given account has inverted signs.
An inverted sign is the inverse as you'd expect in an external report, i.e.,
with all positive signs expected.
Args:
account_name: A string, an account name.
account_types: An instance of AccountTypes.
Returns:
A boolean, true if the account has an inverted sign.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
assert isinstance(account_types, AccountTypes), (
"Account types has invalid type: {}".format(account_types))
account_type = get_account_type(account_name)
return account_type in (account_types.liabilities,
account_types.income,
account_types.equity)
beancount.core.account_types.is_root_account(account_name)
如果账户名称是根账户,则返回真。
此函数不验证根账户是否有效,仅判断其是否为根账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/account_types.py
def is_root_account(account_name: Account) -> bool:
"""Return true if the account name is a root account.
This function does not verify whether the account root is a valid
one, just that it is a root account or not.
Args:
account_name: A string, the name of the account to check for.
Returns:
A boolean, true if the account is root account.
"""
assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
return (account_name and
bool(re.match(r'([A-Z][A-Za-z0-9\-]+)$', account_name)))
beancount.core.amount
Amount 类。
这个简单的类用于将某种货币的单位数量与其货币关联起来:
(数量, 货币)。
beancount.core.amount.Amount (_Amount)
一个 'Amount' 表示某种单位的特定数量。
它本质上是一个有类型的数字,并定义了相应的操作方法。
beancount.core.amount.Amount.__bool__(self)
特殊
布尔谓词,当数字非零时返回真。
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __bool__(self):
"""Boolean predicate returns true if the number is non-zero.
Returns:
A boolean, true if non-zero number.
"""
return self.number != ZERO
beancount.core.amount.Amount.__eq__(self, other)
特殊
相等性谓词。当数字和货币都相等时返回真。
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __eq__(self, other):
"""Equality predicate. Returns true if both number and currency are equal.
Returns:
A boolean.
"""
if other is None:
return False
return (self.number, self.currency) == (other.number, other.currency)
beancount.core.amount.Amount.__hash__(self)
特殊
用于金额的哈希函数。哈希值包含货币信息。
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __hash__(self):
"""A hashing function for amounts. The hash includes the currency.
Returns:
An integer, the hash for this amount.
"""
return hash((self.number, self.currency))
beancount.core.amount.Amount.__lt__(self, other)
特殊
排序比较。用于持仓排序键。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __lt__(self, other):
"""Ordering comparison. This is used in the sorting key of positions.
Args:
other: An instance of Amount.
Returns:
True if this is less than the other Amount.
"""
return sortkey(self) < sortkey(other)
beancount.core.amount.Amount.__neg__(self)
特殊
返回此金额的负值。
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __neg__(self):
"""Return the negative of this amount.
Returns:
A new instance of Amount, with the negative number of units.
"""
return Amount(-self.number, self.currency)
beancount.core.amount.Amount.__new__(cls, number, currency)
特殊
静态方法
通过数字和货币构造。
| 参数: |
|
|---|
源代码位于 beancount/core/amount.py
def __new__(cls, number, currency):
"""Constructor from a number and currency.
Args:
number: A Decimal instance.
currency: A string, the currency symbol to use.
"""
assert isinstance(number, Amount.valid_types_number), repr(number)
assert isinstance(currency, Amount.valid_types_currency), repr(currency)
return _Amount.__new__(cls, number, currency)
beancount.core.amount.Amount.__repr__(self)
特殊
将 Amount 实例转换为默认格式的可打印字符串。
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __str__(self):
"""Convert an Amount instance to a printable string with the defaults.
Returns:
A formatted string of the quantized amount and symbol.
"""
return self.to_string()
beancount.core.amount.Amount.__str__(self)
特殊
将 Amount 实例转换为默认格式的可打印字符串。
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def __str__(self):
"""Convert an Amount instance to a printable string with the defaults.
Returns:
A formatted string of the quantized amount and symbol.
"""
return self.to_string()
beancount.core.amount.Amount.from_string(string)
静态方法
从字符串创建一个金额。
这是一个用于构建测试的小型解析器。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
@staticmethod
def from_string(string):
"""Create an amount from a string.
This is a miniature parser used for building tests.
Args:
string: A string of <number> <currency>.
Returns:
A new instance of Amount.
"""
match = re.match(r'\s*([-+]?[0-9.]+)\s+({currency})'.format(currency=CURRENCY_RE),
string)
if not match:
raise ValueError("Invalid string for amount: '{}'".format(string))
number, currency = match.group(1, 2)
return Amount(D(number), currency)
beancount.core.amount.Amount.to_string(self, dformat=)
将 Amount 实例转换为可打印的字符串。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def to_string(self, dformat=DEFAULT_FORMATTER):
"""Convert an Amount instance to a printable string.
Args:
dformat: An instance of DisplayFormatter.
Returns:
A formatted string of the quantized amount and symbol.
"""
if isinstance(self.number, Decimal):
number_fmt = dformat.format(self.number, self.currency)
elif self.number is MISSING:
number_fmt = ''
else:
number_fmt = str(self.number)
return "{} {}".format(number_fmt, self.currency)
beancount.core.amount.A(string)
从字符串创建一个金额。
这是一个用于构建测试的小型解析器。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
@staticmethod
def from_string(string):
"""Create an amount from a string.
This is a miniature parser used for building tests.
Args:
string: A string of <number> <currency>.
Returns:
A new instance of Amount.
"""
match = re.match(r'\s*([-+]?[0-9.]+)\s+({currency})'.format(currency=CURRENCY_RE),
string)
if not match:
raise ValueError("Invalid string for amount: '{}'".format(string))
number, currency = match.group(1, 2)
return Amount(D(number), currency)
beancount.core.amount.abs(amount)
返回给定金额的绝对值。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def abs(amount):
"""Return the absolute value of the given amount.
Args:
amount: An instance of Amount.
Returns:
An instance of Amount.
"""
return (amount
if amount.number >= ZERO
else Amount(-amount.number, amount.currency))
beancount.core.amount.add(amount1, amount2)
将具有相同货币的两个金额相加。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def add(amount1, amount2):
"""Add the given amounts with the same currency.
Args:
amount1: An instance of Amount.
amount2: An instance of Amount.
Returns:
An instance of Amount, with the sum the two amount's numbers, in the same
currency.
"""
assert isinstance(amount1.number, Decimal), (
"Amount1's number is not a Decimal instance: {}".format(amount1.number))
assert isinstance(amount2.number, Decimal), (
"Amount2's number is not a Decimal instance: {}".format(amount2.number))
if amount1.currency != amount2.currency:
raise ValueError(
"Unmatching currencies for operation on {} and {}".format(
amount1, amount2))
return Amount(amount1.number + amount2.number, amount1.currency)
beancount.core.amount.div(amount, number)
将给定金额除以一个数值。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def div(amount, number):
"""Divide the given amount by a number.
Args:
amount: An instance of Amount.
number: A decimal number.
Returns:
An Amount, with the same currency, but with amount units divided by 'number'.
"""
assert isinstance(amount.number, Decimal), (
"Amount's number is not a Decimal instance: {}".format(amount.number))
assert isinstance(number, Decimal), (
"Number is not a Decimal instance: {}".format(number))
return Amount(amount.number / number, amount.currency)
beancount.core.amount.from_string(string)
从字符串创建一个金额。
这是一个用于构建测试的小型解析器。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
@staticmethod
def from_string(string):
"""Create an amount from a string.
This is a miniature parser used for building tests.
Args:
string: A string of <number> <currency>.
Returns:
A new instance of Amount.
"""
match = re.match(r'\s*([-+]?[0-9.]+)\s+({currency})'.format(currency=CURRENCY_RE),
string)
if not match:
raise ValueError("Invalid string for amount: '{}'".format(string))
number, currency = match.group(1, 2)
return Amount(D(number), currency)
beancount.core.amount.mul(amount, number)
将给定金额乘以一个数值。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def mul(amount, number):
"""Multiply the given amount by a number.
Args:
amount: An instance of Amount.
number: A decimal number.
Returns:
An Amount, with the same currency, but with 'number' times units.
"""
assert isinstance(amount.number, Decimal), (
"Amount's number is not a Decimal instance: {}".format(amount.number))
assert isinstance(number, Decimal), (
"Number is not a Decimal instance: {}".format(number))
return Amount(amount.number * number, amount.currency)
beancount.core.amount.sortkey(amount)
一种比较函数,优先按货币排序。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def sortkey(amount):
"""A comparison function that sorts by currency first.
Args:
amount: An instance of Amount.
Returns:
A sort key, composed of the currency first and then the number.
"""
return (amount.currency, amount.number)
beancount.core.amount.sub(amount1, amount2)
将具有相同货币的两个金额相减。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/amount.py
def sub(amount1, amount2):
"""Subtract the given amounts with the same currency.
Args:
amount1: An instance of Amount.
amount2: An instance of Amount.
Returns:
An instance of Amount, with the difference between the two amount's
numbers, in the same currency.
"""
assert isinstance(amount1.number, Decimal), (
"Amount1's number is not a Decimal instance: {}".format(amount1.number))
assert isinstance(amount2.number, Decimal), (
"Amount2's number is not a Decimal instance: {}".format(amount2.number))
if amount1.currency != amount2.currency:
raise ValueError(
"Unmatching currencies for operation on {} and {}".format(
amount1, amount2))
return Amount(amount1.number - amount2.number, amount1.currency)
beancount.core.compare
用于数据对象的比较辅助工具。
beancount.core.compare.CompareError (元组)
CompareError(source, message, entry)
beancount.core.compare.CompareError.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/compare.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.compare.CompareError.__new__(_cls, source, message, entry)
特殊
静态方法
创建 CompareError(source, message, entry) 的新实例
beancount.core.compare.CompareError.__replace__(/, self, **kwds)
特殊
返回一个新的 CompareError 对象,用指定的新值替换字段
源代码位于 beancount/core/compare.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.compare.CompareError.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/compare.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.compare.compare_entries(entries1, entries2)
比较两个条目列表。此函数用于测试。
比较时忽略条目的文件位置。
| 参数: |
|
|---|
| 返回: |
|
|---|
| 异常: |
|
|---|
源代码位于 beancount/core/compare.py
def compare_entries(entries1, entries2):
"""Compare two lists of entries. This is used for testing.
The entries are compared with disregard for their file location.
Args:
entries1: A list of directives of any type.
entries2: Another list of directives of any type.
Returns:
A tuple of (success, not_found1, not_found2), where the fields are:
success: A boolean, true if all the values are equal.
missing1: A list of directives from 'entries1' not found in
'entries2'.
missing2: A list of directives from 'entries2' not found in
'entries1'.
Raises:
ValueError: If a duplicate entry is found.
"""
hashes1, errors1 = hash_entries(entries1, exclude_meta=True)
hashes2, errors2 = hash_entries(entries2, exclude_meta=True)
keys1 = set(hashes1.keys())
keys2 = set(hashes2.keys())
if errors1 or errors2:
error = (errors1 + errors2)[0]
raise ValueError(str(error))
same = keys1 == keys2
missing1 = data.sorted([hashes1[key] for key in keys1 - keys2])
missing2 = data.sorted([hashes2[key] for key in keys2 - keys1])
return (same, missing1, missing2)
beancount.core.compare.excludes_entries(subset_entries, entries)
检查一个条目列表是否不出现在另一个列表中。
| 参数: |
|
|---|
| 返回: |
|
|---|
| 异常: |
|
|---|
源代码位于 beancount/core/compare.py
def excludes_entries(subset_entries, entries):
"""Check that a list of entries does not appear in another list.
Args:
subset_entries: The set of entries to look for in 'entries'.
entries: The larger list of entries that should not include 'subset_entries'.
Returns:
A boolean and a list of entries that are not supposed to appear.
Raises:
ValueError: If a duplicate entry is found.
"""
subset_hashes, subset_errors = hash_entries(subset_entries, exclude_meta=True)
subset_keys = set(subset_hashes.keys())
hashes, errors = hash_entries(entries, exclude_meta=True)
keys = set(hashes.keys())
if subset_errors or errors:
error = (subset_errors + errors)[0]
raise ValueError(str(error))
intersection = keys.intersection(subset_keys)
excludes = not bool(intersection)
extra = data.sorted([subset_hashes[key] for key in intersection])
return (excludes, extra)
beancount.core.compare.hash_entries(entries, exclude_meta=False)
计算每个条目的唯一哈希值并返回映射。
此函数用于比较条目集合。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/compare.py
def hash_entries(entries, exclude_meta=False):
"""Compute unique hashes of each of the entries and return a map of them.
This is used for comparisons between sets of entries.
Args:
entries: A list of directives.
exclude_meta: If set, exclude the metadata from the hash. Use this for
unit tests comparing entries coming from different sources as the
filename and lineno will be distinct. However, when you're using the
hashes to uniquely identify transactions, you want to include the
filenames and line numbers (the default).
Returns:
A dict of hash-value to entry (for all entries) and a list of errors.
Errors are created when duplicate entries are found.
"""
entry_hash_dict = {}
errors = []
num_legal_duplicates = 0
for entry in entries:
hash_ = hash_entry(entry, exclude_meta)
if hash_ in entry_hash_dict:
if isinstance(entry, Price):
# Note: Allow duplicate Price entries, they should be common
# because of the nature of stock markets (if they're closed, the
# data source is likely to return an entry for the previously
# available date, which may already have been fetched).
num_legal_duplicates += 1
else:
other_entry = entry_hash_dict[hash_]
errors.append(
CompareError(entry.meta,
"Duplicate entry: {} == {}".format(entry, other_entry),
entry))
entry_hash_dict[hash_] = entry
if not errors:
assert len(entry_hash_dict) + num_legal_duplicates == len(entries), (
len(entry_hash_dict), len(entries), num_legal_duplicates)
return entry_hash_dict, errors
beancount.core.compare.hash_entry(entry, exclude_meta=False)
计算单个条目的稳定哈希值。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/compare.py
def hash_entry(entry, exclude_meta=False):
"""Compute the stable hash of a single entry.
Args:
entry: A directive instance.
exclude_meta: If set, exclude the metadata from the hash. Use this for
unit tests comparing entries coming from different sources as the
filename and lineno will be distinct. However, when you're using the
hashes to uniquely identify transactions, you want to include the
filenames and line numbers (the default).
Returns:
A stable hexadecimal hash of this entry.
"""
return stable_hash_namedtuple(entry,
IGNORED_FIELD_NAMES if exclude_meta else frozenset())
beancount.core.compare.includes_entries(subset_entries, entries)
检查一个条目列表是否包含在另一个列表中。
| 参数: |
|
|---|
| 返回: |
|
|---|
| 异常: |
|
|---|
源代码位于 beancount/core/compare.py
def includes_entries(subset_entries, entries):
"""Check if a list of entries is included in another list.
Args:
subset_entries: The set of entries to look for in 'entries'.
entries: The larger list of entries that could include 'subset_entries'.
Returns:
A boolean and a list of missing entries.
Raises:
ValueError: If a duplicate entry is found.
"""
subset_hashes, subset_errors = hash_entries(subset_entries, exclude_meta=True)
subset_keys = set(subset_hashes.keys())
hashes, errors = hash_entries(entries, exclude_meta=True)
keys = set(hashes.keys())
if subset_errors or errors:
error = (subset_errors + errors)[0]
raise ValueError(str(error))
includes = subset_keys.issubset(keys)
missing = data.sorted([subset_hashes[key] for key in subset_keys - keys])
return (includes, missing)
beancount.core.compare.stable_hash_namedtuple(objtuple, ignore=frozenset())
对给定的命名元组及其子字段进行哈希计算。
此函数遍历 objtuple 的所有成员,跳过 'ignore' 集合中的属性,并计算一个唯一的哈希字符串。如果元素是列表或集合,则对其进行排序以确保稳定性。
| 参数: |
|
|---|
源代码位于 beancount/core/compare.py
def stable_hash_namedtuple(objtuple, ignore=frozenset()):
"""Hash the given namedtuple and its child fields.
This iterates over all the members of objtuple, skipping the attributes from
the 'ignore' set, and computes a unique hash string code. If the elements
are lists or sets, sorts them for stability.
Args:
objtuple: A tuple object or other.
ignore: A set of strings, attribute names to be skipped in
computing a stable hash. For instance, circular references to objects
or irrelevant data.
"""
# Note: this routine is slow and would stand to be implemented in C.
hashobj = hashlib.md5()
for attr_name, attr_value in zip(objtuple._fields, objtuple):
if attr_name in ignore:
continue
if isinstance(attr_value, (list, set, frozenset)):
subhashes = []
for element in attr_value:
if isinstance(element, tuple):
subhashes.append(stable_hash_namedtuple(element, ignore))
else:
md5 = hashlib.md5()
md5.update(str(element).encode())
subhashes.append(md5.hexdigest())
for subhash in sorted(subhashes):
hashobj.update(subhash.encode())
else:
hashobj.update(str(attr_value).encode())
return hashobj.hexdigest()
beancount.core.convert
从 Position(或 Posting)转换为单位、成本、重量、市场价值。
- 单位:仅指头寸的主要金额。
- 成本:头寸的成本基础(如果可用)。
- 重量:头寸的成本基础或价格。
- 市场价值:通过价格映射将单位转换为的价值。
要转换库存内容,只需将这些函数与 Inventory.reduce() 结合使用,例如
cost_inv = inv.reduce(convert.get_cost)
本模块等效地转换 Position 和 Posting 实例。请注意,我们特意避免创建对 beancount.core.data 的导入依赖,以保持本模块的可隔离性,但通过鸭子类型,它可作用于 Posting。
名为 get_*() 的函数用于从 Posting 计算其价格货币的值;名为 convert_*() 的函数用于将 Posting 和金额转换为任意货币。
beancount.core.convert.convert_amount(amt, target_currency, price_map, date=None, via=None)
返回 Amount 在特定货币下的市场价值。
此外,如果无法获取转换汇率,您可以提供一个货币列表,尝试通过隐含汇率合成一个转换率。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/convert.py
def convert_amount(amt, target_currency, price_map, date=None, via=None):
"""Return the market value of an Amount in a particular currency.
In addition, if a conversion rate isn't available, you can provide a list of
currencies to attempt to synthesize a rate for via implied rates.
Args:
amt: An instance of Amount.
target_currency: The target currency to convert to.
price_map: A dict of prices, as built by prices.build_price_map().
date: A datetime.date instance to evaluate the value at, or None.
via: A list of currencies to attempt to synthesize an implied rate if the
direct conversion fails.
Returns:
An Amount, either with a successful value currency conversion, or if we
could not convert the value, the amount itself, unmodified.
"""
# First, attempt to convert directly. This should be the most
# straightforward conversion.
base_quote = (amt.currency, target_currency)
_, rate = prices.get_price(price_map, base_quote, date)
if rate is not None:
# On success, just make the conversion directly.
return Amount(amt.number * rate, target_currency)
elif via:
assert isinstance(via, (tuple, list))
# A price is unavailable, attempt to convert via cost/price currency
# hop, if the value currency isn't the target currency.
for implied_currency in via:
if implied_currency == target_currency:
continue
base_quote1 = (amt.currency, implied_currency)
_, rate1 = prices.get_price(price_map, base_quote1, date)
if rate1 is not None:
base_quote2 = (implied_currency, target_currency)
_, rate2 = prices.get_price(price_map, base_quote2, date)
if rate2 is not None:
return Amount(amt.number * rate1 * rate2, target_currency)
# We failed to infer a conversion rate; return the amt.
return amt
beancount.core.convert.convert_position(pos, target_currency, price_map, date=None)
返回 Position 或 Posting 在特定货币下的市场价值。
此外,如果从头寸货币到目标货币的汇率不可用,系统将尝试使用其成本货币(如果存在)进行转换。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/convert.py
def convert_position(pos, target_currency, price_map, date=None):
"""Return the market value of a Position or Posting in a particular currency.
In addition, if the rate from the position's currency to target_currency
isn't available, an attempt is made to convert from its cost currency, if
one is available.
Args:
pos: An instance of Position or Posting, equivalently.
target_currency: The target currency to convert to.
price_map: A dict of prices, as built by prices.build_price_map().
date: A datetime.date instance to evaluate the value at, or None.
Returns:
An Amount, either with a successful value currency conversion, or if we
could not convert the value, just the units, unmodified. (See get_value()
above for details.)
"""
cost = pos.cost
value_currency = (
(isinstance(cost, Cost) and cost.currency) or
(hasattr(pos, 'price') and pos.price and pos.price.currency) or
None)
return convert_amount(pos.units, target_currency, price_map,
date=date, via=(value_currency,))
beancount.core.convert.get_cost(pos)
返回 Position 或 Posting 的总成本。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/convert.py
def get_cost(pos):
"""Return the total cost of a Position or Posting.
Args:
pos: An instance of Position or Posting, equivalently.
Returns:
An Amount.
"""
assert isinstance(pos, Position) or type(pos).__name__ == 'Posting'
cost = pos.cost
return (Amount(cost.number * pos.units.number, cost.currency)
if (isinstance(cost, Cost) and isinstance(cost.number, Decimal))
else pos.units)
beancount.core.convert.get_units(pos)
返回 Position 或 Posting 的单位。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/convert.py
def get_units(pos):
"""Return the units of a Position or Posting.
Args:
pos: An instance of Position or Posting, equivalently.
Returns:
An Amount.
"""
assert isinstance(pos, Position) or type(pos).__name__ == 'Posting'
return pos.units
beancount.core.convert.get_value(pos, price_map, date=None, output_date_prices=None)
返回 Position 或 Posting 的市场价值。
请注意,如果该头寸不是按成本持有,则即使 price_map 中存在价格,也不会进行任何转换。我们在此未指定目标货币。如果你试图进行此类转换,请参阅下面的 convert_*() 函数。然而,如果该对象是 Posting 且具有价格,我们将使用该价格推断目标货币并进行转换。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/convert.py
def get_value(pos, price_map, date=None, output_date_prices=None):
"""Return the market value of a Position or Posting.
Note that if the position is not held at cost, this does not convert
anything, even if a price is available in the 'price_map'. We don't specify
a target currency here. If you're attempting to make such a conversion, see
``convert_*()`` functions below. However, is the object is a posting and it
has a price, we will use that price to infer the target currency and those
will be converted.
Args:
pos: An instance of Position or Posting, equivalently.
price_map: A dict of prices, as built by prices.build_price_map().
date: A datetime.date instance to evaluate the value at, or None.
output_date_prices: An optional output list of (date, price). If this list
is provided, it will be appended to (mutated) to output the price
pulled in making the conversions.
Returns:
An Amount, either with a successful value currency conversion, or if we
could not convert the value, just the units, unmodified. This is designed
so that you could reduce an inventory with this and not lose any
information silently in case of failure to convert (possibly due to an
empty price map). Compare the returned currency to that of the input
position if you need to check for success.
"""
assert isinstance(pos, Position) or type(pos).__name__ == 'Posting'
units = pos.units
cost = pos.cost
# Try to infer what the cost/price currency should be.
value_currency = (
(isinstance(cost, Cost) and cost.currency) or
(hasattr(pos, 'price') and pos.price and pos.price.currency) or
None)
if isinstance(value_currency, str):
# We have a value currency; hit the price database.
base_quote = (units.currency, value_currency)
price_date, price_number = prices.get_price(price_map, base_quote, date)
if output_date_prices is not None:
output_date_prices.append((price_date, price_number))
if price_number is not None:
return Amount(units.number * price_number, value_currency)
# We failed to infer a conversion rate; return the units.
return units
beancount.core.convert.get_weight(pos)
返回 Position 或 Posting 的重量。
这是交易中一笔分录需要平衡的金额。
这是本软件中交易语义的关键要素。平衡金额是用于检查交易平衡的金额。以下是所有相关示例,其中列出了用于平衡分录的金额:
Assets:Account 5234.50 USD -> 5234.50 USD
Assets:Account 3877.41 EUR @ 1.35 USD -> 5234.50 USD
Assets:Account 10 HOOL {523.45 USD} -> 5234.50 USD
Assets:Account 10 HOOL {523.45 USD} @ 545.60 CAD -> 5234.50 USD
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/convert.py
def get_weight(pos):
"""Return the weight of a Position or Posting.
This is the amount that will need to be balanced from a posting of a
transaction.
This is a *key* element of the semantics of transactions in this software. A
balance amount is the amount used to check the balance of a transaction.
Here are all relevant examples, with the amounts used to balance the
postings:
Assets:Account 5234.50 USD -> 5234.50 USD
Assets:Account 3877.41 EUR @ 1.35 USD -> 5234.50 USD
Assets:Account 10 HOOL {523.45 USD} -> 5234.50 USD
Assets:Account 10 HOOL {523.45 USD} @ 545.60 CAD -> 5234.50 USD
Args:
pos: An instance of Position or Posting, equivalently.
Returns:
An Amount.
"""
assert isinstance(pos, Position) or type(pos).__name__ == 'Posting'
units = pos.units
cost = pos.cost
# It the object has a cost, use that as the weight, to balance.
if isinstance(cost, Cost) and isinstance(cost.number, Decimal):
weight = Amount(cost.number * pos.units.number, cost.currency)
else:
# Otherwise use the postings.
weight = units
# Unless there is a price available; use that if present.
if not isinstance(pos, Position):
price = pos.price
if price is not None:
# Note: Here we could assert that price.currency == units.currency.
if price.number is MISSING or units.number is MISSING:
converted_number = MISSING
else:
converted_number = price.number * units.number
weight = Amount(converted_number, price.currency)
return weight
beancount.core.data
用于表示账本条目的基本数据结构。
beancount.core.data.Balance (元组)
一种“检查该账户余额”的指令。此指令断言,在指定日期开始时,声明的账户应具有特定货币的已知单位数量。这本质上是一种断言,对应于现实世界对账单中的“对账余额”行。这些断言作为检查点,帮助确保你正确录入了交易。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示在指定日期需要检查余额的账户。 |
金额 |
金额 |
一个 Amount,表示你期望该账户在该日期持有的货币单位数量。 |
差额 |
Optional[beancount.core.amount.Amount] |
如果余额检查成功,则为 None;如果失败,则设为一个 Amount 实例,表示差额金额。 |
容差 |
Optional[decimal.Decimal] |
一个 Decimal 对象,表示验证时使用的容差值。 |
beancount.core.data.Balance.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Balance.__new__(_cls, meta, date, account, amount, tolerance, diff_amount)
特殊
静态方法
创建 Balance(meta, date, account, amount, tolerance, diff_amount) 的新实例
beancount.core.data.Balance.__replace__(/, self, **kwds)
特殊
返回一个新的 Balance 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Balance.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Close (元组)
“关闭账户”指令。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示被关闭的账户名称。 |
beancount.core.data.Close.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Close.__new__(_cls, meta, date, account)
特殊
静态方法
创建 Close(meta, date, account) 的新实例
beancount.core.data.Close.__replace__(/, self, **kwds)
特殊
返回一个新的 Close 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Close.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Commodity (元组)
可选的商品声明指令。通常不需要声明商品,但可以声明,主要用于为商品名称附加元数据。当插件需要针对特定商品的元数据时,您应定义此类商品指令。另一个用途是定义一个尚未在任何输入文件中使用的商品。(目前日期无实际意义,但为了与其他指令保持一致而保留;如果您有好的使用场景,请告诉我们)。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
货币 |
str |
一个字符串,表示所考虑的商品。 |
beancount.core.data.Commodity.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Commodity.__new__(_cls, meta, date, currency)
特殊
静态方法
创建 Commodity(meta, date, currency) 的新实例
beancount.core.data.Commodity.__replace__(/, self, **kwds)
特殊
返回一个新的 Commodity 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Commodity.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Custom (元组)
自定义指令。此指令可用于在 Beancount 文件中实现新的实验性日期功能。当您需要在插件中实现新指令时,这可作为临时措施。这些指令将被宽松地解析……支持任意的标记列表。唯一要求是为它们提供一个唯一的名称作为“类型”。这些指令会被包含在数据流中,插件应能收集它们。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
type |
str |
表示指令类型的字符串。 |
值 |
列表 |
由语法支持的各种简单类型的值组成的列表。(注意:解析器不会强制要求同一类型的所有指令在此列表中保持一致性。) |
beancount.core.data.Custom.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Custom.__new__(_cls, meta, date, type, values)
特殊
静态方法
创建 Custom(meta, date, type, values) 的新实例
beancount.core.data.Custom.__replace__(/, self, **kwds)
特殊
返回一个新的 Custom 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Custom.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Document (元组)
文档文件声明指令。此指令用于在特定日期将对账单附加到账户。典型用法是将银行对账单的 PDF 文件或扫描件关联到账户的日记账中。虽然您可以在输入语法中显式创建这些指令,但更便捷的方式是为 Beancount 提供一个根目录,用于按与会计科目表结构一致的层级搜索文件名,文件名应符合以下带日期的格式:"YYYY-MM-DD.*"。详见选项说明。Beancount 将根据文件层级自动创建这些文档指令,您可以通过解析条目列表获取它们。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
字符串,该对账单或文档关联的账户。 |
filename |
str |
文档文件的绝对路径。 |
标签 |
可选[集合] |
标签字符串集合(不含 '#'),若为空集则为 None。 |
链接 |
可选[集合] |
链接字符串集合(不含 '^'),若为空集则为 None。 |
beancount.core.data.Document.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Document.__new__(_cls, meta, date, account, filename, tags, links)
特殊
静态方法
创建 Document(meta, date, account, filename, tags, links) 的新实例
beancount.core.data.Document.__replace__(/, self, **kwds)
特殊
返回一个新的 Document 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Document.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Event (元组)
“事件值变更”指令。这些指令用于表示随时间变化的字符串变量。您可以使用它们来跟踪地址、所在地、当前雇主等任何信息。对这些通用事件的报表基于天数和时间线。例如,若您需要跟踪在每个国家或州停留的天数,可创建一个“location”事件,每次旅行时添加一条事件指令以标明新值。您可编写简单脚本计算是否在某地停留了特定天数。举例而言,为维持加拿大健康保险资格,您需在该国停留至少 183 天,且不计算少于 30 天的短期出行。美国对非居民也有类似测试(即所谓的“实际居留测试”),以判断是否需视为税务居民。通过将这些指令整合到您的记账系统中,您可以轻松编写程序自动执行这些计算。当然,这完全属于可选功能,与复式记账的核心目的略有偏离,但与您录入的交易高度相关,因此将其放在同一输入文件中非常方便。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
"类型" |
短字符串,通常为单个小写单词,用于定义一个随时间变化的唯一变量。例如:'location'。 |
|
描述 |
str |
自由格式字符串,表示截至交易日期该变量的值。 |
beancount.core.data.Event.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Event.__new__(_cls, meta, date, type, description)
特殊
静态方法
创建 Event(meta, date, type, description) 的新实例
beancount.core.data.Event.__replace__(/, self, **kwds)
特殊
返回一个新的 Event 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Event.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Note (元组)
一条注释指令,用于附加到账户的一般性注释。这些注释用于在特定日期将文本附加到特定账户。注释内容可以是任意文本;典型用途是记录与账户所代表机构电话沟通的答复。它应显示在账户的日记账中。如果你不希望它被渲染,请使用输入文件中的注释语法,该语法不会被解析和存储。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示要附加注释的账户。此值永不为 None,注释总是对应某个账户。 |
注释 |
str |
一个自由格式的字符串,表示注释的文本内容。如果需要,它可以很长。 |
beancount.core.data.Note.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Note.__new__(_cls, meta, date, account, comment, tags, links)
特殊
静态方法
创建 Note(meta, date, account, comment, tags, links) 的新实例
beancount.core.data.Note.__replace__(/, self, **kwds)
特殊
返回一个新的 Note 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Note.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Open (元组)
一条“打开账户”指令。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示正在打开的账户名称。 |
货币 |
List[str] |
一个字符串列表,表示允许存入该账户的货币。可以为 None,表示对该账户可存储的货币没有限制。 |
记账 |
Optional[beancount.core.data.Booking] |
一个 Booking 枚举,用于在多个记账项匹配时消歧该账户的记账方式,或未指定时为 None。实践中,绝大多数情况下应保持此属性未指定(None)。详见下方的 Booking 以获取有效方法列表。 |
beancount.core.data.Open.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Open.__new__(_cls, meta, date, account, currencies, booking)
特殊
静态方法
创建 Open(meta, date, account, currencies, booking) 的新实例
beancount.core.data.Open.__replace__(/, self, **kwds)
特殊
返回一个新的 Open 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Open.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Pad (元组)
一条“用其他账户填充此账户”的指令。此指令会自动插入交易,以确保下一个按时间顺序的余额指令能够成功执行。它可用于方便地填补交易历史中缺失的日期范围。你不必使用它,这只是在录入历史账目时提供的一种便利包装。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示需要被填充的账户名称。 |
源账户 |
str |
一个字符串,表示用于向“account”账户转账的借方账户名称。 |
beancount.core.data.Pad.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Pad.__new__(_cls, meta, date, account, source_account)
特殊
静态方法
创建一个新的 Pad 实例 (meta, date, account, source_account)
beancount.core.data.Pad.__replace__(/, self, **kwds)
特殊
返回一个新的 Pad 对象,用指定的新值替换相应字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Pad.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Posting (元组)
记账条目包含记账项。这些代表交易的各个分录。注意:一个记账项只能出现在单个条目中(多个交易不能共享同一个 Posting 实例),因此 entry 字段应设置为该条目。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
账户 |
str |
一个字符串,表示此记账项所修改的账户。 |
units |
Optional[beancount.core.amount.Amount] |
一个 Amount 对象,表示持仓的单位数量,或在交易中其他记账项可推断时设为 None。 |
cost |
Union[beancount.core.position.Cost, beancount.core.position.CostSpec] |
一个 Cost 或 CostSpec 实例,表示持仓的单位成本。 |
价格 |
Optional[beancount.core.amount.Amount] |
一个 Amount 对象,表示交易发生时的价格,或在不相关时设为 None。为记账项提供 price 成员会自动在交易日期向价格数据库添加一条价格记录。 |
flag |
Optional[str] |
一个可选标志,为一个字符的字符串或 None,用于关联此记账项。大多数记账项没有标志,但标记某个记账项为有问题或待对账,便于将来导入其账户时识别,这非常方便。 |
meta |
Optional[Dict[str, Any]] |
一个字符串到值的字典,表示该记账项附加的元数据,或未提供时为 None。实际上,大多数实例不太可能包含元数据。 |
beancount.core.data.Posting.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Posting.__new__(_cls, account, units, cost, price, flag, meta)
特殊
静态方法
创建一个新的 Posting 实例 (account, units, cost, price, flag, meta)
beancount.core.data.Posting.__replace__(/, self, **kwds)
特殊
返回一个新的 Posting 对象,用指定的新值替换相应字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Posting.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Price (元组)
价格声明指令。该指令确立了某一货币相对于另一货币在指令日期的价值。系统将为每对货币构建价格历史并可在记账系统中查询。注意:由于 Beancount 不存储时间精度为秒级的数据,因此在同一日期存在多个价格指令是没有意义的。(Beancount 不会尝试解决此问题;这超出了复式记账的一般范围;若需构建日内交易系统,建议使用其他工具)。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
currency:一个字符串,表示被定价的货币,例如 HOOL。amount:一个 Amount 实例,表示该货币的价值数量及单位,例如 1200.12 USD。
beancount.core.data.Price.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Price.__new__(_cls, meta, date, currency, amount)
特殊
静态方法
创建一个新的 Price 实例 (meta, date, currency, amount)
beancount.core.data.Price.__replace__(/, self, **kwds)
特殊
返回一个新的 Price 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Price.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Query (tuple)
命名查询声明。此指令用于创建预定义的查询,这些查询可自动运行、供 shell 使用,或作为网页界面的一部分呈现。此功能的目的是为特定的 Beancount 输入文件定义有用的查询。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
此查询应运行的日期。在此日期之后的所有指令将被自动忽略。这本质上等同于 shell 语法中的 CLOSE 修饰符。 |
名称 |
str |
一个字符串,查询的唯一标识符。 |
query_string |
str |
要运行或可用的 SQL 查询字符串。 |
beancount.core.data.Query.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Query.__new__(_cls, meta, date, name, query_string)
特殊
静态方法
创建 Query(meta, date, name, query_string) 的新实例
beancount.core.data.Query.__replace__(/, self, **kwds)
特殊
返回一个新的 Query 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Query.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.Transaction (tuple)
一笔交易!这是我们要操作的主要对象类型,也是整个项目存在的根本原因,因为用电子表格表示这类结构非常困难。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
flag |
str |
单字符字符串或 None。此用户指定的字符串表示交易的自定义状态。您可以将其用于各种目的。否则,预定义的标志在 beancount.core.flags 中定义,用于标记自动生成的交易。 |
payee |
Optional[str] |
一个自由格式的字符串,用于标识交易的收款方,若不存在则为 None。 |
narration |
str |
一个自由格式的字符串,用于描述交易。所有交易都至少包含一个叙述字符串,此字段永不为 None。 |
标签 |
FrozenSet |
一组标签字符串(不含 '#'),或 EMPTY_SET。 |
链接 |
FrozenSet |
一组链接字符串(不含 '^'),或 EMPTY_SET。 |
分录 |
List[beancount.core.data.Posting] |
Posting 实例的列表,即此交易的分录。参见上方 Posting 的文档。 |
beancount.core.data.Transaction.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.Transaction.__new__(_cls, meta, date, flag, payee, narration, tags, links, postings)
特殊
静态方法
创建 Transaction(meta, date, flag, payee, narration, tags, links, postings) 的新实例
beancount.core.data.Transaction.__replace__(/, self, **kwds)
特殊
返回一个新的 Transaction 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.Transaction.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.TxnPosting (元组)
一个 Posting 及其父 Transaction 的配对。它作为临时项插入到条目 postings 列表中,该列表是实现(realization)的结果。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
交易 |
交易 |
父 Transaction 实例。 |
记账 |
分录 |
Posting 实例。 |
beancount.core.data.TxnPosting.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.TxnPosting.__new__(_cls, txn, posting)
特殊
静态方法
创建一个新的 TxnPosting 实例 (txn, posting)
beancount.core.data.TxnPosting.__replace__(/, self, **kwds)
特殊
返回一个新的 TxnPosting 对象,用指定的新值替换相应字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.TxnPosting.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes
指令的类型。
beancount.core.data.dtypes.Balance (元组)
一种“检查该账户余额”的指令。此指令断言,在指定日期开始时,声明的账户应具有特定货币的已知单位数量。这本质上是一种断言,对应于现实世界对账单中的“对账余额”行。这些断言作为检查点,帮助确保你正确录入了交易。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示在指定日期需要检查余额的账户。 |
金额 |
金额 |
一个 Amount,表示你期望该账户在该日期持有的货币单位数量。 |
差额 |
Optional[beancount.core.amount.Amount] |
如果余额检查成功,则为 None;如果失败,则设为一个 Amount 实例,表示差额金额。 |
容差 |
Optional[decimal.Decimal] |
一个 Decimal 对象,表示验证时使用的容差值。 |
beancount.core.data.dtypes.Balance.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Balance.__new__(_cls, meta, date, account, amount, tolerance, diff_amount)
特殊
静态方法
创建 Balance(meta, date, account, amount, tolerance, diff_amount) 的新实例
beancount.core.data.dtypes.Balance.__replace__(/, self, **kwds)
特殊
返回一个新的 Balance 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Balance.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Close (元组)
“关闭账户”指令。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示被关闭的账户名称。 |
beancount.core.data.dtypes.Close.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Close.__new__(_cls, meta, date, account)
特殊
静态方法
创建 Close(meta, date, account) 的新实例
beancount.core.data.dtypes.Close.__replace__(/, self, **kwds)
特殊
返回一个新的 Close 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Close.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Commodity (元组)
可选的商品声明指令。通常不需要声明商品,但可以声明,主要用于为商品名称附加元数据。当插件需要针对特定商品的元数据时,您应定义此类商品指令。另一个用途是定义一个尚未在任何输入文件中使用的商品。(目前日期无实际意义,但为了与其他指令保持一致而保留;如果您有好的使用场景,请告诉我们)。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
货币 |
str |
一个字符串,表示所考虑的商品。 |
beancount.core.data.dtypes.Commodity.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Commodity.__new__(_cls, meta, date, currency)
特殊
静态方法
创建 Commodity(meta, date, currency) 的新实例
beancount.core.data.dtypes.Commodity.__replace__(/, self, **kwds)
特殊
返回一个新的 Commodity 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Commodity.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Custom (元组)
自定义指令。此指令可用于在 Beancount 文件中实现新的实验性日期功能。当您需要在插件中实现新指令时,这可作为临时措施。这些指令将被宽松地解析……支持任意的标记列表。唯一要求是为它们提供一个唯一的名称作为“类型”。这些指令会被包含在数据流中,插件应能收集它们。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
type |
str |
表示指令类型的字符串。 |
值 |
列表 |
由语法支持的各种简单类型的值组成的列表。(注意:解析器不会强制要求同一类型的所有指令在此列表中保持一致性。) |
beancount.core.data.dtypes.Custom.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Custom.__new__(_cls, meta, date, type, values)
特殊
静态方法
创建 Custom(meta, date, type, values) 的新实例
beancount.core.data.dtypes.Custom.__replace__(/, self, **kwds)
特殊
返回一个新的 Custom 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Custom.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Document (元组)
文档文件声明指令。此指令用于在特定日期将对账单附加到账户。典型用法是将银行对账单的 PDF 文件或扫描件关联到账户的日记账中。虽然您可以在输入语法中显式创建这些指令,但更便捷的方式是为 Beancount 提供一个根目录,用于按与会计科目表结构一致的层级搜索文件名,文件名应符合以下带日期的格式:"YYYY-MM-DD.*"。详见选项说明。Beancount 将根据文件层级自动创建这些文档指令,您可以通过解析条目列表获取它们。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
字符串,该对账单或文档关联的账户。 |
filename |
str |
文档文件的绝对路径。 |
标签 |
可选[集合] |
标签字符串集合(不含 '#'),若为空集则为 None。 |
链接 |
可选[集合] |
链接字符串集合(不含 '^'),若为空集则为 None。 |
beancount.core.data.dtypes.Document.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Document.__new__(_cls, meta, date, account, filename, tags, links)
特殊
静态方法
创建 Document(meta, date, account, filename, tags, links) 的新实例
beancount.core.data.dtypes.Document.__replace__(/, self, **kwds)
特殊
返回一个新的 Document 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Document.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Event (元组)
“事件值变更”指令。这些指令用于表示随时间变化的字符串变量。您可以使用它们来跟踪地址、所在地、当前雇主等任何信息。对这些通用事件的报表基于天数和时间线。例如,若您需要跟踪在每个国家或州停留的天数,可创建一个“location”事件,每次旅行时添加一条事件指令以标明新值。您可编写简单脚本计算是否在某地停留了特定天数。举例而言,为维持加拿大健康保险资格,您需在该国停留至少 183 天,且不计算少于 30 天的短期出行。美国对非居民也有类似测试(即所谓的“实际居留测试”),以判断是否需视为税务居民。通过将这些指令整合到您的记账系统中,您可以轻松编写程序自动执行这些计算。当然,这完全属于可选功能,与复式记账的核心目的略有偏离,但与您录入的交易高度相关,因此将其放在同一输入文件中非常方便。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
"类型" |
短字符串,通常为单个小写单词,用于定义一个随时间变化的唯一变量。例如:'location'。 |
|
描述 |
str |
自由格式字符串,表示截至交易日期该变量的值。 |
beancount.core.data.dtypes.Event.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Event.__new__(_cls, meta, date, type, description)
特殊
静态方法
创建 Event(meta, date, type, description) 的新实例
beancount.core.data.dtypes.Event.__replace__(/, self, **kwds)
特殊
返回一个新的 Event 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Event.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Note (元组)
一条注释指令,用于附加到账户的一般性注释。这些注释用于在特定日期将文本附加到特定账户。注释内容可以是任意文本;典型用途是记录与账户所代表机构电话沟通的答复。它应显示在账户的日记账中。如果你不希望它被渲染,请使用输入文件中的注释语法,该语法不会被解析和存储。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示要附加注释的账户。此值永不为 None,注释总是对应某个账户。 |
注释 |
str |
一个自由格式的字符串,表示注释的文本内容。如果需要,它可以很长。 |
beancount.core.data.dtypes.Note.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Note.__new__(_cls, meta, date, account, comment, tags, links)
特殊
静态方法
创建 Note(meta, date, account, comment, tags, links) 的新实例
beancount.core.data.dtypes.Note.__replace__(/, self, **kwds)
特殊
返回一个新的 Note 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Note.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Open (元组)
一条“打开账户”指令。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示正在打开的账户名称。 |
货币 |
List[str] |
一个字符串列表,表示允许存入该账户的货币。可以为 None,表示对该账户可存储的货币没有限制。 |
记账 |
Optional[beancount.core.data.Booking] |
一个 Booking 枚举,用于在多个记账项匹配时消歧该账户的记账方式,或未指定时为 None。实践中,绝大多数情况下应保持此属性未指定(None)。详见下方的 Booking 以获取有效方法列表。 |
beancount.core.data.dtypes.Open.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Open.__new__(_cls, meta, date, account, currencies, booking)
特殊
静态方法
创建 Open(meta, date, account, currencies, booking) 的新实例
beancount.core.data.dtypes.Open.__replace__(/, self, **kwds)
特殊
返回一个新的 Open 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Open.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Pad (元组)
一条“用其他账户填充此账户”的指令。此指令会自动插入交易,以确保下一个按时间顺序的余额指令能够成功执行。它可用于方便地填补交易历史中缺失的日期范围。你不必使用它,这只是在录入历史账目时提供的一种便利包装。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
账户 |
str |
一个字符串,表示需要被填充的账户名称。 |
源账户 |
str |
一个字符串,表示用于向“account”账户转账的借方账户名称。 |
beancount.core.data.dtypes.Pad.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Pad.__new__(_cls, meta, date, account, source_account)
特殊
静态方法
创建一个新的 Pad 实例 (meta, date, account, source_account)
beancount.core.data.dtypes.Pad.__replace__(/, self, **kwds)
特殊
返回一个新的 Pad 对象,用指定的新值替换相应字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Pad.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Price (元组)
价格声明指令。该指令确立了某一货币相对于另一货币在指令日期的价值。系统将为每对货币构建价格历史并可在记账系统中查询。注意:由于 Beancount 不存储时间精度为秒级的数据,因此在同一日期存在多个价格指令是没有意义的。(Beancount 不会尝试解决此问题;这超出了复式记账的一般范围;若需构建日内交易系统,建议使用其他工具)。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
currency:一个字符串,表示被定价的货币,例如 HOOL。amount:一个 Amount 实例,表示该货币的价值数量及单位,例如 1200.12 USD。
beancount.core.data.dtypes.Price.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Price.__new__(_cls, meta, date, currency, amount)
特殊
静态方法
创建一个新的 Price 实例 (meta, date, currency, amount)
beancount.core.data.dtypes.Price.__replace__(/, self, **kwds)
特殊
返回一个新的 Price 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Price.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Query (元组)
命名查询声明。此指令用于创建预定义的查询,这些查询可自动运行、供 shell 使用,或作为网页界面的一部分呈现。此功能的目的是为特定的 Beancount 输入文件定义有用的查询。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
此查询应运行的日期。在此日期之后的所有指令将被自动忽略。这本质上等同于 shell 语法中的 CLOSE 修饰符。 |
名称 |
str |
一个字符串,查询的唯一标识符。 |
query_string |
str |
要运行或可用的 SQL 查询字符串。 |
beancount.core.data.dtypes.Query.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Query.__new__(_cls, meta, date, name, query_string)
特殊
静态方法
创建 Query(meta, date, name, query_string) 的新实例
beancount.core.data.dtypes.Query.__replace__(/, self, **kwds)
特殊
返回一个新的 Query 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Query.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.dtypes.Transaction (元组)
一笔交易!这是我们要操作的主要对象类型,也是整个项目存在的根本原因,因为用电子表格表示这类结构非常困难。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
meta |
Dict[str, Any] |
参见上文。 |
date |
date |
参见上文。 |
flag |
str |
单字符字符串或 None。此用户指定的字符串表示交易的自定义状态。您可以将其用于各种目的。否则,预定义的标志在 beancount.core.flags 中定义,用于标记自动生成的交易。 |
payee |
Optional[str] |
一个自由格式的字符串,用于标识交易的收款方,若不存在则为 None。 |
narration |
str |
一个自由格式的字符串,用于描述交易。所有交易都至少包含一个叙述字符串,此字段永不为 None。 |
标签 |
FrozenSet |
一组标签字符串(不含 '#'),或 EMPTY_SET。 |
链接 |
FrozenSet |
一组链接字符串(不含 '^'),或 EMPTY_SET。 |
分录 |
List[beancount.core.data.Posting] |
Posting 实例的列表,即此交易的分录。参见上方 Posting 的文档。 |
beancount.core.data.dtypes.Transaction.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/data.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.data.dtypes.Transaction.__new__(_cls, meta, date, flag, payee, narration, tags, links, postings)
特殊
静态方法
创建 Transaction(meta, date, flag, payee, narration, tags, links, postings) 的新实例
beancount.core.data.dtypes.Transaction.__replace__(/, self, **kwds)
特殊
返回一个新的 Transaction 对象,用指定的新值替换字段
源代码位于 beancount/core/data.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.data.dtypes.Transaction.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/data.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.data.create_simple_posting(entry, account, number, currency)
创建一个简单的过账项,仅包含金额和货币(无成本)。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def create_simple_posting(entry, account, number, currency):
"""Create a simple posting on the entry, with just a number and currency (no cost).
Args:
entry: The entry instance to add the posting to.
account: A string, the account to use on the posting.
number: A Decimal number or string to use in the posting's Amount.
currency: A string, the currency for the Amount.
Returns:
An instance of Posting, and as a side-effect the entry has had its list of
postings modified with the new Posting instance.
"""
if isinstance(account, str):
pass
if number is None:
units = None
else:
if not isinstance(number, Decimal):
number = D(number)
units = Amount(number, currency)
posting = Posting(account, units, None, None, None, None)
if entry is not None:
entry.postings.append(posting)
return posting
beancount.core.data.create_simple_posting_with_cost(entry, account, number, currency, cost_number, cost_currency)
创建一个简单的过账项,仅包含金额和货币(无成本)。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def create_simple_posting_with_cost(entry, account,
number, currency,
cost_number, cost_currency):
"""Create a simple posting on the entry, with just a number and currency (no cost).
Args:
entry: The entry instance to add the posting to.
account: A string, the account to use on the posting.
number: A Decimal number or string to use in the posting's Amount.
currency: A string, the currency for the Amount.
cost_number: A Decimal number or string to use for the posting's cost Amount.
cost_currency: a string, the currency for the cost Amount.
Returns:
An instance of Posting, and as a side-effect the entry has had its list of
postings modified with the new Posting instance.
"""
if isinstance(account, str):
pass
if not isinstance(number, Decimal):
number = D(number)
if cost_number and not isinstance(cost_number, Decimal):
cost_number = D(cost_number)
units = Amount(number, currency)
cost = Cost(cost_number, cost_currency, None, None)
posting = Posting(account, units, cost, None, None, None)
if entry is not None:
entry.postings.append(posting)
return posting
beancount.core.data.entry_sortkey(entry)
条目的排序键。我们按日期排序,但支票应排在同一天所有条目的最前面,以便线性平衡。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def entry_sortkey(entry):
"""Sort-key for entries. We sort by date, except that checks
should be placed in front of every list of entries of that same day,
in order to balance linearly.
Args:
entry: An entry instance.
Returns:
A tuple of (date, integer, integer), that forms the sort key for the
entry.
"""
return (entry.date, SORT_ORDER.get(type(entry), 0), entry.meta["lineno"])
beancount.core.data.filter_txns(entries)
一个生成器,仅输出 Transaction 实例。
这是一个极其常见的操作,因此值得提供一个简洁的过滤机制。
| 参数: |
|
|---|
返回:仅包含 Transaction 指令的已排序列表。
源代码位于 beancount/core/data.py
def filter_txns(entries):
"""A generator that yields only the Transaction instances.
This is such an incredibly common operation that it deserves a terse
filtering mechanism.
Args:
entries: A list of directives.
Yields:
A sorted list of only the Transaction directives.
"""
for entry in entries:
if isinstance(entry, Transaction):
yield entry
beancount.core.data.find_closest(entries, filename, lineno)
从条目中查找最接近 (filename, lineno) 的条目。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def find_closest(entries, filename, lineno):
"""Find the closest entry from entries to (filename, lineno).
Args:
entries: A list of directives.
filename: A string, the name of the ledger file to look for. Be careful
to provide the very same filename, and note that the parser stores the
absolute path of the filename here.
lineno: An integer, the line number closest after the directive we're
looking for. This may be the exact/first line of the directive.
Returns:
The closest entry found in the given file for the given filename, or
None, if none could be found.
"""
min_diffline = sys.maxsize
closest_entry = None
for entry in entries:
emeta = entry.meta
if emeta["filename"] == filename and emeta["lineno"] > 0:
diffline = lineno - emeta["lineno"]
if 0 <= diffline < min_diffline:
min_diffline = diffline
closest_entry = entry
return closest_entry
beancount.core.data.get_entry(posting_or_entry)
返回与记账项或条目关联的条目。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def get_entry(posting_or_entry):
"""Return the entry associated with the posting or entry.
Args:
entry: A TxnPosting or entry instance
Returns:
A datetime instance.
"""
return (posting_or_entry.txn
if isinstance(posting_or_entry, TxnPosting)
else posting_or_entry)
beancount.core.data.has_entry_account_component(entry, component)
如果条目的任一记账项包含指定账户组件,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def has_entry_account_component(entry, component):
"""Return true if one of the entry's postings has an account component.
Args:
entry: A Transaction entry.
component: A string, a component of an account name. For instance,
``Food`` in ``Expenses:Food:Restaurant``. All components are considered.
Returns:
Boolean: true if the component is in the account. Note that a component
name must be whole, that is ``NY`` is not in ``Expenses:Taxes:StateNY``.
"""
return (isinstance(entry, Transaction) and
any(has_component(posting.account, component)
for posting in entry.postings))
beancount.core.data.iter_entry_dates(entries, date_begin, date_end)
在指定日期范围内迭代条目。
| 参数: |
|
|---|
生成:在指定日期范围内、按出现顺序排列的带日期指令实例。
源代码位于 beancount/core/data.py
def iter_entry_dates(entries, date_begin, date_end):
"""Iterate over the entries in a date window.
Args:
entries: A date-sorted list of dated directives.
date_begin: A datetime.date instance, the first date to include.
date_end: A datetime.date instance, one day beyond the last date.
Yields:
Instances of the dated directives, between the dates, and in the order in
which they appear.
"""
getdate = lambda entry: entry.date
index_begin = bisect_left_with_key(entries, date_begin, key=getdate)
index_end = bisect_left_with_key(entries, date_end, key=getdate)
for index in range(index_begin, index_end):
yield entries[index]
beancount.core.data.new_metadata(filename, lineno, kvlist=None)
根据文件名和行号创建一个新的元数据容器。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def new_metadata(filename, lineno, kvlist=None):
"""Create a new metadata container from the filename and line number.
Args:
filename: A string, the filename for the creator of this directive.
lineno: An integer, the line number where the directive has been created.
kvlist: An optional container of key-values.
Returns:
A metadata dict.
"""
meta = {'filename': filename,
'lineno': lineno}
if kvlist:
meta.update(kvlist)
return meta
beancount.core.data.posting_has_conversion(posting)
如果此持仓涉及转换,则返回 True。
转换是指金额附有价格但无成本的情况。这用于交易中在不同单位之间进行转换。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def posting_has_conversion(posting):
"""Return true if this position involves a conversion.
A conversion is when there is a price attached to the amount but no cost.
This is used on transactions to convert between units.
Args:
posting: an instance of Posting
Return:
A boolean, true if this posting has a price conversion.
"""
return (posting.cost is None and
posting.price is not None)
beancount.core.data.posting_sortkey(entry)
条目或分录的排序键。我们按日期排序,但支票应排在同一天所有条目列表的前面,以实现线性平衡。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def posting_sortkey(entry):
"""Sort-key for entries or postings. We sort by date, except that checks
should be placed in front of every list of entries of that same day,
in order to balance linearly.
Args:
entry: A Posting or entry instance
Returns:
A tuple of (date, integer, integer), that forms the sort key for the
posting or entry.
"""
if isinstance(entry, TxnPosting):
entry = entry.txn
return (entry.date, SORT_ORDER.get(type(entry), 0), entry.meta["lineno"])
beancount.core.data.remove_account_postings(account, entries)
移除所有具有指定账户的分录。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def remove_account_postings(account, entries):
"""Remove all postings with the given account.
Args:
account: A string, the account name whose postings we want to remove.
Returns:
A list of entries without the rounding postings.
"""
new_entries = []
for entry in entries:
if isinstance(entry, Transaction) and (
any(posting.account == account for posting in entry.postings)):
entry = entry._replace(postings=[posting
for posting in entry.postings
if posting.account != account])
new_entries.append(entry)
return new_entries
beancount.core.data.sanity_check_types(entry, allow_none_for_tags_and_links=False)
检查条目及其分录是否具有所有正确的数据类型。
| 参数: |
|
|---|
| 异常: |
|
|---|
源代码位于 beancount/core/data.py
def sanity_check_types(entry, allow_none_for_tags_and_links=False):
"""Check that the entry and its postings has all correct data types.
Args:
entry: An instance of one of the entries to be checked.
allow_none_for_tags_and_links: A boolean, whether to allow plugins to
generate Transaction objects with None as value for the 'tags' or 'links'
attributes.
Raises:
AssertionError: If there is anything that is unexpected, raises an exception.
"""
assert isinstance(entry, ALL_DIRECTIVES), "Invalid directive type"
assert isinstance(entry.meta, dict), "Invalid type for meta"
assert 'filename' in entry.meta, "Missing filename in metadata"
assert 'lineno' in entry.meta, "Missing line number in metadata"
assert isinstance(entry.date, datetime.date), "Invalid date type"
if isinstance(entry, Transaction):
assert isinstance(entry.flag, (NoneType, str)), "Invalid flag type"
assert isinstance(entry.payee, (NoneType, str)), "Invalid payee type"
assert isinstance(entry.narration, (NoneType, str)), "Invalid narration type"
set_types = ((NoneType, set, frozenset)
if allow_none_for_tags_and_links
else (set, frozenset))
assert isinstance(entry.tags, set_types), (
"Invalid tags type: {}".format(type(entry.tags)))
assert isinstance(entry.links, set_types), (
"Invalid links type: {}".format(type(entry.links)))
assert isinstance(entry.postings, list), "Invalid postings list type"
for posting in entry.postings:
assert isinstance(posting, Posting), "Invalid posting type"
assert isinstance(posting.account, str), "Invalid account type"
assert isinstance(posting.units, (Amount, NoneType)), "Invalid units type"
assert isinstance(posting.cost, (Cost, CostSpec, NoneType)), "Invalid cost type"
assert isinstance(posting.price, (Amount, NoneType)), "Invalid price type"
assert isinstance(posting.flag, (str, NoneType)), "Invalid flag type"
beancount.core.data.sorted(entries)
一种便捷方法,使用 entry_sortkey() 对条目列表进行排序。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def sorted(entries):
"""A convenience to sort a list of entries, using entry_sortkey().
Args:
entries: A list of directives.
Returns:
A sorted list of directives.
"""
return builtins.sorted(entries, key=entry_sortkey)
beancount.core.data.transaction_has_conversion(transaction)
给定一个交易条目,若至少有一个分录包含价格转换(无关联成本),则返回 True。这些是产生非零转换余额的来源。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/data.py
def transaction_has_conversion(transaction):
"""Given a Transaction entry, return true if at least one of
the postings has a price conversion (without an associated
cost). These are the source of non-zero conversion balances.
Args:
transaction: an instance of a Transaction entry.
Returns:
A boolean, true if this transaction contains at least one posting with a
price conversion.
"""
assert isinstance(transaction, Transaction), (
"Invalid type of entry for transaction: {}".format(transaction))
for posting in transaction.postings:
if posting_has_conversion(posting):
return True
return False
beancount.core.display_context
一个设置类,用于控制渲染数字的位数。
本模块包含用于累积数字渲染所需的宽度和精度信息,并据此推导出在满足常见对齐要求下一致渲染所有数字所需的精度。这是为了以整齐对齐的列格式输出各种风格的数字所必需的。
一种常见情况是,可以从输入文件中的数字观察到其精度。此显示精度可作为“默认精度”,当我们编写一个不方便传入所有数字来构建累加器的例程时,可以使用它。
本模块支持以下所有方面:
PRECISION:特定货币的数字始终以相同的精度渲染,且可选择以下两种精度之一:
- 最常见的小数位数,或
- 观察到的最大位数(适用于渲染价格)。
ALIGNMENT:支持多种对齐方式。
-
"natural":以最小长度渲染字符串,不添加填充,但遵循其货币的精度。例如:
'1.2345' '764' '-7,409.01' '0.00000125'
-
"点对齐":小数点将垂直对齐,左右两侧填充,使数字列具有相同的宽度:
' 1.2345 ' ' 764 ' '-7,409.01 ' ' 0.00000125'
-
"右对齐":所有字符串右对齐,左侧填充,使数字列具有相同的宽度:
' 1.2345' ' 764' ' -7,409.01' ' 0.00000125'
符号:如果输入数字中包含负号,则渲染时会为其预留空间;否则,节省该空间。
逗号:如果用户请求渲染逗号,则输出中将包含逗号。
预留位:在左侧预留一定数量的整数位,以便容纳尚未见过的更大数字。例如,余额可能包含远大于输入文件中数字的值,这些数字在右对齐时需要被容纳。
beancount.core.display_context.Align (枚举)
数字的对齐样式。
beancount.core.display_context.DisplayContext
一个用于从一系列数字构建 DisplayContext 的构建器对象。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
ccontexts |
一个字典,键为货币字符串,值为 CurrencyContext 实例。 |
|
commas |
布尔值,若为 True 则渲染逗号。此值将作为默认值传递给后续构建过程。 |
beancount.core.display_context.DisplayContext.build(self, alignment=<Align.NATURAL: 1>, precision=<Precision.MOST_COMMON: 1>, commas=None, reserved=0)
为给定的显示上下文构建格式化器。
| 参数: |
|
|---|
源代码位于 beancount/core/display_context.py
def build(self,
alignment=Align.NATURAL,
precision=Precision.MOST_COMMON,
commas=None,
reserved=0):
"""Build a formatter for the given display context.
Args:
alignment: The desired alignment.
precision: The desired precision.
commas: Whether to render commas or not. If 'None', the default value carried
by the context will be used.
reserved: An integer, the number of extra digits to be allocated in
the maximum width calculations.
"""
if commas is None:
commas = self.commas
if alignment == Align.NATURAL:
build_method = self._build_natural
elif alignment == Align.RIGHT:
build_method = self._build_right
elif alignment == Align.DOT:
build_method = self._build_dot
else:
raise ValueError("Unknown alignment: {}".format(alignment))
fmtstrings = build_method(precision, commas, reserved)
return DisplayFormatter(self, precision, fmtstrings)
beancount.core.display_context.DisplayContext.quantize(self, number, currency, precision=<Precision.MOST_COMMON: 1>)
将给定数字四舍五入至指定精度。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/display_context.py
def quantize(self, number, currency, precision=Precision.MOST_COMMON):
"""Quantize the given number to the given precision.
Args:
number: A Decimal instance, the number to be quantized.
currency: A currency string.
precision: Which precision to use.
Returns:
A Decimal instance, the quantized number.
"""
assert isinstance(number, Decimal), "Invalid data: {}".format(number)
ccontext = self.ccontexts[currency]
num_fractional_digits = ccontext.get_fractional(precision)
if num_fractional_digits is None:
# Note: We could probably logging.warn() this situation here.
return number
qdigit = Decimal(1).scaleb(-num_fractional_digits)
with decimal.localcontext() as ctx:
# Allow precision for numbers as large as 1 billion in addition to
# the required number of fractional digits.
#
# TODO(blais): Review this to assess performance impact, and whether
# we could fold this outside a calling loop.
ctx.prec = num_fractional_digits + 9
return number.quantize(qdigit)
beancount.core.display_context.DisplayContext.set_commas(self, commas)
设置渲染逗号的默认值。
源代码位于 beancount/core/display_context.py
def set_commas(self, commas):
"""Set the default value for rendering commas."""
self.commas = commas
beancount.core.display_context.DisplayContext.update(self, number, currency='__default__')
使用给定的数值更新指定货币的构建器。
| 参数: |
|
|---|
源代码位于 beancount/core/display_context.py
def update(self, number, currency='__default__'):
"""Update the builder with the given number for the given currency.
Args:
number: An instance of Decimal to consider for this currency.
currency: An optional string, the currency this numbers applies to.
"""
self.ccontexts[currency].update(number)
beancount.core.display_context.DisplayContext.update_from(self, other)
使用另一个 DisplayContext 更新构建器。
| 参数: |
|
|---|
源代码位于 beancount/core/display_context.py
def update_from(self, other):
"""Update the builder with the other given DisplayContext.
Args:
other: Another DisplayContext.
"""
for currency, ccontext in other.ccontexts.items():
self.ccontexts[currency].update_from(ccontext)
beancount.core.display_context.DisplayFormatter
一个用于包含控制数字输出方式的各种设置的类。特别是每种货币的精度以及是否打印千位分隔符。此对象旨在传递给所有将数字格式化为字符串的函数。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
dcontext |
一个 DisplayContext 实例。 |
|
precision |
用于构建它的 Precision 枚举类型。 |
|
fmtstrings |
一个字典,将货币映射到为其预生成的格式化字符串。 |
|
fmtfuncs |
一个字典,将货币映射到为其预生成的格式化函数。 |
beancount.core.display_context.Precision (Enum)
所需的精度类型。
beancount.core.distribution
一个用于累积数学分布数据的简单累加器。
beancount.core.distribution.Distribution
一个用于计算整数值直方图的类。用于计算能覆盖至少一定比例样本的长度。
beancount.core.distribution.Distribution.empty(self)
如果分布为空,则返回 True。
| 返回: |
|
|---|
源代码位于 beancount/core/distribution.py
def empty(self):
"""Return true if the distribution is empty.
Returns:
A boolean.
"""
return len(self.hist) == 0
beancount.core.distribution.Distribution.max(self)
返回分布中观察到的最小值。
| 返回: |
|
|---|
源代码位于 beancount/core/distribution.py
def max(self):
"""Return the minimum value seen in the distribution.
Returns:
An element of the value type, or None, if the distribution was empty.
"""
if not self.hist:
return None
value, _ = sorted(self.hist.items())[-1]
return value
beancount.core.distribution.Distribution.min(self)
返回分布中观察到的最小值。
| 返回: |
|
|---|
源代码位于 beancount/core/distribution.py
def min(self):
"""Return the minimum value seen in the distribution.
Returns:
An element of the value type, or None, if the distribution was empty.
"""
if not self.hist:
return None
value, _ = sorted(self.hist.items())[0]
return value
beancount.core.distribution.Distribution.mode(self)
返回分布的众数。
| 返回: |
|
|---|
源代码位于 beancount/core/distribution.py
def mode(self):
"""Return the mode of the distribution.
Returns:
An element of the value type, or None, if the distribution was empty.
"""
if not self.hist:
return None
max_value = 0
max_count = 0
for value, count in sorted(self.hist.items()):
if count >= max_count:
max_count = count
max_value = value
return max_value
beancount.core.distribution.Distribution.update(self, value)
向分布中添加一个样本。
| 参数: |
|
|---|
源代码位于 beancount/core/distribution.py
def update(self, value):
"""Add a sample to the distribution.
Args:
value: A value of the function.
"""
self.hist[value] += 1
beancount.core.distribution.Distribution.update_from(self, other)
将另一个分布的样本添加到当前分布中。
| 参数: |
|
|---|
源代码位于 beancount/core/distribution.py
def update_from(self, other):
"""Add samples from the other distribution to this one.
Args:
other: Another distribution.
"""
for value, count in other.hist.items():
self.hist[value] += count
beancount.core.flags
标志常量。
beancount.core.getters
用于操作条目列表的获取函数,返回它们引用的各种内容列表,如账户、标签、链接、货币等。
beancount.core.getters.GetAccounts
账户收集器。
beancount.core.getters.GetAccounts.Balance(_, entry)
处理具有单个账户属性的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _one(_, entry):
"""Process directives with a single account attribute.
Args:
entry: An instance of a directive.
Returns:
The single account of this directive.
"""
return (entry.account,)
beancount.core.getters.GetAccounts.Close(_, entry)
处理具有单个账户属性的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _one(_, entry):
"""Process directives with a single account attribute.
Args:
entry: An instance of a directive.
Returns:
The single account of this directive.
"""
return (entry.account,)
beancount.core.getters.GetAccounts.Commodity(_, entry)
处理不包含账户的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _zero(_, entry):
"""Process directives with no accounts.
Args:
entry: An instance of a directive.
Returns:
An empty list
"""
return ()
beancount.core.getters.GetAccounts.Custom(_, entry)
处理不包含账户的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _zero(_, entry):
"""Process directives with no accounts.
Args:
entry: An instance of a directive.
Returns:
An empty list
"""
return ()
beancount.core.getters.GetAccounts.Document(_, entry)
处理具有单个账户属性的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _one(_, entry):
"""Process directives with a single account attribute.
Args:
entry: An instance of a directive.
Returns:
The single account of this directive.
"""
return (entry.account,)
beancount.core.getters.GetAccounts.Event(_, entry)
处理不包含账户的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _zero(_, entry):
"""Process directives with no accounts.
Args:
entry: An instance of a directive.
Returns:
An empty list
"""
return ()
beancount.core.getters.GetAccounts.Note(_, entry)
处理具有单个账户属性的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _one(_, entry):
"""Process directives with a single account attribute.
Args:
entry: An instance of a directive.
Returns:
The single account of this directive.
"""
return (entry.account,)
beancount.core.getters.GetAccounts.Open(_, entry)
处理具有单个账户属性的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _one(_, entry):
"""Process directives with a single account attribute.
Args:
entry: An instance of a directive.
Returns:
The single account of this directive.
"""
return (entry.account,)
beancount.core.getters.GetAccounts.Pad(_, entry)
处理 Pad 指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def Pad(_, entry):
"""Process a Pad directive.
Args:
entry: An instance of Pad.
Returns:
The two accounts of the Pad directive.
"""
return (entry.account, entry.source_account)
beancount.core.getters.GetAccounts.Price(_, entry)
处理不包含账户的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _zero(_, entry):
"""Process directives with no accounts.
Args:
entry: An instance of a directive.
Returns:
An empty list
"""
return ()
beancount.core.getters.GetAccounts.Query(_, entry)
处理不包含账户的指令。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def _zero(_, entry):
"""Process directives with no accounts.
Args:
entry: An instance of a directive.
Returns:
An empty list
"""
return ()
beancount.core.getters.GetAccounts.Transaction(_, entry)
处理一个 Transaction 指令。
| 参数: |
|
|---|
生成:交易各条目所涉及的账户。
源代码位于 beancount/core/getters.py
def Transaction(_, entry):
"""Process a Transaction directive.
Args:
entry: An instance of Transaction.
Yields:
The accounts of the legs of the transaction.
"""
for posting in entry.postings:
yield posting.account
beancount.core.getters.GetAccounts.get_accounts_use_map(self, entries)
从条目列表中收集所有账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_accounts_use_map(self, entries):
"""Gather the list of accounts from the list of entries.
Args:
entries: A list of directive instances.
Returns:
A pair of dictionaries of account name to date, one for first date
used and one for last date used. The keys should be identical.
"""
accounts_first = {}
accounts_last = {}
for entry in entries:
method = getattr(self, entry.__class__.__name__)
for account_ in method(entry):
if account_ not in accounts_first:
accounts_first[account_] = entry.date
accounts_last[account_] = entry.date
return accounts_first, accounts_last
beancount.core.getters.GetAccounts.get_entry_accounts(self, entry)
收集单个指令引用的所有账户。
注意:最终应由每个指令自身提供该方法,这才是更清晰的实现方式。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_entry_accounts(self, entry):
"""Gather all the accounts references by a single directive.
Note: This should get replaced by a method on each directive eventually,
that would be the clean way to do this.
Args:
entry: A directive instance.
Returns:
A set of account name strings.
"""
method = getattr(self, entry.__class__.__name__)
return set(method(entry))
beancount.core.getters.get_account_components(entries)
收集给定指令中所有可用的账户组件。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_account_components(entries):
"""Gather all the account components available in the given directives.
Args:
entries: A list of directive instances.
Returns:
A list of strings, the unique account components, including the root
account names.
"""
accounts = get_accounts(entries)
components = set()
for account_name in accounts:
components.update(account.split(account_name))
return sorted(components)
beancount.core.getters.get_account_open_close(entries)
获取每个账户的开户和销户指令。
如果开户或销户指令重复出现,则采用最早的那个(按时间顺序)。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_account_open_close(entries):
"""Fetch the open/close entries for each of the accounts.
If an open or close entry happens to be duplicated, accept the earliest
entry (chronologically).
Args:
entries: A list of directive instances.
Returns:
A map of account name strings to pairs of (open-directive, close-directive)
tuples.
"""
# A dict of account name to (open-entry, close-entry).
open_close_map = defaultdict(lambda: [None, None])
for entry in entries:
if not isinstance(entry, (Open, Close)):
continue
open_close = open_close_map[entry.account]
index = 0 if isinstance(entry, Open) else 1
previous_entry = open_close[index]
if previous_entry is not None:
if previous_entry.date <= entry.date:
entry = previous_entry
open_close[index] = entry
return dict(open_close_map)
beancount.core.getters.get_accounts(entries)
从指令列表中收集所有引用的账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_accounts(entries):
"""Gather all the accounts references by a list of directives.
Args:
entries: A list of directive instances.
Returns:
A set of account strings.
"""
_, accounts_last = _GetAccounts.get_accounts_use_map(entries)
return accounts_last.keys()
beancount.core.getters.get_accounts_use_map(entries)
从指令列表中收集所有引用的账户。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_accounts_use_map(entries):
"""Gather all the accounts references by a list of directives.
Args:
entries: A list of directive instances.
Returns:
A pair of dictionaries of account name to date, one for first date
used and one for last date used. The keys should be identical.
"""
return _GetAccounts.get_accounts_use_map(entries)
beancount.core.getters.get_active_years(entries)
生成所有至少包含一条记录的年份。
| 参数: |
|
|---|
生成:指令列表中出现的唯一日期。
源代码位于 beancount/core/getters.py
def get_active_years(entries):
"""Yield all the years that have at least one entry in them.
Args:
entries: A list of directive instances.
Yields:
Unique dates see in the list of directives.
"""
seen = set()
prev_year = None
for entry in entries:
year = entry.date.year
if year != prev_year:
prev_year = year
assert year not in seen
seen.add(year)
yield year
beancount.core.getters.get_all_links(entries)
返回给定条目中所有链接的列表。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_all_links(entries):
"""Return a list of all the links seen in the given entries.
Args:
entries: A list of directive instances.
Returns:
A set of links strings.
"""
all_links = set()
for entry in entries:
if not isinstance(entry, Transaction):
continue
if entry.links:
all_links.update(entry.links)
return sorted(all_links)
beancount.core.getters.get_all_payees(entries)
返回给定条目中所有唯一收款人的列表。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_all_payees(entries):
"""Return a list of all the unique payees seen in the given entries.
Args:
entries: A list of directive instances.
Returns:
A set of payee strings.
"""
all_payees = set()
for entry in entries:
if not isinstance(entry, Transaction):
continue
all_payees.add(entry.payee)
all_payees.discard(None)
return sorted(all_payees)
beancount.core.getters.get_all_tags(entries)
返回给定条目中所有标签的列表。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_all_tags(entries):
"""Return a list of all the tags seen in the given entries.
Args:
entries: A list of directive instances.
Returns:
A set of tag strings.
"""
all_tags = set()
for entry in entries:
if not isinstance(entry, Transaction):
continue
if entry.tags:
all_tags.update(entry.tags)
return sorted(all_tags)
beancount.core.getters.get_commodity_directives(entries)
创建商品名称到 Commodity 条目的映射。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_commodity_directives(entries):
"""Create map of commodity names to Commodity entries.
Args:
entries: A list of directive instances.
Returns:
A map of commodity name strings to Commodity directives.
"""
return {entry.currency: entry for entry in entries if isinstance(entry, Commodity)}
beancount.core.getters.get_dict_accounts(account_names)
返回所有唯一叶名称的嵌套字典。账户名称用 LABEL=True 标记。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_dict_accounts(account_names):
"""Return a nested dict of all the unique leaf names.
account names are labelled with LABEL=True
Args:
account_names: An iterable of account names (strings)
Returns:
A nested OrderedDict of account leafs
"""
leveldict = OrderedDict()
for account_name in account_names:
nested_dict = leveldict
for component in account.split(account_name):
nested_dict = nested_dict.setdefault(component, OrderedDict())
nested_dict[get_dict_accounts.ACCOUNT_LABEL] = True
return leveldict
beancount.core.getters.get_entry_accounts(entry)
收集单个指令引用的所有账户。
注意:最终应由每个指令自身提供该方法,这才是更清晰的实现方式。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_entry_accounts(entry):
"""Gather all the accounts references by a single directive.
Note: This should get replaced by a method on each directive eventually,
that would be the clean way to do this.
Args:
entries: A directive instance.
Returns:
A set of account strings.
"""
return _GetAccounts.get_entry_accounts(entry)
beancount.core.getters.get_leveln_parent_accounts(account_names, level, nrepeats=0)
返回账户层次结构中第 N 级的所有唯一叶名称。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_leveln_parent_accounts(account_names, level, nrepeats=0):
"""Return a list of all the unique leaf names at level N in an account hierarchy.
Args:
account_names: A list of account names (strings)
level: The level to cross-cut. 0 is for root accounts.
nrepeats: A minimum number of times a leaf is required to be present in the
the list of unique account names in order to be returned by this function.
Returns:
A list of leaf node names.
"""
leveldict = defaultdict(int)
for account_name in set(account_names):
components = account.split(account_name)
if level < len(components):
leveldict[components[level]] += 1
levels = {level_
for level_, count in leveldict.items()
if count > nrepeats}
return sorted(levels)
beancount.core.getters.get_min_max_dates(entries, types=None)
返回条目列表中的最小和最大日期。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_min_max_dates(entries, types=None):
"""Return the minimum and maximum dates in the list of entries.
Args:
entries: A list of directive instances.
types: An optional tuple of types to restrict the entries to.
Returns:
A pair of datetime.date dates, the minimum and maximum dates seen in the
directives.
"""
date_first = date_last = None
for entry in entries:
if types and not isinstance(entry, types):
continue
date_first = entry.date
break
for entry in reversed(entries):
if types and not isinstance(entry, types):
continue
date_last = entry.date
break
return (date_first, date_last)
beancount.core.getters.get_values_meta(name_to_entries_map, *meta_keys, *, default=None)
从条目值的映射中获取元数据。
给定一个字典,其键映射到指令实例(或 None),返回一个将键映射到从每个指令中提取的元数据(或默认值)的映射。此函数可用于从账户映射或商品映射中收集特定的元数据。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/getters.py
def get_values_meta(name_to_entries_map, *meta_keys, default=None):
"""Get a map of the metadata from a map of entries values.
Given a dict of some key to a directive instance (or None), return a mapping
of the key to the metadata extracted from each directive, or a default
value. This can be used to gather a particular piece of metadata from an
accounts map or a commodities map.
Args:
name_to_entries_map: A dict of something to an entry or None.
meta_keys: A list of strings, the keys to fetch from the metadata.
default: The default value to use if the metadata is not available or if
the value/entry is None.
Returns:
A mapping of the keys of name_to_entries_map to the values of the 'meta_keys'
metadata. If there are multiple 'meta_keys', each value is a tuple of them.
On the other hand, if there is only a single one, the value itself is returned.
"""
value_map = {}
for key, entry in name_to_entries_map.items():
value_list = []
for meta_key in meta_keys:
value_list.append(entry.meta.get(meta_key, default)
if entry is not None
else default)
value_map[key] = (value_list[0]
if len(meta_keys) == 1
else tuple(value_list))
return value_map
beancount.core.interpolate
用于自动补全无仓位的过账的代码。
beancount.core.interpolate.BalanceError (元组)
BalanceError(source, message, entry)
beancount.core.interpolate.BalanceError.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/interpolate.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.interpolate.BalanceError.__new__(_cls, source, message, entry)
特殊
静态方法
创建 BalanceError(source, message, entry) 的新实例
beancount.core.interpolate.BalanceError.__replace__(/, self, **kwds)
特殊
返回一个新的 BalanceError 对象,用指定的新值替换字段
源代码位于 beancount/core/interpolate.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.interpolate.BalanceError.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/interpolate.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.interpolate.compute_entries_balance(entries, prefix=None, date=None)
计算一组条目中所有过账的余额。
对列表中所有交易的所有过账的仓位求和,并返回一个库存对象。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def compute_entries_balance(entries, prefix=None, date=None):
"""Compute the balance of all postings of a list of entries.
Sum up all the positions in all the postings of all the transactions in the
list of entries and return an inventory of it.
Args:
entries: A list of directives.
prefix: If specified, a prefix string to restrict by account name. Only
postings with an account that starts with this prefix will be summed up.
date: A datetime.date instance at which to stop adding up the balance.
The date is exclusive.
Returns:
An instance of Inventory.
"""
total_balance = Inventory()
for entry in entries:
if not (date is None or entry.date < date):
break
if isinstance(entry, Transaction):
for posting in entry.postings:
if prefix is None or posting.account.startswith(prefix):
total_balance.add_position(posting)
return total_balance
beancount.core.interpolate.compute_entry_context(entries, context_entry, additional_accounts=None)
计算直到指定条目为止,所有被引用账户的余额。
提供在应用该条目之前和之后的账户库存状态。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def compute_entry_context(entries, context_entry, additional_accounts=None):
"""Compute the balances of all accounts referenced by entry up to entry.
This provides the inventory of the accounts to which the entry is to be
applied, before and after.
Args:
entries: A list of directives.
context_entry: The entry for which we want to obtain the before and after
context.
additional_accounts: Additional list of accounts to include in calculating
the balance. This is used when invoked for debugging, in case the booked
& interpolated transaction doesn't have all the accounts we need because
it had an error (the booking code will remove invalid postings).
Returns:
Two dicts of account-name to Inventory instance, one which represents the
context before the entry is applied, and one that represents the context
after it has been applied.
"""
assert context_entry is not None, "context_entry is missing."
# Get the set of accounts for which to compute the context.
context_accounts = getters.get_entry_accounts(context_entry)
if additional_accounts:
context_accounts.update(additional_accounts)
# Iterate over the entries until we find the target one and accumulate the
# balance.
context_before = collections.defaultdict(inventory.Inventory)
for entry in entries:
if entry is context_entry:
break
if isinstance(entry, Transaction):
for posting in entry.postings:
if not any(posting.account == account
for account in context_accounts):
continue
balance = context_before[posting.account]
balance.add_position(posting)
# Compute the after context for the entry.
context_after = copy.deepcopy(context_before)
if isinstance(context_entry, Transaction):
for posting in entry.postings:
balance = context_after[posting.account]
balance.add_position(posting)
return context_before, context_after
beancount.core.interpolate.compute_residual(postings)
计算一组完整过账的残差及每种货币的精度。
用于校验一笔平衡交易。
精度是每种货币所使用的最大小数位数(字典形式)。我们通过权重金额的货币来推断每种货币的量化精度。整数金额不参与精度的确定。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def compute_residual(postings):
"""Compute the residual of a set of complete postings, and the per-currency precision.
This is used to cross-check a balanced transaction.
The precision is the maximum fraction that is being used for each currency
(a dict). We use the currency of the weight amount in order to infer the
quantization precision for each currency. Integer amounts aren't
contributing to the determination of precision.
Args:
postings: A list of Posting instances.
Returns:
An instance of Inventory, with the residual of the given list of postings.
"""
inventory = Inventory()
for posting in postings:
# Skip auto-postings inserted to absorb the residual (rounding error).
if posting.meta and posting.meta.get(AUTOMATIC_RESIDUAL, False):
continue
# Add to total residual balance.
inventory.add_amount(convert.get_weight(posting))
return inventory
beancount.core.interpolate.fill_residual_posting(entry, account_rounding)
如有必要,插入一条分录以吸收剩余金额,使交易完全平衡。
注意:此功能旨在导出到 Ledger 之前微调交易。更好的方法是启用自动为所有交易插入这些四舍五入分录的功能,因此如果我们实现该功能,此方法或许可以弃用。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def fill_residual_posting(entry, account_rounding):
"""If necessary, insert a posting to absorb the residual.
This makes the transaction balance exactly.
Note: This was developed in order to tweak transactions before exporting
them to Ledger. A better method would be to enable the feature that
automatically inserts these rounding postings on all transactions, and so
maybe this method can be deprecated if we do so.
Args:
entry: An instance of a Transaction.
account_rounding: A string, the name of the rounding account that
absorbs residuals / rounding errors.
Returns:
A possibly new, modified entry with a new posting. If a residual
was not needed - the transaction already balanced perfectly - no new
leg is inserted.
"""
residual = compute_residual(entry.postings)
if not residual.is_empty():
new_postings = list(entry.postings)
new_postings.extend(get_residual_postings(residual, account_rounding))
entry = entry._replace(postings=new_postings)
return entry
beancount.core.interpolate.get_residual_postings(residual, account_rounding)
创建用于记账给定剩余金额的分录。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def get_residual_postings(residual, account_rounding):
"""Create postings to book the given residuals.
Args:
residual: An Inventory, the residual positions.
account_rounding: A string, the name of the rounding account that
absorbs residuals / rounding errors.
Returns:
A list of new postings to be inserted to reduce the given residual.
"""
meta = {AUTOMATIC_META: True,
AUTOMATIC_RESIDUAL: True}
return [Posting(account_rounding, -position.units, position.cost, None, None,
meta.copy())
for position in residual.get_positions()]
beancount.core.interpolate.has_nontrivial_balance(posting)
如果一条分录的余额金额需要计算,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def has_nontrivial_balance(posting):
"""Return True if a Posting has a balance amount that would have to be calculated.
Args:
posting: A Posting instance.
Returns:
A boolean.
"""
return posting.cost or posting.price
beancount.core.interpolate.infer_tolerances(postings, options_map, use_cost=None)
从一组分录中推断容差。
容差是每种货币所允许的最大比例(字典形式)。我们使用权重金额的货币来推断每种货币的量化精度。整数金额不参与精度的确定。
'use_cost' 选项允许您实验性地让成本和价格分录影响容差的最大值。使用该选项会以非平凡方式改变容差的定义,需谨慎使用。容差将扩展为所有按成本持有分录的‘成本 × 最小单位数字的分数 M’之和。
例如,在以下交易中:
2006-01-17 * "Plan Contribution"
Assets:Investments:VWELX 18.572 VWELX {30.96 USD}
Assets:Investments:VWELX 18.572 VWELX {30.96 USD}
Assets:Investments:Cash -1150.00 USD
USD 数量的容差将计算为以下各项的最大值:
0.01 * M = 0.005(来自 1150.00 USD 分录)
0.001 * M × 30.96 = 0.01548 加上 0.001 * M × 30.96 = 0.01548,合计为 0.03096
因此,此情况下 USD 的容差为 max(0.005, 0.03096) = 0.03096。价格对最大容差的贡献方式类似。
请注意,上述 'M' 为 inferred_tolerance_multiplier,默认值为 0.5。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def infer_tolerances(postings, options_map, use_cost=None):
"""Infer tolerances from a list of postings.
The tolerance is the maximum fraction that is being used for each currency
(a dict). We use the currency of the weight amount in order to infer the
quantization precision for each currency. Integer amounts aren't
contributing to the determination of precision.
The 'use_cost' option allows one to experiment with letting postings at cost
and at price influence the maximum value of the tolerance. It's tricky to
use and alters the definition of the tolerance in a non-trivial way, if you
use it. The tolerance is expanded by the sum of the cost times a fraction 'M'
of the smallest digits in the number of units for all postings held at cost.
For example, in this transaction:
2006-01-17 * "Plan Contribution"
Assets:Investments:VWELX 18.572 VWELX {30.96 USD}
Assets:Investments:VWELX 18.572 VWELX {30.96 USD}
Assets:Investments:Cash -1150.00 USD
The tolerance for units of USD will calculated as the MAXIMUM of:
0.01 * M = 0.005 (from the 1150.00 USD leg)
The sum of
0.001 * M x 30.96 = 0.01548 +
0.001 * M x 30.96 = 0.01548
= 0.03096
So the tolerance for USD in this case is max(0.005, 0.03096) = 0.03096. Prices
contribute similarly to the maximum tolerance allowed.
Note that 'M' above is the inferred_tolerance_multiplier and its default
value is 0.5.
Args:
postings: A list of Posting instances.
options_map: A dict of options.
use_cost: A boolean, true if we should be using a combination of the smallest
digit of the number times the cost or price in order to infer the tolerance.
If the value is left unspecified (as 'None'), the default value can be
overridden by setting an option.
Returns:
A dict of currency to the tolerated difference amount to be used for it,
e.g. 0.005.
"""
if use_cost is None:
use_cost = options_map["infer_tolerance_from_cost"]
inferred_tolerance_multiplier = options_map["inferred_tolerance_multiplier"]
default_tolerances = options_map["inferred_tolerance_default"]
tolerances = default_tolerances.copy()
cost_tolerances = collections.defaultdict(D)
for posting in postings:
# Skip the precision on automatically inferred postings.
if posting.meta and AUTOMATIC_META in posting.meta:
continue
units = posting.units
if not (isinstance(units, Amount) and isinstance(units.number, Decimal)):
continue
# Compute bounds on the number.
currency = units.currency
expo = units.number.as_tuple().exponent
if expo < 0:
# Note: the exponent is a negative value.
tolerance = ONE.scaleb(expo) * inferred_tolerance_multiplier
# Note that we take the max() and not the min() here because the
# tolerance has a dual purpose: it's used to infer the resolution
# for interpolation (where we might want the min()) and also for
# balance checks (where we favor the looser/larger tolerance).
tolerances[currency] = max(tolerance, tolerances.get(currency,
-1024))
if not use_cost:
continue
# Compute bounds on the smallest digit of the number implied as cost.
cost = posting.cost
if cost is not None:
cost_currency = cost.currency
if isinstance(cost, Cost):
cost_tolerance = min(tolerance * cost.number, MAXIMUM_TOLERANCE)
else:
assert isinstance(cost, CostSpec)
cost_tolerance = MAXIMUM_TOLERANCE
for cost_number in cost.number_total, cost.number_per:
if cost_number is None or cost_number is MISSING:
continue
cost_tolerance = min(tolerance * cost_number, cost_tolerance)
cost_tolerances[cost_currency] += cost_tolerance
# Compute bounds on the smallest digit of the number implied as cost.
price = posting.price
if isinstance(price, Amount) and isinstance(price.number, Decimal):
price_currency = price.currency
price_tolerance = min(tolerance * price.number, MAXIMUM_TOLERANCE)
cost_tolerances[price_currency] += price_tolerance
for currency, tolerance in cost_tolerances.items():
tolerances[currency] = max(tolerance, tolerances.get(currency, -1024))
default = tolerances.pop('*', ZERO)
return defdict.ImmutableDictWithDefault(tolerances, default=default)
beancount.core.interpolate.is_tolerance_user_specified(tolerance)
如果给定的容差值由用户指定,则返回 True。
这允许用户指定如 # 0.1234 这样的容差,但不允许 # 0.123456。用于检测容差值是否由用户手动输入而非自动推断。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def is_tolerance_user_specified(tolerance):
"""Return true if the given tolerance number was user-specified.
This would allow the user to provide a tolerance like # 0.1234 but not
0.123456. This is used to detect whether a tolerance value # is input by the
user and not inferred automatically.
Args:
tolerance: An instance of Decimal.
Returns:
A boolean.
"""
return len(tolerance.as_tuple().digits) < MAX_TOLERANCE_DIGITS
beancount.core.interpolate.quantize_with_tolerance(tolerances, currency, number)
使用容差字典对单位进行量化。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/interpolate.py
def quantize_with_tolerance(tolerances, currency, number):
"""Quantize the units using the tolerance dict.
Args:
tolerances: A dict of currency to tolerance Decimalvalues.
number: A number to quantize.
currency: A string currency.
Returns:
A Decimal, the number possibly quantized.
"""
# Applying rounding to the default tolerance, if there is one.
tolerance = tolerances.get(currency)
if tolerance:
quantum = (tolerance * 2).normalize()
# If the tolerance is a neat number provided by the user,
# quantize the inferred numbers. See doc on quantize():
#
# Unlike other operations, if the length of the coefficient
# after the quantize operation would be greater than
# precision, then an InvalidOperation is signaled. This
# guarantees that, unless there is an error condition, the
# quantized exponent is always equal to that of the
# right-hand operand.
if is_tolerance_user_specified(quantum):
number = number.quantize(quantum)
return number
beancount.core.inventory
一个用于存储仓位库存的容器。
本模块提供了一个可以保存仓位的容器类。库存是一个仓位的映射,每个仓位通过
(货币: str, 成本: Cost) -> 仓位: Position
其中
'货币': 所考虑的商品,如 USD、CAD 或股票单位如 HOOL、MSFT、AAPL 等;
'成本': None 或一个包含成本货币、数量、日期和标签的 Cost 实例;
'仓位': 一个 Position 对象,其 'units' 属性保证与 '货币' 具有相同的货币,且其 '成本' 属性等于 '成本' 键。它本质上存储了单位数量。
这旨在同时容纳已记账和未记账的金额。我们采用的巧妙方法是:对于未记账的仓位,我们简单地将 '成本' 留为 None。大多数交易都属于这种情况。
= 转换 =
通常需要将此库存转换为其成本的等效仓位,或仅将具有相同货币的所有仓位合并以计算单位总数,或在特定日期计算库存的市场价值。这些转换可通过 reduce() 方法完成:
inventory.reduce(convert.get_cost) inventory.reduce(convert.get_units) inventory.reduce(convert.get_value, price_map, date)
beancount.core.inventory.Inventory (字典)
Inventory 是一组经过高效索引的仓位。
beancount.core.inventory.Inventory.__abs__(self)
特殊
返回一个包含每个仓位绝对值的库存。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __abs__(self):
"""Return an inventory with the absolute value of each position.
Returns:
An instance of Inventory.
"""
return Inventory({key: abs(pos) for key, pos in self.items()})
beancount.core.inventory.Inventory.__add__(self, other)
特殊
将另一个库存加到当前库存上。当前库存不会被修改。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __add__(self, other):
"""Add another inventory to this one. This inventory is not modified.
Args:
other: An instance of Inventory.
Returns:
A new instance of Inventory.
"""
new_inventory = self.__copy__()
new_inventory.add_inventory(other)
return new_inventory
beancount.core.inventory.Inventory.__copy__(self)
特殊
此库存对象的浅拷贝。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __copy__(self):
"""A shallow copy of this inventory object.
Returns:
An instance of Inventory, equal to this one.
"""
return Inventory(self)
beancount.core.inventory.Inventory.__iadd__(self, other)
特殊
将另一个 Inventory 实例的所有仓位添加到当前库存中。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def add_inventory(self, other):
"""Add all the positions of another Inventory instance to this one.
Args:
other: An instance of Inventory to add to this one.
Returns:
This inventory, modified.
"""
if self.is_empty():
# Optimization for empty inventories; if the current one is empty,
# adopt all of the other inventory's positions without running
# through the full aggregation checks. This should be very cheap. We
# can do this because the positions are immutable.
self.update(other)
else:
for position in other.get_positions():
self.add_position(position)
return self
beancount.core.inventory.Inventory.__init__(self, positions=None)
特殊
使用现有位置列表创建一个新的库存。
| 参数: |
|
|---|
源代码位于 beancount/core/inventory.py
def __init__(self, positions=None):
"""Create a new inventory using a list of existing positions.
Args:
positions: A list of Position instances or an existing dict or
Inventory instance.
"""
if isinstance(positions, (dict, Inventory)):
dict.__init__(self, positions)
else:
dict.__init__(self)
if positions:
assert isinstance(positions, Iterable)
for position in positions:
self.add_position(position)
beancount.core.inventory.Inventory.__iter__(self)
特殊
遍历所有位置。注意,顺序没有保证。
源代码位于 beancount/core/inventory.py
def __iter__(self):
"""Iterate over the positions. Note that there is no guaranteed order."""
return iter(self.values())
beancount.core.inventory.Inventory.__lt__(self, other)
特殊
不等比较运算符。
源代码位于 beancount/core/inventory.py
def __lt__(self, other):
"""Inequality comparison operator."""
return sorted(self) < sorted(other)
beancount.core.inventory.Inventory.__mul__(self, scalar)
特殊
缩放/乘以库存的内容。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __mul__(self, scalar):
"""Scale/multiply the contents of the inventory.
Args:
scalar: A Decimal.
Returns:
An instance of Inventory.
"""
return Inventory({key: pos * scalar for key, pos in self.items()})
beancount.core.inventory.Inventory.__neg__(self)
特殊
返回一个值为当前库存负值的库存。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __neg__(self):
"""Return an inventory with the negative of values of this one.
Returns:
An instance of Inventory.
"""
return Inventory({key: -pos for key, pos in self.items()})
beancount.core.inventory.Inventory.__repr__(self)
特殊
以人类可读的字符串形式呈现。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __str__(self):
"""Render as a human-readable string.
Returns:
A string, for human consumption.
"""
return self.to_string()
beancount.core.inventory.Inventory.__str__(self)
特殊
以人类可读的字符串形式呈现。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def __str__(self):
"""Render as a human-readable string.
Returns:
A string, for human consumption.
"""
return self.to_string()
beancount.core.inventory.Inventory.add_amount(self, units, cost=None)
使用金额和成本向此库存添加内容。此方法采用严格的批次匹配,即不会对库存键进行部分匹配。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def add_amount(self, units, cost=None):
"""Add to this inventory using amount and cost. This adds with strict lot
matching, that is, no partial matches are done on the arguments to the
keys of the inventory.
Args:
units: An Amount instance to add.
cost: An instance of Cost or None, as a key to the inventory.
Returns:
A pair of (position, matched) where 'position' is the position that
that was modified BEFORE it was modified, and where 'matched' is a
MatchResult enum that hints at how the lot was booked to this inventory.
Position may be None if there is no corresponding Position object,
e.g. the position was deleted.
"""
if ASSERTS_TYPES:
assert isinstance(units, Amount), (
"Internal error: {!r} (type: {})".format(units, type(units).__name__))
assert cost is None or isinstance(cost, Cost), (
"Internal error: {!r} (type: {})".format(cost, type(cost).__name__))
# Find the position.
key = (units.currency, cost)
pos = self.get(key, None)
if pos is not None:
# Note: In order to augment or reduce, all the fields have to match.
# Check if reducing.
booking = (MatchResult.REDUCED
if not same_sign(pos.units.number, units.number)
else MatchResult.AUGMENTED)
# Compute the new number of units.
number = pos.units.number + units.number
if number == ZERO:
# If empty, delete the position.
del self[key]
else:
# Otherwise update it.
self[key] = Position(Amount(number, units.currency), cost)
else:
# If not found, create a new one.
if units.number == ZERO:
booking = MatchResult.IGNORED
else:
self[key] = Position(units, cost)
booking = MatchResult.CREATED
return pos, booking
beancount.core.inventory.Inventory.add_inventory(self, other)
将另一个 Inventory 实例的所有仓位添加到当前库存中。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def add_inventory(self, other):
"""Add all the positions of another Inventory instance to this one.
Args:
other: An instance of Inventory to add to this one.
Returns:
This inventory, modified.
"""
if self.is_empty():
# Optimization for empty inventories; if the current one is empty,
# adopt all of the other inventory's positions without running
# through the full aggregation checks. This should be very cheap. We
# can do this because the positions are immutable.
self.update(other)
else:
for position in other.get_positions():
self.add_position(position)
return self
beancount.core.inventory.Inventory.add_position(self, position)
使用位置(严格批次匹配)添加。如果此位置与另一个位置匹配并减少其数量,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def add_position(self, position):
"""Add using a position (with strict lot matching).
Return True if this position was booked against and reduced another.
Args:
position: The Posting or Position to add to this inventory.
Returns:
A pair of (position, booking) where 'position' is the position that
that was modified, and where 'matched' is a MatchResult enum that
hints at how the lot was booked to this inventory.
"""
if ASSERTS_TYPES:
assert hasattr(position, 'units') and hasattr(position, 'cost'), (
"Invalid type for position: {}".format(position))
assert isinstance(position.cost, (type(None), Cost)), (
"Invalid type for cost: {}".format(position.cost))
return self.add_amount(position.units, position.cost)
beancount.core.inventory.Inventory.average(self)
将相同货币的所有批次平均合并。
使用每组聚合批次中的最小日期。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def average(self):
"""Average all lots of the same currency together.
Use the minimum date from each aggregated set of lots.
Returns:
An instance of Inventory.
"""
groups = collections.defaultdict(list)
for position in self:
key = (position.units.currency,
position.cost.currency if position.cost else None)
groups[key].append(position)
average_inventory = Inventory()
for (currency, cost_currency), positions in groups.items():
total_units = sum(position.units.number
for position in positions)
# Explicitly skip aggregates when resulting in zero units.
if total_units == ZERO:
continue
units_amount = Amount(total_units, currency)
if cost_currency:
total_cost = sum(convert.get_cost(position).number
for position in positions)
cost_number = (Decimal('Infinity')
if total_units == ZERO
else (total_cost / total_units))
min_date = None
for pos in positions:
pos_date = pos.cost.date if pos.cost else None
if pos_date is not None:
min_date = (pos_date
if min_date is None
else min(min_date, pos_date))
cost = Cost(cost_number, cost_currency, min_date, None)
else:
cost = None
average_inventory.add_amount(units_amount, cost)
return average_inventory
beancount.core.inventory.Inventory.cost_currencies(self)
返回此库存中持有的单位货币列表。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def cost_currencies(self):
"""Return the list of unit currencies held in this inventory.
Returns:
A set of currency strings.
"""
return set(cost.currency
for _, cost in self.keys()
if cost is not None)
beancount.core.inventory.Inventory.currencies(self)
返回此库存中持有的单位货币列表。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def currencies(self):
"""Return the list of unit currencies held in this inventory.
Returns:
A list of currency strings.
"""
return set(currency for currency, _ in self.keys())
beancount.core.inventory.Inventory.currency_pairs(self)
返回此库存中持有的商品。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def currency_pairs(self):
"""Return the commodities held in this inventory.
Returns:
A set of currency strings.
"""
return set(position.currency_pair() for position in self)
beancount.core.inventory.Inventory.from_string(string)
静态方法
从字符串创建一个库存实例。这在编写测试时非常有用。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
@staticmethod
def from_string(string):
"""Create an Inventory from a string. This is useful for writing tests.
Args:
string: A comma-separated string of <number> <currency> with an
optional {<number> <currency>} for the cost.
Returns:
A new instance of Inventory with the given balances.
"""
new_inventory = Inventory()
# We need to split the comma-separated positions but ignore commas
# occurring within a {...cost...} specification.
position_strs = re.split(
r'([-+]?[0-9,.]+\s+[A-Z]+\s*(?:{[^}]*})?)\s*,?\s*', string)[1::2]
for position_str in position_strs:
new_inventory.add_position(position_from_string(position_str))
return new_inventory
beancount.core.inventory.Inventory.get_currency_units(self, currency)
获取指定货币的所有仓位的总金额。这可能会对同一货币面额的多个批次进行求和。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def get_currency_units(self, currency):
"""Fetch the total amount across all the position in the given currency.
This may sum multiple lots in the same currency denomination.
Args:
currency: A string, the currency to filter the positions with.
Returns:
An instance of Amount, with the given currency.
"""
total_units = ZERO
for position in self:
if position.units.currency == currency:
total_units += position.units.number
return Amount(total_units, currency)
beancount.core.inventory.Inventory.get_only_position(self)
返回第一个仓位,并断言不存在其他仓位。如果库存为空,则返回 None。
源代码位于 beancount/core/inventory.py
def get_only_position(self):
"""Return the first position and assert there are no more.
If the inventory is empty, return None.
"""
if len(self) > 0:
if len(self) > 1:
raise AssertionError("Inventory has more than one expected "
"position: {}".format(self))
return next(iter(self))
beancount.core.inventory.Inventory.get_positions(self)
返回此库存中的所有仓位。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def get_positions(self):
"""Return the positions in this inventory.
Returns:
A shallow copy of the list of positions.
"""
return list(iter(self))
beancount.core.inventory.Inventory.is_empty(self)
如果库存为空(即没有仓位),则返回 True。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def is_empty(self):
"""Return true if the inventory is empty, that is, has no positions.
Returns:
A boolean.
"""
return len(self) == 0
beancount.core.inventory.Inventory.is_mixed(self)
如果库存中至少有一种商品同时包含正负批次,则返回 True。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def is_mixed(self):
"""Return true if the inventory contains a mix of positive and negative lots for
at least one instrument.
Returns:
A boolean.
"""
signs_map = {}
for position in self:
sign = position.units.number >= 0
prev_sign = signs_map.setdefault(position.units.currency, sign)
if sign != prev_sign:
return True
return False
beancount.core.inventory.Inventory.is_reduced_by(self, ramount)
如果给定金额能够减少此库存,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def is_reduced_by(self, ramount):
"""Return true if the amount could reduce this inventory.
Args:
ramount: An instance of Amount.
Returns:
A boolean.
"""
if ramount.number == ZERO:
return False
for position in self:
units = position.units
if (ramount.currency == units.currency and
not same_sign(ramount.number, units.number)):
return True
return False
beancount.core.inventory.Inventory.is_small(self, tolerances)
如果库存中的所有仓位都很小,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def is_small(self, tolerances):
"""Return true if all the positions in the inventory are small.
Args:
tolerances: A Decimal, the small number of units under which a position
is considered small, or a dict of currency to such epsilon precision.
Returns:
A boolean.
"""
if isinstance(tolerances, dict):
for position in self:
tolerance = tolerances.get(position.units.currency, ZERO)
if abs(position.units.number) > tolerance:
return False
small = True
else:
small = not any(abs(position.units.number) > tolerances
for position in self)
return small
beancount.core.inventory.Inventory.reduce(self, reducer, *args)
使用其中一个转换函数简化库存。
参见 beancount.core.convert 中的函数。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def reduce(self, reducer, *args):
"""Reduce an inventory using one of the conversion functions.
See functions in beancount.core.convert.
Returns:
An instance of Inventory.
"""
inventory = Inventory()
for position in self:
inventory.add_amount(reducer(position, *args))
return inventory
beancount.core.inventory.Inventory.segregate_units(self, currencies)
将持仓列表按指定的货币进行分离。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def segregate_units(self, currencies):
"""Split up the list of positions to the given currencies.
Args:
currencies: A list of currency strings, the currencies to isolate.
Returns:
A dict of currency to Inventory instances.
"""
per_currency_dict = {currency: Inventory()
for currency in currencies}
per_currency_dict[None] = Inventory()
for position in self:
currency = position.units.currency
key = (currency if currency in currencies else None)
per_currency_dict[key].add_position(position)
return per_currency_dict
beancount.core.inventory.Inventory.split(self)
将持仓列表按其对应的货币进行拆分。
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def split(self):
"""Split up the list of positions to their corresponding currencies.
Returns:
A dict of currency to Inventory instances.
"""
per_currency_dict = collections.defaultdict(Inventory)
for position in self:
per_currency_dict[position.units.currency].add_position(position)
return dict(per_currency_dict)
beancount.core.inventory.Inventory.to_string(self, dformat=, parens=True)
将 Inventory 实例转换为可打印的字符串。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def to_string(self, dformat=DEFAULT_FORMATTER, parens=True):
"""Convert an Inventory instance to a printable string.
Args:
dformat: An instance of DisplayFormatter.
parents: A boolean, true if we should surround the results by parentheses.
Returns:
A formatted string of the quantized amount and symbol.
"""
fmt = '({})' if parens else '{}'
return fmt.format(
', '.join(pos.to_string(dformat) for pos in sorted(self)))
beancount.core.inventory.MatchResult (Enum)
将新批次记入现有库存时的返回结果。
beancount.core.inventory.check_invariants(inv)
检查库存的不变量。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
def check_invariants(inv):
"""Check the invariants of the Inventory.
Args:
inventory: An instance of Inventory.
Returns:
True if the invariants are respected.
"""
# Check that all the keys are unique.
lots = set((pos.units.currency, pos.cost) for pos in inv)
assert len(lots) == len(inv), "Invalid inventory: {}".format(inv)
# Check that none of the amounts is zero.
for pos in inv:
assert pos.units.number != ZERO, "Invalid position size: {}".format(pos)
beancount.core.inventory.from_string(string)
从字符串创建一个库存实例。这在编写测试时非常有用。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/inventory.py
@staticmethod
def from_string(string):
"""Create an Inventory from a string. This is useful for writing tests.
Args:
string: A comma-separated string of <number> <currency> with an
optional {<number> <currency>} for the cost.
Returns:
A new instance of Inventory with the given balances.
"""
new_inventory = Inventory()
# We need to split the comma-separated positions but ignore commas
# occurring within a {...cost...} specification.
position_strs = re.split(
r'([-+]?[0-9,.]+\s+[A-Z]+\s*(?:{[^}]*})?)\s*,?\s*', string)[1::2]
for position_str in position_strs:
new_inventory.add_position(position_from_string(position_str))
return new_inventory
beancount.core.number
该模块包含基本的 Decimal 类型导入。
关于 Decimal 的使用:
-
请勿从 'decimal' 或 'cdecimal' 模块导入 Decimal;始终从 beancount.core.amount 导入您的 Decimal 类。
-
建议使用 D() 来创建新的 Decimal 对象,它支持更多语法,例如能处理 None 和带逗号的数字。
beancount.core.number.D(strord=None)
将字符串转换为 Decimal 对象。
此函数用于从文件中解析金额(在导入器中使用)。这是您应始终用于构建系统处理的所有数值的主要函数(绝不要在会计系统中使用浮点数)。逗号会被移除并忽略,因为它们被假定为千位分隔符(不支持法语中用逗号作为小数点的情况)。如果参数已经是 Decimal 对象,此函数将直接返回该参数,以方便使用。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/number.py
def D(strord=None):
"""Convert a string into a Decimal object.
This is used in parsing amounts from files in the importers. This is the
main function you should use to build all numbers the system manipulates
(never use floating-point in an accounting system). Commas are stripped and
ignored, as they are assumed to be thousands separators (the French comma
separator as decimal is not supported). This function just returns the
argument if it is already a Decimal object, for convenience.
Args:
strord: A string or Decimal instance.
Returns:
A Decimal instance.
"""
try:
# Note: try a map lookup and optimize performance here.
if strord is None or strord == '':
return Decimal()
elif isinstance(strord, str):
return Decimal(_CLEAN_NUMBER_RE.sub('', strord))
elif isinstance(strord, Decimal):
return strord
elif isinstance(strord, (int, float)):
return Decimal(strord)
else:
assert strord is None, "Invalid value to convert: {}".format(strord)
except Exception as exc:
raise ValueError("Impossible to create Decimal instance from {!s}: {}".format(
strord, exc)) from exc
beancount.core.number.auto_quantize(number, threshold)
在给定阈值下自动对数字进行量化。
例如,当阈值为 0.01 时,此函数将转换:
20.899999618530273 20.9 20.290000000000000000000000000000 20.29 110.90 110.9 11.0600004196167 11.06 10.539999961853027 10.54 134.3300018310547 134.33 253.920200000000000000000000000000 253.9202
源代码位于 beancount/core/number.py
def auto_quantize(number: Decimal, threshold: float) -> Decimal:
"""Automatically quantize the number at a given threshold.
For example, with a threshold of 0.01, this will convert:
20.899999618530273 20.9
20.290000000000000000000000000000 20.29
110.90 110.9
11.0600004196167 11.06
10.539999961853027 10.54
134.3300018310547 134.33
253.920200000000000000000000000000 253.9202
"""
exponent = auto_quantized_exponent(number, threshold)
if exponent != number.as_tuple().exponent:
quant = TEN ** exponent
qnumber = number.quantize(quant).normalize()
return qnumber
else:
return number
beancount.core.number.auto_quantized_exponent(number, threshold)
自动推断在给定阈值下所使用的指数。
源代码位于 beancount/core/number.py
def auto_quantized_exponent(number: Decimal, threshold: float) -> int:
"""Automatically infer the exponent that would be used below a given threshold."""
dtuple = number.normalize().as_tuple()
norm = Decimal(dtuple._replace(sign=0, exponent=-len(dtuple.digits)))
low_threshold = threshold
high_threshold = 1. - low_threshold
while norm != ZERO:
if not (low_threshold <= norm <= high_threshold):
break
ntuple = norm.scaleb(1).as_tuple()
norm = Decimal(ntuple._replace(digits=ntuple.digits[ntuple.exponent:]))
return dtuple.exponent - norm.as_tuple().exponent
beancount.core.number.infer_quantum_from_list(numbers, threshold=0.01)
给定一个浮点数列表,推断其公共量化精度。
对于以浮点数形式提供的数字序列(例如来自价格源的价格),我们希望推断出合适的量化精度,以避免超过指定阈值的舍入误差。
该简单算法会对所有数字进行自动量化,并以最大精度进行量化,确保所有舍入误差均低于阈值。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/number.py
def infer_quantum_from_list(numbers: List[Decimal],
threshold: float=0.01) -> Optional[Decimal]:
"""Given a list of numbers from floats, infer the common quantization.
For a series of numbers provided as floats, e.g., prices from a price
source, we'd like to infer what the right quantization that should be used
to avoid rounding errors above some threshold.
from the numbers. This simple algorithm auto-quantizes all the numbers and
quantizes all of them at the maximum precision that would result in rounding
under the threshold.
Args:
prices: A list of float or Decimal prices to infer from. If floats are
provided, conversion is done naively.
threshold: A fraction, the maximum error to tolerate before stopping the
search.
Returns:
A decimal object to use with decimal.Decimal.quantize().
"""
# Auto quantize all the numbers.
qnumbers = [auto_quantize(num, threshold) for num in numbers]
exponent = max(num_fractional_digits(n) for n in qnumbers)
return -exponent
beancount.core.number.num_fractional_digits(number)
返回小数部分的位数。
源代码位于 beancount/core/number.py
def num_fractional_digits(number: Decimal) -> int:
"""Return the number of fractional digits."""
return -number.as_tuple().exponent
beancount.core.number.round_to(number, increment)
将数字向下舍入到指定的增量。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/number.py
def round_to(number, increment):
"""Round a number *down* to a particular increment.
Args:
number: A Decimal, the number to be rounded.
increment: A Decimal, the size of the increment.
Returns:
A Decimal, the rounded number.
"""
return int((number / increment)) * increment
beancount.core.number.same_sign(number1, number2)
如果两个数字符号相同,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/number.py
def same_sign(number1, number2):
"""Return true if both numbers have the same sign.
Args:
number1: An instance of Decimal.
number2: An instance of Decimal.
Returns:
A boolean.
"""
return (number1 >= 0) == (number2 >= 0)
beancount.core.position
一个头寸对象,由单位 Amount 和成本 Cost 组成。
详见下方类型说明。
beancount.core.position.Cost (元组)
Cost(number, currency, date, label)
beancount.core.position.Cost.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/position.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.position.Cost.__new__(_cls, number, currency, date, label)
特殊
静态方法
创建 Cost(number, currency, date, label) 的新实例
beancount.core.position.Cost.__replace__(/, self, **kwds)
特殊
返回一个新的 Cost 对象,用指定的新值替换字段
源代码位于 beancount/core/position.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.position.Cost.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/position.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.position.CostSpec (tuple)
CostSpec(number_per, number_total, currency, date, label, merge)
beancount.core.position.CostSpec.__getnewargs__(self)
特殊
将自身返回为一个普通元组。供 copy 和 pickle 使用。
源代码位于 beancount/core/position.py
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
beancount.core.position.CostSpec.__new__(_cls, number_per, number_total, currency, date, label, merge)
特殊
静态方法
创建 CostSpec(number_per, number_total, currency, date, label, merge) 的新实例
beancount.core.position.CostSpec.__replace__(/, self, **kwds)
特殊
返回一个新的 CostSpec 对象,用指定的新值替换字段
源代码位于 beancount/core/position.py
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise TypeError(f'Got unexpected field names: {list(kwds)!r}')
return result
beancount.core.position.CostSpec.__repr__(self)
特殊
返回一个格式良好的表示字符串
源代码位于 beancount/core/position.py
def __repr__(self):
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
beancount.core.position.Position (_Position)
“Position”是单位和可选成本的组合,用于跟踪库存。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
units |
金额 |
一个 Amount,表示单位数量及其货币。 |
cost |
成本 |
表示批次的成本,或为 None。 |
beancount.core.position.Position.__abs__(self)
特殊
返回该头寸的绝对值。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __abs__(self):
"""Return the absolute value of the position.
Returns:
An instance of Position with the absolute units.
"""
return Position(amount_abs(self.units), self.cost)
beancount.core.position.Position.__copy__(self)
特殊
浅拷贝,但批次可以共享。这在性能上很重要;在平衡过程中会在此处花费大量时间。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __copy__(self):
"""Shallow copy, except for the lot, which can be shared. This is important for
performance reasons; a lot of time is spent here during balancing.
Returns:
A shallow copy of this position.
"""
# Note: We use Decimal() for efficiency.
return Position(copy.copy(self.units), copy.copy(self.cost))
beancount.core.position.Position.__eq__(self, other)
特殊
与另一个 Position 进行相等性比较。如果两个对象的数值和批次均匹配,则认为相等;若单位数量为零且另一个头寸为 None,也被视为相等。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __eq__(self, other):
"""Equality comparison with another Position. The objects are considered equal
if both number and lot are matching, and if the number of units is zero
and the other position is None, that is also okay.
Args:
other: An instance of Position, or None.
Returns:
A boolean, true if the positions are equal.
"""
return (self.units.number == ZERO
if other is None
else (self.units == other.units and self.cost == other.cost))
beancount.core.position.Position.__hash__(self)
特殊
计算此头寸的哈希值。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __hash__(self):
"""Compute a hash for this position.
Returns:
A hash of this position object.
"""
return hash((self.units, self.cost))
beancount.core.position.Position.__lt__(self, other)
特殊
位置的小于比较运算符。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __lt__(self, other):
"""A less-than comparison operator for positions.
Args:
other: Another instance of Position.
Returns:
True if this positions is smaller than the other position.
"""
return self.sortkey() < other.sortkey()
beancount.core.position.Position.__mul__(self, scalar)
特殊
缩放/乘以位置的内容。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __mul__(self, scalar):
"""Scale/multiply the contents of the position.
Args:
scalar: A Decimal.
Returns:
An instance of Inventory.
"""
return Position(amount_mul(self.units, scalar), self.cost)
beancount.core.position.Position.__neg__(self)
特殊
获取此位置的副本,但数量为负。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def get_negative(self):
"""Get a copy of this position but with a negative number.
Returns:
An instance of Position which represents the inverse of this Position.
"""
# Note: We use Decimal() for efficiency.
return Position(-self.units, self.cost)
beancount.core.position.Position.__new__(cls, units, cost=None)
特殊
静态方法
创建 _Position(units, cost) 的新实例。
源代码位于 beancount/core/position.py
def __new__(cls, units, cost=None):
assert isinstance(units, Amount), (
"Expected an Amount for units; received '{}'".format(units))
assert cost is None or isinstance(cost, Position.cost_types), (
"Expected a Cost for cost; received '{}'".format(cost))
return _Position.__new__(cls, units, cost)
beancount.core.position.Position.__repr__(self)
特殊
返回位置的字符串表示形式。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __str__(self):
"""Return a string representation of the position.
Returns:
A string, a printable representation of the position.
"""
return self.to_string()
beancount.core.position.Position.__str__(self)
特殊
返回位置的字符串表示形式。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def __str__(self):
"""Return a string representation of the position.
Returns:
A string, a printable representation of the position.
"""
return self.to_string()
beancount.core.position.Position.currency_pair(self)
返回与此位置关联的货币对。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def currency_pair(self):
"""Return the currency pair associated with this position.
Returns:
A pair of a currency string and a cost currency string or None.
"""
return (self.units.currency, self.cost.currency if self.cost else None)
beancount.core.position.Position.from_amounts(units, cost_amount=None)
静态方法
从数量和成本创建一个位置。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
@staticmethod
def from_amounts(units, cost_amount=None):
"""Create a position from an amount and a cost.
Args:
amount: An amount, that represents the number of units and the lot currency.
cost_amount: If not None, represents the cost amount.
Returns:
A Position instance.
"""
assert cost_amount is None or isinstance(cost_amount, Amount), (
"Invalid type for cost: {}".format(cost_amount))
cost = (Cost(cost_amount.number, cost_amount.currency, None, None)
if cost_amount else
None)
return Position(units, cost)
beancount.core.position.Position.from_string(string)
静态方法
从字符串规范创建一个位置。
这是一个用于构建测试的小型解析器。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
@staticmethod
def from_string(string):
"""Create a position from a string specification.
This is a miniature parser used for building tests.
Args:
string: A string of <number> <currency> with an optional {<number>
<currency>} for the cost, similar to the parser syntax.
Returns:
A new instance of Position.
"""
match = re.match(
(r'\s*({})\s+({})'
r'(?:\s+{{([^}}]*)}})?'
r'\s*$').format(NUMBER_RE, CURRENCY_RE),
string)
if not match:
raise ValueError("Invalid string for position: '{}'".format(string))
number = D(match.group(1))
currency = match.group(2)
# Parse a cost expression.
cost_number = None
cost_currency = None
date = None
label = None
cost_expression = match.group(3)
if match.group(3):
expressions = [expr.strip() for expr in re.split('[,/]', cost_expression)]
for expr in expressions:
# Match a compound number.
match = re.match(
r'({NUMBER_RE})\s*(?:#\s*({NUMBER_RE}))?\s+({CURRENCY_RE})$'
.format(NUMBER_RE=NUMBER_RE, CURRENCY_RE=CURRENCY_RE),
expr
)
if match:
per_number, total_number, cost_currency = match.group(1, 2, 3)
per_number = D(per_number) if per_number else ZERO
total_number = D(total_number) if total_number else ZERO
if total_number:
# Calculate the per-unit cost.
total = number * per_number + total_number
per_number = total / number
cost_number = per_number
continue
# Match a date.
match = re.match(r'(\d\d\d\d)[-/](\d\d)[-/](\d\d)$', expr)
if match:
date = datetime.date(*map(int, match.group(1, 2, 3)))
continue
# Match a label.
match = re.match(r'"([^"]+)*"$', expr)
if match:
label = match.group(1)
continue
# Match a merge-cost marker.
match = re.match(r'\*$', expr)
if match:
raise ValueError("Merge-code not supported in string constructor.")
raise ValueError("Invalid cost component: '{}'".format(expr))
cost = Cost(cost_number, cost_currency, date, label)
else:
cost = None
return Position(Amount(number, currency), cost)
beancount.core.position.Position.get_negative(self)
获取此位置的副本,但数量为负。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def get_negative(self):
"""Get a copy of this position but with a negative number.
Returns:
An instance of Position which represents the inverse of this Position.
"""
# Note: We use Decimal() for efficiency.
return Position(-self.units, self.cost)
beancount.core.position.Position.is_negative_at_cost(self)
如果位置以成本持有且为负数,则返回 True。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def is_negative_at_cost(self):
"""Return true if the position is held at cost and negative.
Returns:
A boolean.
"""
return (self.units.number < ZERO and self.cost is not None)
beancount.core.position.Position.sortkey(self)
返回一个用于对持仓进行排序的键。此键取决于持仓货币的顺序(我们希望优先排序常见货币)以及单位数量。
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def sortkey(self):
"""Return a key to sort positions by. This key depends on the order of the
currency of the lot (we want to order common currencies first) and the
number of units.
Returns:
A tuple, used to sort lists of positions.
"""
currency = self.units.currency
order_units = CURRENCY_ORDER.get(currency, NCURRENCIES + len(currency))
if self.cost is not None:
cost_number = self.cost.number
cost_currency = self.cost.currency
else:
cost_number = ZERO
cost_currency = ''
return (order_units, cost_number, cost_currency, self.units.number)
beancount.core.position.Position.to_string(self, dformat=, detail=True)
将持仓渲染为字符串。详情请参见 to_string()。
源代码位于 beancount/core/position.py
def to_string(self, dformat=DEFAULT_FORMATTER, detail=True):
"""Render the position to a string.See to_string() for details.
"""
return to_string(self, dformat, detail)
beancount.core.position.cost_to_str(cost, dformat, detail=True)
将 Cost 或 CostSpec 实例格式化为字符串。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def cost_to_str(cost, dformat, detail=True):
"""Format an instance of Cost or a CostSpec to a string.
Args:
cost: An instance of Cost or CostSpec.
dformat: A DisplayFormatter object.
detail: A boolean, true if we should render the non-amount components.
Returns:
A string, suitable for formatting.
"""
strlist = []
if isinstance(cost, Cost):
if isinstance(cost.number, Decimal):
strlist.append(Amount(cost.number, cost.currency).to_string(dformat))
if detail:
if cost.date:
strlist.append(cost.date.isoformat())
if cost.label:
strlist.append('"{}"'.format(cost.label))
elif isinstance(cost, CostSpec):
if isinstance(cost.number_per, Decimal) or isinstance(cost.number_total, Decimal):
amountlist = []
if isinstance(cost.number_per, Decimal):
amountlist.append(dformat.format(cost.number_per))
if isinstance(cost.number_total, Decimal):
amountlist.append('#')
amountlist.append(dformat.format(cost.number_total))
if isinstance(cost.currency, str):
amountlist.append(cost.currency)
strlist.append(' '.join(amountlist))
if detail:
if cost.date:
strlist.append(cost.date.isoformat())
if cost.label:
strlist.append('"{}"'.format(cost.label))
if cost.merge:
strlist.append('*')
return ', '.join(strlist)
beancount.core.position.from_amounts(units, cost_amount=None)
从数量和成本创建一个位置。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
@staticmethod
def from_amounts(units, cost_amount=None):
"""Create a position from an amount and a cost.
Args:
amount: An amount, that represents the number of units and the lot currency.
cost_amount: If not None, represents the cost amount.
Returns:
A Position instance.
"""
assert cost_amount is None or isinstance(cost_amount, Amount), (
"Invalid type for cost: {}".format(cost_amount))
cost = (Cost(cost_amount.number, cost_amount.currency, None, None)
if cost_amount else
None)
return Position(units, cost)
beancount.core.position.from_string(string)
从字符串规范创建一个位置。
这是一个用于构建测试的小型解析器。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
@staticmethod
def from_string(string):
"""Create a position from a string specification.
This is a miniature parser used for building tests.
Args:
string: A string of <number> <currency> with an optional {<number>
<currency>} for the cost, similar to the parser syntax.
Returns:
A new instance of Position.
"""
match = re.match(
(r'\s*({})\s+({})'
r'(?:\s+{{([^}}]*)}})?'
r'\s*$').format(NUMBER_RE, CURRENCY_RE),
string)
if not match:
raise ValueError("Invalid string for position: '{}'".format(string))
number = D(match.group(1))
currency = match.group(2)
# Parse a cost expression.
cost_number = None
cost_currency = None
date = None
label = None
cost_expression = match.group(3)
if match.group(3):
expressions = [expr.strip() for expr in re.split('[,/]', cost_expression)]
for expr in expressions:
# Match a compound number.
match = re.match(
r'({NUMBER_RE})\s*(?:#\s*({NUMBER_RE}))?\s+({CURRENCY_RE})$'
.format(NUMBER_RE=NUMBER_RE, CURRENCY_RE=CURRENCY_RE),
expr
)
if match:
per_number, total_number, cost_currency = match.group(1, 2, 3)
per_number = D(per_number) if per_number else ZERO
total_number = D(total_number) if total_number else ZERO
if total_number:
# Calculate the per-unit cost.
total = number * per_number + total_number
per_number = total / number
cost_number = per_number
continue
# Match a date.
match = re.match(r'(\d\d\d\d)[-/](\d\d)[-/](\d\d)$', expr)
if match:
date = datetime.date(*map(int, match.group(1, 2, 3)))
continue
# Match a label.
match = re.match(r'"([^"]+)*"$', expr)
if match:
label = match.group(1)
continue
# Match a merge-cost marker.
match = re.match(r'\*$', expr)
if match:
raise ValueError("Merge-code not supported in string constructor.")
raise ValueError("Invalid cost component: '{}'".format(expr))
cost = Cost(cost_number, cost_currency, date, label)
else:
cost = None
return Position(Amount(number, currency), cost)
beancount.core.position.get_position(posting)
从 Posting 实例构建一个 Position 实例。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def get_position(posting):
"""Build a Position instance from a Posting instance.
Args:
posting: An instance of Posting.
Returns:
An instance of Position.
"""
return Position(posting.units, posting.cost)
beancount.core.position.to_string(pos, dformat=, detail=True)
将 Position 或 Posting 实例渲染为字符串。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/position.py
def to_string(pos, dformat=DEFAULT_FORMATTER, detail=True):
"""Render the Position or Posting instance to a string.
Args:
pos: An instance of Position or Posting.
dformat: An instance of DisplayFormatter.
detail: A boolean, true if we should only render the lot details
beyond the cost (lot-date, label, etc.). If false, we only render
the cost, if present.
Returns:
A string, the rendered position.
"""
pos_str = pos.units.to_string(dformat)
if pos.cost is not None:
pos_str = '{} {{{}}}'.format(pos_str, cost_to_str(pos.cost, dformat, detail))
return pos_str
beancount.core.prices
本模块包含用于构建不同时点历史价格数据库的代码,从中可推导出未实现的资本收益和市场价值。
价格来源于文件中的 Price 条目,或由脚本生成(例如,您可以编写一个脚本从在线来源获取实时价格并动态创建条目)。
beancount.core.prices.PriceMap (dict)
价格映射字典。
键包括正向(基础货币,报价货币)对及其反向对。要确定哪些是正向对,请访问 'forward_pairs' 属性。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
forward_pairs |
正向对的 (基础货币, 报价货币) 键列表。 |
beancount.core.prices.build_price_map(entries)
根据任意条目列表构建价格映射。
如果在同一天为同一(货币,计价货币)对找到多个价格,则保留最新的价格,丢弃该日中较早的价格。
如果发现反向价格对,例如 USD 对 AUD 和 AUD 对 USD,则将价格点较少的反向对转换为价格点较多的对,从而将它们统一为单一价格对。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/prices.py
def build_price_map(entries):
"""Build a price map from a list of arbitrary entries.
If multiple prices are found for the same (currency, cost-currency) pair at
the same date, the latest date is kept and the earlier ones (for that day)
are discarded.
If inverse price pairs are found, e.g. USD in AUD and AUD in USD, the
inverse that has the smallest number of price points is converted into the
one that has the most price points. In that way they are reconciled into a
single one.
Args:
entries: A list of directives, hopefully including some Price and/or
Transaction entries.
Returns:
A dict of (currency, cost-currency) keys to sorted lists of (date, number)
pairs, where 'date' is the date the price occurs at and 'number' a Decimal
that represents the price, or rate, between these two
currencies/commodities. Each date occurs only once in the sorted list of
prices of a particular key. All of the inverses are automatically
generated in the price map.
"""
# Fetch a list of all the price entries seen in the ledger.
price_entries = [entry
for entry in entries
if isinstance(entry, Price)]
# Build a map of exchange rates between these units.
# (base-currency, quote-currency) -> List of (date, rate).
price_map = collections.defaultdict(list)
for price in price_entries:
base_quote = (price.currency, price.amount.currency)
price_map[base_quote].append((price.date, price.amount.number))
# Find pairs of inversed units.
inversed_units = []
for base_quote, values in price_map.items():
base, quote = base_quote
if (quote, base) in price_map:
inversed_units.append(base_quote)
# Find pairs of inversed units, and swallow the conversion with the smaller
# number of rates into the other one.
for base, quote in inversed_units:
bq_prices = price_map[(base, quote)]
qb_prices = price_map[(quote, base)]
remove = ((base, quote)
if len(bq_prices) < len(qb_prices)
else (quote, base))
base, quote = remove
remove_list = price_map[remove]
insert_list = price_map[(quote, base)]
del price_map[remove]
inverted_list = [(date, ONE/rate)
for (date, rate) in remove_list
if rate != ZERO]
insert_list.extend(inverted_list)
# Unzip and sort each of the entries and eliminate duplicates on the date.
sorted_price_map = PriceMap({
base_quote: list(misc_utils.sorted_uniquify(date_rates, lambda x: x[0], last=True))
for (base_quote, date_rates) in price_map.items()})
# Compute and insert all the inverted rates.
forward_pairs = list(sorted_price_map.keys())
for (base, quote), price_list in list(sorted_price_map.items()):
# Note: You have to filter out zero prices for zero-cost postings, like
# gifted options.
sorted_price_map[(quote, base)] = [
(date, ONE/price) for date, price in price_list
if price != ZERO]
sorted_price_map.forward_pairs = forward_pairs
return sorted_price_map
beancount.core.prices.get_all_prices(price_map, base_quote)
返回所有(日期,数值)价格对的排序列表。
| 参数: |
|
|---|
| 返回: |
|
|---|
| 异常: |
|
|---|
源代码位于 beancount/core/prices.py
def get_all_prices(price_map, base_quote):
"""Return a sorted list of all (date, number) price pairs.
Args:
price_map: A price map, which is a dict of (base, quote) -> list of (date,
number) tuples, as created by build_price_map.
base_quote: A pair of strings, the base currency to lookup, and the quote
currency to lookup, which expresses which units the base currency is
denominated in. This may also just be a string, with a '/' separator.
Returns:
A list of (date, Decimal) pairs, sorted by date.
Raises:
KeyError: If the base/quote could not be found.
"""
base_quote = normalize_base_quote(base_quote)
return _lookup_price_and_inverse(price_map, base_quote)
beancount.core.prices.get_last_price_entries(entries, date)
遍历条目直至指定日期,返回每个(货币,计价货币)对遇到的最后一个 Price 条目。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/prices.py
def get_last_price_entries(entries, date):
"""Run through the entries until the given date and return the last
Price entry encountered for each (currency, cost-currency) pair.
Args:
entries: A list of directives.
date: An instance of datetime.date. If None, the very latest price
is returned.
Returns:
A list of price entries.
"""
price_entry_map = {}
for entry in entries:
if date is not None and entry.date >= date:
break
if isinstance(entry, Price):
base_quote = (entry.currency, entry.amount.currency)
price_entry_map[base_quote] = entry
return sorted(price_entry_map.values(), key=data.entry_sortkey)
beancount.core.prices.get_latest_price(price_map, base_quote)
从价格映射中返回给定基础/报价货币对的最新价格/汇率。通常用于在查看全部条目时获取“当前”价格。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/prices.py
def get_latest_price(price_map, base_quote):
"""Return the latest price/rate from a price map for the given base/quote pair.
This is often used to just get the 'current' price if you're looking at the
entire set of entries.
Args:
price_map: A price map, which is a dict of (base, quote) -> list of (date,
number) tuples, as created by build_price_map.
Returns:
A pair of (date, number), where 'date' is a datetime.date instance and
'number' is a Decimal of the price, or rate, at that date. The date is the
latest date which we have an available price for in the price map.
"""
base_quote = normalize_base_quote(base_quote)
# Handle the degenerate case of a currency priced into its own.
base, quote = base_quote
if quote is None or base == quote:
return (None, ONE)
# Look up the list and return the latest element. The lists are assumed to
# be sorted.
try:
price_list = _lookup_price_and_inverse(price_map, base_quote)
except KeyError:
price_list = None
if price_list:
return price_list[-1]
else:
return None, None
beancount.core.prices.get_price(price_map, base_quote, date=None)
返回截至指定日期的价格。
如果未指定日期,则返回最新价格。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/prices.py
def get_price(price_map, base_quote, date=None):
"""Return the price as of the given date.
If the date is unspecified, return the latest price.
Args:
price_map: A price map, which is a dict of (base, quote) -> list of (date,
number) tuples, as created by build_price_map.
base_quote: A pair of strings, the base currency to lookup, and the quote
currency to lookup, which expresses which units the base currency is
denominated in. This may also just be a string, with a '/' separator.
date: A datetime.date instance, the date at which we want the conversion
rate.
Returns:
A pair of (datetime.date, Decimal) instance. If no price information could
be found, return (None, None).
"""
if date is None:
return get_latest_price(price_map, base_quote)
base_quote = normalize_base_quote(base_quote)
# Handle the degenerate case of a currency priced into its own.
base, quote = base_quote
if quote is None or base == quote:
return (None, ONE)
try:
price_list = _lookup_price_and_inverse(price_map, base_quote)
index = bisect_key.bisect_right_with_key(price_list, date, key=lambda x: x[0])
if index == 0:
return None, None
else:
return price_list[index-1]
except KeyError:
return None, None
beancount.core.prices.normalize_base_quote(base_quote)
将用斜杠分隔的字符串转换为一对字符串。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/prices.py
def normalize_base_quote(base_quote):
"""Convert a slash-separated string to a pair of strings.
Args:
base_quote: A pair of strings, the base currency to lookup, and the quote
currency to lookup, which expresses which units the base currency is
denominated in. This may also just be a string, with a '/' separator.
Returns:
A pair of strings.
"""
if isinstance(base_quote, str):
base_quote_norm = tuple(base_quote.split('/'))
assert len(base_quote_norm) == 2, base_quote
base_quote = base_quote_norm
assert isinstance(base_quote, tuple), base_quote
return base_quote
beancount.core.prices.project(orig_price_map, from_currency, to_currency, base_currencies=None)
将所有报价货币的价格投影到另一种报价货币。
假设你有一个 HOOL 的美元价格,并希望将 HOOL 转换为加元。如果数据库中不存在 (HOOL, CAD) 的价格对,则不会进行转换。从美元到加元的投影将计算组合汇率,并为所有基础货币(如 HOOL)插入相应的价格。在此示例中,每个 (HOOL, USD) 价格都会在相同日期插入一个对应的 (HOOL, CAD) 价格。
当简化包含多种运营货币对的账簿库存时,通常会进行此类投影,例如,当你希望计算一组账户在其中一种货币下的总价值时。
请注意:
-
即使目标货币对已存在条目,投影仍会应用。例如,若已存在一些 (HOOL, CAD) 价格,上述投影仍会向其中插入新的价格点。
-
然而,若投影价格与现有价格在相同日期冲突,则不会覆盖原有价格。
-
如果目标货币与源货币之间的转换没有现有价格(例如,在其首次价格记录之前),投影将无法插入新价格。
-
或许最重要的是,我们仅在基础商品存在价格点的日期插入价格点。换句话说,如果我们只有日期 A 和 C 的价格,而汇率在日期 B 发生变化,我们不会在日期 B 合成新的价格。要获得更精确、考虑汇率变化的投影价格,应进行多次查询。我们最终将添加一种方法,允许通过指定的中间货币对列表进行查询。{c1bd24f8d4b7}
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/prices.py
def project(orig_price_map: PriceMap,
from_currency: Currency,
to_currency: Currency,
base_currencies: Optional[Set[Currency]] = None) -> PriceMap:
"""Project all prices with a quote currency to another quote currency.
Say you have a price for HOOL in USD and you'd like to convert HOOL to CAD.
If there aren't any (HOOL, CAD) price pairs in the database it will remain
unconverted. Projecting from USD to CAD will compute combined rates and
insert corresponding prices over all base currencies (like HOOL). In this
example, each of the (HOOL, USD) prices would see an inserted (HOOL, CAD)
price inserted at the same date.
It is common to make these projections when reducing inventories in a ledger
that states multiple operating currency pairs, when for example, one wants
to compute total value of a set of accounts in one of those currencies.
Please note that:
- Even if the target pair has existing entries, projection will still be
applied. For example, is there exist some (HOOL, CAD) prices, the
projection in the example above will still insert some new price points to
it.
- However, projected prices colliding existing ones at the same date will
not override them.
- Projection will fail to insert a new price if the conversion between to
and from currencies has no existing prices (e.g. before its first price
entry).
- Perhaps most importantly, we only insert price points at dates where the
base commodity has a price point. In other words, if we have prices for
dates A and C and the rate changes between these dates at date B, we don't
synthesize a new price at date B. A more accurate method to get projected
prices that takes into account varying rates is to do multiple lookups.
We'll eventually add a method to query it via a specified list of
intermediate pairs. {c1bd24f8d4b7}
Args:
orig_price_map: An existing price map.
from_currency: The quote currency with existing project points (e.g., USD).
to_currency: The quote currency to insert price points for (e.g., CAD).
base_currencies: An optional set of commodities to restrict the
projections to (e.g., {HOOL}).
Returns:
A new price map, with the extra projected prices. The original price map
is kept intact.
"""
# If nothing is requested, return the original map.
if from_currency == to_currency:
return orig_price_map
# Avoid mutating the input map.
price_map = {key: list(value) for key, value in orig_price_map.items()}
# Process the entire database (it's not indexed by quote currency).
currency_pair = (from_currency, to_currency)
for base_quote, prices in list(price_map.items()):
# Filter just the currencies to convert.
base, quote = base_quote
if quote != from_currency:
continue
# Skip currencies not requested if a constraint has been provided.
# {4bb702d82c8a}
if base_currencies and base not in base_currencies:
continue
# Create a mapping of existing prices so we can avoid date collisions.
existing_prices = ({date for date, _ in price_map[(base, to_currency)]}
if (base, to_currency) in price_map
else set())
# Project over each of the prices.
new_projected = []
for date, price in prices:
rate_date, rate = get_price(price_map, currency_pair, date)
if rate is None:
# There is no conversion rate at this time; skip projection.
# {b2b23353275d}.
continue
if rate_date in existing_prices:
# Skip collisions in date. {97a5703ac517}
continue
# Append the new rate.
new_price = price * rate
new_projected.append((date, new_price))
# Make sure the resulting lists are sorted.
if new_projected:
projected = price_map.setdefault((base, to_currency), [])
projected.extend(new_projected)
projected.sort()
inverted = price_map.setdefault((to_currency, base), [])
inverted.extend((date, ZERO if rate == ZERO else ONE/rate)
for date, rate in new_projected)
inverted.sort()
return price_map
beancount.core.realization
将特定的账户条目列表实现为报告。
此代码将条目列表转换为 RealAccount 节点树(代表“已实现账户”)。RealAccount 对象包含 Posting 实例列表,而非交易或其他附加到账户的条目类型(如余额或备注条目)。
RealAccount 的接口与常规 Python 字典一致,其中键是账户名称的各个组成部分,值始终是其他 RealAccount 实例。若要通过完整账户名称获取账户,本模块提供了辅助函数(例如,realization.get())。RealAccount 实例还包含该账户所有条目所产生的最终余额。
你不应自行构建 RealAccount 树;相反,应筛选出要显示的所需指令列表,然后调用 realize() 函数处理它们。
beancount.core.realization.RealAccount (dict)
一个插入在树中的已实现账户,包含已实现条目的列表。
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
账户 |
一个字符串,表示对应账户的完整名称。 |
|
分录 |
与此账户关联的过账列表(不包括子账户的过账)。 |
|
余额 |
与此账户关联的过账列表的最终余额。 |
beancount.core.realization.RealAccount.__eq__(self, other)
特殊
相等性判断。比较所有属性。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def __eq__(self, other):
"""Equality predicate. All attributes are compared.
Args:
other: Another instance of RealAccount.
Returns:
A boolean, True if the two real accounts are equal.
"""
return (dict.__eq__(self, other) and
self.account == other.account and
self.balance == other.balance and
self.txn_postings == other.txn_postings)
beancount.core.realization.RealAccount.__init__(self, account_name, *args, **kwargs)
特殊
创建一个 RealAccount 实例。
| 参数: |
|
|---|
源代码位于 beancount/core/realization.py
def __init__(self, account_name, *args, **kwargs):
"""Create a RealAccount instance.
Args:
account_name: a string, the name of the account. Maybe not be None.
"""
super().__init__(*args, **kwargs)
assert isinstance(account_name, str)
self.account = account_name
self.txn_postings = []
self.balance = inventory.Inventory()
beancount.core.realization.RealAccount.__ne__(self, other)
特殊
不等性判断。参见 eq。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def __ne__(self, other):
"""Not-equality predicate. See __eq__.
Args:
other: Another instance of RealAccount.
Returns:
A boolean, True if the two real accounts are not equal.
"""
return not self.__eq__(other)
beancount.core.realization.RealAccount.__setitem__(self, key, value)
特殊
防止在此字典中设置非字符串或空键。
| 参数: |
|
|---|
| 异常: |
|
|---|
源代码位于 beancount/core/realization.py
def __setitem__(self, key, value):
"""Prevent the setting of non-string or non-empty keys on this dict.
Args:
key: The dictionary key. Must be a string.
value: The value, must be a RealAccount instance.
Raises:
KeyError: If the key is not a string, or is invalid.
ValueError: If the value is not a RealAccount instance.
"""
if not isinstance(key, str) or not key:
raise KeyError("Invalid RealAccount key: '{}'".format(key))
if not isinstance(value, RealAccount):
raise ValueError("Invalid RealAccount value: '{}'".format(value))
if not value.account.endswith(key):
raise ValueError("RealAccount name '{}' inconsistent with key: '{}'".format(
value.account, key))
return super().__setitem__(key, value)
beancount.core.realization.RealAccount.copy(self)
重写 dict.copy() 以克隆 RealAccount。
仅为了正确实现复制方法而必需。否则,对 RealAccount 实例调用 .copy() 将会调用基类方法,仅返回一个字典。
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def copy(self):
"""Override dict.copy() to clone a RealAccount.
This is only necessary to correctly implement the copy method.
Otherwise, calling .copy() on a RealAccount instance invokes the base
class' method, which return just a dict.
Returns:
A cloned instance of RealAccount, with all members shallow-copied.
"""
return copy.copy(self)
beancount.core.realization.compute_balance(real_account, leaf_only=False)
计算此账户及其所有子账户的总余额。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def compute_balance(real_account, leaf_only=False):
"""Compute the total balance of this account and all its subaccounts.
Args:
real_account: A RealAccount instance.
leaf_only: A boolean flag, true if we should yield only leaves.
Returns:
An Inventory.
"""
return functools.reduce(operator.add, [
ra.balance for ra in iter_children(real_account, leaf_only)])
beancount.core.realization.compute_postings_balance(txn_postings)
计算一组 Posting 或 TxnPosting 位置的余额。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def compute_postings_balance(txn_postings):
"""Compute the balance of a list of Postings's or TxnPosting's positions.
Args:
postings: A list of Posting instances and other directives (which are
skipped).
Returns:
An Inventory.
"""
final_balance = inventory.Inventory()
for txn_posting in txn_postings:
if isinstance(txn_posting, Posting):
final_balance.add_position(txn_posting)
elif isinstance(txn_posting, TxnPosting):
final_balance.add_position(txn_posting.posting)
return final_balance
beancount.core.realization.contains(real_account, account_name)
如果给定的账户节点包含子账户名称,则返回 True。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def contains(real_account, account_name):
"""True if the given account node contains the subaccount name.
Args:
account_name: A string, the name of a direct or indirect subaccount of
this node.
Returns:
A boolean, true the name is a child of this node.
"""
return get(real_account, account_name) is not None
beancount.core.realization.dump(root_account)
将 RealAccount 节点转换为多行文本。
注意:此函数不应用于生成文本报告;报告代码应生成一个包含结构的中间对象,然后可将其渲染为 ASCII、HTML 或 CSV 格式。此函数仅用于方便地转储数据树以供调试。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def dump(root_account):
"""Convert a RealAccount node to a line of lines.
Note: this is not meant to be used to produce text reports; the reporting
code should produce an intermediate object that contains the structure of
it, which can then be rendered to ASCII, HTML or CSV formats. This is
intended as a convenient little function for dumping trees of data for
debugging purposes.
Args:
root_account: A RealAccount instance.
Returns:
A list of tuples of (first_line, continuation_line, real_account) where
first_line: A string, the first line to render, which includes the
account name.
continuation_line: A string, further line to render if necessary.
real_account: The RealAccount instance which corresponds to this
line.
"""
# Compute all the lines ahead of time in order to calculate the width.
lines = []
# Start with the root node. We push the constant prefix before this node,
# the account name, and the RealAccount instance. We will maintain a stack
# of children nodes to render.
stack = [('', root_account.account, root_account, True)]
while stack:
prefix, name, real_account, is_last = stack.pop(-1)
if real_account is root_account:
# For the root node, we don't want to render any prefix.
first = cont = ''
else:
# Compute the string that precedes the name directly and the one below
# that for the continuation lines.
# |
# @@@ Bank1 <----------------
# @@@ |
# | |-- Checking
if is_last:
first = prefix + PREFIX_LEAF_1
cont = prefix + PREFIX_LEAF_C
else:
first = prefix + PREFIX_CHILD_1
cont = prefix + PREFIX_CHILD_C
# Compute the name to render for continuation lines.
# |
# |-- Bank1
# | @@@ <----------------
# | |-- Checking
if len(real_account) > 0:
cont_name = PREFIX_CHILD_C
else:
cont_name = PREFIX_LEAF_C
# Add a line for this account.
if not (real_account is root_account and not name):
lines.append((first + name,
cont + cont_name,
real_account))
# Push the children onto the stack, being careful with ordering and
# marking the last node as such.
child_items = sorted(real_account.items(), reverse=True)
if child_items:
child_iter = iter(child_items)
child_name, child_account = next(child_iter)
stack.append((cont, child_name, child_account, True))
for child_name, child_account in child_iter:
stack.append((cont, child_name, child_account, False))
if not lines:
return lines
# Compute the maximum width of the lines and convert all of them to the same
# maximal width. This makes it easy on the client.
max_width = max(len(first_line) for first_line, _, __ in lines)
line_format = '{{:{width}}}'.format(width=max_width)
return [(line_format.format(first_line),
line_format.format(cont_line),
real_node)
for (first_line, cont_line, real_node) in lines]
beancount.core.realization.dump_balances(real_root, dformat, at_cost=False, fullnames=False, file=None)
转储带有余额的实现树。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def dump_balances(real_root, dformat, at_cost=False, fullnames=False, file=None):
"""Dump a realization tree with balances.
Args:
real_root: An instance of RealAccount.
dformat: An instance of DisplayFormatter to format the numbers with.
at_cost: A boolean, if true, render the values at cost.
fullnames: A boolean, if true, don't render a tree of accounts and
render the full account names.
file: A file object to dump the output to. If not specified, we
return the output as a string.
Returns:
A string, the rendered tree, or nothing, if 'file' was provided.
"""
if fullnames:
# Compute the maximum account name length;
maxlen = max(len(real_child.account)
for real_child in iter_children(real_root, leaf_only=True))
line_format = '{{:{width}}} {{}}\n'.format(width=maxlen)
else:
line_format = '{} {}\n'
output = file or io.StringIO()
for first_line, cont_line, real_account in dump(real_root):
if not real_account.balance.is_empty():
if at_cost:
rinv = real_account.balance.reduce(convert.get_cost)
else:
rinv = real_account.balance.reduce(convert.get_units)
amounts = [position.units for position in rinv.get_positions()]
positions = [amount_.to_string(dformat)
for amount_ in sorted(amounts, key=amount.sortkey)]
else:
positions = ['']
if fullnames:
for position in positions:
if not position and len(real_account) > 0:
continue # Skip parent accounts with no position to render.
output.write(line_format.format(real_account.account, position))
else:
line = first_line
for position in positions:
output.write(line_format.format(line, position))
line = cont_line
if file is None:
return output.getvalue()
beancount.core.realization.filter(real_account, predicate)
根据谓词过滤 RealAccount 树节点。
此函数遍历树并对每个节点应用谓词。它返回 RealAccount 的部分克隆,其中每个节点要么谓词为真,要么至少有一个子节点的谓词为真。所有叶子节点的谓词均为真。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def filter(real_account, predicate):
"""Filter a RealAccount tree of nodes by the predicate.
This function visits the tree and applies the predicate on each node. It
returns a partial clone of RealAccount whereby on each node
- either the predicate is true, or
- for at least one child of the node the predicate is true.
All the leaves have the predicate be true.
Args:
real_account: An instance of RealAccount.
predicate: A callable/function which accepts a RealAccount and returns
a boolean. If the function returns True, the node is kept.
Returns:
A shallow clone of RealAccount is always returned.
"""
assert isinstance(real_account, RealAccount)
real_copy = RealAccount(real_account.account)
real_copy.balance = real_account.balance
real_copy.txn_postings = real_account.txn_postings
for child_name, real_child in real_account.items():
real_child_copy = filter(real_child, predicate)
if real_child_copy is not None:
real_copy[child_name] = real_child_copy
if len(real_copy) > 0 or predicate(real_account):
return real_copy
beancount.core.realization.find_last_active_posting(txn_postings)
查看交易条目列表末尾,找到最后一个非自动添加的指令。注意:若账户已关闭,则最后一个条目假定为 Close 指令(前提是输入有效且无错误通过检查)。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def find_last_active_posting(txn_postings):
"""Look at the end of the list of postings, and find the last
posting or entry that is not an automatically added directive.
Note that if the account is closed, the last posting is assumed
to be a Close directive (this is the case if the input is valid
and checks without errors.
Args:
txn_postings: a list of postings or entries.
Returns:
An entry, or None, if the input list was empty.
"""
for txn_posting in reversed(txn_postings):
assert not isinstance(txn_posting, Posting)
if not isinstance(txn_posting, (TxnPosting, Open, Close, Pad, Balance, Note)):
continue
return txn_posting
beancount.core.realization.get(real_account, account_name, default=None)
从 real_account 节点中获取子账户名称。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def get(real_account, account_name, default=None):
"""Fetch the subaccount name from the real_account node.
Args:
real_account: An instance of RealAccount, the parent node to look for
children of.
account_name: A string, the name of a possibly indirect child leaf
found down the tree of 'real_account' nodes.
default: The default value that should be returned if the child
subaccount is not found.
Returns:
A RealAccount instance for the child, or the default value, if the child
is not found.
"""
if not isinstance(account_name, str):
raise ValueError
components = account.split(account_name)
for component in components:
real_child = real_account.get(component, default)
if real_child is default:
return default
real_account = real_child
return real_account
beancount.core.realization.get_or_create(real_account, account_name)
从 real_account 节点中获取子账户名称。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def get_or_create(real_account, account_name):
"""Fetch the subaccount name from the real_account node.
Args:
real_account: An instance of RealAccount, the parent node to look for
children of, or create under.
account_name: A string, the name of the direct or indirect child leaf
to get or create.
Returns:
A RealAccount instance for the child, or the default value, if the child
is not found.
"""
if not isinstance(account_name, str):
raise ValueError
components = account.split(account_name)
path = []
for component in components:
path.append(component)
real_child = real_account.get(component, None)
if real_child is None:
real_child = RealAccount(account.join(*path))
real_account[component] = real_child
real_account = real_child
return real_account
beancount.core.realization.get_postings(real_account)
返回 RealAccount 的所有记账项及其子节点的排序列表。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def get_postings(real_account):
"""Return a sorted list a RealAccount's postings and children.
Args:
real_account: An instance of RealAccount.
Returns:
A list of Posting or directories.
"""
# We accumulate all the postings at once here instead of incrementally
# because we need to return them sorted.
accumulator = []
for real_child in iter_children(real_account):
accumulator.extend(real_child.txn_postings)
accumulator.sort(key=data.posting_sortkey)
return accumulator
beancount.core.realization.index_key(sequence, value, key, cmp)
在 'sequence' 中查找第一个等于 'value' 的元素的索引。如果指定了 'key',则将 'value' 与该函数返回的值进行比较。如果未找到该值,则返回 None。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def index_key(sequence, value, key, cmp):
"""Find the index of the first element in 'sequence' which is equal to 'value'.
If 'key' is specified, the value compared to the value returned by this
function. If the value is not found, return None.
Args:
sequence: The sequence to search.
value: The value to search for.
key: A predicate to call to obtain the value to compare against.
cmp: A comparison predicate.
Returns:
The index of the first element found, or None, if the element was not found.
"""
for index, element in enumerate(sequence):
if cmp(key(element), value):
return index
return
beancount.core.realization.iter_children(real_account, leaf_only=False)
深度优先遍历此账户节点及其所有子节点。
| 参数: |
|
|---|
生成:RealAccount 实例,从本账户开始。顺序未定。
源代码位于 beancount/core/realization.py
def iter_children(real_account, leaf_only=False):
"""Iterate this account node and all its children, depth-first.
Args:
real_account: An instance of RealAccount.
leaf_only: A boolean flag, true if we should yield only leaves.
Yields:
Instances of RealAccount, beginning with this account. The order is
undetermined.
"""
if leaf_only:
if len(real_account) == 0:
yield real_account
else:
for key, real_child in sorted(real_account.items()):
for real_subchild in iter_children(real_child, leaf_only):
yield real_subchild
else:
yield real_account
for key, real_child in sorted(real_account.items()):
for real_subchild in iter_children(real_child):
yield real_subchild
beancount.core.realization.iterate_with_balance(txn_postings)
遍历条目,累加累计余额。
对于每个条目,此函数生成如下形式的元组:
(entry, postings, change, balance)
entry:此行的指令。如果列表包含 Posting 实例,则返回对应的 Transaction 对象。postings:影响余额的此条目上的记账项列表。仅包含输入列表中出现的记账项;只有这些记账项会影响余额。如果 'entry' 不是 Transaction 指令,则此列表应始终为空。我们保留输入列表中记账项的原始顺序。change:一个 Inventory 对象,反映此条目中出现在列表中的所有记账项导致的总变化量。例如,若一个 Transaction 有三个记账项,其中两个在输入列表中,则 'change' Inventory 对象将包含这两个记账项的总和。但未包含在输入列表中的第三个记账项的位置不会出现在此 Inventory 中。balance:一个 Inventory 对象,反映在添加此条目交易的 'change' Inventory 后的余额。即使对于不影响余额的条目(即 'change' Inventory 为空),生成的 'balance' 也永远不会为 None。由调用者(渲染条目的代码)决定是否为特定条目类型渲染此条目的变化量。
请注意,如果输入的记账项或条目列表未按日期排序,且同一笔交易的两个记账项在不同日期之间出现两次,则会导致该交易条目出现两次。这是正确的行为,实践中通常不会发生,因为记账项或条目列表应始终已排序。此方法会尝试检测这种情况,并在发现时引发断言错误。
| 参数: |
|
|---|
返回:如上所述的 (条目, 明细, 变动, 余额) 元组。
源代码位于 beancount/core/realization.py
def iterate_with_balance(txn_postings):
"""Iterate over the entries, accumulating the running balance.
For each entry, this yields tuples of the form:
(entry, postings, change, balance)
entry: This is the directive for this line. If the list contained Posting
instance, this yields the corresponding Transaction object.
postings: A list of postings on this entry that affect the balance. Only the
postings encountered in the input list are included; only those affect the
balance. If 'entry' is not a Transaction directive, this should always be
an empty list. We preserve the original ordering of the postings as they
appear in the input list.
change: An Inventory object that reflects the total change due to the
postings from this entry that appear in the list. For example, if a
Transaction has three postings and two are in the input list, the sum of
the two postings will be in the 'change' Inventory object. However, the
position for the transactions' third posting--the one not included in the
input list--will not be in this inventory.
balance: An Inventory object that reflects the balance *after* adding the
'change' inventory due to this entry's transaction. The 'balance' yielded
is never None, even for entries that do not affect the balance, that is,
with an empty 'change' inventory. It's up to the caller, the one rendering
the entry, to decide whether to render this entry's change for a
particular entry type.
Note that if the input list of postings-or-entries is not in sorted date
order, two postings for the same entry appearing twice with a different date
in between will cause the entry appear twice. This is correct behavior, and
it is expected that in practice this should never happen anyway, because the
list of postings or entries should always be sorted. This method attempts to
detect this and raises an assertion if this is seen.
Args:
txn_postings: A list of postings or directive instances.
Postings affect the balance; other entries do not.
Yields:
Tuples of (entry, postings, change, balance) as described above.
"""
# The running balance.
running_balance = inventory.Inventory()
# Previous date.
prev_date = None
# A list of entries at the current date.
date_entries = []
first = lambda pair: pair[0]
for txn_posting in txn_postings:
# Get the posting if we are dealing with one.
assert not isinstance(txn_posting, Posting)
if isinstance(txn_posting, TxnPosting):
posting = txn_posting.posting
entry = txn_posting.txn
else:
posting = None
entry = txn_posting
if entry.date != prev_date:
assert prev_date is None or entry.date > prev_date, (
"Invalid date order for postings: {} > {}".format(prev_date, entry.date))
prev_date = entry.date
# Flush the dated entries.
for date_entry, date_postings in date_entries:
change = inventory.Inventory()
if date_postings:
# Compute the change due to this transaction and update the
# total balance at the same time.
for date_posting in date_postings:
change.add_position(date_posting)
running_balance.add_position(date_posting)
yield date_entry, date_postings, change, running_balance
date_entries.clear()
assert not date_entries
if posting is not None:
# De-dup multiple postings on the same transaction entry by
# grouping their positions together.
index = index_key(date_entries, entry, first, operator.is_)
if index is None:
date_entries.append((entry, [posting]))
else:
# We are indeed de-duping!
postings = date_entries[index][1]
postings.append(posting)
else:
# This is a regular entry; nothing to add/remove.
date_entries.append((entry, []))
# Flush the final dated entries if any, same as above.
for date_entry, date_postings in date_entries:
change = inventory.Inventory()
if date_postings:
for date_posting in date_postings:
change.add_position(date_posting)
running_balance.add_position(date_posting)
yield date_entry, date_postings, change, running_balance
date_entries.clear()
beancount.core.realization.postings_by_account(entries)
按账户创建明细和余额列表。
此例程将明细和条目按账户名称聚合。生成的列表中,交易指令被替换为对应的明细,而其他指令则作为条目保留。结果是按账户组织的明细或其他条目列表。所有账户引用均被考虑在内。
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def postings_by_account(entries):
"""Create lists of postings and balances by account.
This routine aggregates postings and entries grouping them by account name.
The resulting lists contain postings in-lieu of Transaction directives, but
the other directives are stored as entries. This yields a list of postings
or other entries by account. All references to accounts are taken into
account.
Args:
entries: A list of directives.
Returns:
A mapping of account name to list of TxnPosting instances or
non-Transaction directives, sorted in the same order as the entries.
"""
txn_postings_map = collections.defaultdict(list)
for entry in entries:
if isinstance(entry, Transaction):
# Insert an entry for each of the postings.
for posting in entry.postings:
txn_postings_map[posting.account].append(
TxnPosting(entry, posting))
elif isinstance(entry, (Open, Close, Balance, Note, Document)):
# Append some other entries in the realized list.
txn_postings_map[entry.account].append(entry)
elif isinstance(entry, Pad):
# Insert the pad entry in both realized accounts.
txn_postings_map[entry.account].append(entry)
txn_postings_map[entry.source_account].append(entry)
elif isinstance(entry, Custom):
# Insert custom entry for each account in its values.
for custom_value in entry.values:
if custom_value.dtype == account.TYPE:
txn_postings_map[custom_value.value].append(entry)
return txn_postings_map
beancount.core.realization.realize(entries, min_accounts=None, compute_balance=True)
将条目按账户分组,形成一个“树状”的实现账户结构。RealAccount 实质上是明细列表和每个账户最终余额的容器,也可以是非叶账户(仅用于将账户组织成层次结构)。此结构随后用于生成报表。
每个账户中的明细列表可以是任意类型的条目,但交易条目会被替换为属于该账户的具体明细条目。以下是一个简单图示,总结了这一看似复杂但实际简单的数据结构:
+-------------+ postings +------+ | RealAccount |---------->| Open | +-------------+ +------+ | v +------------+ +-------------+ | TxnPosting |---->| Transaction | +------------+ +-------------+ | \ \\ v \.__ +---------+ +-----+-------->| Posting | | Pad | +---------+ +-----+ | v +---------+ | Balance | +---------+ | v +-------+ | Close | +-------+ | .
| 参数: |
|
|---|
| 返回: |
|
|---|
源代码位于 beancount/core/realization.py
def realize(entries, min_accounts=None, compute_balance=True):
r"""Group entries by account, into a "tree" of realized accounts. RealAccount's
are essentially containers for lists of postings and the final balance of
each account, and may be non-leaf accounts (used strictly for organizing
accounts into a hierarchy). This is then used to issue reports.
The lists of postings in each account my be any of the entry types, except
for Transaction, whereby Transaction entries are replaced by the specific
Posting legs that belong to the account. Here's a simple diagram that
summarizes this seemingly complex, but rather simple data structure:
+-------------+ postings +------+
| RealAccount |---------->| Open |
+-------------+ +------+
|
v
+------------+ +-------------+
| TxnPosting |---->| Transaction |
+------------+ +-------------+
| \ \\\
v `\.__ +---------+
+-----+ `-------->| Posting |
| Pad | +---------+
+-----+
|
v
+---------+
| Balance |
+---------+
|
v
+-------+
| Close |
+-------+
|
.
Args:
entries: A list of directives.
min_accounts: A list of strings, account names to ensure we create,
regardless of whether there are postings on those accounts or not.
This can be used to ensure the root accounts all exist.
compute_balance: A boolean, true if we should compute the final
balance on the realization.
Returns:
The root RealAccount instance.
"""
# Create lists of the entries by account.
txn_postings_map = postings_by_account(entries)
# Create a RealAccount tree and compute the balance for each.
real_root = RealAccount('')
for account_name, txn_postings in txn_postings_map.items():
real_account = get_or_create(real_root, account_name)
real_account.txn_postings = txn_postings
if compute_balance:
real_account.balance = compute_postings_balance(txn_postings)
# Ensure a minimum set of accounts that should exist. This is typically
# called with an instance of AccountTypes to make sure that those exist.
if min_accounts:
for account_name in min_accounts:
get_or_create(real_root, account_name)
return real_root