rustfava 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rustfava/__init__.py +30 -0
- rustfava/_ctx_globals_class.py +55 -0
- rustfava/api_models.py +36 -0
- rustfava/application.py +534 -0
- rustfava/beans/__init__.py +6 -0
- rustfava/beans/abc.py +327 -0
- rustfava/beans/account.py +79 -0
- rustfava/beans/create.py +377 -0
- rustfava/beans/flags.py +20 -0
- rustfava/beans/funcs.py +38 -0
- rustfava/beans/helpers.py +52 -0
- rustfava/beans/ingest.py +75 -0
- rustfava/beans/load.py +31 -0
- rustfava/beans/prices.py +151 -0
- rustfava/beans/protocols.py +82 -0
- rustfava/beans/str.py +454 -0
- rustfava/beans/types.py +63 -0
- rustfava/cli.py +187 -0
- rustfava/context.py +13 -0
- rustfava/core/__init__.py +729 -0
- rustfava/core/accounts.py +161 -0
- rustfava/core/attributes.py +145 -0
- rustfava/core/budgets.py +207 -0
- rustfava/core/charts.py +301 -0
- rustfava/core/commodities.py +37 -0
- rustfava/core/conversion.py +229 -0
- rustfava/core/documents.py +87 -0
- rustfava/core/extensions.py +132 -0
- rustfava/core/fava_options.py +255 -0
- rustfava/core/file.py +542 -0
- rustfava/core/filters.py +484 -0
- rustfava/core/group_entries.py +97 -0
- rustfava/core/ingest.py +509 -0
- rustfava/core/inventory.py +167 -0
- rustfava/core/misc.py +105 -0
- rustfava/core/module_base.py +18 -0
- rustfava/core/number.py +106 -0
- rustfava/core/query.py +180 -0
- rustfava/core/query_shell.py +301 -0
- rustfava/core/tree.py +265 -0
- rustfava/core/watcher.py +219 -0
- rustfava/ext/__init__.py +232 -0
- rustfava/ext/auto_commit.py +61 -0
- rustfava/ext/portfolio_list/PortfolioList.js +34 -0
- rustfava/ext/portfolio_list/__init__.py +29 -0
- rustfava/ext/portfolio_list/templates/PortfolioList.html +15 -0
- rustfava/ext/rustfava_ext_test/RustfavaExtTest.js +42 -0
- rustfava/ext/rustfava_ext_test/__init__.py +207 -0
- rustfava/ext/rustfava_ext_test/templates/RustfavaExtTest.html +45 -0
- rustfava/ext/rustfava_ext_test/templates/RustfavaExtTestInclude.html +1 -0
- rustfava/help/__init__.py +15 -0
- rustfava/help/_index.md +29 -0
- rustfava/help/beancount_syntax.md +156 -0
- rustfava/help/budgets.md +31 -0
- rustfava/help/conversion.md +29 -0
- rustfava/help/extensions.md +111 -0
- rustfava/help/features.md +179 -0
- rustfava/help/filters.md +103 -0
- rustfava/help/import.md +27 -0
- rustfava/help/options.md +289 -0
- rustfava/helpers.py +30 -0
- rustfava/internal_api.py +221 -0
- rustfava/json_api.py +952 -0
- rustfava/plugins/__init__.py +3 -0
- rustfava/plugins/link_documents.py +107 -0
- rustfava/plugins/tag_discovered_documents.py +44 -0
- rustfava/py.typed +0 -0
- rustfava/rustledger/__init__.py +31 -0
- rustfava/rustledger/constants.py +76 -0
- rustfava/rustledger/engine.py +485 -0
- rustfava/rustledger/loader.py +273 -0
- rustfava/rustledger/options.py +202 -0
- rustfava/rustledger/query.py +331 -0
- rustfava/rustledger/types.py +830 -0
- rustfava/serialisation.py +220 -0
- rustfava/static/app.css +2988 -0
- rustfava/static/app.css.map +7 -0
- rustfava/static/app.js +12854 -0
- rustfava/static/app.js.map +7 -0
- rustfava/static/beancount-JFV44ZVZ.css +5 -0
- rustfava/static/beancount-JFV44ZVZ.css.map +7 -0
- rustfava/static/beancount-VTTKRGSK.js +4642 -0
- rustfava/static/beancount-VTTKRGSK.js.map +7 -0
- rustfava/static/bql-MGFRUMBP.js +333 -0
- rustfava/static/bql-MGFRUMBP.js.map +7 -0
- rustfava/static/chunk-E7ZF4ASL.js +23061 -0
- rustfava/static/chunk-E7ZF4ASL.js.map +7 -0
- rustfava/static/chunk-V24TLQHT.js +12673 -0
- rustfava/static/chunk-V24TLQHT.js.map +7 -0
- rustfava/static/favicon.ico +0 -0
- rustfava/static/fira-mono-cyrillic-400-normal-BLAGXRCE.woff2 +0 -0
- rustfava/static/fira-mono-cyrillic-500-normal-EN7JUAAW.woff2 +0 -0
- rustfava/static/fira-mono-cyrillic-ext-400-normal-EX7VARTS.woff2 +0 -0
- rustfava/static/fira-mono-cyrillic-ext-500-normal-ZDPTUPRR.woff2 +0 -0
- rustfava/static/fira-mono-greek-400-normal-COGHKMOA.woff2 +0 -0
- rustfava/static/fira-mono-greek-500-normal-4EN2PKZT.woff2 +0 -0
- rustfava/static/fira-mono-greek-ext-400-normal-DYEQIJH7.woff2 +0 -0
- rustfava/static/fira-mono-greek-ext-500-normal-SG73CVKQ.woff2 +0 -0
- rustfava/static/fira-mono-latin-400-normal-NA3VLV7E.woff2 +0 -0
- rustfava/static/fira-mono-latin-500-normal-YC77GFWD.woff2 +0 -0
- rustfava/static/fira-mono-latin-ext-400-normal-DIKTZ5PW.woff2 +0 -0
- rustfava/static/fira-mono-latin-ext-500-normal-ZWY4UO4V.woff2 +0 -0
- rustfava/static/fira-mono-symbols2-400-normal-UITXT77Q.woff2 +0 -0
- rustfava/static/fira-mono-symbols2-500-normal-VWPC2EFN.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-400-normal-KLQMBCA6.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-500-normal-NFG7UD6J.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-ext-400-normal-GWO44OPC.woff2 +0 -0
- rustfava/static/fira-sans-cyrillic-ext-500-normal-SP47E5SC.woff2 +0 -0
- rustfava/static/fira-sans-greek-400-normal-UMQBTLC3.woff2 +0 -0
- rustfava/static/fira-sans-greek-500-normal-4ZKHN4FQ.woff2 +0 -0
- rustfava/static/fira-sans-greek-ext-400-normal-O2DVJAJZ.woff2 +0 -0
- rustfava/static/fira-sans-greek-ext-500-normal-SK6GNWGO.woff2 +0 -0
- rustfava/static/fira-sans-latin-400-normal-OYYTPMAV.woff2 +0 -0
- rustfava/static/fira-sans-latin-500-normal-SMQPZW5A.woff2 +0 -0
- rustfava/static/fira-sans-latin-ext-400-normal-OAUP3WK5.woff2 +0 -0
- rustfava/static/fira-sans-latin-ext-500-normal-LY3YDR5Y.woff2 +0 -0
- rustfava/static/fira-sans-vietnamese-400-normal-OBMQ72MR.woff2 +0 -0
- rustfava/static/fira-sans-vietnamese-500-normal-Y4NZR5EU.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-400-normal-TO22V6M3.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-500-normal-OGBWWWYW.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-ext-400-normal-XH44UCIA.woff2 +0 -0
- rustfava/static/source-code-pro-cyrillic-ext-500-normal-3Z6MMVM6.woff2 +0 -0
- rustfava/static/source-code-pro-greek-400-normal-OUXXUQWK.woff2 +0 -0
- rustfava/static/source-code-pro-greek-500-normal-JA2Z5UXO.woff2 +0 -0
- rustfava/static/source-code-pro-greek-ext-400-normal-WCDKMX7U.woff2 +0 -0
- rustfava/static/source-code-pro-greek-ext-500-normal-ZHVI4VKW.woff2 +0 -0
- rustfava/static/source-code-pro-latin-400-normal-QOGTXED5.woff2 +0 -0
- rustfava/static/source-code-pro-latin-500-normal-X57QEOLQ.woff2 +0 -0
- rustfava/static/source-code-pro-latin-ext-400-normal-QXC74NBF.woff2 +0 -0
- rustfava/static/source-code-pro-latin-ext-500-normal-QGOY7MTT.woff2 +0 -0
- rustfava/static/source-code-pro-vietnamese-400-normal-NPDCDTBA.woff2 +0 -0
- rustfava/static/source-code-pro-vietnamese-500-normal-M6PJKTR5.woff2 +0 -0
- rustfava/static/tree-sitter-beancount-MLXFQBZ5.wasm +0 -0
- rustfava/static/web-tree-sitter-RNOQ6E74.wasm +0 -0
- rustfava/template_filters.py +64 -0
- rustfava/templates/_journal_table.html +156 -0
- rustfava/templates/_layout.html +26 -0
- rustfava/templates/_query_table.html +88 -0
- rustfava/templates/beancount_file +18 -0
- rustfava/templates/help.html +23 -0
- rustfava/templates/macros/_account_macros.html +5 -0
- rustfava/templates/macros/_commodity_macros.html +13 -0
- rustfava/translations/bg/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/bg/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/ca/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/ca/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/de/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/de/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/es/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/es/LC_MESSAGES/messages.po +619 -0
- rustfava/translations/fa/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/fa/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/fr/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/fr/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/ja/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/ja/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/nl/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/nl/LC_MESSAGES/messages.po +617 -0
- rustfava/translations/pt/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/pt/LC_MESSAGES/messages.po +617 -0
- rustfava/translations/pt_BR/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/pt_BR/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/ru/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/ru/LC_MESSAGES/messages.po +617 -0
- rustfava/translations/sk/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/sk/LC_MESSAGES/messages.po +623 -0
- rustfava/translations/sv/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/sv/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/uk/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/uk/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/zh/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/zh/LC_MESSAGES/messages.po +618 -0
- rustfava/translations/zh_Hant_TW/LC_MESSAGES/messages.mo +0 -0
- rustfava/translations/zh_Hant_TW/LC_MESSAGES/messages.po +618 -0
- rustfava/util/__init__.py +157 -0
- rustfava/util/date.py +576 -0
- rustfava/util/excel.py +118 -0
- rustfava/util/ranking.py +79 -0
- rustfava/util/sets.py +18 -0
- rustfava/util/unreachable.py +20 -0
- rustfava-0.1.0.dist-info/METADATA +102 -0
- rustfava-0.1.0.dist-info/RECORD +187 -0
- rustfava-0.1.0.dist-info/WHEEL +5 -0
- rustfava-0.1.0.dist-info/entry_points.txt +2 -0
- rustfava-0.1.0.dist-info/licenses/AUTHORS +11 -0
- rustfava-0.1.0.dist-info/licenses/LICENSE +21 -0
- rustfava-0.1.0.dist-info/top_level.txt +1 -0
rustfava/beans/abc.py
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""Abstract base classes for Beancount types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC
|
|
6
|
+
from abc import abstractmethod
|
|
7
|
+
from typing import Any
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
# Try to import beancount types for backwards compatibility
|
|
11
|
+
# These are only needed to register beancount types with the ABCs
|
|
12
|
+
_HAS_BEANCOUNT = False
|
|
13
|
+
try:
|
|
14
|
+
from beancount.core import data as _bc_data
|
|
15
|
+
from beancount.core import position as _bc_position
|
|
16
|
+
_HAS_BEANCOUNT = True
|
|
17
|
+
except ImportError: # pragma: no cover
|
|
18
|
+
_bc_data = None # type: ignore[assignment]
|
|
19
|
+
_bc_position = None # type: ignore[assignment]
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
22
|
+
import datetime
|
|
23
|
+
from collections.abc import Mapping
|
|
24
|
+
from collections.abc import Sequence
|
|
25
|
+
from decimal import Decimal
|
|
26
|
+
from typing import TypeAlias
|
|
27
|
+
|
|
28
|
+
from rustfava.beans import protocols
|
|
29
|
+
|
|
30
|
+
MetaValue: TypeAlias = (
|
|
31
|
+
str | int | bool | Decimal | datetime.date | protocols.Amount
|
|
32
|
+
)
|
|
33
|
+
Meta: TypeAlias = Mapping[str, MetaValue]
|
|
34
|
+
TagsOrLinks: TypeAlias = set[str] | frozenset[str]
|
|
35
|
+
Account = str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Position(ABC):
|
|
39
|
+
"""A Beancount position - just cost and units."""
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def units(self) -> protocols.Amount:
|
|
44
|
+
"""Units of the posting."""
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def cost(self) -> protocols.Cost | None:
|
|
49
|
+
"""Units of the position."""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if _HAS_BEANCOUNT:
|
|
53
|
+
Position.register(_bc_position.Position)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Posting(Position):
|
|
57
|
+
"""A Beancount posting."""
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
@abstractmethod
|
|
61
|
+
def account(self) -> str:
|
|
62
|
+
"""Account of the posting."""
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
@abstractmethod
|
|
66
|
+
def units(self) -> protocols.Amount:
|
|
67
|
+
"""Units of the posting."""
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
@abstractmethod
|
|
71
|
+
def cost(self) -> protocols.Cost | None:
|
|
72
|
+
"""Units of the posting."""
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def price(self) -> protocols.Amount | None:
|
|
77
|
+
"""Price of the posting."""
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
@abstractmethod
|
|
81
|
+
def meta(self) -> Meta | None:
|
|
82
|
+
"""Metadata of the posting."""
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
@abstractmethod
|
|
86
|
+
def flag(self) -> str | None:
|
|
87
|
+
"""Flag of the posting."""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if _HAS_BEANCOUNT:
|
|
91
|
+
Posting.register(_bc_data.Posting)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Directive(ABC):
|
|
95
|
+
"""A Beancount directive."""
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
@abstractmethod
|
|
99
|
+
def date(self) -> datetime.date:
|
|
100
|
+
"""Metadata of the directive."""
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def meta(self) -> Meta:
|
|
105
|
+
"""Metadata of the directive."""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class Transaction(Directive):
|
|
109
|
+
"""A Beancount Transaction directive."""
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
@abstractmethod
|
|
113
|
+
def flag(self) -> str:
|
|
114
|
+
"""Flag of the transaction."""
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
@abstractmethod
|
|
118
|
+
def payee(self) -> str:
|
|
119
|
+
"""Payee of the transaction."""
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
@abstractmethod
|
|
123
|
+
def narration(self) -> str:
|
|
124
|
+
"""Narration of the transaction."""
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
@abstractmethod
|
|
128
|
+
def postings(self) -> Sequence[Posting]:
|
|
129
|
+
"""Payee of the transaction."""
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
@abstractmethod
|
|
133
|
+
def tags(self) -> frozenset[str]:
|
|
134
|
+
"""Entry tags."""
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
@abstractmethod
|
|
138
|
+
def links(self) -> frozenset[str]:
|
|
139
|
+
"""Entry links."""
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class Balance(Directive):
|
|
143
|
+
"""A Beancount Balance directive."""
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
@abstractmethod
|
|
147
|
+
def account(self) -> str:
|
|
148
|
+
"""Account of the directive."""
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
@abstractmethod
|
|
152
|
+
def amount(self) -> protocols.Amount:
|
|
153
|
+
"""Balance amount."""
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
@abstractmethod
|
|
157
|
+
def diff_amount(self) -> protocols.Amount | None:
|
|
158
|
+
"""Difference amount if balance failed."""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class Commodity(Directive):
|
|
162
|
+
"""A Beancount Commodity directive."""
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
@abstractmethod
|
|
166
|
+
def currency(self) -> str:
|
|
167
|
+
"""Currency."""
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class Close(Directive):
|
|
171
|
+
"""A Beancount Close directive."""
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
@abstractmethod
|
|
175
|
+
def account(self) -> str:
|
|
176
|
+
"""Account of the directive."""
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class Custom(Directive):
|
|
180
|
+
"""A Beancount Custom directive."""
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
@abstractmethod
|
|
184
|
+
def type(self) -> str:
|
|
185
|
+
"""Directive type."""
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
@abstractmethod
|
|
189
|
+
def values(self) -> Sequence[Any]:
|
|
190
|
+
"""Custom values."""
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class Document(Directive):
|
|
194
|
+
"""A Beancount Document directive."""
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
@abstractmethod
|
|
198
|
+
def filename(self) -> str:
|
|
199
|
+
"""Filename of the document."""
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
@abstractmethod
|
|
203
|
+
def account(self) -> str:
|
|
204
|
+
"""Account of the directive."""
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
@abstractmethod
|
|
208
|
+
def tags(self) -> frozenset[str]:
|
|
209
|
+
"""Entry tags."""
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
@abstractmethod
|
|
213
|
+
def links(self) -> frozenset[str]:
|
|
214
|
+
"""Entry links."""
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class Event(Directive):
|
|
218
|
+
"""A Beancount Event directive."""
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
@abstractmethod
|
|
222
|
+
def account(self) -> str:
|
|
223
|
+
"""Account of the directive."""
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class Note(Directive):
|
|
227
|
+
"""A Beancount Note directive."""
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
@abstractmethod
|
|
231
|
+
def account(self) -> str:
|
|
232
|
+
"""Account of the directive."""
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
@abstractmethod
|
|
236
|
+
def comment(self) -> str:
|
|
237
|
+
"""Note comment."""
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class Open(Directive):
|
|
241
|
+
"""A Beancount Open directive."""
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
@abstractmethod
|
|
245
|
+
def account(self) -> str:
|
|
246
|
+
"""Account of the directive."""
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
@abstractmethod
|
|
250
|
+
def currencies(self) -> Sequence[str]:
|
|
251
|
+
"""Valid currencies for the account."""
|
|
252
|
+
|
|
253
|
+
@property
|
|
254
|
+
@abstractmethod
|
|
255
|
+
def booking(self) -> str | None:
|
|
256
|
+
"""Booking method for the account."""
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class Pad(Directive):
|
|
260
|
+
"""A Beancount Pad directive."""
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
@abstractmethod
|
|
264
|
+
def account(self) -> str:
|
|
265
|
+
"""Account of the directive."""
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
@abstractmethod
|
|
269
|
+
def source_account(self) -> str:
|
|
270
|
+
"""Source account of the pad."""
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class Price(Directive):
|
|
274
|
+
"""A Beancount Price directive."""
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
@abstractmethod
|
|
278
|
+
def currency(self) -> str:
|
|
279
|
+
"""Currency for which this is a price."""
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
@abstractmethod
|
|
283
|
+
def amount(self) -> protocols.Amount:
|
|
284
|
+
"""Price amount."""
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class Query(Directive):
|
|
288
|
+
"""A Beancount Query directive."""
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
@abstractmethod
|
|
292
|
+
def name(self) -> str:
|
|
293
|
+
"""Name of this query."""
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
@abstractmethod
|
|
297
|
+
def query_string(self) -> str:
|
|
298
|
+
"""BQL query."""
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class TxnPosting(ABC):
|
|
302
|
+
"""A transaction and a posting."""
|
|
303
|
+
|
|
304
|
+
@property
|
|
305
|
+
@abstractmethod
|
|
306
|
+
def txn(self) -> Transaction:
|
|
307
|
+
"""Transaction."""
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
@abstractmethod
|
|
311
|
+
def posting(self) -> Posting:
|
|
312
|
+
"""Posting."""
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
if _HAS_BEANCOUNT:
|
|
316
|
+
Balance.register(_bc_data.Balance)
|
|
317
|
+
Commodity.register(_bc_data.Commodity)
|
|
318
|
+
Close.register(_bc_data.Close)
|
|
319
|
+
Custom.register(_bc_data.Custom)
|
|
320
|
+
Document.register(_bc_data.Document)
|
|
321
|
+
Event.register(_bc_data.Event)
|
|
322
|
+
Note.register(_bc_data.Note)
|
|
323
|
+
Open.register(_bc_data.Open)
|
|
324
|
+
Pad.register(_bc_data.Pad)
|
|
325
|
+
Price.register(_bc_data.Price)
|
|
326
|
+
Transaction.register(_bc_data.Transaction)
|
|
327
|
+
Query.register(_bc_data.Query)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Account name helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from rustfava.rustledger.constants import ACCOUNT_TYPE
|
|
8
|
+
|
|
9
|
+
from rustfava.beans.abc import Custom
|
|
10
|
+
from rustfava.beans.abc import Pad
|
|
11
|
+
from rustfava.beans.abc import Transaction
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
14
|
+
from collections.abc import Callable
|
|
15
|
+
from collections.abc import Sequence
|
|
16
|
+
|
|
17
|
+
from rustfava.beans.abc import Directive
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def parent(account: str) -> str | None:
|
|
21
|
+
"""Get the name of the parent of the given account."""
|
|
22
|
+
parts = account.rsplit(":", maxsplit=1)
|
|
23
|
+
return parts[0] if len(parts) == 2 else None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def root(account: str) -> str:
|
|
27
|
+
"""Get root account of the given account."""
|
|
28
|
+
parts = account.split(":", maxsplit=1)
|
|
29
|
+
return parts[0]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def child_account_tester(account: str) -> Callable[[str], bool]:
|
|
33
|
+
"""Get a function to check if an account is a descendant of the account."""
|
|
34
|
+
account_as_parent = account + ":"
|
|
35
|
+
|
|
36
|
+
def is_child_account(other: str) -> bool:
|
|
37
|
+
return other == account or other.startswith(account_as_parent)
|
|
38
|
+
|
|
39
|
+
return is_child_account
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def account_tester(
|
|
43
|
+
account: str, *, with_children: bool
|
|
44
|
+
) -> Callable[[str], bool]:
|
|
45
|
+
"""Get a function to check if an account is equal to the account.
|
|
46
|
+
|
|
47
|
+
Arguments:
|
|
48
|
+
account: An account name to check.
|
|
49
|
+
with_children: Whether to include all child accounts.
|
|
50
|
+
"""
|
|
51
|
+
if with_children:
|
|
52
|
+
return child_account_tester(account)
|
|
53
|
+
|
|
54
|
+
def is_account(other: str) -> bool:
|
|
55
|
+
return other == account
|
|
56
|
+
|
|
57
|
+
return is_account
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_entry_accounts(entry: Directive) -> Sequence[str]:
|
|
61
|
+
"""Accounts for an entry.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
entry: An entry.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
A list with the entry's accounts ordered by priority: For
|
|
68
|
+
transactions the posting accounts are listed in reverse order.
|
|
69
|
+
"""
|
|
70
|
+
if isinstance(entry, Transaction):
|
|
71
|
+
return list(reversed([p.account for p in entry.postings]))
|
|
72
|
+
if isinstance(entry, Custom):
|
|
73
|
+
return [val.value for val in entry.values if val.dtype == ACCOUNT_TYPE]
|
|
74
|
+
if isinstance(entry, Pad):
|
|
75
|
+
return [entry.account, entry.source_account]
|
|
76
|
+
account_ = getattr(entry, "account", None)
|
|
77
|
+
if account_ is not None:
|
|
78
|
+
return [account_]
|
|
79
|
+
return []
|