Skip to content

fix: parse_float(bool/int) and parse_int(float-string) return wrong results#578

Open
gaoflow wants to merge 1 commit into
fabiocaccamo:mainfrom
gaoflow:fix/parse-bool-int-float
Open

fix: parse_float(bool/int) and parse_int(float-string) return wrong results#578
gaoflow wants to merge 1 commit into
fabiocaccamo:mainfrom
gaoflow:fix/parse-bool-int-float

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 24, 2026

Copy link
Copy Markdown

What

Three related bugs in parse_float / parse_int that cause silent wrong results:

call before after
get_float(True) 0.0 1.0
get_float(False) 0.0 0.0
get_int(True) True (bool) 1 (int)
get_int(False) False (bool) 0 (int)
get_int("3.5") 0 (default) 3

Root causes

parse_float with bool/int input:
is_float(True) is False (bool is not a float subclass), so _parse_with falls through to str(True)"True"float("True") raises ValueErrorNone → caller's default (0.0).

parse_int with bool input:
is_integer(True) is True (bool is an int subclass), so _parse_with short-circuits and returns True unchanged — a bool, not an int.

parse_int with a float-string:
int("3.5") raises ValueError with no fallback, so numeric strings with a fractional part always fall through to the caller's default.

Fix

# parse_float: short-circuit bool/int before string conversion
def parse_float(val: str) -> float | None:
    if isinstance(val, (bool, int)):
        return float(val)
    return _parse_with(val, type_util.is_float, _parse_float)

# parse_int: explicit bool cast + float-string fallback
def _parse_int(val: str) -> int | None:
    try:
        return int(val)
    except ValueError:
        try:
            return int(float(val))
        except ValueError:
            return None

def parse_int(val: int | str) -> int | None:
    if isinstance(val, bool):
        return int(val)
    return _parse_with(val, type_util.is_integer, _parse_int)

All 756 existing tests pass with the corrected expectations.

…s to int

- `get_float(True)` wrongly returned `0.0` (the default) because `bool`
  failed the `is_float` type-check, `str(True)` produced `"True"`, and
  `float("True")` raised `ValueError`.  Now `parse_float` short-circuits
  on any `bool`/`int` value and returns `float(val)` directly, so
  `get_float(True)` → `1.0` and `get_float(False)` → `0.0`.

- `get_int("3.5")` wrongly returned the caller-supplied default instead
  of `3` because `int("3.5")` raises `ValueError`.  `_parse_int` now
  falls back to `int(float(val))` so numeric strings with a fractional
  part are truncated correctly.

- `get_int(True)` returned `True` (a `bool`) rather than the `int` `1`
  because `isinstance(True, int)` is `True` and `_parse_with` returned
  the value unchanged.  `parse_int` now explicitly casts `bool` inputs
  with `int(val)` before any further processing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant