目录

16 · account_types.py:五大账户类型与正负号约定

核对基线 · 范围 · 依赖

核对基线:beancount 仓库 commit 97472138(2026-08-22)。路径相对仓库根目录,引用格式 文件:起-止行 (名称),行号已逐条核对。 本篇范围beancount/core/account_types.py(195 行)与 beancount/core/account_types_test.py(149 行)。 上游依赖beancount/core/account.pysepsplit、类型别名 Account = str)。运行期依赖标准库 retyping.NamedTupletyping.TYPE_CHECKING 仅用于条件导入 Account 类型别名。 下游使用者:非测试文件 7 个——beancount/parser/options.py(把选项装配成 AccountTypes)、beancount/parser/grammar.py(间接,用五个根名拼校验正则)、beancount/ops/summarize.pybeancount/plugins/check_drained.pybeancount/plugins/sellgains.pybeancount/projects/export.pybeancount/scripts/doctor.py;八个函数经 beancount/api.py:21-28,149-164 对外导出。

1. 模块解决什么问题

复式记账把所有账户归入五个根类别:资产、负债、权益、收入、费用。这个分类是三件事的依据:账户名合法性(解析器只接受以五个根名开头的名字)、余额正负号解释(同一负数在资产与收入账户里含义相反)、一条记录出现在资产负债表还是损益表。

本模块集中定义 AccountTypes、默认根名和分类谓词:一个五字段的具名元组存放五个根名,一组无状态函数在账户名字符串上做判定。五分类结构不止本模块一处——解析器的五个 name_* 选项(beancount/parser/options.py:322-330)及校验正则(beancount/parser/grammar.py:109-127)同样依赖它。模块不持有账本数据,也不校验账户根是否属于当前配置,只做根名提取、分类判断、部分参数类型断言,以及 is_root_account 的语法形状判断。

2. 结构一览

名称 位置 作用
模块 docstring account_types.py:1-9 声称模块使用全局量与副作用;实际代码已无全局可变状态(见第 8 节)
class AccountTypes(NamedTuple) :26-33 五个 str 字段:assetsliabilitiesequityincomeexpenses
DEFAULT_ACCOUNT_TYPES :37-39 AccountTypes("Assets", "Liabilities", "Equity", "Income", "Expenses")
get_account_type :42-55 取账户名第一段;带 Warning 注释说明不校验有效性
get_account_sort_key :58-69 排序键 (类型在元组里的下标, 账户全名)
is_account_type :72-81 用正则判断"以某类型加分隔符开头"
is_root_account :84-96 判断名字形状像不像一个根账户
is_balance_sheet_account :99-118 资产、负债、权益三类
is_income_statement_account :121-136 收入、费用两类
is_equity_account :139-153 仅权益
is_inverted_account :156-177 负债、收入、权益三类
get_account_sign :180-195 资产、费用返回 +1,其余返回 -1

3. 五大根类型的定义与可配置性

3.1 AccountTypes 与默认值

class AccountTypes(NamedTuple):
    """A tuple that contains the names of the root accounts."""

    assets: str  # the name of the prefix for the Asset subaccounts.
    liabilities: str  # the name of the prefix for the Liabilities subaccounts.
    equity: str  # the name of the prefix for the Equity subaccounts.
    income: str  # the name of the prefix for the Income subaccounts.
    expenses: str  # the name of the prefix for the Expenses subaccounts.

account_types.py:26-33。字段顺序(资产、负债、权益、收入、费用)决定 get_account_sort_key 所定义的类型排序——它直接拿 account_types.index(...) 当第一排序键(:69)。基线仓库仅测试并公开导出该函数(api.py:22,150),没有内部报表调用点。

DEFAULT_ACCOUNT_TYPES:37-39 用五个英文名实例化。account_types_test.py:11-13 (test_basics) 只锁定它非 Noneassets == "Assets"

它是不可变具名元组而非全局可变状态:五个名字要么用默认值,要么由调用方从选项现装一个实例传进来。2024-12-22 commit 85950542 把它从 collections.namedtuple 改写成 typing.NamedTuple 类语法:字段类型注解取代了旧注释里的 a str,剩余描述文字移到行尾注释。

3.2 用 name_* 选项覆盖根名

账本可以改这五个名字。beancount/parser/options.py:312-332 定义了对应的五个选项,默认值直接取自本模块:

_TYPES = account_types.DEFAULT_ACCOUNT_TYPES
...
Opt("name_assets", _TYPES.assets, converter=options_validate_root_account),

options.py:218,322。选项组的说明文字写明用途是自定义类别名,例如用 "Revenue" 代替 "Income"、用 "Capital" 代替 "Equity"(options.py:314-319)。options_validate_root_account:121-133)要求值必须通过 account.is_valid_root,即 regex.fullmatch(ACC_COMP_TYPE_RE, value)beancount/core/account.py:37,49-58),所以 "Foo:Bar" 这种带分隔符的值被拒绝,报 Invalid root account namebeancount/parser/options_test.py:67-74)。

反向装配在 options.py:744-763 (get_account_types):按固定顺序从选项字典取五个值构造 AccountTypes。需要类型判定的下游均调用 get_account_types 构造实例(summarize.py:205,224,317,387check_drained.py:49sellgains.py:95export.py:146doctor.py:431)。

3.3 强制五大类型的地方在解析器,不在本模块

names = map(
    options.__getitem__,
    ("name_assets", "name_liabilities", "name_equity", "name_income", "name_expenses"),
)
return regex.compile(
    "(?:{})(?:{}{})+".format("|".join(names), account.sep, account.ACC_COMP_NAME_RE)
)

beancount/parser/grammar.py:109-127 (valid_account_regexp)。解析器把五个根名拼成一个正则,每遇到账户名匹配一次,不中就记一条 Invalid account name 错误(grammar.py:286-290)。"账户属于五大类之一"这条约束由解析层强制,account_types.py 的任何函数都不做这项检查。

正则在选项被设置时重建(grammar.py:434-437),因此选项在账本文件里的位置有语义:options_test.py:87-97,110-132 锁定改名前写旧名合法、改名后写新名合法,而改名前写新名、改名后写旧名都报错。options_test.py:49-64 用一整套法语根名(Actif / Passif / Capital / Revenu / Dépenses)验证五个 open 全部解析成功。

4. 类型判定:只看语法形状

4.1 get_account_type:取第一段,不问是否有效

def get_account_type(account_name: Account) -> str:
    """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.
    """
    assert isinstance(account_name, str), "Account is not a string: {}".format(account_name)
    return account.split(account_name)[0]

account_types.py:42-55。实现是 account_name.split(":")[0]account.py:98-106)。Warning 注释是本模块最核心的边界声明:函数不知道当前配置有哪五个类型,也不接受 AccountTypes 参数。account_types_test.py:32 锁定 get_account_type("Invalid:Toys:Computer") == "Invalid"——不报错,照样返回。

这份宽松分三步定型,均在 2014-05-18:commit 720b9cdf 删掉函数里 assert atype in ACCOUNT_TYPES 的有效性断言,改为只返回第一段并补上 Warning 注释;同日 1c73039b 删掉最后的全局 ACCOUNT_TYPESupdate_valid_account_names() 副作用函数;同日 e9289947 才把函数从 account_name_type 更名为现在的 get_account_type

4.2 is_account_type:前缀匹配而非相等

return bool(re.match("^{}{}".format(account_type, account.sep), account_name))

account_types.py:81。2018-01-29 commit d83bb21a 加入,提交信息与 CHANGES:1180,1187-1188 都把它记为 get_account_type 之上的首选写法。区别在于它把分隔符也算进匹配:is_account_type("Assets", "AssetsUS:RBS:Checking")Falseaccount_types_test.py:68);先取 get_account_type 再比字符串同样得 False,写成 account_name.startswith("Assets") 则会误判。

代价是 account_type 未经转义直接拼进正则:传入含正则元字符的类型名会被当模式解释,例如 is_account_type("A.sets", "Assets:X") 返回 True。默认五个名字不含元字符,而选项值受 ACC_COMP_TYPE_RE 约束(只允许大写字母开头、字母数字和连字符),经选项验证的根名不会触发该问题。

4.3 is_root_account:形状判定,且规则比账户名规则窄

return bool(account_name) and bool(re.match(r"([A-Z][A-Za-z0-9\-]+)$", account_name))

account_types.py:96。docstring 明说 "This function does not verify whether the account root is a valid one, just that it is a root account or not."(:87-88)。account_types_test.py:70-85 的对照表锁定:五个默认根名为 True,任何带冒号的名字为 False_invalid_False,而 InvalidTrue——这条 True 断言在参数表和参数表之后重复出现一次。

这条正则与 account.py 里账户名组件的正则并不等价:ACC_COMP_TYPE_RE = r"[\p{Lu}][\p{L}\p{Nd}\-]*"account.py:37)用 Unicode 属性且尾部是 *,这里是 ASCII 字符类且尾部是 +。后果有二:单字母根名 "A"account.is_valid_root 下合法、在 is_root_account 下为 Falseoptions_test.py:55 实际用过的合法配置值 "Dépenses" 同样为 False

该函数在 v3 里没有调用点,api.py:21-28 的八个导出也不含它。现在的形态定型于 2020-11-15 commit 6baaf51f:此前签名带可选 account_types 参数,给了就用成员判定、不给才用正则,C++ 移植时删除该参数只留正则分支;同日 86ee760f 把测试里 _invalid_ 的期望从 True 改成 False 并补上 Invalid → True

5. 符号约定

5.1 get_account_sign

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

account_types.py:191-195。资产与费用 +1,负债、权益、收入 -1account_types_test.py:132-145 (test_get_account_sign) 的五行对照表逐类锁定这个映射。

这个符号对应"正常余额方向"的约定,不是解析器强制的规则:解析器原样保留 posting 符号,不按账户类型改写(grammar.py:461-475 原样构造 Amount:948 原样放入 Postingsummarize_test.py:45-48,72-74 收录了合法的正数写法 Income:Salary 10000 USD)。按惯例收入记为负数,借贷平衡表现为一笔交易所有 posting 权重和为零。get_account_sign 把这套惯例方向换算成正向显示的乘数,但在当前基线仓库内部没有调用点(git grep get_account_sign 只命中 api.py、本模块和测试文件),doctor.py:457-464 只对汇总后的 net_income 整体取负打印,不逐账户调用该函数(见第 6 节)。

它是本模块唯一 account_types 参数可选的函数(:181),默认值自 2014-11-02 commit a3a91792 引入时就在,提交信息给出的动机是给作者的 iracontribs 插件用。CHANGES:884-887 记 2018-04-29 SQL shell 新增多态 POSSIGN(_, account)95f7f3c6 的 diff 显示它落地为四个类型重载(DecimalAmountPositionInventory),均调用 get_account_sign 决定取负——属于 v2 SQL 查询函数,与当前基线仓库内部报表无关。查询模块 2022-02-06 commit 3db1836a 整体移除后,get_account_sign 在仓库内部无调用点,只留在 api.py 公开面。

5.2 is_inverted_account

return account_type in (
    account_types.liabilities,
    account_types.income,
    account_types.equity,
)

account_types.py:173-177。docstring 的定义是"符号与外部报表期望的相反,外部报表期望全是正号"(:159-160)。2021-01-31 commit 14808cfb 加入,提交正文原话为 "I'm starting to invert some of my outputs for options reporting."——作者开始反转其期权报告(options reporting)中的部分输出。

它挑出的三类恰好就是 get_account_sign 返回 -1 的三类,两者对五大类的判断完全一致;account_types_test.py:117-130test_get_account_sign 用的是同一组账户名。差别只在五大类之外:对 "Invalid:Foo"get_account_signelse 分支返回 -1is_inverted_account 的成员判定返回 False(详见第 8 节)。

它与 get_account_sign 一样,v3 内部零调用点,只经 api.py:28,164 导出。

6. 两张报表的划分与账户排序

is_balance_sheet_account:99-118)覆盖资产、负债、权益;is_income_statement_account:121-136)覆盖收入、费用;is_equity_account:139-153)只比较权益一项。三者实现同构:两条 assert isinstance 检查账户名是字符串、account_typesAccountTypes 实例,再取 get_account_type 与成员比较。account_types_test.py:95-115 (test_is_account_categories) 用一张表同时验证前两个函数,第二个断言写成 not expected,把"非此即彼"也锁进了测试。

划分用于期末结转。beancount/ops/summarize.py 的三个函数——clear:164-198)、clamp:229-296)、cap:334-373)——各自构造谓词 is_income_statement_account(account, account_types)(依次在 :191-193:278-280:363-365),交给 transfer_balances 把损益表账户的余额转到某个权益账户,使资产负债表配平。open:44-108)不自行构造谓词,在 :103 调用 clear 完成同一件事。转入的目标账户名同样拼在权益根名下:options.py:766-785 (get_previous_accounts):788-802 (get_current_accounts)account.join(equity, ...)Opening-BalancesEarnings:PreviousEarnings:Current 等叶名接到 name_equity 之后。

另外两个消费者:check_drained.py:49-52is_balance_sheet_account 限定"关闭时须清零"的检查范围;doctor.py:457-464 遍历实现树累加损益表账户余额,末行打印 "Net Income: {}".format(-net_income)——第 5.1 节所说约定的直接体现:内部累加原值(收入为负),对外打印整体取负。

排序键由 get_account_sort_key 给出:

return (account_types.index(get_account_type(account_name)), account_name)

account_types.py:69。第一键是类型在 AccountTypes 元组里的下标,第二键是账户全名。account_types_test.py:34-61functools.partial 绑定类型元组后排序八个账户,期望顺序为资产、负债、权益、收入、费用,同类内按名字字母序。

这里曾有一个模块级字典 TYPES_ORDER,由 update_valid_account_names() 在导入时和每次解析前重设,2014-05-18 起改用元组自带的 .index()。线性查找与字典查找的差别可忽略,换来的是无全局状态。

7. 设计决策与理由

决策 理由 证据
五个根名装进不可变具名元组,而非模块全局量 全局量意味着解析不同账本要靠副作用切换状态;元组按账本各持一份,函数保持纯粹 account_types.py:26-39e44f84e61c73039b(均 2014-05-18)
字段顺序决定 get_account_sort_key 的类型排序 直接用 .index(),不需要另建顺序表;该函数仅测试覆盖并经 api.py 导出,无内部报表调用点 :69account_types_test.py:34-61git grep get_account_sort_key 仅命中 api.py/定义/测试
根名可由 name_* 选项覆盖 支持非英语账本,选项组说明给出 Revenue / Capital 的替换例子 options.py:312-331,744-763options_test.py:47-64
get_account_typeis_root_account 不校验类型是否在配置里 解析器负责账户合法性校验 account_types.py:45-46,87-88grammar.py:109-127,286-291
符号乘数按类型统一定义,而非逐账户配置 正常余额方向约定资产、费用以正表示,负债、权益、收入以负表示;get_account_sign 只提供这套约定到显示方向的换算乘数,不改写 posting 本身 account_types.py:195account_types_test.py:132-145
内部一律存带符号原值 存原值才能让一笔交易的权重直接求和判平;get_account_sign 提供转正乘数,但基线仓库内部不调用它,doctor.py 只对汇总后的 net_income 整体取负 doctor.py:457-464;v2 曾提供显式 POSSIGNCHANGES:884-88795f7f3c6
get_account_signaccount_types 参数可选 提交信息给出的动机是给 iracontribs 插件用;参数从首次提交起即为可选,提交未进一步说明设计理由 account_types.py:181,191-192a3a91792(2014-11-02)
is_account_type 把分隔符纳入匹配 避免 startswithAssetsUS:... 误判为 Assets 类 :81account_types_test.py:68CHANGES:1187-1188
划分函数用 assert 检查参数类型 提供提前且更针对性的类型失败;python -O 剥离断言后,字典等无同名属性的对象会在 .assets.income 等属性访问处失败 :109-112,131-134,148-151,168-171

