Skip to content

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

Closed
gaoflow wants to merge 3 commits into
fabiocaccamo:mainfrom
gaoflow:fix/parse-bool-int-float
Closed

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

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes silent misparsing in ParseDict numeric getters by improving parse_float and parse_int behavior for boolean/int inputs and for integer parsing from float-like numeric strings.

Changes:

  • parse_float: handle bool/int inputs before falling back to string parsing.
  • parse_int: ensure bool returns an int, and add a fallback to parse int from float-like strings (e.g., "3.5"3).
  • Update unit tests to reflect the corrected results for these cases.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
benedict/dicts/parse/parse_util.py Fixes numeric parsing logic for bool/int and float-like strings.
tests/dicts/parse/test_parse_dict.py Updates expectations for get_float/get_int based on corrected parsing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 249 to +253
except ValueError:
return None
try:
return int(float(val))
except ValueError:
return None
Comment thread benedict/dicts/parse/parse_util.py Outdated
fabiocaccamo pushed a commit that referenced this pull request Jul 7, 2026
… and fix parse_float annotation (#584)

* Initial plan

* fix: convert bool/int to float in parse_float, and parse float-strings 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.

* Address review comments: catch OverflowError in _parse_int, fix parse_float annotation

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Vincent Gao <gaobing1230@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.38%. Comparing base (1383959) to head (bda9819).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #578   +/-   ##
=======================================
  Coverage   98.38%   98.38%           
=======================================
  Files          64       64           
  Lines        2418     2418           
=======================================
  Hits         2379     2379           
  Misses         39       39           
Flag Coverage Δ
unittests 98.38% <0.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

3 participants