anon-iclr-submission/benchname-bug-localization huggingface dataset:
Repository: graphite-project/graphite-web
Issue: [BUG] SVG rendering returns bytes object, leading to XML Parsing Error

**Describe the bug**
When attempting to render an SVG file, I get an "XML Parsing Error: not well-formed [...] Line Number 1, Column 2:" in Firefox.

```
b'<?xml version="1.0" encoding="UTF-8"?>\\n ...
```
Note the b' in the beginning, it looks like a string representation of a bytes object is returned

**To Reproduce**
Enter the rendering URL https://example.com/render?&target=test.count&format=svg

**Expected behavior**
The requests succeeds with a valid SVG file.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Environment (please complete the following information):**
 - Debian Buster
 - Graphite-web version 1.1.6
 - Python 3.7.3
 - Django version 2.2.7
 - graphite-web and Django installed via pip from pypi (pip install graphite-web) in a venv
 - run/started via uwsgi (also installed in venv), served by nginx

**Additional context**

uwsgi ini file:
```
[uwsgi]
processes = 1
socket = localhost:12222
virtualenv = /opt/graphite
chdir = /opt/graphite/conf
module = wsgi:application
```

```
# conf/wsgi.py 
import sys
import os

sys.path.append('/opt/graphite/webapp')

from graphite.wsgi import application
```

Changed files:
webapp/graphite/render/glyph.py

diff --git a/webapp/graphite/render/glyph.py b/webapp/graphite/render/glyph.py
index 2851321a..9d999426 100644
--- a/webapp/graphite/render/glyph.py
+++ b/webapp/graphite/render/glyph.py
@@ -885,10 +885,10 @@ class Graph:
         metaData = { }
 
       self.surface.finish()
-      svgData = str(self.surfaceData.getvalue())
+      svgData = self.surfaceData.getvalue().decode('utf-8')
       self.surfaceData.close()
 
-      svgData = svgData.replace('pt"', 'px"', 2) # we expect height/width in pixels, not points
+      svgData = svgData.replace('pt"', 'px"', 2)  # we expect height/width in pixels, not points
       svgData = svgData.replace('</svg>\\n', '', 1)
       svgData = svgData.replace('</defs>\\n<g', '</defs>\\n<g class="graphite"', 1)
 
@@ -903,10 +903,10 @@ class Graph:
         (svgData, subsMade) = re.subn(r'<path.+?d="M -88 -88 (.+?)"/>', onHeaderPath, svgData)
 
         # Replace the first </g><g> with <g>, and close out the last </g> at the end
-        svgData = svgData.replace('</g><g data-header','<g data-header',1)
+        svgData = svgData.replace('</g><g data-header', '<g data-header', 1)
         if subsMade > 0:
-          svgData += "</g>"
-        svgData = svgData.replace(' data-header="true"','')
+          svgData += '</g>'
+        svgData = svgData.replace(' data-header="true"', '')
 
       fileObj.write(svgData.encode('utf-8'))
       fileObj.write(("""<script>
Repository: graphite-project/graphite-web
Issue: [BUG] Parameter `total` of function `asPercent()` has a wrong type defined

**Describe the bug**
Under certain circumstances the parameter `total` of the function `asPercent()` may have different types, depending on other specified parameters. But the type assigned with this parameter is always `seriesList`, this isn't always correct: https://github.com/graphite-project/graphite-web/blob/master/webapp/graphite/render/functions.py#L871
This may cause the input validation to incorrectly consider a the given value invalid

**To Reproduce**
Enforce input validation and use the `asPercent()` function with a numeric value as `total`

**Expected behavior**
This should be considered valid

**Additional context**
I'll make a PR to fix it


Changed files:
webapp/graphite/render/functions.py, webapp/tests/test_functions.py, webapp/graphite/functions/params.py

diff --git a/webapp/graphite/functions/params.py b/webapp/graphite/functions/params.py
index 3c5398d9..ea730e27 100644
--- a/webapp/graphite/functions/params.py
+++ b/webapp/graphite/functions/params.py
@@ -72,6 +72,9 @@ ParamType.register('seriesLists', validateSeriesList)
 ParamType.register('string')
 ParamType.register('tag')
 
+# special type that accepts everything
+ParamType.register('any')
+
 
 class ParamTypeAggFunc(ParamType):
 
diff --git a/webapp/graphite/render/functions.py b/webapp/graphite/render/functions.py
index 2dcbc85f..0fcbbcce 100644
--- a/webapp/graphite/render/functions.py
+++ b/webapp/graphite/render/functions.py
@@ -868,7 +868,7 @@ def asPercent(requestContext, seriesList, total=None, *nodes):
 asPercent.group = 'Combine'
 asPercent.params = [
   Param('seriesList', ParamTypes.seriesList, required=True),
-  Param('total', ParamTypes.seriesList),
+  Param('total', ParamTypes.any),
   Param('nodes', ParamTypes.nodeOrTag, multiple=True),
 ]
 
diff --git a/webapp/tests/test_functions.py b/webapp/tests/test_functions.py
index 8eace86a..0010dfd5 100644
--- a/webapp/tests/test_functions.py
+++ b/webapp/tests/test_functions.py
@@ -6176,7 +6176,7 @@ class FunctionsTest(TestCase):
                 },
                 {
                     'name': 'total',
-                    'type': 'seriesList'
+                    'type': 'any'
                 },
                 {
                     'multiple': True,
Repository: graphite-project/graphite-web
Issue: Documentation link always points to latest version

This is confusing. I've had users click "Documentation" and complain to me that functions don't work, only to find out they're newly committed functions that haven't made into a release yet.

It should point to the version that is running.

Changed files:
webapp/graphite/settings.py

diff --git a/webapp/graphite/settings.py b/webapp/graphite/settings.py
index 700d5085..17d621f4 100644
--- a/webapp/graphite/settings.py
+++ b/webapp/graphite/settings.py
@@ -113,7 +113,8 @@ REMOTE_RENDER_CONNECT_TIMEOUT = 1.0
 
 #Miscellaneous settings
 SMTP_SERVER = "localhost"
-DOCUMENTATION_URL = "http://graphite.readthedocs.io/"
+DOCUMENTATION_VERSION = 'latest' if 'dev' in WEBAPP_VERSION else WEBAPP_VERSION
+DOCUMENTATION_URL = 'https://graphite.readthedocs.io/en/{}/'.format(DOCUMENTATION_VERSION)
 ALLOW_ANONYMOUS_CLI = True
 LEGEND_MAX_ITEMS = 10
 RRD_CF = 'AVERAGE'
Repository: graphite-project/graphite-web
Issue: [BUG] pickled Interval and IntervalSet objects returned from python 2 graphite web cannot be unpickled in python3

**Describe the bug**
The pickled data returned from the `/metrics/find` endpoint of graphite-web running on python2 cannot be unpickled by graphite-web running on python3.

**To Reproduce**
While this can be observed by configuring an instance of graphite-web running on python 3 to point to any graphite-web hosts running on python2 as their "cluster servers". The minimal reproducible bug is easily arrived at in the python repl
```
$ python2.7
Python 2.7.16 (default, Aug  7 2019, 19:39:03)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-23)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import graphite.intervals
>>> i = graphite.intervals.Interval(1,10)
>>> s = graphite.intervals.IntervalSet([i])
>>> import pickle
>>> with open("py2.pickle", "wb") as f:
...     pickle.dump(s, f)
...
>>>
$ python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> with open('py2.pickle', 'rb') as f:
...     contents=pickle.load(f)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'Interval' object has no attribute '__dict__'
```

**Expected behavior**
I would expect that regardless of python version being run on graphite-web hosts that the wire protocols used to between them would be compatible.

**Environment (please complete the following information):**
 - OS flavor: Centos
 - Graphite-web version 1.1.7

**Additional context**
The cause of this seems to be a difference in how slotted objects are stored in python2 and python3. If you modify the `Interval` and `IntervalSet` class definitions to not use slots the objects unpickle just fine on python3. A side effect of this problem is that graphite-web on python3 is incompatible with other graphite-web implementations (carbonapi for example) which use pickled objects that copy the official graphite-web.

While it seems unlikely that there are many mixed python2/3 graphite-web clusters in the wild there definitely are people using graphite-web as a front end to carbonapi that will be surprised to find that graphite-web running on python3 will not work for them.

Changed files:
webapp/graphite/intervals.py

diff --git a/webapp/graphite/intervals.py b/webapp/graphite/intervals.py
index a7ab260d..42d585ef 100644
--- a/webapp/graphite/intervals.py
+++ b/webapp/graphite/intervals.py
@@ -3,7 +3,6 @@ NEGATIVE_INFINITY = -INFINITY
 
 
 class IntervalSet:
-    __slots__ = ('intervals', 'size')
 
     def __init__(self, intervals, disjoint=False):
         self.intervals = intervals
@@ -74,7 +73,6 @@ class IntervalSet:
 
 
 class Interval:
-    __slots__ = ('start', 'end', 'tuple', 'size')
 
     def __init__(self, start, end):
         if end - start < 0:
Repository: graphite-project/graphite-web
Issue: Something is causing graph rendering to change between reloads

#### Imported from https://bugs.launchpad.net/bugs/860161

|  |  |
| --- | --- |
| Reported by | [ohlol](https://launchpad.net/~ohlol) |
| Date Created | Sep 27, 2011 |

http://dl.dropbox.com/u/1613178/render1.png
http://dl.dropbox.com/u/1613178/render2.png
http://dl.dropbox.com/u/1613178/render3.png

The only difference beteween these three images is that I hit reload. It's not consistent (sometimes I can reload the same graph several times with no obvious variance).


Changed files:
webapp/graphite/readers/whisper.py

diff --git a/webapp/graphite/readers/whisper.py b/webapp/graphite/readers/whisper.py
index 1fd71810..09c32c70 100644
--- a/webapp/graphite/readers/whisper.py
+++ b/webapp/graphite/readers/whisper.py
@@ -51,12 +51,12 @@ class WhisperReader(BaseReader):
         end = max(stat(self.fs_path).st_mtime, start)
         return IntervalSet([Interval(start, end)])
 
-    def fetch_data(self, startTime, endTime):
-        return whisper.fetch(self.fs_path, startTime, endTime)
+    def fetch_data(self, startTime, endTime, now=None):
+        return whisper.fetch(self.fs_path, startTime, endTime, now=now)
 
-    def fetch(self, startTime, endTime):
+    def fetch(self, startTime, endTime, now=None, requestContext=None):
         try:
-            data = self.fetch_data(startTime, endTime)
+            data = self.fetch_data(startTime, endTime, now=now)
         except IOError:
             log.exception("Failed fetch of whisper file '%s'" % self.fs_path)
             return None
@@ -88,9 +88,9 @@ class GzippedWhisperReader(WhisperReader):
                 fh.close()
         return self.meta_info
 
-    def fetch_data(self, startTime, endTime):
+    def fetch_data(self, startTime, endTime, now=None):
         fh = gzip.GzipFile(self.fs_path, 'rb')
         try:
-            return whisper.file_fetch(fh, startTime, endTime)
+            return whisper.file_fetch(fh, startTime, endTime, now=now)
         finally:
             fh.close()