8. 行为细节与边界

现象 后果 证据
get_account_type 对任何字符串都返回第一段 "Invalid:Foo" 返回 "Invalid" 而不报错,类型有效性全靠解析层 account_types.py:45-46,55account_types_test.py:32
get_account_type("") 返回 "" "".split(":")[""],空串走到 get_account_sign 会得到 -1 account.py:98-106account_types.py:195
不带冒号的名字也能取到"类型" get_account_type("Assets") 返回 "Assets"is_balance_sheet_account("Assets", ...)True :55,113-118
get_account_sign 对未知类型返回 -1 五大类之外的名字被当作反向账户;没有"未知"这个返回值。省略第二参数时固定用英文默认根名,自定义根名账本若忘记传当前 AccountTypes(如 Actif:Cash)也会被当未知类型返回 -1 :191-195
is_balance_sheet_accountis_income_statement_account 对未知根名均返回 False 测试里两者结果"互补"(not expected)只覆盖五个合法默认根名,未知字符串上两者同时为 False,不构成互补 :113-118,135-136account_types_test.py:95-115
is_inverted_account 对未知类型返回 False get_account_sign 对同一个 "Invalid:Foo" 给出相反结论(-1False :173-177,195
is_account_type 不转义 account_type,也不做 isinstance 断言 类型名里的正则元字符按模式解释,is_account_type("A.sets", "Assets:X")True;且只检查"类型名加冒号"前缀,不校验冒号后的账户组件,is_account_type("Assets", "Assets:") 同样为 True :72-81
is_root_account 的正则要求至少两个字符 单字母根名 "A" 返回 False,而 account.is_valid_root("A")True :96account.py:37,58
is_root_account 只认 ASCII 字母,且 $ 可在末尾换行符前匹配 "Dépenses" 是合法的 name_expenses 取值却判为非根账户;"Assets\n"re.match$ 语义返回 True :96options_test.py:55
is_root_account 在 v3 无调用点,也未导出 只有测试引用它,api.py 的八个导出里没有它 api.py:21-28
get_account_signis_inverted_accountis_equity_account 在 v3 内部无调用点 三者只经 api.py 对外提供;get_account_sign 的最后一个内部消费者随查询模块于 2022-02-06 移除 api.py:21,26,283db1836a
get_account_sort_key 对未知类型抛异常,且不校验 account_types 类型 tuple.index 找不到成员时抛 ValueError,没有兜底下标;与 get_account_sign 一样不做 isinstance(account_types, AccountTypes) 断言,四个分类谓词则会断言 :58-69,99-195
AccountTypesstr 注解不做运行期校验,也不保证五个根名互异 直接构造可放入非字符串或重复根名;重复值会让 tuple.index() 总取第一次出现的位置,可能使分类集合意外重叠 :26-39,69
划分函数用 assert 做类型检查 python -O 下断言被剥离,传入非 AccountTypes 的对象会在属性访问处才失败 :109-112,131-134,148-151,168-171
【文档漂移】模块 docstring 说使用 globals 与 side-effects 全局量与 update_valid_account_names() 已于 2014-05-18 删除,模块现在只有常量;2025-12-25 commit 01adfb37glboalsglobalsside-effectside-effectsMaybe we changeMaybe we will change,未纠正全局状态已不存在这一过时描述 :1-91c73039b01adfb37
【文档漂移】get_account_sort_key 的 docstring 缺参数(历史) account_name 一项到 2026-01-01 commit 448580ff 才补进 Args :61-68448580ff

9. 测试锁定了什么

account_types_test.py 共 8 个测试,一个类 TestAccountTypes:10):

