Reject negative numbers in dehumanize instead of silently dropping the sign - #1344
Reject negative numbers in dehumanize instead of silently dropping the sign#1344afonsojanu wants to merge 1 commit into
Conversation
…e sign The number pattern used to extract digits from a matched time unit is unsigned (\d+), so a literal minus sign right before a number, as in "in -1 hours" or "-3 minutes ago", is simply invisible to it. The direction of the shift already comes from matching the whole string against the locale's "ago"/"in" templates, so the minus sign gets silently thrown away and the result ends up in the opposite direction from what was written, with no error at all. Since direction is already conveyed by that phrasing, a signed number on top of it is contradictory input rather than something with a sensible meaning to fall back to, so this now raises instead.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1344 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 10 10
Lines 2315 2318 +3
Branches 358 359 +1
=========================================
+ Hits 2315 2318 +3 ☔ View full report in Codecov by Harness. |
There was a problem hiding this comment.
Pull request overview
This PR updates Arrow.dehumanize() to reject user input containing negative numeric values (e.g., "in -1 hours", "-3 minutes ago") which were previously parsed incorrectly due to unsigned digit matching, and adds regression tests to ensure the new behavior.
Changes:
- Add a validation check in
Arrow.dehumanize()to detect and reject a literal-immediately preceding matched digits. - Add a new test (
test_negative_numbers_rejected) covering multiple negative-value inputs and confirming unsigned behavior is unchanged.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
arrow/arrow.py |
Adds explicit rejection of negative numeric literals during dehumanize parsing. |
tests/test_arrow.py |
Adds regression test coverage for negative-number inputs and confirms existing unsigned behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| "Invalid input String. Negative numbers are not " | ||
| "supported by dehumanize(), as direction is already " | ||
| "conveyed by phrases such as 'ago' or 'in'. Found a " | ||
| f"negative value near: {match_string!r}" |
Fixes #1278
dehumanize()extracts the number for each matched time unit with an unsigned pattern (\d+), so a literal minus sign right before it, as in"in -1 hours"or"-3 minutes ago", is invisible to that regex. Direction already comes from matching the whole string against the locale's "ago"/"in" templates separately, so the sign just gets thrown away and the result lands in the opposite direction from what was written, with nothing raised:Since direction is already conveyed by that phrasing, a signed number on top of it doesn't have a sensible fallback meaning, so this raises a
ValueErrorinstead. The check looks at the character in the original input immediately before the matched digits, since the number match itself never includes a preceding minus (word-boundary matching stops right at the digit).Added
test_negative_numbers_rejectedcovering the two cases from the issue plus"in -2 days", and confirmed unsigned input in both directions still behaves exactly as before. Verified the new test actually catches the bug by reverting just the source change and rerunning it, full suite (1903 tests) passes, and black/flake8/mypy/isort are all clean on the touched files.