Skip to content

bug: bare 'B' unit in string does not override the units= parameter #2

@underwoo

Description

@underwoo

Summary

When a string like "1024 B" is passed to the constructor, the "B" is matched by a non-capturing alternative in _RE_STR_PARSE and is not placed in group 2. As a result, m.group(2) is None and the units parameter is not updated from the string. If the caller also passed an explicit units keyword argument, that argument (incorrectly) wins.

Every other unit string in the input (e.g. "KiB", "KB") is captured in group 2 and correctly overrides the units parameter; bare "B" is the only exception.

Reproduction

from fsize import FSize

FSize("1024 B", "MB")  # returns 1_024_000 bytes — expected 1_024 bytes
FSize("1024 B", "KiB") # returns 1_048_576 bytes — expected 1_024 bytes

Compare with the consistent behaviour for other unit strings:

FSize("1024 KB", "MB")  # correctly uses KB from the string → 1_024_000 bytes

Root cause

src/fsize/__init__.py, lines 55–57 & 93–94:

_RE_STR_PARSE = re.compile(
    r"(\d*\.?\d+)\s*(?:([KkMmGgTtPpEe]i?[Bb])|[Bb])?\s*$"
)

The [Bb] alternative is outside the capturing group, so m.group(2) is None for "1024 B".

if m.group(2) is not None:
    units = m.group(2)   # never reached for bare "B"

Fix

Either extend the capturing group to also include bare "B":

r"(\d*\.?\d+)\s*(?P<unit>[KkMmGgTtPpEe]i?[Bb]|[Bb])?\s*$"

Or explicitly set units = "B" when the number is followed by bare "B" and no prefix letter was captured.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions