Skip to content

_bumpversion_config

rhiza_hooks._bumpversion_config

Read bump-my-version's configuration out of the filenames it auto-discovers.

This module is responsible solely for obtaining a bumpversion configuration — locating the file bump-my-version would actually read, and normalising whichever of its two formats that file uses into a :class:BumpversionConfig. Judging the result (is it discoverable at all, does it agree with pyproject, are its targets rewritable) lives in :mod:rhiza_hooks.check_bumpversion_config.

The two formats disagree about more than syntax, which is why they need separate readers even though they produce the same shape:

  • TOML holds the section at the top level (.bumpversion.toml) or nested under [tool] (pyproject.toml), and its targets are [[tool.bumpversion.files]] tables carrying a filename key.
  • INI holds a flat [bumpversion] section, and encodes each target's path in a sibling section name[bumpversion:file:<path>] — rather than in a key.

Both readers take the same lenient stance as the rest of this package: a file that is missing, malformed, or unreadable reads as absent rather than raising. A broken pyproject.toml is somebody else's error to report.

BumpversionConfig dataclass

The bumpversion configuration bump-my-version would read, and its targets.

current_version is None when the section omits that key: there is then no stale value to bump from, which is different from one that disagrees with the project's. targets holds the normalised file entries, unusable ones dropped.

Source code in rhiza_hooks/_bumpversion_config.py
@dataclass(frozen=True)
class BumpversionConfig:
    """The bumpversion configuration bump-my-version would read, and its targets.

    ``current_version`` is None when the section omits that key: there is then no
    stale value to bump from, which is different from one that disagrees with the
    project's. ``targets`` holds the normalised file entries, unusable ones dropped.
    """

    filename: str
    current_version: str | None
    targets: list[BumpversionTarget]

BumpversionTarget dataclass

One file entry a release would rewrite, normalised across both formats.

search is None when the entry omits it (or gives a non-string) — bump-my-version then defaults to {current_version}. regex marks an entry whose pattern is a regular expression, which cannot be counted literally; bump-my-version owns that check.

Source code in rhiza_hooks/_bumpversion_config.py
@dataclass(frozen=True)
class BumpversionTarget:
    """One file entry a release would rewrite, normalised across both formats.

    ``search`` is None when the entry omits it (or gives a non-string) —
    bump-my-version then defaults to ``{current_version}``. ``regex`` marks an
    entry whose pattern is a regular expression, which cannot be counted
    literally; bump-my-version owns that check.
    """

    filename: str
    search: str | None
    regex: bool

find_config(repo_root)

Locate the bumpversion config bump-my-version would read, with its file entries.

TOML candidates are searched before INI candidates, and the first file carrying a section wins — bump-my-version's own search order.

Parameters:

Name Type Description Default
repo_root Path

Root directory of the repository.

required

Returns:

Type Description
BumpversionConfig | None

The winning :class:BumpversionConfig, or None when no searched file

BumpversionConfig | None

carries a bumpversion section.

Source code in rhiza_hooks/_bumpversion_config.py
def find_config(repo_root: Path) -> BumpversionConfig | None:
    """Locate the bumpversion config bump-my-version would read, with its file entries.

    TOML candidates are searched before INI candidates, and the first file carrying
    a section wins — bump-my-version's own search order.

    Args:
        repo_root: Root directory of the repository.

    Returns:
        The winning :class:`BumpversionConfig`, or None when no searched file
        carries a bumpversion section.
    """
    return _find_toml_config(repo_root) or _find_ini_config(repo_root)

load_toml(path)

Parse a TOML file, treating unreadable or malformed input as absent.

Part of this module's cross-module surface: :mod:check_bumpversion_config reads [project].version and probes the undiscovered .rhiza/.cfg.toml with it, so both go through the same lenient parse as the candidate search.

Parameters:

Name Type Description Default
path Path

File to parse.

required

Returns:

Type Description
dict[str, Any] | None

The parsed mapping, or None if the file is missing, malformed, or cannot

dict[str, Any] | None

be opened.

Source code in rhiza_hooks/_bumpversion_config.py
def load_toml(path: Path) -> dict[str, Any] | None:
    """Parse a TOML file, treating unreadable or malformed input as absent.

    Part of this module's cross-module surface: :mod:`check_bumpversion_config`
    reads ``[project].version`` and probes the undiscovered ``.rhiza/.cfg.toml``
    with it, so both go through the same lenient parse as the candidate search.

    Args:
        path: File to parse.

    Returns:
        The parsed mapping, or None if the file is missing, malformed, or cannot
        be opened.
    """
    if not path.exists():
        return None
    try:
        with path.open("rb") as handle:
            return tomllib.load(handle)
    except (tomllib.TOMLDecodeError, OSError, UnicodeDecodeError):
        # tomllib decodes the stream itself, so invalid UTF-8 surfaces as
        # UnicodeDecodeError rather than a TOML error — without this the hook
        # crashed with a traceback on a binary pyproject.toml.
        return None