测试 行号 锁定的行为
test_basics 11-13 DEFAULT_ACCOUNT_TYPES 存在且 assets == "Assets"
test_get_account_type 15-32 五类账户各取到正确根名;"Invalid:Toys:Computer" 返回 "Invalid" 而不报错
test_get_account_sort_key 34-61 八个账户排序为资产、负债、权益、收入、费用,同类内按名字升序
test_is_account_type 63-68 类型匹配、类型不匹配、缺分隔符("AssetsUS:RBS:Checking")三种情形
test_is_root_account 70-85 十个名字的形状判定;InvalidTrue_invalid_False
test_is_account_categories 95-115 五类账户的资产负债表 / 损益表归属,两个函数结果互补
test_is_inverted_account 117-130 五类账户的反号归属:负债、权益、收入为 True
test_get_account_sign 132-145 五类账户的符号:资产 +1、负债 -1、权益 -1、收入 -1、费用 +1

测试文件里还有一个类属性 OPTIONS:87-93),字面量列出五个 name_* 选项及默认值,无任何测试引用它。自定义根名的端到端行为由 beancount/parser/options_test.py:47-132 (TestAccountTypeOptions) 覆盖。

没有测试覆盖的行为:is_equity_account 完全无测试;所有函数的 assert 分支;get_account_sort_key 遇未知类型抛 ValueErrorget_account_sign 省略第二参数走默认值的路径(测试总是显式传 DEFAULT_ACCOUNT_TYPES);用非默认 AccountTypes 实例调用判定函数;空字符串账户名;is_account_type 的正则元字符注入与空叶名(如 "Assets:");未知类型在两个报表谓词、is_inverted_accountget_account_sign 上的结果差异;is_root_account 的单字母、Unicode、末尾换行行为;AccountTypes 字段重复或非字符串的情形。

10. 演变史

