Skip to content

helpers layering: split parseformat, dissolve the helpers/__init__ shim, make imports point downward again #10016

Description

@ThomasWaldmann

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions