From ad5412a78f6f8378625d83f29dcc30dd8144355b Mon Sep 17 00:00:00 2001 From: Jakob Schnitzer Date: Mon, 16 Dec 2024 18:54:29 +0100 Subject: [PATCH] try out more complete Beancount types --- src/fava/beans/abc.py | 59 ++------- src/fava/beans/create.py | 51 +++++--- src/fava/beans/load.py | 6 +- src/fava/beans/str.py | 34 ++++-- src/fava/core/__init__.py | 8 +- src/fava/core/charts.py | 12 +- src/fava/core/filters.py | 6 +- src/fava/core/number.py | 2 + src/fava/core/query_shell.py | 5 +- src/fava/core/tree.py | 4 +- src/fava/serialisation.py | 5 +- stubs/beancount/__init__.pyi | 1 - stubs/beancount/core/__init__.pyi | 0 stubs/beancount/core/account.pyi | 3 - stubs/beancount/core/amount.pyi | 14 --- stubs/beancount/core/data.pyi | 146 ----------------------- stubs/beancount/core/display_context.pyi | 12 -- stubs/beancount/core/inventory.pyi | 11 -- stubs/beancount/core/number.pyi | 1 - stubs/beancount/core/position.pyi | 23 ---- stubs/beancount/loader.pyi | 20 ---- stubs/beancount/parser/__init__.pyi | 0 stubs/beancount/parser/options.pyi | 3 - stubs/beancount/parser/parser.pyi | 3 - stubs/beancount/utils/__init__.pyi | 0 stubs/beancount/utils/encryption.pyi | 1 - stubs/beanquery/__init__.pyi | 4 +- tests/test_core_ingest.py | 5 +- tests/test_util_excel.py | 5 +- 29 files changed, 102 insertions(+), 342 deletions(-) delete mode 100644 stubs/beancount/__init__.pyi delete mode 100644 stubs/beancount/core/__init__.pyi delete mode 100644 stubs/beancount/core/account.pyi delete mode 100644 stubs/beancount/core/amount.pyi delete mode 100644 stubs/beancount/core/data.pyi delete mode 100644 stubs/beancount/core/display_context.pyi delete mode 100644 stubs/beancount/core/inventory.pyi delete mode 100644 stubs/beancount/core/number.pyi delete mode 100644 stubs/beancount/core/position.pyi delete mode 100644 stubs/beancount/loader.pyi delete mode 100644 stubs/beancount/parser/__init__.pyi delete mode 100644 stubs/beancount/parser/options.pyi delete mode 100644 stubs/beancount/parser/parser.pyi delete mode 100644 stubs/beancount/utils/__init__.pyi delete mode 100644 stubs/beancount/utils/encryption.pyi diff --git a/src/fava/beans/abc.py b/src/fava/beans/abc.py index 3832b644f..d46054e44 100644 --- a/src/fava/beans/abc.py +++ b/src/fava/beans/abc.py @@ -7,7 +7,6 @@ from typing import Any from typing import TYPE_CHECKING -from beancount.core import amount from beancount.core import data from beancount.core import position @@ -28,61 +27,17 @@ Account = str -class Amount(ABC): - """An amount in some currency.""" - - @property - @abstractmethod - def number(self) -> Decimal: - """Number of units in the amount.""" - - @property - @abstractmethod - def currency(self) -> str: - """Currency of the amount.""" - - -Amount.register(amount.Amount) - - -class Cost(ABC): - """A cost (basically an amount with date and label).""" - - @property - @abstractmethod - def number(self) -> Decimal: - """Number of units in the cost.""" - - @property - @abstractmethod - def currency(self) -> str: - """Currency of the cost.""" - - @property - @abstractmethod - def date(self) -> datetime.date: - """Date of the cost.""" - - @property - @abstractmethod - def label(self) -> str | None: - """Label of the cost.""" - - -Cost.register(position.Cost) - - class Position(ABC): """A Beancount position - just cost and units.""" @property @abstractmethod - def units(self) -> Amount: + def units(self) -> protocols.Amount: """Units of the posting.""" @property @abstractmethod - def cost(self) -> Cost | None: + def cost(self) -> protocols.Cost | None: """Units of the position.""" @@ -99,17 +54,17 @@ def account(self) -> str: @property @abstractmethod - def units(self) -> Amount: + def units(self) -> protocols.Amount: """Units of the posting.""" @property @abstractmethod - def cost(self) -> Cost | None: + def cost(self) -> protocols.Cost | None: """Units of the posting.""" @property @abstractmethod - def price(self) -> Amount | None: + def price(self) -> protocols.Amount | None: """Price of the posting.""" @property @@ -184,7 +139,7 @@ def account(self) -> str: @property @abstractmethod - def diff_amount(self) -> Amount | None: + def diff_amount(self) -> protocols.Amount | None: """Account of the directive.""" @@ -310,7 +265,7 @@ def currency(self) -> str: @property @abstractmethod - def amount(self) -> Amount: + def amount(self) -> protocols.Amount: """Price amount.""" diff --git a/src/fava/beans/create.py b/src/fava/beans/create.py index 8821ce4e2..2c8848969 100644 --- a/src/fava/beans/create.py +++ b/src/fava/beans/create.py @@ -6,15 +6,12 @@ from typing import TYPE_CHECKING from beancount.core import data -from beancount.core.amount import ( # type: ignore[attr-defined] - A as BEANCOUNT_A, -) +from beancount.core.amount import A as BEANCOUNT_A from beancount.core.amount import Amount as BeancountAmount from beancount.core.position import Cost as BeancountCost from beancount.core.position import Position as BeancountPosition from fava.beans import BEANCOUNT_V3 -from fava.beans.abc import Amount if TYPE_CHECKING: # pragma: no cover import datetime @@ -22,7 +19,6 @@ from fava.beans.abc import Balance from fava.beans.abc import Close - from fava.beans.abc import Cost from fava.beans.abc import Document from fava.beans.abc import Meta from fava.beans.abc import Note @@ -31,6 +27,8 @@ from fava.beans.abc import Posting from fava.beans.abc import Transaction from fava.beans.flags import Flag + from fava.beans.protocols import Amount + from fava.beans.protocols import Cost @overload @@ -47,10 +45,10 @@ def amount(amt: Decimal, currency: str) -> Amount: ... # pragma: no cover def amount(amt: Amount | Decimal | str, currency: str | None = None) -> Amount: """Amount from a string or tuple.""" - if isinstance(amt, Amount): - return amt if isinstance(amt, str): - return BEANCOUNT_A(amt) # type: ignore[no-any-return] + return BEANCOUNT_A(amt) # type: ignore[return-value] + if hasattr(amt, "number") and hasattr(amt, "currency"): + return amt if not isinstance(currency, str): # pragma: no cover raise TypeError return BeancountAmount(amt, currency) # type: ignore[return-value] @@ -66,7 +64,7 @@ def cost( label: str | None = None, ) -> Cost: """Create a Cost.""" - return BeancountCost(number, currency, date, label) # type: ignore[return-value] + return BeancountCost(number, currency, date, label) def position(units: Amount, cost: Cost | None) -> Position: @@ -94,7 +92,7 @@ def posting( cost, # type: ignore[arg-type] price, # type: ignore[arg-type] flag, - meta, + dict(meta) if meta is not None else None, ) @@ -113,7 +111,7 @@ def transaction( ) -> Transaction: """Create a Beancount Transaction.""" return data.Transaction( # type: ignore[return-value] - meta, + dict(meta), date, flag, payee, @@ -134,7 +132,7 @@ def balance( ) -> Balance: """Create a Beancount Balance.""" return data.Balance( # type: ignore[return-value] - meta, + dict(meta), date, account, _amount(amount), # type: ignore[arg-type] @@ -150,7 +148,9 @@ def close( ) -> Close: """Create a Beancount Open.""" return data.Close( # type: ignore[return-value] - meta, date, account + dict(meta), + date, + account, ) @@ -164,7 +164,12 @@ def document( ) -> Document: """Create a Beancount Document.""" return data.Document( # type: ignore[return-value] - meta, date, account, filename, tags, links + dict(meta), + date, + account, + filename, + tags, + links, ) @@ -179,10 +184,18 @@ def note( """Create a Beancount Note.""" if not BEANCOUNT_V3: # pragma: no cover return data.Note( # type: ignore[call-arg,return-value] - meta, date, account, comment + dict(meta), + date, + account, + comment, ) return data.Note( # type: ignore[return-value] - meta, date, account, comment, tags, links + dict(meta), + date, + account, + comment, + tags, + links, ) @@ -195,5 +208,9 @@ def open( # noqa: A001 ) -> Open: """Create a Beancount Open.""" return data.Open( # type: ignore[return-value] - meta, date, account, currencies, booking + dict(meta), + date, + account, + currencies, + booking, ) diff --git a/src/fava/beans/load.py b/src/fava/beans/load.py index 01b23d7e4..28da8b02b 100644 --- a/src/fava/beans/load.py +++ b/src/fava/beans/load.py @@ -12,7 +12,7 @@ def load_string(value: str) -> LoaderResult: """Load a Beancoun string.""" - return loader.load_string(value) + return loader.load_string(value) # type: ignore[return-value] def load_uncached( @@ -22,9 +22,9 @@ def load_uncached( ) -> LoaderResult: """Load a Beancount file.""" if is_encrypted: # pragma: no cover - return loader.load_file(beancount_file_path) + return loader.load_file(beancount_file_path) # type: ignore[return-value] - return loader._load( # type: ignore[attr-defined,no-any-return] # noqa: SLF001 + return loader._load( # type: ignore[return-value] # noqa: SLF001 [(beancount_file_path, True)], None, None, diff --git a/src/fava/beans/str.py b/src/fava/beans/str.py index 926e606bb..0bdca1a08 100644 --- a/src/fava/beans/str.py +++ b/src/fava/beans/str.py @@ -6,11 +6,12 @@ from functools import singledispatch from typing import TYPE_CHECKING +from beancount.core import amount +from beancount.core import data +from beancount.core import position from beancount.core.position import CostSpec from beancount.parser.printer import format_entry -from fava.beans.abc import Amount -from fava.beans.abc import Cost from fava.beans.abc import Directive from fava.beans.abc import Position from fava.beans.helpers import replace @@ -22,22 +23,36 @@ @singledispatch def to_string( - obj: Amount | Cost | CostSpec | Directive | Position, + obj: amount.Amount + | protocols.Amount + | protocols.Cost + | CostSpec + | Directive + | Position, _currency_column: int | None = None, _indent: int | None = None, ) -> str: """Convert to a string.""" + number = getattr(obj, "number", None) + currency = getattr(obj, "currency", None) + if isinstance(number, Decimal) and isinstance(currency, str): + # The Amount and Cost protocols are ambigous, so handle this here + # instead of having this be dispatched + if hasattr(obj, "date"): # pragma: no cover + cost_to_string(obj) # type: ignore[arg-type] + return f"{number} {currency}" msg = f"Unsupported object of type {type(obj)}" raise TypeError(msg) -@to_string.register(Amount) -def _(obj: Amount) -> str: +@to_string.register(amount.Amount) +def amount_to_string(obj: amount.Amount | protocols.Amount) -> str: + """Convert an amount to a string.""" return f"{obj.number} {obj.currency}" -@to_string.register(Cost) -def cost_to_string(cost: Cost | protocols.Cost) -> str: +@to_string.register(position.Cost) +def cost_to_string(cost: protocols.Cost | position.Cost) -> str: """Convert a cost to a string.""" res = f"{cost.number} {cost.currency}, {cost.date.isoformat()}" return f'{res}, "{cost.label}"' if cost.label else res @@ -69,7 +84,7 @@ def _(cost: CostSpec) -> str: @to_string.register(Position) def _(obj: Position) -> str: - units_str = to_string(obj.units) + units_str = amount_to_string(obj.units) if obj.cost is None: return units_str cost_str = to_string(obj.cost) @@ -86,7 +101,8 @@ def _format_entry( key: entry.meta[key] for key in entry.meta if not key.startswith("_") } entry = replace(entry, meta=meta) - printed_entry = format_entry(entry, prefix=" " * indent) # type: ignore[arg-type] + assert isinstance(entry, data.ALL_DIRECTIVES) # noqa: S101 + printed_entry = format_entry(entry, prefix=" " * indent) string = align(printed_entry, currency_column) string = string.replace("", "") return "\n".join(line.rstrip() for line in string.split("\n")) diff --git a/src/fava/core/__init__.py b/src/fava/core/__init__.py index 0869053d5..a00c38047 100644 --- a/src/fava/core/__init__.py +++ b/src/fava/core/__init__.py @@ -443,7 +443,7 @@ def interval_balances( interval_balances = [ Tree( iter_entry_dates( - filtered.entries, + filtered.entries, # type: ignore[arg-type] date.min if accumulate else date_range.begin, date_range.end, ), @@ -558,10 +558,10 @@ def context( for posting in entry_.postings: balance = balances.get(posting.account, None) if balance is not None: - balance.add_position(posting) + balance.add_position(posting) # type: ignore[arg-type] def visualise(inv: Inventory) -> Sequence[str]: - return [to_string(pos) for pos in sorted(inv)] + return [to_string(pos) for pos in sorted(iter(inv))] before = {acc: visualise(inv) for acc, inv in balances.items()} @@ -569,7 +569,7 @@ def visualise(inv: Inventory) -> Sequence[str]: return entry, before, None, source_slice, sha256sum for posting in entry.postings: - balances[posting.account].add_position(posting) + balances[posting.account].add_position(posting) # type: ignore[arg-type] after = {acc: visualise(inv) for acc, inv in balances.items()} return entry, before, after, source_slice, sha256sum diff --git a/src/fava/core/charts.py b/src/fava/core/charts.py index a60c26ce1..297bbaa0b 100644 --- a/src/fava/core/charts.py +++ b/src/fava/core/charts.py @@ -13,6 +13,7 @@ from typing import Any from typing import TYPE_CHECKING +from beancount.core.amount import Amount from beancount.core.data import Booking from beancount.core.data import iter_entry_dates from beancount.core.number import MISSING @@ -20,7 +21,6 @@ from simplejson import dumps as simplejson_dumps from simplejson import loads as simplejson_loads -from fava.beans.abc import Amount from fava.beans.abc import Position from fava.beans.abc import Transaction from fava.beans.account import account_tester @@ -117,7 +117,13 @@ def hierarchy( ) -> SerialisedTreeNode: """Render an account tree.""" if begin is not None and end is not None: - tree = Tree(iter_entry_dates(filtered.entries, begin, end)) + tree = Tree( + iter_entry_dates( + filtered.entries, # type: ignore[arg-type] + begin, + end, + ) + ) else: tree = filtered.root_tree return tree.get(account_name).serialise( @@ -156,7 +162,7 @@ def interval_totals( for date_range in intervals: inventory = CounterInventory() entries = iter_entry_dates( - filtered.entries, + filtered.entries, # type: ignore[arg-type] date_range.begin, date_range.end, ) diff --git a/src/fava/core/filters.py b/src/fava/core/filters.py index 6263b0e67..7cb2231d2 100644 --- a/src/fava/core/filters.py +++ b/src/fava/core/filters.py @@ -409,13 +409,13 @@ def __init__( self.date_range = DateRange(begin, end) def apply(self, entries: Sequence[Directive]) -> Sequence[Directive]: - entries, _ = clamp_opt( - entries, + clamped_entries, _ = clamp_opt( + entries, # type: ignore[arg-type] self.date_range.begin, self.date_range.end, self._options, ) - return entries + return clamped_entries # type: ignore[return-value] LEXER = FilterSyntaxLexer() diff --git a/src/fava/core/number.py b/src/fava/core/number.py index 0d34fb7b4..0b44ab7a5 100644 --- a/src/fava/core/number.py +++ b/src/fava/core/number.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING from babel.core import Locale +from beancount.core.display_context import DisplayContext from beancount.core.display_context import Precision from fava.core.module_base import FavaModule @@ -74,6 +75,7 @@ def load_file(self) -> None: # noqa: D102 locale = Locale.parse(locale_option) dcontext = self.ledger.options["dcontext"] + assert isinstance(dcontext, DisplayContext) # noqa: S101 precisions: dict[str, int] = {} for currency, ccontext in dcontext.ccontexts.items(): prec = ccontext.get_fractional(Precision.MOST_COMMON) diff --git a/src/fava/core/query_shell.py b/src/fava/core/query_shell.py index 107f533d9..8a943bfee 100644 --- a/src/fava/core/query_shell.py +++ b/src/fava/core/query_shell.py @@ -7,6 +7,7 @@ import textwrap from typing import TYPE_CHECKING +from beancount.core.display_context import DisplayContext from beanquery import CompilationError from beanquery import connect from beanquery import Cursor @@ -227,7 +228,9 @@ def query_to_file( rrows = res.fetchall() rtypes = res.description - dformat = self.ledger.options["dcontext"].build() # type: ignore[attr-defined] + dcontext = self.ledger.options["dcontext"] + assert isinstance(dcontext, DisplayContext) # noqa: S101 + dformat = dcontext.build() types, rows = numberify_results(rtypes, rrows, dformat) if result_format == "csv": diff --git a/src/fava/core/tree.py b/src/fava/core/tree.py index e1690c68d..3ca6cd990 100644 --- a/src/fava/core/tree.py +++ b/src/fava/core/tree.py @@ -20,6 +20,8 @@ from collections.abc import Iterable from collections.abc import Sequence + from beancount.core import data + from fava.beans.abc import Directive from fava.beans.prices import FavaPriceMap from fava.beans.types import BeancountOptions @@ -125,7 +127,7 @@ class Tree(dict[str, TreeNode]): def __init__( self, - entries: Iterable[Directive] | None = None, + entries: Iterable[Directive | data.Directive] | None = None, create_accounts: list[str] | None = None, ) -> None: super().__init__(self) diff --git a/src/fava/serialisation.py b/src/fava/serialisation.py index 461dc4743..f5d617f7a 100644 --- a/src/fava/serialisation.py +++ b/src/fava/serialisation.py @@ -19,7 +19,6 @@ from beancount.parser.parser import parse_string from fava.beans import create -from fava.beans.abc import Amount from fava.beans.abc import Balance from fava.beans.abc import Custom from fava.beans.abc import Directive @@ -83,9 +82,7 @@ def _(entry: Balance) -> Any: @serialise.register(Posting) def _(posting: Posting) -> Any: """Serialise a posting.""" - position_str = ( - to_string(posting) if isinstance(posting.units, Amount) else "" - ) + position_str = to_string(posting) if posting.units is not None else "" if posting.price is not None: position_str += f" @ {to_string(posting.price)}" diff --git a/stubs/beancount/__init__.pyi b/stubs/beancount/__init__.pyi deleted file mode 100644 index bda5b5a7f..000000000 --- a/stubs/beancount/__init__.pyi +++ /dev/null @@ -1 +0,0 @@ -__version__: str diff --git a/stubs/beancount/core/__init__.pyi b/stubs/beancount/core/__init__.pyi deleted file mode 100644 index e69de29bb..000000000 diff --git a/stubs/beancount/core/account.pyi b/stubs/beancount/core/account.pyi deleted file mode 100644 index 5a4d19cca..000000000 --- a/stubs/beancount/core/account.pyi +++ /dev/null @@ -1,3 +0,0 @@ -TYPE: str - -def has_component(account_name: str, component: str) -> bool: ... diff --git a/stubs/beancount/core/amount.pyi b/stubs/beancount/core/amount.pyi deleted file mode 100644 index 1bca8b1b1..000000000 --- a/stubs/beancount/core/amount.pyi +++ /dev/null @@ -1,14 +0,0 @@ -from decimal import Decimal -from typing import Any -from typing import NamedTuple - -class Amount(NamedTuple): - number: Decimal | None - currency: str - - def to_string(self, dformat: Any = ...) -> str: ... - def __bool__(self) -> bool: ... - def __eq__(self, other: object) -> bool: ... - def __lt__(self, other: Any) -> bool: ... - def __hash__(self) -> int: ... - def __neg__(self) -> Amount: ... diff --git a/stubs/beancount/core/data.pyi b/stubs/beancount/core/data.pyi deleted file mode 100644 index 4ceb09e5d..000000000 --- a/stubs/beancount/core/data.pyi +++ /dev/null @@ -1,146 +0,0 @@ -import datetime -import enum -from collections.abc import Iterable -from collections.abc import Mapping -from collections.abc import Sequence -from decimal import Decimal -from typing import Any -from typing import NamedTuple -from typing import TypeAlias - -from beancount.core.amount import Amount -from beancount.core.number import MISSING -from beancount.core.position import Cost -from beancount.core.position import CostSpec - -from fava.beans import abc - -Account: TypeAlias = str -Currency: TypeAlias = str -Flag: TypeAlias = str -Meta: TypeAlias = Mapping[str, Any] -Tags: TypeAlias = set[str] | frozenset[str] -Links: TypeAlias = Tags - -EMPTY_SET: frozenset[str] - -class Booking(enum.Enum): - STRICT = "STRICT" - NONE = "NONE" - AVERAGE = "AVERAGE" - FIFO = "FIFO" - LIFO = "LIFO" - -class Close(NamedTuple): - meta: Meta - date: datetime.date - account: Account - -class Commodity(NamedTuple): - meta: Meta - date: datetime.date - currency: Currency - -class Open(NamedTuple): - meta: Meta - date: datetime.date - account: Account - currencies: list[Currency] - booking: Booking | None - -class Pad(NamedTuple): - meta: Meta - date: datetime.date - account: Account - source_account: Account - -class Balance(NamedTuple): - meta: Meta - date: datetime.date - account: Account - amount: Amount - tolerance: Decimal | None - diff_amount: Amount | None - -class Posting(NamedTuple): - account: Account - units: Amount | type[MISSING] - cost: Cost | CostSpec | None - price: Amount | None - flag: Flag | None - meta: Meta | None - -class Transaction(NamedTuple): - meta: Meta - date: datetime.date - flag: Flag - payee: str | None - narration: str - tags: Tags - links: Links - postings: list[Posting] - -class TxnPosting(NamedTuple): - txn: Transaction - posting: Posting - -class Note(NamedTuple): - meta: Meta - date: datetime.date - account: Account - comment: str - tags: Tags | None - links: Links | None - -class Event(NamedTuple): - meta: Meta - date: datetime.date - type: str - description: str - -class Query(NamedTuple): - meta: Meta - date: datetime.date - name: str - query_string: str - -class Price(NamedTuple): - meta: Meta - date: datetime.date - currency: Currency - amount: Amount - -class Document(NamedTuple): - meta: Meta - date: datetime.date - account: Account - filename: str - tags: Tags | None - links: Links | None - -class Custom(NamedTuple): - meta: Meta - date: datetime.date - type: str - values: list[Any] - -Directive: TypeAlias = ( - Open - | Close - | Commodity - | Pad - | Balance - | Transaction - | Note - | Event - | Query - | Price - | Document - | Custom -) - -def iter_entry_dates( - entries: Sequence[abc.Directive], - date_begin: datetime.date, - date_end: datetime.date, -) -> Iterable[abc.Directive]: ... diff --git a/stubs/beancount/core/display_context.pyi b/stubs/beancount/core/display_context.pyi deleted file mode 100644 index 26ec78fd5..000000000 --- a/stubs/beancount/core/display_context.pyi +++ /dev/null @@ -1,12 +0,0 @@ -import enum - -class Precision(enum.Enum): - MOST_COMMON = 1 - MAXIMUM = 2 - -class _CurrencyContext: - has_sign: bool = ... - def get_fractional(self, precision: Precision) -> int | None: ... - -class DisplayContext: - ccontexts: dict[str, _CurrencyContext] = ... diff --git a/stubs/beancount/core/inventory.pyi b/stubs/beancount/core/inventory.pyi deleted file mode 100644 index fa4cfbaca..000000000 --- a/stubs/beancount/core/inventory.pyi +++ /dev/null @@ -1,11 +0,0 @@ -from collections.abc import Iterable -from typing import Any - -from fava.beans.abc import Position - -class Inventory(dict[Any, Position]): - def __init__(self, positions: Iterable[Position] | None = ...) -> None: ... - def is_empty(self) -> bool: ... - def __neg__(self) -> Inventory: ... - def reduce(self, reducer: Any, *args: Any) -> Inventory: ... - def add_position(self, position: Position) -> None: ... diff --git a/stubs/beancount/core/number.pyi b/stubs/beancount/core/number.pyi deleted file mode 100644 index 109b012a8..000000000 --- a/stubs/beancount/core/number.pyi +++ /dev/null @@ -1 +0,0 @@ -class MISSING: ... diff --git a/stubs/beancount/core/position.pyi b/stubs/beancount/core/position.pyi deleted file mode 100644 index 9e6b72e93..000000000 --- a/stubs/beancount/core/position.pyi +++ /dev/null @@ -1,23 +0,0 @@ -import datetime -from decimal import Decimal -from typing import NamedTuple - -from beancount.core.amount import Amount - -class Cost(NamedTuple): - number: Decimal - currency: str - date: datetime.date - label: str | None - -class CostSpec(NamedTuple): - number_per: Decimal | None - number_total: Decimal | None - currency: str | None - date: datetime.date | None - label: str | None - merge: bool | None - -class Position(NamedTuple): - units: Amount - cost: Cost diff --git a/stubs/beancount/loader.pyi b/stubs/beancount/loader.pyi deleted file mode 100644 index 9e8404cdb..000000000 --- a/stubs/beancount/loader.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Any - -from fava.beans.types import LoaderResult - -def load_file( - filename: str, - log_timings: Any | None = ..., - log_errors: Any | None = ..., - extra_validations: Any | None = ..., - encoding: Any | None = ..., -) -> LoaderResult: ... -def load_string( - string: str, - log_timings: Any | None = ..., - log_errors: Any | None = ..., - extra_validations: Any | None = ..., - *, - dedent: bool = ..., - encoding: Any | None = ..., -) -> LoaderResult: ... diff --git a/stubs/beancount/parser/__init__.pyi b/stubs/beancount/parser/__init__.pyi deleted file mode 100644 index e69de29bb..000000000 diff --git a/stubs/beancount/parser/options.pyi b/stubs/beancount/parser/options.pyi deleted file mode 100644 index dd9e02fc5..000000000 --- a/stubs/beancount/parser/options.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from fava.beans.types import BeancountOptions - -OPTIONS_DEFAULTS: BeancountOptions diff --git a/stubs/beancount/parser/parser.pyi b/stubs/beancount/parser/parser.pyi deleted file mode 100644 index aa2bb3639..000000000 --- a/stubs/beancount/parser/parser.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from beancount.core.data import Directive - -def parse_string(string: str) -> tuple[list[Directive], None, None]: ... diff --git a/stubs/beancount/utils/__init__.pyi b/stubs/beancount/utils/__init__.pyi deleted file mode 100644 index e69de29bb..000000000 diff --git a/stubs/beancount/utils/encryption.pyi b/stubs/beancount/utils/encryption.pyi deleted file mode 100644 index 8a8dd16ca..000000000 --- a/stubs/beancount/utils/encryption.pyi +++ /dev/null @@ -1 +0,0 @@ -def is_encrypted_file(filename: str) -> bool: ... diff --git a/stubs/beanquery/__init__.pyi b/stubs/beanquery/__init__.pyi index 5fe9c86ed..f395106c2 100644 --- a/stubs/beanquery/__init__.pyi +++ b/stubs/beanquery/__init__.pyi @@ -2,8 +2,6 @@ from collections.abc import Iterator from collections.abc import Sequence from typing import Any -from fava.beans.types import BeancountOptions - class CompilationError(Exception): ... class ParseError(Exception): ... @@ -26,6 +24,6 @@ def connect( dsn: str, *, entries: Sequence[Any], - options: BeancountOptions, + options: Any, errors: Sequence[Any], ) -> Connection: ... diff --git a/tests/test_core_ingest.py b/tests/test_core_ingest.py index 64570a5f4..1a635b8d4 100644 --- a/tests/test_core_ingest.py +++ b/tests/test_core_ingest.py @@ -8,7 +8,6 @@ import pytest from fava.beans import BEANCOUNT_V3 -from fava.beans.abc import Amount from fava.beans.abc import Note from fava.beans.abc import Transaction from fava.beans.ingest import BeanImporterProtocol @@ -180,11 +179,11 @@ def test_ingest_examplefile( == "Payment to Company XYZ REF: 31000161205-6944556-0000463" ) assert not entries[1].postings[0].account - assert isinstance(entries[1].postings[0].units, Amount) + assert entries[1].postings[0].units is not None assert entries[1].postings[0].units.number == 50.00 assert entries[1].postings[0].units.currency == "EUR" assert entries[1].postings[1].account == "Assets:Checking" - assert isinstance(entries[1].postings[1].units, Amount) + assert entries[1].postings[1].units is not None assert entries[1].postings[1].units.number == -50.00 assert entries[1].postings[1].units.currency == "EUR" if not BEANCOUNT_V3: diff --git a/tests/test_util_excel.py b/tests/test_util_excel.py index 887efe04e..784fff5ad 100644 --- a/tests/test_util_excel.py +++ b/tests/test_util_excel.py @@ -5,6 +5,7 @@ import beanquery import pytest +from beancount.core.display_context import DisplayContext from fava.util import excel @@ -22,7 +23,9 @@ def _run_query(ledger: FavaLedger, query: str) -> Any: curs = conn.execute(query) rrows = curs.fetchall() rtypes = curs.description - dformat = ledger.options["dcontext"].build() # type: ignore[attr-defined] + dcontext = ledger.options["dcontext"] + assert isinstance(dcontext, DisplayContext) + dformat = dcontext.build() rtypes, rrows = beanquery.numberify.numberify_results( rtypes, rrows, dformat )