beancount-cli 0.2.9__tar.gz → 0.2.12__tar.gz

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.
Files changed (32) hide show
  1. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/CHANGELOG.md +24 -0
  2. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/PKG-INFO +2 -2
  3. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/pyproject.toml +5 -2
  4. beancount_cli-0.2.12/src/beancount_cli/__init__.py +1 -0
  5. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/common.py +7 -2
  6. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/price.py +124 -67
  7. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_cli.py +4 -4
  8. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_coverage_gap.py +10 -6
  9. beancount_cli-0.2.9/src/beancount_cli/__init__.py +0 -1
  10. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/.gitignore +0 -0
  11. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/LICENSE +0 -0
  12. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/README.md +0 -0
  13. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/adapters.py +0 -0
  14. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/cli.py +0 -0
  15. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/__init__.py +0 -0
  16. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/account.py +0 -0
  17. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/commodity.py +0 -0
  18. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/report.py +0 -0
  19. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/root.py +0 -0
  20. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/commands/transaction.py +0 -0
  21. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/config.py +0 -0
  22. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/formatting.py +0 -0
  23. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/models.py +0 -0
  24. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/py.typed +0 -0
  25. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/src/beancount_cli/services.py +0 -0
  26. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/conftest.py +0 -0
  27. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/smoke_test.py +0 -0
  28. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_advanced.py +0 -0
  29. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_bql.py +0 -0
  30. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_config.py +0 -0
  31. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_models.py +0 -0
  32. {beancount_cli-0.2.9 → beancount_cli-0.2.12}/tests/test_services.py +0 -0
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.12] - 2026-04-08
9
+
10
+ ### Fixed
11
+ - `price fetch --update`: cap `date_last` to yesterday (today exclusive) to avoid fetching intraday prices while the market is still open.
12
+
13
+ ## [0.2.11] - 2026-04-07
14
+
15
+ ### Fixed
16
+ - `price fetch`: use `[tool.uv.sources]` git override for `beanprice` so the romamo fork is installed correctly; PyPI metadata keeps `beanprice>=2.1.0` for compatibility.
17
+
18
+ ## [0.2.10] - 2026-04-07
19
+
20
+ ### Changed
21
+ - `price fetch`: use `romamo/beanprice` fork via `[tool.uv.sources]` git override; PyPI metadata retains `beanprice>=2.1.0` for compatibility.
22
+ - `price fetch --update`: include today's date in the fetch window (`date_last` is exclusive, so now passes `today + 1`).
23
+
24
+ ### Added
25
+ - `price fetch -vv`: log each redundant fetched price at DEBUG level so skipped prices are visible.
26
+
27
+ ## [0.2.9] - 2026-04-05
28
+
29
+ ### Fixed
30
+ - Smoke test: check stderr as well as stdout when probing `--help` output, fixing false negatives in isolated environments.
31
+
8
32
  ## [0.2.8] - 2026-04-04
9
33
 
10
34
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beancount-cli
3
- Version: 0.2.9
3
+ Version: 0.2.12
4
4
  Summary: A CLI tool to manage Beancount ledgers
5
5
  Project-URL: Homepage, https://github.com/romamo/beancount-cli
6
6
  Project-URL: Repository, https://github.com/romamo/beancount-cli
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Programming Language :: Python :: 3.13
21
21
  Classifier: Topic :: Office/Business :: Financial :: Accounting
22
22
  Requires-Python: >=3.10
23
- Requires-Dist: agentyper
23
+ Requires-Dist: agentyper==0.1.8
24
24
  Requires-Dist: beancount>=3.0.0
25
25
  Requires-Dist: beanprice>=2.1.0
26
26
  Requires-Dist: beanquery>=0.1.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "beancount-cli"
3
- version = "0.2.9"
3
+ version = "0.2.12"
4
4
  description = "A CLI tool to manage Beancount ledgers"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -15,7 +15,7 @@ dependencies = [
15
15
  "python-dateutil>=2.8.2",
16
16
  "beanprice>=2.1.0",
17
17
  "pydantic-settings>=2.0.0",
18
- "agentyper",
18
+ "agentyper==0.1.8",
19
19
  ]
20
20
  keywords = ["beancount", "cli", "accounting", "automation", "agent"]
21
21
  classifiers = [
@@ -62,6 +62,9 @@ packages = ["src/beancount_cli"]
62
62
  requires = ["hatchling"]
63
63
  build-backend = "hatchling.build"
64
64
 
65
+ [tool.uv.sources]
66
+ beanprice = { git = "https://github.com/romamo/beanprice" }
67
+
65
68
  [dependency-groups]
66
69
  dev = [
67
70
  "bandit>=1.8.6",
@@ -0,0 +1 @@
1
+ __version__ = "0.2.12"
@@ -6,8 +6,13 @@ from pathlib import Path
6
6
  from rich.console import Console
7
7
  from rich.table import Table
8
8
 
9
- console = Console()
10
- error_console = Console(stderr=True)
9
+ # REQ-F-056: Handle agentyper width suppression (COLUMNS=0)
10
+ _width = None
11
+ if os.environ.get("COLUMNS") == "0":
12
+ _width = 100
13
+
14
+ console = Console(width=_width)
15
+ error_console = Console(stderr=True, width=_width)
11
16
 
12
17
 
13
18
  def read_json_input(json_data: str) -> str:
@@ -8,6 +8,7 @@ from tempfile import gettempdir
8
8
 
9
9
  import agentyper as typer
10
10
  from beancount.core import data
11
+ from beancount.core.data import sorted as bean_sorted
11
12
  from beancount.parser import printer
12
13
  from beanprice import price as bp_price
13
14
 
@@ -26,9 +27,6 @@ def price_check(
26
27
  tolerance: int = typer.Option(
27
28
  7, "--tolerance", "-t", help="Allowed delay in days before flagging a gap"
28
29
  ),
29
- verbose: bool = typer.Option(
30
- False, "--verbose", "-v", help="Verbosity level (-v for INFO, -vv for DEBUG)"
31
- ),
32
30
  rate: str = typer.Option(
33
31
  "daily", "--rate", "-r", help="Check frequency: daily, weekday, weekly, monthly"
34
32
  ),
@@ -38,7 +36,6 @@ def price_check(
38
36
  ledger_service = LedgerService(actual_file)
39
37
  price_service = PriceService(ledger_service)
40
38
 
41
- _setup_logging(verbose)
42
39
  _warn_missing_price_meta(ledger_service, "Price history cannot be verified.")
43
40
 
44
41
  gaps = price_service.get_price_gaps(tolerance_days=tolerance, rate=rate)
@@ -62,11 +59,14 @@ def price_check(
62
59
  typer.output(gaps, title="Price Gaps")
63
60
 
64
61
 
65
- @app.command(name="fetch")
62
+ @app.command(name="fetch", mutating=True)
66
63
  def price_fetch(
67
- ledger_file: Path | None = typer.Argument(None, help="Path to ledger file"),
64
+ ledger_files: list[Path] = typer.Argument(
65
+ [],
66
+ help="One or more beancount ledger files to merge before fetching prices",
67
+ ),
68
68
  file: Path | None = typer.Option(
69
- None, "--file", "-f", envvar="BEANCOUNT_FILE", help="Main beancount file"
69
+ None, "--file", "-f", envvar="BEANCOUNT_FILE", help="Main beancount file (legacy fallback)"
70
70
  ),
71
71
  update: bool = typer.Option(
72
72
  False, "--update", "-u", help="Fetch from last price forward and update ledger"
@@ -75,33 +75,57 @@ def price_fetch(
75
75
  False, "--inactive", "-i", help="Include commodities with no balance"
76
76
  ),
77
77
  fill_gaps: bool = typer.Option(False, "--fill-gaps", help="Fill gaps in price history"),
78
- dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Don't actually fetch, just print"),
79
- verbose: bool = typer.Option(
80
- False, "--verbose", "-v", help="Verbosity level (-v for INFO, -vv for DEBUG)"
81
- ),
78
+ dry_run: bool = False,
82
79
  ):
83
- """Fetch and update prices using bean-price library."""
84
- actual_file = get_ledger_file(ledger_file or file)
85
- error_console.print(f"Fetching prices for {actual_file}...")
80
+ """Fetch and update prices using bean-price library.
81
+
82
+ Accepts one or more beancount ledger files as positional arguments. When
83
+ multiple files are provided they are all loaded and their entries merged
84
+ before price jobs are computed. This lets you split commodities/prices
85
+ across separate files (e.g. a common registry and a portfolio ledger) while
86
+ still running a single fetch pass.
87
+
88
+ If no positional arguments are given the command falls back to --file / the
89
+ BEANCOUNT_FILE environment variable for backward compatibility.
90
+ """
91
+ # Resolve the list of ledger files to load.
92
+ if ledger_files:
93
+ files_to_load = ledger_files
94
+ else:
95
+ files_to_load = [get_ledger_file(file)]
86
96
 
87
- _setup_logging(verbose)
97
+ label = ", ".join(str(f) for f in files_to_load)
98
+ error_console.print(f"Fetching prices for {label}...", highlight=False)
88
99
 
89
100
  try:
90
101
  cache_path = Path(gettempdir()) / "bean-price.cache"
91
102
  bp_price.setup_cache(str(cache_path), clear_cache=False)
92
103
 
93
- ledger_service = LedgerService(actual_file)
94
- ledger_service.load()
95
- entries = ledger_service.entries
104
+ # Load and merge all ledger files
105
+ all_entries: list[data.Directive] = []
106
+ all_errors: list = []
107
+ primary_ledger_service: LedgerService | None = None
96
108
 
97
- _warn_missing_price_meta(ledger_service, "Skipping fetch.")
109
+ for ledger_path in files_to_load:
110
+ svc = LedgerService(ledger_path)
111
+ svc.load()
112
+ all_entries.extend(svc.entries)
113
+ all_errors.extend(svc.errors)
114
+ if primary_ledger_service is None:
115
+ primary_ledger_service = svc
116
+
117
+ # Sort merged entries by date (beancount canonical order)
118
+ entries = bean_sorted(all_entries)
119
+
120
+ assert primary_ledger_service is not None # always set — files_to_load is non-empty
121
+
122
+ _warn_missing_price_meta_entries(entries, "Skipping fetch.")
98
123
 
99
124
  if update or fill_gaps:
100
125
  jobs = bp_price.get_price_jobs_up_to_date(
101
126
  entries,
102
127
  date_last=datetime.now().date(),
103
128
  inactive=inactive,
104
- fill_gaps=fill_gaps,
105
129
  )
106
130
  else:
107
131
  jobs = bp_price.get_price_jobs_at_date(entries, date=None, inactive=inactive)
@@ -121,11 +145,14 @@ def price_fetch(
121
145
  # This keeps the streaming output clean of duplicates already in the ledger
122
146
  existing_prices = {(e.date, e.currency) for e in entries if isinstance(e, data.Price)}
123
147
 
148
+ failed_jobs = []
149
+ redundant_count = 0
124
150
  try:
125
151
  with ThreadPoolExecutor(max_workers=min(8, len(jobs))) as executor:
126
152
  future_to_job = {executor.submit(bp_price.fetch_price, job): job for job in jobs}
127
153
 
128
154
  for future in as_completed(future_to_job):
155
+ job = future_to_job[future]
129
156
  price_entry = future.result()
130
157
  if price_entry:
131
158
  price_entry = price_entry._replace(
@@ -139,6 +166,13 @@ def price_fetch(
139
166
  existing_prices.add((price_entry.date, price_entry.currency))
140
167
  print(printer.format_entry(price_entry), end="")
141
168
  sys.stdout.flush()
169
+ else:
170
+ redundant_count += 1
171
+ logging.debug(
172
+ "Redundant: %s", printer.format_entry(price_entry).strip()
173
+ )
174
+ else:
175
+ failed_jobs.append(job)
142
176
  except KeyboardInterrupt:
143
177
  error_console.print("\n[yellow]Interrupt received. Stopping fetch...[/yellow]")
144
178
 
@@ -153,18 +187,32 @@ def price_fetch(
153
187
 
154
188
  prices_output = "".join(printer.format_entry(p) for p in filtered_prices)
155
189
 
156
- map_service = MapService(actual_file)
157
- inc_tree = map_service.get_include_tree()
158
- target_price_file = actual_file
159
-
160
- # Prioritize standard names
161
- sibling_prices = actual_file.parent / "prices.beancount"
162
- if sibling_prices.exists():
163
- target_price_file = sibling_prices
164
- else:
165
- found = _find_price_file(inc_tree)
166
- if found:
167
- target_price_file = found
190
+ # Resolve target price file.
191
+ # Strategy:
192
+ # 1. Look for a file named 'prices.beancount' in the argument list itself.
193
+ # 2. Look for a sibling named 'prices.beancount' relative to the primary ledger.
194
+ # 3. Search the include tree for a file with 'price' in the name.
195
+ # 4. Fallback to the primary ledger.
196
+
197
+ target_price_file = None
198
+ for f in files_to_load:
199
+ if f.name == "prices.beancount":
200
+ target_price_file = f
201
+ break
202
+
203
+ if target_price_file is None:
204
+ primary_file = files_to_load[0]
205
+ sibling_prices = primary_file.parent / "prices.beancount"
206
+ if sibling_prices.exists():
207
+ target_price_file = sibling_prices
208
+ else:
209
+ map_service = MapService(primary_file)
210
+ inc_tree = map_service.get_include_tree()
211
+ found = _find_price_file(inc_tree)
212
+ if found:
213
+ target_price_file = found
214
+ else:
215
+ target_price_file = primary_file
168
216
 
169
217
  with open(target_price_file, "a") as f:
170
218
  f.write(prices_output)
@@ -172,7 +220,21 @@ def price_fetch(
172
220
  error_console.print(
173
221
  f"[green]Appended {len(filtered_prices)} new prices to {target_price_file.name}[/green]"
174
222
  )
175
- elif not new_price_entries:
223
+
224
+ if redundant_count:
225
+ error_console.print(
226
+ f"[yellow]Ignored {redundant_count} fetched prices as they are already in the ledger.[/yellow]"
227
+ )
228
+
229
+ if failed_jobs:
230
+ failed_info = ", ".join(f"{j.currency} on {j.date}" for j in failed_jobs[:5])
231
+ if len(failed_jobs) > 5:
232
+ failed_info += f" (+{len(failed_jobs) - 5} more)"
233
+ error_console.print(
234
+ f"[yellow]Skipped {len(failed_jobs)} jobs with no data from source: {failed_info}[/yellow]"
235
+ )
236
+
237
+ if not new_price_entries and not failed_jobs and not redundant_count:
176
238
  error_console.print("[yellow]No new prices found.[/yellow]")
177
239
 
178
240
  except Exception as e:
@@ -195,44 +257,39 @@ def _find_price_file(tree: dict) -> Path | None:
195
257
 
196
258
  def _warn_missing_price_meta(ledger_service: LedgerService, context: str) -> None:
197
259
  """Warn about held commodities that lack 'price' metadata and cannot be priced."""
198
- held = ledger_service.get_inventory(date.today())
199
- op_currs = set(ledger_service.get_operating_currencies()) or {"USD"}
200
- commodity_meta = {
201
- e.currency: e.meta for e in ledger_service.entries if isinstance(e, data.Commodity)
260
+ _warn_missing_price_meta_entries(ledger_service.entries, context)
261
+
262
+
263
+ def _warn_missing_price_meta_entries(entries: list[data.Directive], context: str) -> None:
264
+ """Warn about held commodities (from a merged entry list) that lack 'price' metadata."""
265
+ from beancount.core import convert
266
+ from beancount.core.inventory import Inventory
267
+
268
+ inv = Inventory()
269
+ today = date.today()
270
+ for e in entries:
271
+ if e.date > today:
272
+ break
273
+ if isinstance(e, data.Transaction):
274
+ for p in e.postings:
275
+ if p.account.startswith(("Assets", "Liabilities")):
276
+ inv.add_position(p)
277
+
278
+ held = {
279
+ pos.units.currency
280
+ for pos in inv.reduce(convert.get_units)
281
+ if not pos.units.number.is_zero()
202
282
  }
283
+
284
+ # Extract operating currencies from options if possible
285
+ # In a merged entry list, we might have 'option' directives as Custom entries or similar?
286
+ # Actually, Beancount usually loads them into an options map.
287
+ # For now, we'll just check commodity metadata.
288
+
289
+ commodity_meta = {e.currency: e.meta for e in entries if isinstance(e, data.Commodity)}
203
290
  for curr in sorted(held):
204
- if curr in op_currs:
205
- continue
206
291
  meta = commodity_meta.get(curr, {})
207
292
  if not meta or "price" not in meta:
208
293
  error_console.print(
209
294
  f"[red]Error: Commodity {curr} is held but has no 'price' metadata. {context}[/red]"
210
295
  )
211
-
212
-
213
- def _setup_logging(verbose: bool):
214
- """Sets up logging levels based on verbosity count in sys.argv."""
215
- # Manual count of 'v' flags in sys.argv to handle -v, -vv, etc.
216
- count = 0
217
- for arg in sys.argv:
218
- if arg == "-v":
219
- count += 1
220
- elif arg.startswith("-") and not arg.startswith("--"):
221
- # Handle combined flags like -uvv
222
- count += arg.count("v")
223
- elif arg == "--verbose":
224
- count += 1
225
-
226
- if count >= 2:
227
- log_level = logging.DEBUG
228
- elif count == 1 or verbose:
229
- log_level = logging.INFO
230
- else:
231
- log_level = logging.WARNING
232
-
233
- logging.basicConfig(level=log_level, format="%(levelname)-8s: %(message)s", force=True)
234
-
235
- # Silence noisy loggers unless -vv is used
236
- if count < 2:
237
- for logger_name in ["yfinance", "urllib3", "requests", "diskcache"]:
238
- logging.getLogger(logger_name).setLevel(logging.WARNING)
@@ -136,7 +136,7 @@ def test_price_cmd(temp_beancount_file):
136
136
  # `price` is now a subcommand group; calling it without a subcommand shows help
137
137
  code, out, err = run_cli("price", "--help")
138
138
  assert code in (0, None)
139
- assert "check" in out or "fetch" in out
139
+ assert "check" in (out + err) or "fetch" in (out + err)
140
140
 
141
141
 
142
142
  def test_missing_ledger_file(monkeypatch):
@@ -148,7 +148,7 @@ def test_missing_ledger_file(monkeypatch):
148
148
  monkeypatch.delenv("BEANCOUNT_PATH")
149
149
 
150
150
  code, out, err = run_cli("check", "doesnt_exist_file.beancount")
151
- assert code == 2 # EXIT_SYSTEM
151
+ assert code == 1 # EXIT_SYSTEM
152
152
  assert "Traceback" not in err
153
153
 
154
154
 
@@ -162,5 +162,5 @@ def test_report_holdings_help_hides_audit_only_flags():
162
162
  def test_report_audit_help_shows_audit_only_flags():
163
163
  code, out, err = run_cli("report", "audit", "--help")
164
164
  assert code in (0, None)
165
- assert "--limit" in out
166
- assert "--all" in out
165
+ assert "--limit" in (out + err)
166
+ assert "--all" in (out + err)
@@ -21,6 +21,8 @@ def test_report_holdings_json(temp_beancount_file):
21
21
  """Exercises the holdings JSON output path (render_output(holdings, format='json'))."""
22
22
  code, out, _ = _run_cli("report", "holdings", str(temp_beancount_file), "--format", "json")
23
23
  data = jsonlib.loads(out)
24
+ if "data" in data and "ok" in data:
25
+ data = data["data"]
24
26
  if isinstance(data, list):
25
27
  if data:
26
28
  assert "Account" in data[0]
@@ -49,21 +51,21 @@ def test_check_cmd_with_errors(temp_beancount_file):
49
51
  with open(temp_beancount_file, "a") as f:
50
52
  f.write("\n2022-01-01 INVALID_STATEMENT\n")
51
53
  code, out, err = _run_cli("check", str(temp_beancount_file))
52
- assert code == 1 # EXIT_VALIDATION, not system error
54
+ assert code == 3 # EXIT_VALIDATION, not system error
53
55
  assert "Traceback" not in err
54
56
 
55
57
 
56
58
  def test_check_missing_file_exits_system(tmp_path):
57
59
  code, out, err = _run_cli("check", str(tmp_path / "nope.beancount"))
58
- assert code == 2 # EXIT_SYSTEM
60
+ assert code == 1 # EXIT_SYSTEM
59
61
  assert "Traceback" not in err
60
62
 
61
63
 
62
64
  def test_check_missing_file_json(tmp_path):
63
65
  code, out, err = _run_cli("check", "--format", "json", str(tmp_path / "nope.beancount"))
64
- assert code == 2
66
+ assert code == 1
65
67
  payload = jsonlib.loads(err)
66
- assert payload["exit_code"] == 2
68
+ assert payload["exit_code"] == 1
67
69
  assert payload["error_type"] == "FileNotFoundError"
68
70
  assert "Traceback" not in err
69
71
 
@@ -72,11 +74,11 @@ def test_check_validation_errors_json(temp_beancount_file):
72
74
  with open(temp_beancount_file, "a") as f:
73
75
  f.write("\n2022-01-01 INVALID_STATEMENT\n")
74
76
  code, out, err = _run_cli("check", "--format", "json", str(temp_beancount_file))
75
- assert code == 1
77
+ assert code == 3
76
78
  payload = jsonlib.loads(err)
77
79
  assert payload["error"] is True
78
80
  assert payload["error_type"] == "BeancountValidationError"
79
- assert payload["exit_code"] == 1
81
+ assert payload["exit_code"] == 3
80
82
  assert isinstance(payload["errors"], list)
81
83
  assert len(payload["errors"]) > 0
82
84
 
@@ -87,6 +89,8 @@ def test_report_audit_json(temp_beancount_file):
87
89
  )
88
90
  assert code == 0
89
91
  data = jsonlib.loads(out)
92
+ if "data" in data and "ok" in data:
93
+ data = data["data"]
90
94
  assert isinstance(data, list)
91
95
 
92
96
 
@@ -1 +0,0 @@
1
- __version__ = "0.2.9"
File without changes
File without changes
File without changes