Skip to content

Commit 20cffe0

Browse files
fix(export): restore incremental mtime diagnostic and batch parse resilience
1 parent 9b7a9f0 commit 20cffe0

4 files changed

Lines changed: 19 additions & 21 deletions

File tree

api/export_api.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@
2525
from utils.md_exporter import session_to_markdown
2626
from utils.json_exporter import session_to_json
2727
from utils.slugify import slugify
28-
from utils.export_engine import EXPORT_ERRORS, ZipSink, run_bulk_export
28+
from utils.export_engine import EXPORT_ERRORS as _EXPORT_ERRORS, ZipSink, run_bulk_export
2929

3030
export_bp = Blueprint("export", __name__)
3131

3232
# Tests monkeypatch this path; keep in sync with utils.export_state_store.
3333
_STATE_FILE = EXPORT_STATE_FILE
3434

35-
_EXPORT_ERRORS = EXPORT_ERRORS
36-
3735

3836
def _state_lock() -> Any:
3937
return export_state_lock(_STATE_FILE)

scripts/export.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from utils.slugify import slugify
3535
from utils.export_engine import (
3636
ExportFormat,
37-
ListSink,
37+
NoopSink,
3838
SinceMode,
3939
ZipSink,
4040
run_bulk_export,
@@ -437,7 +437,7 @@ def cmd_export(args):
437437
def _on_export_error(sid: str, exc: Exception) -> None:
438438
print(f" Warning: failed to export {sid}: {exc}", file=sys.stderr)
439439

440-
collect_sink = ListSink()
440+
collect_sink = NoopSink()
441441
export_result = run_bulk_export(
442442
projects=projects,
443443
since=cast(SinceMode, since),
@@ -471,12 +471,8 @@ def _on_export_error(sid: str, exc: Exception) -> None:
471471
"nothing to export."
472472
)
473473
return
474-
skipped = (
475-
export_result.latest_day_scan_total
476-
- export_result.latest_day_match_count
477-
)
478474
elif since == "incremental":
479-
skipped_mtime_unchanged = skipped
475+
skipped_mtime_unchanged = export_result.skipped_mtime_unchanged_count
480476

481477
exported = len(all_exports)
482478
print(

tests/test_export_engine_parity.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from tests.test_cli_e2e import _run_cli, _seed_base_dir # noqa: E402
2020
from utils.export_engine import ( # noqa: E402
2121
MANIFEST_SHARED_KEYS,
22-
ListSink,
22+
NoopSink,
2323
manifest_shared_subset,
2424
run_bulk_export,
2525
)
@@ -37,7 +37,7 @@ def test_engine_api_vs_cli_layout_same_markdown_and_manifest(tmp_path: Path) ->
3737
projects = list_projects(str(base))
3838
rules: list = []
3939

40-
api_sink = ListSink()
40+
api_sink = NoopSink()
4141
api_result = run_bulk_export(
4242
projects=projects,
4343
since="all",
@@ -48,7 +48,7 @@ def test_engine_api_vs_cli_layout_same_markdown_and_manifest(tmp_path: Path) ->
4848
path_layout="api",
4949
manifest_style="api",
5050
)
51-
cli_sink = ListSink()
51+
cli_sink = NoopSink()
5252
cli_result = run_bulk_export(
5353
projects=projects,
5454
since="all",

utils/export_engine.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class BulkExportResult:
6161
exported_session_count: int = 0
6262
failure_count: int = 0
6363
skipped_count: int = 0
64+
skipped_mtime_unchanged_count: int = 0
6465
total_candidates: int = 0
6566
latest_day: date | None = None
6667
latest_day_scan_total: int = 0
@@ -82,20 +83,22 @@ def finalize(self, manifest: list[dict[str, Any]]) -> None:
8283

8384

8485
@dataclass
85-
class ListSink:
86-
"""In-memory sink for tests; use :attr:`BulkExportResult.exports` for file pairs."""
87-
88-
manifest: list[dict[str, Any]] = field(default_factory=list)
86+
class NoopSink:
87+
"""Satisfies :class:`ExportSink` when only :attr:`BulkExportResult` fields are needed."""
8988

9089
def add_session(
9190
self,
9291
files: list[tuple[str, str]],
9392
manifest_entry: dict[str, Any],
9493
) -> None:
95-
self.manifest.append(manifest_entry)
94+
del files, manifest_entry
9695

9796
def finalize(self, manifest: list[dict[str, Any]]) -> None:
98-
self.manifest = manifest
97+
del manifest
98+
99+
100+
# Backward-compatible alias for tests/docs written during PR1.
101+
ListSink = NoopSink
99102

100103

101104
class ZipSink:
@@ -277,7 +280,7 @@ def _export_parsed(
277280
result.exports.extend(files)
278281
result.new_sessions_map[sid] = float(sess_info.get("modified", 0))
279282
result.exported_session_count += 1
280-
except EXPORT_ERRORS as exc:
283+
except Exception as exc:
281284
_record_failure(sid, exc)
282285

283286
if since == "last":
@@ -306,6 +309,7 @@ def _export_parsed(
306309
curr_mtime = float(sess_info.get("modified", 0))
307310
if curr_mtime and curr_mtime <= prev_mtime:
308311
result.skipped_count += 1
312+
result.skipped_mtime_unchanged_count += 1
309313
continue
310314

311315
session = parse_session(sess_info["path"])
@@ -322,7 +326,7 @@ def _export_parsed(
322326
continue
323327

324328
_export_parsed(project, sess_info, session)
325-
except EXPORT_ERRORS as exc:
329+
except Exception as exc:
326330
_record_failure(sid, exc)
327331

328332
result.manifest = manifest

0 commit comments

Comments
 (0)