naturaltime and precisedelta: return non-finite floats unchanged instead of raising OverflowError#344
Open
HrachShah wants to merge 2 commits into
Conversation
naturaltime and precisedelta both routed their float input through
_date_and_delta, which fed it straight to round() (or skipped round
in precise mode) and then dt.timedelta(seconds=...). For a non-finite
float like inf or -inf, round(float("inf")) raises OverflowError
and dt.timedelta(seconds=float("inf")) raises OverflowError too.
NaN happened to work because round(float("nan")) raises ValueError
which the except clause caught, but inf/-inf slipped past.
The naturaldelta path caught inf/-inf via a different probe (it
calls int(value) first, which raises OverflowError for inf) and
that case is fixed in the still-open PR python-humanize#342 -- this commit leaves
that probe alone and adds the equivalent isfinite guard inside
_date_and_delta, which is what both naturaltime and precisedelta
go through. Adding OverflowError to the except tuple covers the
last remaining case where a finite but oversized number
(> ~3e9 days in seconds) would otherwise crash.
Three new parametrized test functions in tests/test_time.py cover
naturaltime, precisedelta, and the internal _date_and_delta
contract for inf/-inf/nan. The inf and -inf cases fail on the
pre-fix code with OverflowError; the nan case already worked and
is included as a regression guard. Full suite: 724 passed,
69 skipped.
for more information, see https://pre-commit.ci
Member
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both
naturaltime()andprecisedelta()feed a float input through_date_and_delta(), which passes it straight toround()(or skips rounding whenprecise=True). Forfloat('inf')andfloat('-inf'),round()raisesOverflowError: cannot convert float infinity to integeranddt.timedelta(seconds=float('inf'))raises the same. The except clause in the function catchesValueError,TypeError, but notOverflowError, so the user gets a traceback rather than the documented "return str(value) unchanged" behavior.naturaldelta()already had the same bug, fixed in #342 by widening the except to includeOverflowError.naturaltime()andprecisedelta()still crash because they take a different path (round()instead ofint()). This PR mirrors #342's fix for the two other public functions, by guarding the float-input branch with an explicitmath.isfinitecheck beforeround()/timedelta()and by widening the except to(ValueError, TypeError, OverflowError)so a huge but finite value (e.g.1e100) falls through the same way.precise=True(used byprecisedelta()) skips theround()call but still constructsdt.timedelta(seconds=value), which raisesOverflowErrorfor non-finite floats. The isfinite guard handles both paths.Verified:
python3 -m pytest tests/-> 724 passed, 69 skipped.OverflowError: cannot convert float infinity to integerand pass with the fix. 3 additional cases (the NaN parametrizations) pass on both pre-fix and post-fix becauseround(float('nan'))raisesValueError, which the original except already caught.naturaltime(30)still returns "30 seconds ago",precisedelta(dt.timedelta(days=2, seconds=3633, microseconds=123000))still returns "2 days, 1 hour and 33.12 seconds".