Fix TypeError in _nonNegativeDelta when val is None and maxValue is set#2912
Conversation
Move the None check before the maxValue/minValue comparisons to avoid comparing None against a float/int.
|
Not sure about this... it's definitely changing function behaviour - see broken tests. |
|
@deniszh sorry I had missed those failures locally. I did spot the behavior change but it seemed harmless to me. I guess it's not. Reworked, behavior should be preserved now. All tests pass locally |
There was a problem hiding this comment.
Pull request overview
Fixes a runtime TypeError in Graphite’s rate/delta helpers when processing series containing None values while maxValue/minValue bounds are provided, ensuring perSecond() (and callers of _nonNegativeDelta) safely handle sparse data.
Changes:
- Add an early return in
_nonNegativeDeltaforval is Noneto avoid invalid comparisons againstmaxValue/minValue. - Simplify the “first reading” check to
prev is None(sinceval is Noneis now handled upfront). - Add a regression assertion in
test_perSecond_nonesto coverperSecond(..., maxValue=...)withNonevalues.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
webapp/graphite/render/functions.py |
Prevents TypeError by guarding None values before bound comparisons in _nonNegativeDelta. |
webapp/tests/test_functions.py |
Adds a regression check ensuring perSecond with maxValue handles None datapoints without crashing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| # None values should not raise TypeError when maxValue is set | ||
| result = functions.perSecond({}, seriesList, maxValue=1000) | ||
| self.assertEqual(list(expected[0]), list(result[0])) |
There was a problem hiding this comment.
The new maxValue regression assertion only compares the values via list(...), but doesn’t assert the full TimeSeries equality (name/start/end/step/tags). For consistency with nearby perSecond tests (e.g., test_perSecond_float / test_perSecond_max) and to ensure metadata doesn’t regress, add self.assertEqual(expected, result) (or an equivalent full-object assertion) for this new call as well.
| self.assertEqual(list(expected[0]), list(result[0])) | |
| self.assertEqual(list(expected[0]), list(result[0])) | |
| self.assertEqual(expected, result) |
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2912 +/- ##
==========================================
+ Coverage 76.80% 76.90% +0.09%
==========================================
Files 88 88
Lines 9700 9703 +3
Branches 1805 1806 +1
==========================================
+ Hits 7450 7462 +12
+ Misses 1983 1971 -12
- Partials 267 270 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
_nonNegativeDeltacomparedvalagainstmaxValue/minValuebefore checking whethervalisNone, causing aTypeErrorwhen a series containsNonevalues andmaxValue(orminValue) is provided.Fix: move the
None in (prev, val)early-return before the comparisons. This also makes semantic sense — on the first reading or aNonevalue there is no delta to compute, regardless of bounds.The added test case reproduces the issue, and fails without the fix: