helpers layering: split parseformat, dissolve the helpers/__init__ shim, make imports point downward again
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. intoborg/output.pyorborg.archiver. - Move
Locationparsing 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
Source: borgbackup/borg