Skip to content

Python Beancount 3.x Conformance

This document tracks how the Python beancount implementation (v3.x) conforms to the Beancount v3 specification.

Version Information

PropertyValue
SpecificationBeancount v3
ImplementationPython beancount
Tested Version3.2.0
Last Updated2026-02-07

Conformance Legend

SymbolMeaning
Fully conformant
⚠️Partial - missing features or minor deviations
Non-conformant - significant deviation from spec
Spec undefined - awaiting clarification

Summary

AreaStatusNotes
Lexical StructureFully conformant
DirectivesFully conformant
Amounts & NumbersFully conformant
AccountsFully conformant
Transactions⚠️Elision rule deviation
Costs⚠️Merge cost not implemented
Booking⚠️AVERAGE method not implemented
Balance AssertionsFully conformant
TolerancesFully conformant
MetadataFully conformant
PluginsFully conformant

Detailed Conformance

Transactions

Amount Elision

Spec RequirementImplementationStatus
One elided posting per currencyOne elided posting total

Deviation: The specification states that one posting per currency may omit its amount. Python beancount only allows ONE elided posting total per transaction. The single posting expands to cover all currencies.

Error Produced: CategorizationError: You may not have more than one auto-posting per currency

Note: The error message says "per currency" but the actual behavior is "one total".

Tracking: Awaiting spec clarification. See Pending Issues.


Costs

Merge Cost Operator {*}

Spec RequirementImplementationStatus
Merge all lots into average-cost lotNot implemented⚠️

Deviation: The merge cost syntax {*} is parsed but not implemented.

Error Produced: ParserError: Cost merging is not supported yet

Note: This is a known unimplemented feature, not a bug.


Booking Methods

AVERAGE Booking

Spec RequirementImplementationStatus
Average cost basis bookingNot implemented⚠️

Deviation: The AVERAGE booking method is parsed but not implemented.

Error Produced: AmbiguousMatchError: AVERAGE method is not supported

Note: This is a known unimplemented feature, not a bug.


Error Type Mapping

Python beancount maps spec error categories to the following types:

Spec CategoryPython TypeModule
Lexical errorsLexerErrorbeancount.parser.parser
Syntax errorsParserError, ParserSyntaxErrorbeancount.parser.parser
Semantic errorsValidationErrorbeancount.ops.validation
Balance errorsBalanceErrorbeancount.ops.balance
Booking errors (lot)ReductionErrorbeancount.parser.booking_full
Booking errors (elision)CategorizationErrorbeancount.parser.booking_full
Pad errorsPadErrorbeancount.ops.pad
Document errorsDocumentErrorbeancount.ops.documents

Additional Types

TypePurpose
DeprecatedErrorWarnings for deprecated features
AmbiguousMatchErrorBooking ambiguity (also used for unimplemented AVERAGE)

Error Inspection

python
from beancount import loader

entries, errors, options = loader.load_file('ledger.beancount')

for error in errors:
    print(f"Type: {type(error).__name__}")
    print(f"File: {error.source.get('filename')}")
    print(f"Line: {error.source.get('lineno')}")
    print(f"Message: {error.message}")

JSON Output

bash
bean-check --json ledger.beancount

Pending Issues

Issues to be filed to clarify undefined spec items:

TopicStatusSpec Section
Amount elision ruleNeeds upstream clarificationposting.md
Close date semanticsNeeds upstream clarificationvalidation/accounts.md
Close with non-zero balanceNeeds upstream clarificationvalidation/accounts.md
Empty transaction validityNeeds upstream clarificationvalidation/balance.md
Duplicate metadata behaviorNeeds upstream clarificationmetadata.md
Currency length limitsNeeds upstream clarificationvalidation/commodities.md

Python Beancount Behaviors (Pending Spec Clarification)

The following behaviors are observed in Python beancount. They are documented here for reference while spec clarification is pending.

Amount Elision

  • Python allows only ONE auto-posting total per transaction
  • The single posting expands to cover all currencies
  • Error message misleadingly says "per currency"

Close Date Semantics

  • Posting ON the close date is allowed
  • Only postings AFTER the close date produce an error

Close with Non-Zero Balance

  • Closing an account with remaining balance is allowed
  • No error or warning is produced

Empty Transactions

  • Transactions with zero postings are syntactically valid
  • They pass validation (trivially balance)

Duplicate Metadata

  • Produces ParserError
  • First value is retained

Currency Length

  • Minimum 2 characters required
  • No maximum length is enforced
  • The 24-character limit in older docs is not implemented

String Escape Sequences

  • Only \" (escaped quote) and \\ (escaped backslash) are processed
  • Other sequences like \n, \t, \r are kept literally (not converted to newline/tab/etc.)

Booking Methods (case sensitivity)

  • Booking method names MUST be uppercase ("FIFO", not "fifo")
  • Lowercase booking methods produce an error

Other Behaviors

  1. Unused pad produces error - PadError when pad has no effect
  2. operating_currency is additive - Values from included files accumulate
  3. Implicit prices require plugin - No option; requires beancount.plugins.implicit_prices
  4. Leading decimals invalid - .50 is not valid; must use 0.50

Test Results

Last test run: 2026-02-07
Implementation: Python beancount 3.2.0
Tests passed: 155
Tests failed: 0
Tests skipped: 9

Skipped tests:
- account-closed-posting-same-day: Close date semantics UNDEFINED
- metadata-duplicate-key: Duplicate metadata behavior UNDEFINED
- include-cycle-detection: Requires external file setup
- booking-average-cost: AVERAGE method not implemented
- cost-asterisk-merge: Cost merging {*} not implemented
- document-directive: Requires fixture file
- bql-tag-filter: has_tag function not in beanquery
- bql-link-filter: matches_link function not in beanquery
- invalid-transaction-no-postings: Empty transactions UNDEFINED