日期 提交 / 记录 变化
2014-02-08 4d213024 创建 account_types.pyAccountTypes 及现行模块 docstring 的初版(当时路径为 src/python/beancount/core/
2014-05-03 911fdd76 把账户类型相关函数从 account.py 移入 account_types.py,使 account.py 不再依赖 account_types;迁移后的 account_types.py 反而依赖 account.py 的分隔符等基础能力
2014-05-18 e44f84e6720b9cdf 删除模块级 TYPES_ORDER 字典,排序键改用 account_types.index(...);随后删除 account_name_type()assert atype in ACCOUNT_TYPES 的有效性断言,改为只返回第一段并加 Warning 注释
2014-05-18 59a92b671c73039be9289947 三个分类谓词的第二参数从 options 字典改为显式 AccountTypes 实例;删除全局 ACCOUNT_TYPESupdate_valid_account_names() 副作用;account_name_type 更名为 get_account_type
2014-07-05 c291509f 账户名语法校验函数从 account_types.py(原 is_valid_account_name)移到 account.py(现 is_valid),用于把 parser.documents.walk_accounts() 上移到 core 层
2014-11-02 a3a91792 新增 get_account_sign()account_types 参数即刻设为可选
2014-12-06 8c1b9d28 排序接口从返回闭包的 get_account_sort_function 重构为直接返回排序键的 get_account_sort_key;查询层新增 ACCOUNT_SORTKEY,使查询余额输出按账户类型排序
2017-04-30 859f341e 仓库布局从 src/python/beancount/... 迁到 beancount/...;此前提交引用的路径都带旧前缀
2018-01-29 d83bb21aCHANGES:1187-1188 新增 is_account_type()CHANGES 记为 get_account_type() 之上的首选写法
2018-04-29 95f7f3c6CHANGES:884-887 CHANGES 记 SQL shell 新增多态 POSSIGN(_, account)query_env.py 的 diff 显示它落地为四个类型重载,均调用 get_account_sign
2020-11-15 49a8b25cae1d102c8cd2d031d590b26f8422c90e 逐个函数移植到 C++ 扩展;c312f227 同日补类型注解
2020-11-15 6baaf51f86ee760f is_root_account 删除 account_types 参数只留正则;测试里 _invalid_ 期望改为 False,补 Invalid → True
2021-01-31 14808cfb 新增 is_inverted_account,提交正文称作者开始反转其期权报告(options reporting)中的部分输出
2022-02-06 3db1836a 移除查询模块,get_account_sign 失去最后一个内部调用点
2022-07-24 b5d2b15e 公开 API 汇总到 api.py,当时导出本模块 7 个函数(不含 get_account_sort_key
2024-06-16 27c78c8b 移除 C++ 代码与 Bazel 构建,回到纯 Python 实现
2024-06-30 5539c79b 补入遗漏的 get_account_sort_keyapi.py 导出的本模块函数增至现行的 8 个
2024-12-22 85950542 AccountTypescollections.namedtuple 改为 typing.NamedTuple 类语法
2024-12-22 5871f962 测试里删除 try: from beancount.core import account_types / except ImportError: from beancount.ccore import _core 的双路径导入
2025-12-25 01adfb37 修订 docstring 拼写;同时把 is_account_type 那段误抄自 get_account_type 的说明改写为正确描述
2026-01-01 448580ff 按 Google 风格补全 Args/Returns,get_account_sort_key 补上 account_name 一项

11. 与其他模块的关系

12. 参考索引

beancount/core/account_types.py:1-9 模块 docstring;11-23 导入与 TYPE_CHECKING;26-33 AccountTypes;37-39 DEFAULT_ACCOUNT_TYPES;42-55 get_account_type(45-46 Warning);58-69 get_account_sort_key;72-81 is_account_type;84-96 is_root_account(87-88 不校验有效性的声明);99-118 is_balance_sheet_account;121-136 is_income_statement_account;139-153 is_equity_account;156-177 is_inverted_account(159-160 反号定义);180-195 get_account_sign

beancount/core/account_types_test.py:11-13、15-32、34-61、63-68、70-85、87-93(未被引用的 OPTIONS)、95-115、117-130、132-145。

其它beancount/core/account.py:25,29,37,41,49-58,98-108beancount/core/realization.py:211,250,269-273beancount/core/realization_test.py:273-278beancount/parser/options.py:121-133,218,312-332,744-763,766-785,788-802beancount/parser/options_test.py:47-132beancount/parser/grammar.py:109-127,286-290,434-437beancount/ops/summarize.py:28,44-108,164-198,191-193,229-296,278-280,334-373,363-365beancount/plugins/check_drained.py:49-52beancount/plugins/sellgains.py:95-97,125-127beancount/projects/export.py:146-151beancount/scripts/doctor.py:431,457-464beancount/api.py:21-28,80,149-164CHANGES:884-887,1180,1187-1188

commit4d213024(2014-02-08)、911fdd76(2014-05-03)、e44f84e6/720b9cdf/59a92b67/1c73039b/e9289947(均 2014-05-18)、c291509f(2014-07-05)、a3a91792(2014-11-02)、8c1b9d28(2014-12-06)、859f341e(2017-04-30)、d83bb21a(2018-01-29)、95f7f3c6(2018-04-29)、49a8b25c/ae1d102c/8cd2d031/d590b26f/8422c90e/6baaf51f/86ee760f/c312f227(均 2020-11-15)、14808cfb(2021-01-31)、3db1836a(2022-02-06)、b5d2b15e(2022-07-24)、27c78c8b(2024-06-16)、5539c79b(2024-06-30)、85950542(2024-12-22)、5871f962(2024-12-22)、129e090e(2025-03-17)、01adfb37(2025-12-25)、448580ff(2026-01-01)。