Skip to content

Don't collapse a plain decimal literal like 1.0 to an int - #43

Open
afonsojanu wants to merge 1 commit into
hjson:masterfrom
afonsojanu:fix-decimal-point-collapsed-to-int
Open

afonsojanu wants to merge 1 commit into
hjson:masterfrom
afonsojanu:fix-decimal-point-collapsed-to-int

Conversation

@afonsojanu

Copy link
Copy Markdown

Fixes #24.

hjson.loads('{test: 1.0}') currently hands back an int, not a float:

>>> import hjson
>>> hjson.loads('{test: 1.0}')
OrderedDict([('test', 1)])
>>> type(hjson.loads('{test: 1.0}')['test'])
<class 'int'>

That's inconsistent both with the standard json module (which keeps 1.0 a float) and with hjson's own serializer, since hjson.dumps(1.0) already produces "1.0". So a value written with an explicit decimal point doesn't round-trip through loads/dumps.

The cause is in scantfnns in hjson/decoder.py. After parsing the number as a float, it checks whether the result is numerically whole and, if so, casts it down to int:

res = context.parse_float(integer + (frac or '') + (exp or ''))
if int(res) == res and abs(res)<1e10: res = int(res)

This collapse is intentional for a case like 17.01e2, where the exponent pushes an otherwise-fractional value up to a whole number (1701.0 -> 1701), and the existing test fixtures (kan_test.hjson / kan_result.json) already pin that behavior. But the same check also fires for a plain decimal literal such as 1.0 or 10.00, where there's no exponent at all - the decimal point was written on purpose and shouldn't be discarded.

The fix narrows the collapse to only apply when an exponent is present, so it keeps the 17.01e2 -> 1701 behavior but leaves 1.0 and 10.00 as floats.

One existing fixture (comments_test.hjson) had a num2: 0.0 entry whose expected result (comments_result.json / comments_result.hjson) was pinning the old, buggy behavior ("num2": 0 instead of 0.0). Updated both to the correct value.

Added two tests in test_decode.py: one confirming a bare decimal literal stays a float, and one confirming the exponent case still collapses to int as before.

Ran the full suite locally (python -m unittest discover -s hjson/tests), 112 tests, all passing.

The number parser in decoder.py used to check whether a parsed float
was numerically whole and, if so, cast it to int regardless of how
the value was written. That means "1.0" and "10.00" came back as
plain ints, even though hjson's own serializer round-trips a float
1.0 back to "1.0", and the plain json module keeps it a float too.

The collapsing logic is genuinely useful for a case like "17.01e2",
where the exponent (not the decimal point) is what pushes the value
to a whole number, and existing fixtures already rely on that giving
an int. This change narrows the collapse so it only fires when an
exponent is present, leaving a bare decimal literal such as "1.0"
as a float.

Updated the comments_test fixture's expected output to match (its
num2 field is 0.0, not 0) and added a couple of decode tests pinning
both the fixed and preserved behavior.
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.

floats ending with '.0' turns into ints

1 participant