From a global code review of the borg2 codebase (2026-08).
Problem
borg.helpers is supposed to be the bottom layer, but it imports upward: helpers/parseformat.py pulls in ..archive, ..manifest, ..compress, ..platform, ..item (inside functions), and cache.py/archive.py import each other. A rough count finds ~175 function-level from ..x import y statements in non-test code, most of them circular-import workarounds rather than genuine lazy loading.
The root cause: parseformat.py (1564 lines, the biggest helpers module) mixes true low-level utilities (bin_to_hex, size/time formatting) with high-level domain formatting (ArchiveFormatter, ItemFormatter, DiffFormatter) that inherently needs Archive/ItemDiff/Manifest. Meanwhile helpers/__init__.py re-exports ~100 names "for compatibility" — internal API compatibility is irrelevant for the breaking 2.0 release, and the shim encourages treating helpers as one big grab-bag.
Proposed direction
- Move
ArchiveFormatter/ItemFormatter/DiffFormatter (and other domain-aware formatting) up and out of helpers, e.g. into borg/output.py or borg.archiver.
- Move
Location parsing near the repository layer where it conceptually belongs.
- Import from the specific helpers submodules directly; shrink
helpers/__init__ to little or nothing.
- Afterwards, most of the ~175 deferred imports can return to module top level.
- Add an import-linter contract (tox/CI) that pins the layer order (constants → helpers → crypto/chunkers → repository → cache/archive → archiver) so cycles cannot silently regrow.
🤖 Generated with Claude Code
From a global code review of the borg2 codebase (2026-08).
Problem
borg.helpersis supposed to be the bottom layer, but it imports upward:helpers/parseformat.pypulls in..archive,..manifest,..compress,..platform,..item(inside functions), andcache.py/archive.pyimport each other. A rough count finds ~175 function-levelfrom ..x import ystatements in non-test code, most of them circular-import workarounds rather than genuine lazy loading.The root cause:
parseformat.py(1564 lines, the biggest helpers module) mixes true low-level utilities (bin_to_hex, size/time formatting) with high-level domain formatting (ArchiveFormatter,ItemFormatter,DiffFormatter) that inherently needsArchive/ItemDiff/Manifest. Meanwhilehelpers/__init__.pyre-exports ~100 names "for compatibility" — internal API compatibility is irrelevant for the breaking 2.0 release, and the shim encourages treating helpers as one big grab-bag.Proposed direction
ArchiveFormatter/ItemFormatter/DiffFormatter(and other domain-aware formatting) up and out of helpers, e.g. intoborg/output.pyorborg.archiver.Locationparsing near the repository layer where it conceptually belongs.helpers/__init__to little or nothing.🤖 Generated with Claude Code