Skip to content

Fix TypeError in _nonNegativeDelta when val is None and maxValue is set#2912

Merged
deniszh merged 2 commits intographite-project:masterfrom
npazosmendez:njpm/fix-non-negative-delta-none-val
Mar 31, 2026
Merged

Fix TypeError in _nonNegativeDelta when val is None and maxValue is set#2912
deniszh merged 2 commits intographite-project:masterfrom
npazosmendez:njpm/fix-non-negative-delta-none-val

Conversation

@npazosmendez
Copy link
Copy Markdown
Contributor

@npazosmendez npazosmendez commented Mar 30, 2026

_nonNegativeDelta compared val against maxValue/minValue before checking whether val is None, causing a TypeError when a series contains None values and maxValue (or minValue) is provided.

Fix: move the None in (prev, val) early-return before the comparisons. This also makes semantic sense — on the first reading or a None value there is no delta to compute, regardless of bounds.

The added test case reproduces the issue, and fails without the fix:

  ======================================================================
     ERROR: test_perSecond_nones (tests.test_functions.FunctionsTest.test_perSecond_nones)
     ----------------------------------------------------------------------
     Traceback (most recent call last):
       File "/home/nicolas/code/graphite-web/webapp/tests/test_functions.py", line 1802, in test_perSecond_nones
         result = functions.perSecond({}, seriesList, maxValue=1000)
       File "/home/nicolas/code/graphite-web/webapp/graphite/render/functions.py", line 2230, in perSecond
         delta, prev = _nonNegativeDelta(val, prev, maxValue, minValue)
                       ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       File "/home/nicolas/code/graphite-web/webapp/graphite/render/functions.py", line 2431, in _nonNegativeDelta
         if maxValue is not None and val > maxValue:
                                     ^^^^^^^^^^^^^^
     TypeError: '>' not supported between instances of 'NoneType' and 'int'

     ----------------------------------------------------------------------
     Ran 1 test in 0.003s

Move the None check before the maxValue/minValue comparisons to avoid
comparing None against a float/int.
@npazosmendez npazosmendez marked this pull request as ready for review March 30, 2026 18:01
@deniszh
Copy link
Copy Markdown
Member

deniszh commented Mar 30, 2026

Not sure about this... it's definitely changing function behaviour - see broken tests.

@npazosmendez
Copy link
Copy Markdown
Contributor Author

npazosmendez commented Mar 30, 2026

@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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 _nonNegativeDelta for val is None to avoid invalid comparisons against maxValue/minValue.
  • Simplify the “first reading” check to prev is None (since val is None is now handled upfront).
  • Add a regression assertion in test_perSecond_nones to cover perSecond(..., maxValue=...) with None values.

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]))
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
self.assertEqual(list(expected[0]), list(result[0]))
self.assertEqual(list(expected[0]), list(result[0]))
self.assertEqual(expected, result)

Copilot uses AI. Check for mistakes.
@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.90%. Comparing base (5df4cd4) to head (f86f943).
⚠️ Report is 10 commits behind head on master.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

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.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@deniszh deniszh merged commit b5d272b into graphite-project:master Mar 31, 2026
12 checks passed
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.

4 participants