about summary refs log tree commit diff
path: root/wqflask/utility
diff options
context:
space:
mode:
Diffstat (limited to 'wqflask/utility')
-rw-r--r--wqflask/utility/Plot.py298
-rw-r--r--wqflask/utility/TDCell.py6
-rw-r--r--wqflask/utility/THCell.py8
-rw-r--r--wqflask/utility/__init__.py16
-rw-r--r--wqflask/utility/after.py5
-rw-r--r--wqflask/utility/authentication_tools.py153
-rw-r--r--wqflask/utility/benchmark.py20
-rw-r--r--wqflask/utility/chunks.py67
-rw-r--r--wqflask/utility/corestats.py9
-rw-r--r--wqflask/utility/corr_result_helpers.py26
-rw-r--r--wqflask/utility/db_tools.py12
-rw-r--r--wqflask/utility/elasticsearch_tools.py21
-rw-r--r--wqflask/utility/external.py3
-rw-r--r--wqflask/utility/formatting.py29
-rw-r--r--wqflask/utility/gen_geno_ob.py41
-rw-r--r--wqflask/utility/genofile_parser.py154
-rw-r--r--wqflask/utility/helper_functions.py82
-rw-r--r--wqflask/utility/hmac.py20
-rw-r--r--wqflask/utility/logger.py64
-rw-r--r--wqflask/utility/pillow_utils.py31
-rw-r--r--wqflask/utility/redis_tools.py200
-rw-r--r--wqflask/utility/startup_config.py37
-rw-r--r--wqflask/utility/svg.py1115
-rw-r--r--wqflask/utility/temp_data.py8
-rw-r--r--wqflask/utility/tools.py180
-rw-r--r--wqflask/utility/type_checking.py29
-rw-r--r--wqflask/utility/webqtlUtil.py71
27 files changed, 1584 insertions, 1121 deletions
diff --git a/wqflask/utility/Plot.py b/wqflask/utility/Plot.py
index cce8435d..d4256a46 100644
--- a/wqflask/utility/Plot.py
+++ b/wqflask/utility/Plot.py
@@ -24,32 +24,36 @@
 #
 # Last updated by GeneNetwork Core Team 2010/10/20
 
-from __future__ import print_function
-
-import piddle as pid
-from pprint import pformat as pf
+from PIL import ImageColor
+from PIL import ImageDraw
+from PIL import ImageFont
 
 from math import *
-import random
-import sys, os
-from numarray import linear_algebra as la
-from numarray import ones, array, dot, swapaxes
-
-import reaper
 
-import webqtlUtil
-import corestats
+import utility.corestats as corestats
 from base import webqtlConfig
-
+from utility.pillow_utils import draw_rotated_text
 import utility.logger
-logger = utility.logger.getLogger(__name__ )
+logger = utility.logger.getLogger(__name__)
+
+# ---- Define common colours ---- #
+BLUE = ImageColor.getrgb("blue")
+BLACK = ImageColor.getrgb("black")
+# ---- END: Define common colours ---- #
+
+# ---- FONT FILES ---- #
+VERDANA_FILE = "./wqflask/static/fonts/verdana.ttf"
+COUR_FILE = "./wqflask/static/fonts/courbd.ttf"
+TAHOMA_FILE = "./wqflask/static/fonts/tahoma.ttf"
+# ---- END: FONT FILES ---- #
+
 
 def cformat(d, rank=0):
     'custom string format'
     strD = "%2.6f" % d
 
     if rank == 0:
-        while strD[-1] in ('0','.'):
+        while strD[-1] in ('0', '.'):
             if strD[-1] == '0' and strD[-2] == '.' and len(strD) <= 4:
                 break
             elif strD[-1] == '.':
@@ -65,22 +69,24 @@ def cformat(d, rank=0):
         strD = '0.0'
     return strD
 
+
 def frange(start, end=None, inc=1.0):
     "A faster range-like function that does accept float increments..."
     if end == None:
         end = start + 0.0
         start = 0.0
     else:
-        start += 0.0 # force it to be a float
+        start += 0.0  # force it to be a float
     count = int((end - start) / inc)
     if start + count * inc != end:
-    # Need to adjust the count. AFAICT, it always comes up one short.
+        # Need to adjust the count. AFAICT, it always comes up one short.
         count += 1
     L = [start] * count
-    for i in xrange(1, count):
+    for i in range(1, count):
         L[i] = start + i * inc
     return L
 
+
 def find_outliers(vals):
     """Calculates the upper and lower bounds of a set of sample/case values
 
@@ -88,7 +94,7 @@ def find_outliers(vals):
     >>> find_outliers([3.504, 5.234, 6.123, 7.234, 3.542, 5.341, 7.852, 4.555, 12.537])
     (11.252500000000001, 0.5364999999999993)
 
-    >>> >>> find_outliers([9,12,15,17,31,50,7,5,6,8])
+    >>> find_outliers([9,12,15,17,31,50,7,5,6,8])
     (32.0, -8.0)
 
     If there are no vals, returns None for the upper and lower bounds,
@@ -116,129 +122,163 @@ def find_outliers(vals):
 
 # parameter: data is either object returned by reaper permutation function (called by MarkerRegressionPage.py)
 # or the first object returned by direct (pair-scan) permu function (called by DirectPlotPage.py)
-def plotBar(canvas, data, barColor=pid.blue, axesColor=pid.black, labelColor=pid.black, XLabel=None, YLabel=None, title=None, offset= (60, 20, 40, 40), zoom = 1):
+
+
+def plotBar(canvas, data, barColor=BLUE, axesColor=BLACK, labelColor=BLACK, XLabel=None, YLabel=None, title=None, offset=(60, 20, 40, 40), zoom=1):
+    im_drawer = ImageDraw.Draw(canvas)
     xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset
 
     plotWidth = canvas.size[0] - xLeftOffset - xRightOffset
     plotHeight = canvas.size[1] - yTopOffset - yBottomOffset
-    if plotHeight<=0 or plotWidth<=0:
-       return
+    if plotHeight <= 0 or plotWidth <= 0:
+        return
 
     if len(data) < 2:
-       return
+        return
 
     max_D = max(data)
     min_D = min(data)
-    #add by NL 06-20-2011: fix the error: when max_D is infinite, log function in detScale will go wrong
-    if max_D == float('inf') or max_D>webqtlConfig.MAXLRS:
-       max_D=webqtlConfig.MAXLRS #maximum LRS value
+    # add by NL 06-20-2011: fix the error: when max_D is infinite, log function in detScale will go wrong
+    if (max_D == float('inf') or max_D > webqtlConfig.MAXLRS) and min_D < webqtlConfig.MAXLRS:
+        max_D = webqtlConfig.MAXLRS  # maximum LRS value
 
     xLow, xTop, stepX = detScale(min_D, max_D)
 
-    #reduce data
-    #ZS: Used to determine number of bins for permutation output
-    step = ceil((xTop-xLow)/50.0)
+    # reduce data
+    # ZS: Used to determine number of bins for permutation output
+    step = ceil((xTop - xLow) / 50.0)
     j = xLow
     dataXY = []
     Count = []
     while j <= xTop:
-       dataXY.append(j)
-       Count.append(0)
-       j += step
+        dataXY.append(j)
+        Count.append(0)
+        j += step
 
     for i, item in enumerate(data):
-       if item == float('inf') or item>webqtlConfig.MAXLRS:
-           item = webqtlConfig.MAXLRS #maximum LRS value
-       j = int((item-xLow)/step)
-       Count[j] += 1
+        if (item == float('inf') or item > webqtlConfig.MAXLRS) and min_D < webqtlConfig.MAXLRS:
+            item = webqtlConfig.MAXLRS  # maximum LRS value
+        j = int((item - xLow) / step)
+        Count[j] += 1
 
-    yLow, yTop, stepY=detScale(0,max(Count))
+    yLow, yTop, stepY = detScale(0, max(Count))
 
-    #draw data
-    xScale = plotWidth/(xTop-xLow)
-    yScale = plotHeight/(yTop-yLow)
-    barWidth = xScale*step
+    # draw data
+    xScale = plotWidth / (xTop - xLow)
+    yScale = plotHeight / (yTop - yLow)
+    barWidth = xScale * step
 
     for i, count in enumerate(Count):
-       if count:
-           xc = (dataXY[i]-xLow)*xScale+xLeftOffset
-           yc =-(count-yLow)*yScale+yTopOffset+plotHeight
-           canvas.drawRect(xc+2,yc,xc+barWidth-2,yTopOffset+plotHeight,edgeColor=barColor,fillColor=barColor)
-
-    #draw drawing region
-    canvas.drawRect(xLeftOffset, yTopOffset, xLeftOffset+plotWidth, yTopOffset+plotHeight)
-
-    #draw scale
-    scaleFont=pid.Font(ttf="cour",size=11,bold=1)
-    x=xLow
-    for i in range(int(stepX)+1):
-       xc=xLeftOffset+(x-xLow)*xScale
-       canvas.drawLine(xc,yTopOffset+plotHeight,xc,yTopOffset+plotHeight+5, color=axesColor)
-       strX = cformat(d=x, rank=0)
-       canvas.drawString(strX,xc-canvas.stringWidth(strX,font=scaleFont)/2,yTopOffset+plotHeight+14,font=scaleFont)
-       x+= (xTop - xLow)/stepX
-
-    y=yLow
-    for i in range(int(stepY)+1):
-       yc=yTopOffset+plotHeight-(y-yLow)*yScale
-       canvas.drawLine(xLeftOffset,yc,xLeftOffset-5,yc, color=axesColor)
-       strY = "%d" %y
-       canvas.drawString(strY,xLeftOffset-canvas.stringWidth(strY,font=scaleFont)-6,yc+5,font=scaleFont)
-       y+= (yTop - yLow)/stepY
-
-    #draw label
-    labelFont=pid.Font(ttf="tahoma",size=17,bold=0)
+        if count:
+            xc = (dataXY[i] - xLow) * xScale + xLeftOffset
+            yc = -(count - yLow) * yScale + yTopOffset + plotHeight
+            im_drawer.rectangle(
+                xy=((xc + 2, yc), (xc + barWidth - 2, yTopOffset + plotHeight)),
+                outline=barColor, fill=barColor)
+
+    # draw drawing region
+    im_drawer.rectangle(
+        xy=((xLeftOffset, yTopOffset),
+            (xLeftOffset + plotWidth, yTopOffset + plotHeight))
+    )
+
+    # draw scale
+    scaleFont = ImageFont.truetype(font=COUR_FILE, size=11)
+    x = xLow
+    for i in range(int(stepX) + 1):
+        xc = xLeftOffset + (x - xLow) * xScale
+        im_drawer.line(
+            xy=((xc, yTopOffset + plotHeight),
+                (xc, yTopOffset + plotHeight + 5)),
+            fill=axesColor)
+        strX = cformat(d=x, rank=0)
+        im_drawer.text(
+            text=strX,
+            xy=(xc - im_drawer.textsize(strX, font=scaleFont)[0] / 2,
+                yTopOffset + plotHeight + 14), font=scaleFont)
+        x += (xTop - xLow) / stepX
+
+    y = yLow
+    for i in range(int(stepY) + 1):
+        yc = yTopOffset + plotHeight - (y - yLow) * yScale
+        im_drawer.line(
+            xy=((xLeftOffset, yc), (xLeftOffset - 5, yc)), fill=axesColor)
+        strY = "%d" % y
+        im_drawer.text(
+            text=strY,
+            xy=(xLeftOffset - im_drawer.textsize(strY,
+                                                 font=scaleFont)[0] - 6, yc + 5),
+            font=scaleFont)
+        y += (yTop - yLow) / stepY
+
+    # draw label
+    labelFont = ImageFont.truetype(font=TAHOMA_FILE, size=17)
     if XLabel:
-       canvas.drawString(XLabel,xLeftOffset+(plotWidth-canvas.stringWidth(XLabel,font=labelFont))/2.0,
-               yTopOffset+plotHeight+yBottomOffset-10,font=labelFont,color=labelColor)
+        im_drawer.text(
+            text=XLabel,
+            xy=(xLeftOffset + (
+                plotWidth - im_drawer.textsize(XLabel, font=labelFont)[0]) / 2.0,
+                yTopOffset + plotHeight + yBottomOffset - 10),
+            font=labelFont, fill=labelColor)
 
     if YLabel:
-       canvas.drawString(YLabel, 19, yTopOffset+plotHeight-(plotHeight-canvas.stringWidth(YLabel,font=labelFont))/2.0,
-               font=labelFont,color=labelColor,angle=90)
-
-    labelFont=pid.Font(ttf="verdana",size=16,bold=0)
+        draw_rotated_text(canvas, text=YLabel,
+                          xy=(19,
+                              yTopOffset + plotHeight - (
+                                  plotHeight - im_drawer.textsize(
+                                      YLabel, font=labelFont)[0]) / 2.0),
+                          font=labelFont, fill=labelColor, angle=90)
+
+    labelFont = ImageFont.truetype(font=VERDANA_FILE, size=16)
     if title:
-       canvas.drawString(title,xLeftOffset+(plotWidth-canvas.stringWidth(title,font=labelFont))/2.0,
-               20,font=labelFont,color=labelColor)
+        im_drawer.text(
+            text=title,
+            xy=(xLeftOffset + (plotWidth - im_drawer.textsize(
+                title, font=labelFont)[0]) / 2.0,
+                20),
+            font=labelFont, fill=labelColor)
 
 # This function determines the scale of the plot
-def detScaleOld(min,max):
-    if min>=max:
+
+
+def detScaleOld(min, max):
+    if min >= max:
         return None
     elif min == -1.0 and max == 1.0:
-        return [-1.2,1.2,12]
+        return [-1.2, 1.2, 12]
     else:
-        a=max-min
-        b=floor(log10(a))
-        c=pow(10.0,b)
-        if a < c*5.0:
-            c/=2.0
-        #print a,b,c
-        low=c*floor(min/c)
-        high=c*ceil(max/c)
-        return [low,high,round((high-low)/c)]
-
-def detScale(min=0,max=0):
-
-    if min>=max:
+        a = max - min
+        b = floor(log10(a))
+        c = pow(10.0, b)
+        if a < c * 5.0:
+            c /= 2.0
+        # print a,b,c
+        low = c * floor(min / c)
+        high = c * ceil(max / c)
+        return [low, high, round((high - low) / c)]
+
+
+def detScale(min=0, max=0):
+
+    if min >= max:
         return None
     elif min == -1.0 and max == 1.0:
-        return [-1.2,1.2,12]
+        return [-1.2, 1.2, 12]
     else:
-        a=max-min
+        a = max - min
         if max != 0:
-            max += 0.1*a
+            max += 0.1 * a
         if min != 0:
-            if min > 0 and min < 0.1*a:
+            if min > 0 and min < 0.1 * a:
                 min = 0.0
             else:
-                min -= 0.1*a
-        a=max-min
-        b=floor(log10(a))
-        c=pow(10.0,b)
-        low=c*floor(min/c)
-        high=c*ceil(max/c)
-        n = round((high-low)/c)
+                min -= 0.1 * a
+        a = max - min
+        b = floor(log10(a))
+        c = pow(10.0, b)
+        low = c * floor(min / c)
+        high = c * ceil(max / c)
+        n = round((high - low) / c)
         div = 2.0
         while n < 5 or n > 15:
             if n < 5:
@@ -246,50 +286,60 @@ def detScale(min=0,max=0):
             else:
                 c *= div
             if div == 2.0:
-                div =5.0
+                div = 5.0
             else:
-                div =2.0
-            low=c*floor(min/c)
-            high=c*ceil(max/c)
-            n = round((high-low)/c)
+                div = 2.0
+            low = c * floor(min / c)
+            high = c * ceil(max / c)
+            n = round((high - low) / c)
+
+        return [low, high, n]
 
-        return [low,high,n]
 
 def bluefunc(x):
-    return 1.0 / (1.0 + exp(-10*(x-0.6)))
+    return 1.0 / (1.0 + exp(-10 * (x - 0.6)))
+
 
 def redfunc(x):
-    return 1.0 / (1.0 + exp(10*(x-0.5)))
+    return 1.0 / (1.0 + exp(10 * (x - 0.5)))
+
 
 def greenfunc(x):
-    return 1 - pow(redfunc(x+0.2),2) - bluefunc(x-0.3)
+    return 1 - pow(redfunc(x + 0.2), 2) - bluefunc(x - 0.3)
+
 
 def colorSpectrum(n=100):
     multiple = 10
     if n == 1:
-        return [pid.Color(1,0,0)]
+        return [ImageColor.getrgb("rgb(100%,0%,0%)")]
     elif n == 2:
-        return [pid.Color(1,0,0),pid.Color(0,0,1)]
+        return [ImageColor.getrgb("100%,0%,0%)"),
+                ImageColor.getrgb("rgb(0%,0%,100%)")]
     elif n == 3:
-        return [pid.Color(1,0,0),pid.Color(0,1,0),pid.Color(0,0,1)]
-    N = n*multiple
-    out = [None]*N;
+        return [ImageColor.getrgb("rgb(100%,0%,0%)"),
+                ImageColor.getrgb("rgb(0%,100%,0%)"),
+                ImageColor.getrgb("rgb(0%,0%,100%)")]
+    N = n * multiple
+    out = [None] * N
     for i in range(N):
-        x = float(i)/N
-        out[i] = pid.Color(redfunc(x), greenfunc(x), bluefunc(x));
+        x = float(i) / N
+        out[i] = ImageColor.getrgb("rgb({}%,{}%,{}%".format(
+            *[int(i * 100) for i in (
+                redfunc(x), greenfunc(x), bluefunc(x))]))
     out2 = [out[0]]
-    step = N/float(n-1)
+    step = N / float(n - 1)
     j = 0
-    for i in range(n-2):
+    for i in range(n - 2):
         j += step
         out2.append(out[int(j)])
     out2.append(out[-1])
     return out2
 
+
 def _test():
     import doctest
     doctest.testmod()
 
 
-if __name__=="__main__":
-    _test()
\ No newline at end of file
+if __name__ == "__main__":
+    _test()
diff --git a/wqflask/utility/TDCell.py b/wqflask/utility/TDCell.py
index 8de8e050..4b0f4b1d 100644
--- a/wqflask/utility/TDCell.py
+++ b/wqflask/utility/TDCell.py
@@ -33,9 +33,9 @@
 
 class TDCell:
     def __init__(self, html="", text="", val=0.0):
-        self.html = html        #html, for web page
-        self.text = text        #text value, for output to a text file
-        self.val = val          #sort by value
+        self.html = html  # html, for web page
+        self.text = text  # text value, for output to a text file
+        self.val = val  # sort by value
 
     def __str__(self):
         return self.text
diff --git a/wqflask/utility/THCell.py b/wqflask/utility/THCell.py
index dde221b5..f533dcb8 100644
--- a/wqflask/utility/THCell.py
+++ b/wqflask/utility/THCell.py
@@ -33,10 +33,10 @@
 
 class THCell:
     def __init__(self, html="", text="", sort=1, idx=-1):
-        self.html = html        #html, for web page
-        self.text = text        #Column text value
-        self.sort = sort        #0: not sortable, 1: yes
-        self.idx = idx          #sort by value
+        self.html = html  # html, for web page
+        self.text = text  # Column text value
+        self.sort = sort  # 0: not sortable, 1: yes
+        self.idx = idx  # sort by value
 
     def __str__(self):
         return self.text
diff --git a/wqflask/utility/__init__.py b/wqflask/utility/__init__.py
index d9856eed..25273fa0 100644
--- a/wqflask/utility/__init__.py
+++ b/wqflask/utility/__init__.py
@@ -2,16 +2,18 @@ from pprint import pformat as pf
 
 # Todo: Move these out of __init__
 
-class Bunch(object):
+
+class Bunch:
     """Like a dictionary but using object notation"""
-    def __init__(self,  **kw):
-            self.__dict__ = kw
+
+    def __init__(self, **kw):
+        self.__dict__ = kw
 
     def __repr__(self):
         return pf(self.__dict__)
 
 
-class Struct(object):
+class Struct:
     '''The recursive class for building and representing objects with.
 
     From http://stackoverflow.com/a/6573827/1175849
@@ -19,7 +21,7 @@ class Struct(object):
     '''
 
     def __init__(self, obj):
-        for k, v in obj.iteritems():
+        for k, v in list(obj.items()):
             if isinstance(v, dict):
                 setattr(self, k, Struct(v))
             else:
@@ -30,6 +32,4 @@ class Struct(object):
 
     def __repr__(self):
         return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for
-            (k, v) in self.__dict__.iteritems()))
-
-
+                                      (k, v) in list(self.__dict__.items())))
diff --git a/wqflask/utility/after.py b/wqflask/utility/after.py
index b628a0a4..2b560e48 100644
--- a/wqflask/utility/after.py
+++ b/wqflask/utility/after.py
@@ -1,5 +1,3 @@
-from __future__ import print_function, division, absolute_import
-
 """
 See: http://flask.pocoo.org/docs/patterns/deferredcallbacks/#deferred-callbacks
 
@@ -9,8 +7,9 @@ from flask import g
 
 from wqflask import app
 
+
 def after_this_request(f):
     if not hasattr(g, 'after_request_callbacks'):
         g.after_request_callbacks = []
     g.after_request_callbacks.append(f)
-    return f
\ No newline at end of file
+    return f
diff --git a/wqflask/utility/authentication_tools.py b/wqflask/utility/authentication_tools.py
new file mode 100644
index 00000000..c4801c8c
--- /dev/null
+++ b/wqflask/utility/authentication_tools.py
@@ -0,0 +1,153 @@
+import json
+import requests
+
+from deprecated import deprecated
+from flask import g
+from base import webqtlConfig
+
+from utility.redis_tools import (get_redis_conn,
+                                 get_resource_info,
+                                 get_resource_id,
+                                 add_resource)
+from utility.tools import GN_PROXY_URL
+
+Redis = get_redis_conn()
+
+def check_resource_availability(dataset, trait_id=None):
+    # At least for now assume temporary entered traits are accessible
+    if type(dataset) == str or dataset.type == "Temp":
+        return webqtlConfig.DEFAULT_PRIVILEGES
+
+    resource_id = get_resource_id(dataset, trait_id)
+
+    # ZS: This should never be false, but it's technically possible if
+    # a non-Temp dataset somehow had a type other than
+    # Publish/ProbeSet/Geno
+    if resource_id:
+        resource_info = get_resource_info(resource_id)
+
+        # If resource isn't already in redis, add it with default
+        # privileges
+        if not resource_info:
+            resource_info = add_new_resource(dataset, trait_id)
+
+    # Check if super-user - we should probably come up with some
+    # way to integrate this into the proxy
+    if g.user_session.user_id in Redis.smembers("super_users"):
+        return webqtlConfig.SUPER_PRIVILEGES
+
+    response = None
+
+    the_url = GN_PROXY_URL + "available?resource={}&user={}".format(
+        resource_id, g.user_session.user_id)
+
+    try:
+        response = json.loads(requests.get(the_url).content)
+    except:
+        response = resource_info['default_mask']
+
+    return response
+
+
+def add_new_resource(dataset, trait_id=None):
+    resource_ob = {
+        'owner_id': "none",  # webqtlConfig.DEFAULT_OWNER_ID,
+        'default_mask': webqtlConfig.DEFAULT_PRIVILEGES,
+        'group_masks': {}
+    }
+
+    if dataset.type == "Publish":
+        group_code = get_group_code(dataset)
+        if group_code is None:
+            group_code = ""
+        resource_ob['name'] = group_code + "_" + str(trait_id)
+        resource_ob['data'] = {
+            'dataset': dataset.id,
+            'trait': trait_id
+        }
+        resource_ob['type'] = 'dataset-publish'
+    elif dataset.type == "Geno":
+        resource_ob['name'] = dataset.name
+        resource_ob['data'] = {
+            'dataset': dataset.id
+        }
+        resource_ob['type'] = 'dataset-geno'
+    else:
+        resource_ob['name'] = dataset.name
+        resource_ob['data'] = {
+            'dataset': dataset.id
+        }
+        resource_ob['type'] = 'dataset-probeset'
+
+    resource_info = add_resource(resource_ob, update=False)
+
+    return resource_info
+
+
+def get_group_code(dataset):
+    results = g.db.execute(
+        "SELECT InbredSetCode from InbredSet where Name='{}'".format(
+            dataset.group.name)).fetchone()
+    if results[0]:
+        return results[0]
+    else:
+        return ""
+
+
+def check_admin(resource_id=None):
+    the_url = GN_PROXY_URL + "available?resource={}&user={}".format(
+        resource_id, g.user_session.user_id)
+    try:
+        response = json.loads(requests.get(the_url).content)['admin']
+    except:
+        resource_info = get_resource_info(resource_id)
+        response = resource_info['default_mask']['admin']
+
+    if type(response) is list:
+        if 'edit-admins' in response:
+            return 'edit_admins'
+        elif 'edit-access' in response:
+            return 'edit-access'
+
+    return response
+
+
+def check_owner(dataset=None, trait_id=None, resource_id=None):
+    if resource_id:
+        resource_info = get_resource_info(resource_id)
+        if g.user_session.user_id == resource_info['owner_id']:
+            return resource_id
+    else:
+        resource_id = get_resource_id(dataset, trait_id)
+        if resource_id:
+            resource_info = get_resource_info(resource_id)
+            if g.user_session.user_id == resource_info['owner_id']:
+                return resource_id
+
+    return False
+
+
+@deprecated
+def check_owner_or_admin(dataset=None, trait_id=None, resource_id=None):
+    if not resource_id:
+        if dataset.type == "Temp":
+            return "not-admin"
+        else:
+            resource_id = get_resource_id(dataset, trait_id)
+
+    try:
+        user_id = g.user_session.user_id.encode('utf-8')
+    except:
+        user_id = g.user_session.user_id
+
+    if user_id in Redis.smembers("super_users"):
+        return "owner"
+
+    resource_info = get_resource_info(resource_id)
+    if resource_info:
+        if user_id == resource_info['owner_id']:
+            return "owner"
+        else:
+            return check_admin(resource_id)
+
+    return "not-admin"
diff --git a/wqflask/utility/benchmark.py b/wqflask/utility/benchmark.py
index 8f1c916b..6ece2f21 100644
--- a/wqflask/utility/benchmark.py
+++ b/wqflask/utility/benchmark.py
@@ -1,14 +1,13 @@
-from __future__ import print_function, division, absolute_import
-
 import collections
 import inspect
 import time
 from utility.tools import LOG_BENCH
 
 from utility.logger import getLogger
-logger = getLogger(__name__ )
+logger = getLogger(__name__)
+
 
-class Bench(object):
+class Bench:
     entries = collections.OrderedDict()
 
     def __init__(self, name=None, write_output=LOG_BENCH):
@@ -20,7 +19,8 @@ class Bench(object):
             if self.name:
                 logger.debug("Starting benchmark: %s" % (self.name))
             else:
-                logger.debug("Starting benchmark at: %s [%i]" % (inspect.stack()[1][3], inspect.stack()[1][2]))
+                logger.debug("Starting benchmark at: %s [%i]" % (
+                    inspect.stack()[1][3], inspect.stack()[1][2]))
         self.start_time = time.time()
 
     def __exit__(self, type, value, traceback):
@@ -34,14 +34,16 @@ class Bench(object):
             logger.info("  %s took: %f seconds" % (name, (time_taken)))
 
         if self.name:
-            Bench.entries[self.name] = Bench.entries.get(self.name, 0) + time_taken
+            Bench.entries[self.name] = Bench.entries.get(
+                self.name, 0) + time_taken
 
     @classmethod
     def report(cls):
-        total_time = sum((time_taken for time_taken in cls.entries.itervalues()))
+        total_time = sum(
+            (time_taken for time_taken in list(cls.entries.values())))
         print("\nTiming report\n")
-        for name, time_taken in cls.entries.iteritems():
-            percent = int(round((time_taken/total_time) * 100))
+        for name, time_taken in list(cls.entries.items()):
+            percent = int(round((time_taken / total_time) * 100))
             print("[{}%] {}: {}".format(percent, name, time_taken))
         print()
 
diff --git a/wqflask/utility/chunks.py b/wqflask/utility/chunks.py
index b0e33c08..484b5de6 100644
--- a/wqflask/utility/chunks.py
+++ b/wqflask/utility/chunks.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, print_function, division
-
 import math
 import time
 
@@ -28,69 +26,6 @@ def divide_into_chunks(the_list, number_chunks):
 
     chunks = []
     for counter in range(0, length, chunksize):
-        chunks.append(the_list[counter:counter+chunksize])
+        chunks.append(the_list[counter:counter + chunksize])
 
     return chunks
-
-def _confirm_chunk(original, result):
-    all_chunked = []
-    for chunk in result:
-        all_chunked.extend(chunk)
-    print("length of all chunked:", len(all_chunked))
-    assert original == all_chunked, "You didn't chunk right"
-
-
-def _chunk_test(divide_func):
-    import random
-    random.seed(7)
-
-    number_exact = 0
-    total_amount_off = 0
-
-    for test in range(1, 1001):
-        print("\n\ntest:", test)
-        number_chunks = random.randint(1, 20)
-        number_elements = random.randint(0, 100)
-        the_list = list(range(1, number_elements))
-        result = divide_func(the_list, number_chunks)
-
-        print("Dividing list of length {} into approximately {} chunks - got {} chunks".format(
-            len(the_list), number_chunks, len(result)))
-        print("result:", result)
-
-        _confirm_chunk(the_list, result)
-
-        amount_off = abs(number_chunks - len(result))
-        if amount_off == 0:
-            number_exact += 1
-        else:
-            total_amount_off += amount_off
-
-
-        print("\n{} exact out of {}    [Total amount off: {}]".format(number_exact,
-                                                                      test,
-                                                                      total_amount_off))
-    assert number_exact == 558
-    assert total_amount_off == 1580
-    return number_exact, total_amount_off
-
-
-def _main():
-    info = dict()
-    #funcs = (("sam", sam_divide_into_chunks), ("zach", zach_divide_into_chunks))
-    funcs = (("only one", divide_into_chunks),)
-    for name, func in funcs:
-        start = time.time()
-        number_exact, total_amount_off = _chunk_test(func)
-        took = time.time() - start
-        info[name] = dict(number_exact=number_exact,
-                          total_amount_off=total_amount_off,
-                          took=took)
-
-    print("info is:", info)
-
-if __name__ == '__main__':
-    _main()
-    print("\nConfirming doctests...")
-    import doctest
-    doctest.testmod()
diff --git a/wqflask/utility/corestats.py b/wqflask/utility/corestats.py
index 67ca3ad3..da0a21db 100644
--- a/wqflask/utility/corestats.py
+++ b/wqflask/utility/corestats.py
@@ -15,7 +15,9 @@
 
 import sys
 
-#ZS: Should switch to using some third party library for this; maybe scipy has an equivalent
+# ZS: Should switch to using some third party library for this; maybe scipy has an equivalent
+
+
 class Stats:
 
     def __init__(self, sequence):
@@ -63,7 +65,8 @@ class Stats:
         if len(self.sequence) < 1:
             value = None
         elif (percentile >= 100):
-            sys.stderr.write('ERROR: percentile must be < 100.  you supplied: %s\n'% percentile)
+            sys.stderr.write(
+                'ERROR: percentile must be < 100.  you supplied: %s\n' % percentile)
             value = None
         else:
             element_idx = int(len(self.sequence) * (percentile / 100.0))
@@ -80,4 +83,4 @@ class Stats:
 #    stats = corestats.Stats(sequence)
 #    print stats.avg()
 #    print stats.percentile(90)
-# -------------------------------------------
\ No newline at end of file
+# -------------------------------------------
diff --git a/wqflask/utility/corr_result_helpers.py b/wqflask/utility/corr_result_helpers.py
index b543c589..ea3ababf 100644
--- a/wqflask/utility/corr_result_helpers.py
+++ b/wqflask/utility/corr_result_helpers.py
@@ -14,15 +14,11 @@ def normalize_values(a_values, b_values):
     min_length = min(len(a_values), len(b_values))
     a_new = []
     b_new = []
-    for counter in range(min_length):
-        if (a_values[counter] or a_values[counter] == 0) and (b_values[counter] or b_values[counter] == 0):
-            a_new.append(a_values[counter])
-            b_new.append(b_values[counter])
-
-    num_overlap = len(a_new)
-    assert num_overlap == len(b_new), "Lengths should be the same"
-
-    return a_new, b_new, num_overlap
+    for a, b in zip(a_values, b_values):
+        if not (a == None or b == None):
+            a_new.append(a)
+            b_new.append(b)
+    return a_new, b_new, len(a_new)
 
 
 def common_keys(a_samples, b_samples):
@@ -37,20 +33,10 @@ def common_keys(a_samples, b_samples):
 
 def normalize_values_with_samples(a_samples, b_samples):
     common_samples = common_keys(a_samples, b_samples)
-
     a_new = {}
     b_new = {}
     for sample in common_samples:
         a_new[sample] = a_samples[sample]
         b_new[sample] = b_samples[sample]
 
-    num_overlap = len(a_new)
-    assert num_overlap == len(b_new), "Lengths should be the same"
-
-    return a_new, b_new, num_overlap
-
-
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
\ No newline at end of file
+    return a_new, b_new, len(a_new)
diff --git a/wqflask/utility/db_tools.py b/wqflask/utility/db_tools.py
index 4034f39c..6e19778f 100644
--- a/wqflask/utility/db_tools.py
+++ b/wqflask/utility/db_tools.py
@@ -1,6 +1,5 @@
-from __future__ import absolute_import, print_function, division
+from MySQLdb import escape_string as escape_
 
-from MySQLdb import escape_string as escape
 
 def create_in_clause(items):
     """Create an in clause for mysql"""
@@ -8,8 +7,11 @@ def create_in_clause(items):
     in_clause = '( {} )'.format(in_clause)
     return in_clause
 
+
 def mescape(*items):
     """Multiple escape"""
-    escaped = [escape(str(item)) for item in items]
-    #print("escaped is:", escaped)
-    return escaped
+    return [escape_(str(item)).decode('utf8') for item in items]
+
+
+def escape(string_):
+    return escape_(string_).decode('utf8')
diff --git a/wqflask/utility/elasticsearch_tools.py b/wqflask/utility/elasticsearch_tools.py
index 15cdd0bc..eae3ba03 100644
--- a/wqflask/utility/elasticsearch_tools.py
+++ b/wqflask/utility/elasticsearch_tools.py
@@ -47,11 +47,14 @@ logger = getLogger(__name__)
 
 from utility.tools import ELASTICSEARCH_HOST, ELASTICSEARCH_PORT
 
+
 def test_elasticsearch_connection():
-    es = Elasticsearch(['http://'+ELASTICSEARCH_HOST+":"+str(ELASTICSEARCH_PORT)+'/'], verify_certs=True)
+    es = Elasticsearch(['http://' + ELASTICSEARCH_HOST + \
+                        ":" + str(ELASTICSEARCH_PORT) + '/'], verify_certs=True)
     if not es.ping():
         logger.warning("Elasticsearch is DOWN")
 
+
 def get_elasticsearch_connection(for_user=True):
     """Return a connection to ES. Returns None on failure"""
     logger.info("get_elasticsearch_connection")
@@ -59,7 +62,7 @@ def get_elasticsearch_connection(for_user=True):
     try:
         assert(ELASTICSEARCH_HOST)
         assert(ELASTICSEARCH_PORT)
-        logger.info("ES HOST",ELASTICSEARCH_HOST)
+        logger.info("ES HOST", ELASTICSEARCH_HOST)
 
         es = Elasticsearch([{
             "host": ELASTICSEARCH_HOST, "port": ELASTICSEARCH_PORT
@@ -77,6 +80,7 @@ def get_elasticsearch_connection(for_user=True):
 
     return es
 
+
 def setup_users_index(es_connection):
     if es_connection:
         index_settings = {
@@ -85,20 +89,24 @@ def setup_users_index(es_connection):
                     "type": "keyword"}}}
 
         es_connection.indices.create(index='users', ignore=400)
-        es_connection.indices.put_mapping(body=index_settings, index="users", doc_type="local")
+        es_connection.indices.put_mapping(
+            body=index_settings, index="users", doc_type="local")
+
 
 def get_user_by_unique_column(es, column_name, column_value, index="users", doc_type="local"):
     return get_item_by_unique_column(es, column_name, column_value, index=index, doc_type=doc_type)
 
+
 def save_user(es, user, user_id):
     es_save_data(es, "users", "local", user, user_id)
 
+
 def get_item_by_unique_column(es, column_name, column_value, index, doc_type):
     item_details = None
     try:
         response = es.search(
-            index = index, doc_type = doc_type, body = {
-                "query": { "match": { column_name: column_value } }
+            index=index, doc_type=doc_type, body={
+                "query": {"match": {column_name: column_value}}
             })
         if len(response["hits"]["hits"]) > 0:
             item_details = response["hits"]["hits"][0]["_source"]
@@ -106,7 +114,8 @@ def get_item_by_unique_column(es, column_name, column_value, index, doc_type):
         pass
     return item_details
 
+
 def es_save_data(es, index, doc_type, data_item, data_id,):
     from time import sleep
     es.create(index, doc_type, body=data_item, id=data_id)
-    sleep(1) # Delay 1 second to allow indexing
+    sleep(1)  # Delay 1 second to allow indexing
diff --git a/wqflask/utility/external.py b/wqflask/utility/external.py
index 50afea08..805d2ffe 100644
--- a/wqflask/utility/external.py
+++ b/wqflask/utility/external.py
@@ -4,6 +4,7 @@ import os
 import sys
 import subprocess
 
+
 def shell(command):
     if subprocess.call(command, shell=True) != 0:
-        raise Exception("ERROR: failed on "+command)
+        raise Exception("ERROR: failed on " + command)
diff --git a/wqflask/utility/formatting.py b/wqflask/utility/formatting.py
index e53dda22..1da3e9b7 100644
--- a/wqflask/utility/formatting.py
+++ b/wqflask/utility/formatting.py
@@ -28,21 +28,20 @@ def numify(number, singular=None, plural=None):
     '12,334 hippopotami'
 
     """
-    num_repr = {1 : "one",
-                2 : "two",
-                3 : "three",
-                4 : "four",
-                5 : "five",
-                6 : "six",
-                7 : "seven",
-                8 : "eight",
-                9 : "nine",
-                10 : "ten",
-                11 : "eleven",
-                12 : "twelve"}
-
-    #Below line commented out cause doesn't work in Python 2.4
-    #assert all((singular, plural)) or not any((singular, plural)), "Need to pass two words or none"
+    num_repr = {0: "zero",
+                1: "one",
+                2: "two",
+                3: "three",
+                4: "four",
+                5: "five",
+                6: "six",
+                7: "seven",
+                8: "eight",
+                9: "nine",
+                10: "ten",
+                11: "eleven",
+                12: "twelve"}
+
     if number == 1:
         word = singular
     else:
diff --git a/wqflask/utility/gen_geno_ob.py b/wqflask/utility/gen_geno_ob.py
index 23b0b650..e619b7b6 100644
--- a/wqflask/utility/gen_geno_ob.py
+++ b/wqflask/utility/gen_geno_ob.py
@@ -1,9 +1,8 @@
-from __future__ import absolute_import, division, print_function
-
 import utility.logger
-logger = utility.logger.getLogger(__name__ )
+logger = utility.logger.getLogger(__name__)
+
 
-class genotype(object):
+class genotype:
     """
     Replacement for reaper.Dataset so we can remove qtlreaper use while still generating mapping output figure
     """
@@ -20,7 +19,7 @@ class genotype(object):
         self.filler = False
         self.mb_exists = False
 
-        #ZS: This is because I'm not sure if some files switch the column that contains Mb/cM positions; might be unnecessary
+        # ZS: This is because I'm not sure if some files switch the column that contains Mb/cM positions; might be unnecessary
         self.cm_column = 2
         self.mb_column = 3
 
@@ -38,14 +37,16 @@ class genotype(object):
         return len(self.chromosomes)
 
     def read_rdata_output(self, qtl_results):
-        #ZS: This is necessary because R/qtl requires centimorgan marker positions, which it normally gets from the .geno file, but that doesn't exist for HET3-ITP (which only has RData), so it needs to read in the marker cM positions from the results
-        self.chromosomes = [] #ZS: Overwriting since the .geno file's contents are just placeholders
+        # ZS: This is necessary because R/qtl requires centimorgan marker positions, which it normally gets from the .geno file, but that doesn't exist for HET3-ITP (which only has RData), so it needs to read in the marker cM positions from the results
+        # ZS: Overwriting since the .geno file's contents are just placeholders
+        self.chromosomes = []
 
-        this_chr = "" #ZS: This is so it can track when the chromosome changes as it iterates through markers
+        this_chr = ""  # ZS: This is so it can track when the chromosome changes as it iterates through markers
         chr_ob = None
         for marker in qtl_results:
             locus = Locus(self)
-            if (str(marker['chr']) != this_chr) and this_chr != "X": #ZS: This is really awkward but works as a temporary fix
+            # ZS: This is really awkward but works as a temporary fix
+            if (str(marker['chr']) != this_chr) and this_chr != "X":
                 if this_chr != "":
                     self.chromosomes.append(chr_ob)
                 this_chr = str(marker['chr'])
@@ -70,7 +71,7 @@ class genotype(object):
         with open(filename, 'r') as geno_file:
             lines = geno_file.readlines()
 
-            this_chr = "" #ZS: This is so it can track when the chromosome changes as it iterates through markers
+            this_chr = ""  # ZS: This is so it can track when the chromosome changes as it iterates through markers
             chr_ob = None
             for line in lines:
                 if line[0] == "#":
@@ -121,7 +122,8 @@ class genotype(object):
 
             self.chromosomes.append(chr_ob)
 
-class Chr(object):
+
+class Chr:
     def __init__(self, name, geno_ob):
         self.name = name
         self.loci = []
@@ -142,8 +144,9 @@ class Chr(object):
     def add_marker(self, marker_row):
         self.loci.append(Locus(self.geno_ob, marker_row))
 
-class Locus(object):
-    def __init__(self, geno_ob, marker_row = None):
+
+class Locus:
+    def __init__(self, geno_ob, marker_row=None):
         self.chr = None
         self.name = None
         self.cM = None
@@ -155,9 +158,11 @@ class Locus(object):
             try:
                 self.cM = float(marker_row[geno_ob.cm_column])
             except:
-                self.cM = float(marker_row[geno_ob.mb_column]) if geno_ob.mb_exists else 0
+                self.cM = float(
+                    marker_row[geno_ob.mb_column]) if geno_ob.mb_exists else 0
             try:
-                self.Mb = float(marker_row[geno_ob.mb_column]) if geno_ob.mb_exists else None
+                self.Mb = float(
+                    marker_row[geno_ob.mb_column]) if geno_ob.mb_exists else None
             except:
                 self.Mb = self.cM
 
@@ -175,7 +180,7 @@ class Locus(object):
                 start_pos = 3
 
             for allele in marker_row[start_pos:]:
-                if allele in geno_table.keys():
+                if allele in list(geno_table.keys()):
                     self.genotype.append(geno_table[allele])
-                else: #ZS: Some genotype appears that isn't specified in the metadata, make it unknown
-                    self.genotype.append("U")
\ No newline at end of file
+                else:  # ZS: Some genotype appears that isn't specified in the metadata, make it unknown
+                    self.genotype.append("U")
diff --git a/wqflask/utility/genofile_parser.py b/wqflask/utility/genofile_parser.py
index af306731..86d9823e 100644
--- a/wqflask/utility/genofile_parser.py
+++ b/wqflask/utility/genofile_parser.py
@@ -1,7 +1,6 @@
 # CTL analysis for GN2
 # Author / Maintainer: Danny Arends <Danny.Arends@gmail.com>
 
-from __future__ import print_function, division, absolute_import
 import sys
 import os
 import glob
@@ -13,88 +12,89 @@ import simplejson as json
 
 from pprint import pformat as pf
 
-class Marker(object):
-  def __init__(self):
-    self.name = None
-    self.chr = None
-    self.cM = None
-    self.Mb = None
-    self.genotypes = []
 
+class Marker:
+    def __init__(self):
+        self.name = None
+        self.chr = None
+        self.cM = None
+        self.Mb = None
+        self.genotypes = []
 
-class ConvertGenoFile(object):
 
-  def __init__(self, input_file):
-    self.mb_exists = False
-    self.cm_exists = False
-    self.markers = []
+class ConvertGenoFile:
 
-    self.latest_row_pos = None
-    self.latest_col_pos = None
+    def __init__(self, input_file):
+        self.mb_exists = False
+        self.cm_exists = False
+        self.markers = []
 
-    self.latest_row_value = None
-    self.latest_col_value = None
-    self.input_fh = open(input_file)
-    print("!!!!!!!!!!!!!!!!PARSER!!!!!!!!!!!!!!!!!!")
-    self.haplotype_notation = {
-      '@mat': "1",
-      '@pat': "2",
-      '@het': "-999",
-      '@unk': "-999"
-    }
-    self.configurations = {}
+        self.latest_row_pos = None
+        self.latest_col_pos = None
 
-  def process_rows(self):
-    for self.latest_row_pos, row in enumerate(self.input_fh):
-        self.latest_row_value = row
-        # Take care of headers
-        if not row.strip():
-            continue
-        if row.startswith('#'):
-            continue
-        if row.startswith('Chr'):
-            if 'Mb' in row.split():
-                self.mb_exists = True
-            if 'cM' in row.split():
-                self.cm_exists = True
-            skip = 2 + self.cm_exists + self.mb_exists
-            self.individuals = row.split()[skip:]
-            continue
-        if row.startswith('@'):
-            key, _separater, value = row.partition(':')
-            key = key.strip()
-            value = value.strip()
-            if key in self.haplotype_notation:
-                self.configurations[value] = self.haplotype_notation[key]
-            continue
-        if not len(self.configurations):
-            raise EmptyConfigurations
-        yield row
+        self.latest_row_value = None
+        self.latest_col_value = None
+        self.input_fh = open(input_file)
+        print("!!!!!!!!!!!!!!!!PARSER!!!!!!!!!!!!!!!!!!")
+        self.haplotype_notation = {
+            '@mat': "1",
+            '@pat': "2",
+            '@het': "-999",
+            '@unk': "-999"
+        }
+        self.configurations = {}
 
-  def process_csv(self):
-    for row in self.process_rows():
-      row_items = row.split("\t")
+    def process_rows(self):
+        for self.latest_row_pos, row in enumerate(self.input_fh):
+            self.latest_row_value = row
+            # Take care of headers
+            if not row.strip():
+                continue
+            if row.startswith('#'):
+                continue
+            if row.startswith('Chr'):
+                if 'Mb' in row.split():
+                    self.mb_exists = True
+                if 'cM' in row.split():
+                    self.cm_exists = True
+                skip = 2 + self.cm_exists + self.mb_exists
+                self.individuals = row.split()[skip:]
+                continue
+            if row.startswith('@'):
+                key, _separater, value = row.partition(':')
+                key = key.strip()
+                value = value.strip()
+                if key in self.haplotype_notation:
+                    self.configurations[value] = self.haplotype_notation[key]
+                continue
+            if not len(self.configurations):
+                raise EmptyConfigurations
+            yield row
 
-      this_marker = Marker()
-      this_marker.name = row_items[1]
-      this_marker.chr = row_items[0]
-      if self.cm_exists and self.mb_exists:
-        this_marker.cM = row_items[2]
-        this_marker.Mb = row_items[3]
-        genotypes = row_items[4:]
-      elif self.cm_exists:
-          this_marker.cM = row_items[2]
-          genotypes = row_items[3:]
-      elif self.mb_exists:
-          this_marker.Mb = row_items[2]
-          genotypes = row_items[3:]
-      else:
-        genotypes = row_items[2:]
-      for item_count, genotype in enumerate(genotypes):
-        if genotype.upper().strip() in self.configurations:
-          this_marker.genotypes.append(self.configurations[genotype.upper().strip()])
-        else:
-          print("WARNING:", genotype.upper())
-          this_marker.genotypes.append("NA")
-      self.markers.append(this_marker.__dict__)
+    def process_csv(self):
+        for row in self.process_rows():
+            row_items = row.split("\t")
 
+            this_marker = Marker()
+            this_marker.name = row_items[1]
+            this_marker.chr = row_items[0]
+            if self.cm_exists and self.mb_exists:
+                this_marker.cM = row_items[2]
+                this_marker.Mb = row_items[3]
+                genotypes = row_items[4:]
+            elif self.cm_exists:
+                this_marker.cM = row_items[2]
+                genotypes = row_items[3:]
+            elif self.mb_exists:
+                this_marker.Mb = row_items[2]
+                genotypes = row_items[3:]
+            else:
+                genotypes = row_items[2:]
+            for item_count, genotype in enumerate(genotypes):
+                if genotype.upper().strip() in self.configurations:
+                    this_marker.genotypes.append(
+                        self.configurations[genotype.upper().strip()])
+                else:
+                    print("WARNING:", genotype.upper())
+                    this_marker.genotypes.append("NA")
+            self.markers.append(this_marker.__dict__)
diff --git a/wqflask/utility/helper_functions.py b/wqflask/utility/helper_functions.py
index e7c04fef..27dd0729 100644
--- a/wqflask/utility/helper_functions.py
+++ b/wqflask/utility/helper_functions.py
@@ -1,72 +1,68 @@
-from __future__ import absolute_import, print_function, division
-
-from base.trait import GeneralTrait
 from base import data_set
+from base.trait import create_trait
 from base.species import TheSpecies
 
 from utility import hmac
 
-from flask import Flask, g
+from flask import g
 
 import logging
-logger = logging.getLogger(__name__ )
+logger = logging.getLogger(__name__)
 
 
 def get_species_dataset_trait(self, start_vars):
-    #assert type(read_genotype) == type(bool()), "Expecting boolean value for read_genotype"
-    if "temp_trait" in start_vars.keys():
-      if start_vars['temp_trait'] == "True":
-        self.dataset = data_set.create_dataset(dataset_name = "Temp", dataset_type = "Temp", group_name = start_vars['group'])
-      else:
-        self.dataset = data_set.create_dataset(start_vars['dataset'])
+    if "temp_trait" in list(start_vars.keys()):
+        if start_vars['temp_trait'] == "True":
+            self.dataset = data_set.create_dataset(
+                dataset_name="Temp",
+                dataset_type="Temp",
+                group_name=start_vars['group'])
+        else:
+            self.dataset = data_set.create_dataset(start_vars['dataset'])
     else:
-      self.dataset = data_set.create_dataset(start_vars['dataset'])
-    logger.debug("After creating dataset")
+        self.dataset = data_set.create_dataset(start_vars['dataset'])
     self.species = TheSpecies(dataset=self.dataset)
-    logger.debug("After creating species")
-    self.this_trait = GeneralTrait(dataset=self.dataset,
+    self.this_trait = create_trait(dataset=self.dataset,
                                    name=start_vars['trait_id'],
                                    cellid=None,
                                    get_qtl_info=True)
-    logger.debug("After creating trait")
-
-    #if read_genotype:
-    #self.dataset.group.read_genotype_file()
-    #self.genotype = self.dataset.group.genotype
-
 
 def get_trait_db_obs(self, trait_db_list):
-    if isinstance(trait_db_list, basestring):
+    if isinstance(trait_db_list, str):
         trait_db_list = trait_db_list.split(",")
 
     self.trait_list = []
     for trait in trait_db_list:
         data, _separator, hmac_string = trait.rpartition(':')
         data = data.strip()
-        assert hmac_string==hmac.hmac_creation(data), "Data tampering?"
-        trait_name, dataset_name = data.split(":")
+        assert hmac_string == hmac.hmac_creation(data), "Data tampering?"
+        trait_name, dataset_name = data.split(":")[:2]
         if dataset_name == "Temp":
-            dataset_ob = data_set.create_dataset(dataset_name=dataset_name, dataset_type="Temp", group_name=trait_name.split("_")[2])
+            dataset_ob = data_set.create_dataset(
+                dataset_name=dataset_name, dataset_type="Temp",
+                group_name=trait_name.split("_")[2])
         else:
             dataset_ob = data_set.create_dataset(dataset_name)
-        trait_ob = GeneralTrait(dataset=dataset_ob,
-                               name=trait_name,
-                               cellid=None)
-        self.trait_list.append((trait_ob, dataset_ob))
-
-def get_species_groups():
+        trait_ob = create_trait(dataset=dataset_ob,
+                                name=trait_name,
+                                cellid=None)
+        if trait_ob:
+            self.trait_list.append((trait_ob, dataset_ob))
 
-    species_query = "SELECT SpeciesId, MenuName FROM Species"
-    species_ids_and_names = g.db.execute(species_query).fetchall()
 
-    species_and_groups = []
-    for species_id, species_name in species_ids_and_names:
-        this_species_groups = {}
-        this_species_groups['species'] = species_name
-        groups_query = "SELECT InbredSetName FROM InbredSet WHERE SpeciesId = %s" % (species_id)
-        groups = [group[0] for group in g.db.execute(groups_query).fetchall()]
-
-        this_species_groups['groups'] = groups
-        species_and_groups.append(this_species_groups)
+def get_species_groups():
+    """Group each species into a group"""
+    _menu = {}
 
-    return species_and_groups
+    for species, group_name in g.db.execute(
+            "SELECT s.MenuName, i.InbredSetName FROM InbredSet i "
+            "INNER JOIN Species s ON s.SpeciesId = i.SpeciesId "
+            "ORDER BY i.SpeciesId ASC, i.Name ASC").fetchall():
+        if species in _menu:
+            if _menu.get(species):
+                _menu = _menu[species].append(group_name)
+            else:
+                _menu[species] = [group_name]
+    return [{"species": key,
+             "groups": value} for key, value in
+            list(_menu.items())]
diff --git a/wqflask/utility/hmac.py b/wqflask/utility/hmac.py
index d8a0eace..d6e515ed 100644
--- a/wqflask/utility/hmac.py
+++ b/wqflask/utility/hmac.py
@@ -1,16 +1,21 @@
-from __future__ import print_function, division, absolute_import
-
 import hmac
 import hashlib
 
+from deprecated import deprecated
+from flask import url_for
+
 from wqflask import app
 
+
+@deprecated("This function leads to circular imports. "
+            "If possible use wqflask.decorators.create_hmac instead.")
 def hmac_creation(stringy):
     """Helper function to create the actual hmac"""
 
     secret = app.config['SECRET_HMAC_CODE']
-
-    hmaced = hmac.new(secret, stringy, hashlib.sha1)
+    hmaced = hmac.new(bytearray(secret, "latin-1"),
+                      bytearray(stringy, "utf-8"),
+                      hashlib.sha1)
     hm = hmaced.hexdigest()
     # ZS: Leaving the below comment here to ask Pjotr about
     # "Conventional wisdom is that you don't lose much in terms of security if you throw away up to half of the output."
@@ -18,10 +23,12 @@ def hmac_creation(stringy):
     hm = hm[:20]
     return hm
 
+
 def data_hmac(stringy):
-    """Takes arbitray data string and appends :hmac so we know data hasn't been tampered with"""
+    """Takes arbitrary data string and appends :hmac so we know data hasn't been tampered with"""
     return stringy + ":" + hmac_creation(stringy)
 
+
 def url_for_hmac(endpoint, **values):
     """Like url_for but adds an hmac at the end to insure the url hasn't been tampered with"""
 
@@ -34,5 +41,6 @@ def url_for_hmac(endpoint, **values):
         combiner = "?"
     return url + combiner + "hm=" + hm
 
+
 app.jinja_env.globals.update(url_for_hmac=url_for_hmac,
-                             data_hmac=data_hmac)
\ No newline at end of file
+                             data_hmac=data_hmac)
diff --git a/wqflask/utility/logger.py b/wqflask/utility/logger.py
index 510b1041..d706e32a 100644
--- a/wqflask/utility/logger.py
+++ b/wqflask/utility/logger.py
@@ -35,6 +35,7 @@ import datetime
 
 from utility.tools import LOG_LEVEL, LOG_LEVEL_DEBUG, LOG_SQL
 
+
 class GNLogger:
     """A logger class with some additional functionality, such as
     multiple parameter logging, SQL logging, timing, colors, and lazy
@@ -42,52 +43,52 @@ class GNLogger:
 
     """
 
-    def __init__(self,name):
+    def __init__(self, name):
         self.logger = logging.getLogger(name)
 
-    def setLevel(self,value):
+    def setLevel(self, value):
         """Set the undelying log level"""
         self.logger.setLevel(value)
 
-    def debug(self,*args):
+    def debug(self, *args):
         """Call logging.debug for multiple args. Use (lazy) debugf and
 level=num to filter on LOG_LEVEL_DEBUG.
 
         """
-        self.collect(self.logger.debug,*args)
+        self.collect(self.logger.debug, *args)
 
-    def debug20(self,*args):
+    def debug20(self, *args):
         """Call logging.debug for multiple args. Use level=num to filter on
 LOG_LEVEL_DEBUG (NYI).
 
         """
         if level <= LOG_LEVEL_DEBUG:
             if self.logger.getEffectiveLevel() < 20:
-                self.collect(self.logger.debug,*args)
+                self.collect(self.logger.debug, *args)
 
-    def info(self,*args):
+    def info(self, *args):
         """Call logging.info for multiple args"""
-        self.collect(self.logger.info,*args)
+        self.collect(self.logger.info, *args)
 
-    def warning(self,*args):
+    def warning(self, *args):
         """Call logging.warning for multiple args"""
-        self.collect(self.logger.warning,*args)
+        self.collect(self.logger.warning, *args)
         # self.logger.warning(self.collect(*args))
 
-    def error(self,*args):
+    def error(self, *args):
         """Call logging.error for multiple args"""
         now = datetime.datetime.utcnow()
         time_str = now.strftime('%H:%M:%S UTC %Y%m%d')
-        l = [time_str]+list(args)
-        self.collect(self.logger.error,*l)
+        l = [time_str] + list(args)
+        self.collect(self.logger.error, *l)
 
-    def infof(self,*args):
+    def infof(self, *args):
         """Call logging.info for multiple args lazily"""
         # only evaluate function when logging
         if self.logger.getEffectiveLevel() < 30:
-            self.collectf(self.logger.debug,*args)
+            self.collectf(self.logger.debug, *args)
 
-    def debugf(self,level=0,*args):
+    def debugf(self, level=0, *args):
         """Call logging.debug for multiple args lazily and handle
         LOG_LEVEL_DEBUG correctly
 
@@ -95,38 +96,38 @@ LOG_LEVEL_DEBUG (NYI).
         # only evaluate function when logging
         if level <= LOG_LEVEL_DEBUG:
             if self.logger.getEffectiveLevel() < 20:
-                self.collectf(self.logger.debug,*args)
+                self.collectf(self.logger.debug, *args)
 
-    def sql(self, sqlcommand, fun = None):
+    def sql(self, sqlcommand, fun=None):
         """Log SQL command, optionally invoking a timed fun"""
         if LOG_SQL:
             caller = stack()[1][3]
-            if caller in ['fetchone','fetch1','fetchall']:
+            if caller in ['fetchone', 'fetch1', 'fetchall']:
                 caller = stack()[2][3]
-            self.info(caller,sqlcommand)
+            self.info(caller, sqlcommand)
         if fun:
             result = fun(sqlcommand)
             if LOG_SQL:
                 self.info(result)
             return result
 
-    def collect(self,fun,*args):
+    def collect(self, fun, *args):
         """Collect arguments and use fun to output"""
-        out = "."+stack()[2][3]
+        out = "." + stack()[2][3]
         for a in args:
-            if len(out)>1:
+            if len(out) > 1:
                 out += ": "
             if isinstance(a, str):
                 out = out + a
             else:
-                out = out + pf(a,width=160)
+                out = out + pf(a, width=160)
         fun(out)
 
-    def collectf(self,fun,*args):
+    def collectf(self, fun, *args):
         """Collect arguments and use fun to output one by one"""
-        out = "."+stack()[2][3]
+        out = "." + stack()[2][3]
         for a in args:
-            if len(out)>1:
+            if len(out) > 1:
                 out += ": "
                 if isfunction(a):
                     out += a()
@@ -134,12 +135,14 @@ LOG_LEVEL_DEBUG (NYI).
                     if isinstance(a, str):
                         out = out + a
                     else:
-                        out = out + pf(a,width=160)
+                        out = out + pf(a, width=160)
         fun(out)
 
 # Get the module logger. You can override log levels at the
 # module level
-def getLogger(name, level = None):
+
+
+def getLogger(name, level=None):
     gnlogger = GNLogger(name)
     logger = gnlogger.logger
 
@@ -148,5 +151,6 @@ def getLogger(name, level = None):
     else:
         logger.setLevel(LOG_LEVEL)
 
-    logger.info("Log level of "+name+" set to "+logging.getLevelName(logger.getEffectiveLevel()))
+    logger.info("Log level of " + name + " set to " + \
+                logging.getLevelName(logger.getEffectiveLevel()))
     return gnlogger
diff --git a/wqflask/utility/pillow_utils.py b/wqflask/utility/pillow_utils.py
new file mode 100644
index 00000000..5713e155
--- /dev/null
+++ b/wqflask/utility/pillow_utils.py
@@ -0,0 +1,31 @@
+from PIL import Image, ImageColor, ImageDraw, ImageFont
+
+from utility.tools import TEMPDIR
+
+import utility.logger
+logger = utility.logger.getLogger(__name__)
+
+BLACK = ImageColor.getrgb("black")
+WHITE = ImageColor.getrgb("white")
+
+# def draw_rotated_text(canvas: Image, text: str, font: ImageFont, xy: tuple, fill: ImageColor=BLACK, angle: int=-90):
+
+
+def draw_rotated_text(canvas, text, font, xy, fill=BLACK, angle=-90):
+    # type: (Image, str, ImageFont, tuple, ImageColor, int)
+    """Utility function draw rotated text"""
+    tmp_img = Image.new("RGBA", font.getsize(text), color=(0, 0, 0, 0))
+    draw_text = ImageDraw.Draw(tmp_img)
+    draw_text.text(text=text, xy=(0, 0), font=font, fill=fill)
+    tmp_img2 = tmp_img.rotate(angle, expand=1)
+    tmp_img2.save("/{0}/{1}.png".format(TEMPDIR, text), format="png")
+    canvas.paste(im=tmp_img2, box=tuple([int(i) for i in xy]))
+
+# def draw_open_polygon(canvas: Image, xy: tuple, fill: ImageColor=WHITE, outline: ImageColor=BLACK):
+
+
+def draw_open_polygon(canvas, xy, fill=None, outline=BLACK, width=0):
+    # type: (Image, tuple, ImageColor, ImageColor)
+    draw_ctx = ImageDraw.Draw(canvas)
+    draw_ctx.polygon(xy, fill=fill)
+    draw_ctx.line(xy, fill=outline, width=width)
diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py
index ca42f7b7..c2a3b057 100644
--- a/wqflask/utility/redis_tools.py
+++ b/wqflask/utility/redis_tools.py
@@ -1,17 +1,23 @@
-from __future__ import print_function, division, absolute_import
-
+import uuid
 import simplejson as json
+import datetime
 
-import redis # used for collections
-Redis = redis.StrictRedis()
-
-import logging
-
-from flask import (render_template, flash)
+import redis  # used for collections
 
+from deprecated import deprecated
+from utility.hmac import hmac_creation
 from utility.logger import getLogger
 logger = getLogger(__name__)
 
+
+def get_redis_conn():
+    Redis = redis.StrictRedis(port=6379)
+    return Redis
+
+
+Redis = get_redis_conn()
+
+
 def is_redis_available():
     try:
         Redis.ping()
@@ -19,8 +25,16 @@ def is_redis_available():
         return False
     return True
 
+
+def load_json_from_redis(item_list, column_value):
+    if type(column_value) == str:
+        column_value = str.encode(column_value)
+    return json.loads(item_list[column_value])
+
+
 def get_user_id(column_name, column_value):
     user_list = Redis.hgetall("users")
+    key_list = []
     for key in user_list:
         user_ob = json.loads(user_list[key])
         if column_name in user_ob and user_ob[column_name] == column_value:
@@ -28,6 +42,7 @@ def get_user_id(column_name, column_value):
 
     return None
 
+
 def get_user_by_unique_column(column_name, column_value):
     item_details = None
 
@@ -38,16 +53,18 @@ def get_user_by_unique_column(column_name, column_value):
             if column_name in user_ob and user_ob[column_name] == column_value:
                 item_details = user_ob
     else:
-        item_details = json.loads(user_list[column_value])
+        item_details = load_json_from_redis(user_list, column_value)
 
     return item_details
 
+
 def set_user_attribute(user_id, column_name, column_value):
     user_info = json.loads(Redis.hget("users", user_id))
     user_info[column_name] = column_value
 
     Redis.hset("users", user_id, json.dumps(user_info))
 
+
 def get_user_collections(user_id):
     collections = None
     collections = Redis.hget("collections", user_id)
@@ -57,45 +74,64 @@ def get_user_collections(user_id):
     else:
         return []
 
+
 def save_user(user, user_id):
     Redis.hset("users", user_id, json.dumps(user))
 
+
 def save_collections(user_id, collections_ob):
     Redis.hset("collections", user_id, collections_ob)
 
+
 def save_verification_code(user_email, code):
     Redis.hset("verification_codes", code, user_email)
 
+
 def check_verification_code(code):
     email_address = None
     user_details = None
     email_address = Redis.hget("verification_codes", code)
-    return email_address
 
     if email_address:
-        user_details = get_user_by_unique_column('email_address', email_address)
-        return user_details
+        user_details = get_user_by_unique_column(
+            'email_address', email_address)
+        if user_details:
+            return user_details
+        else:
+            return None
     else:
         return None
-        flash("Invalid code: Password reset code does not exist or might have expired!", "error")
+
 
 def get_user_groups(user_id):
-    #ZS: Get the groups where a user is an admin or a member and return lists corresponding to those two sets of groups
-    admin_group_ids = []  #ZS: Group IDs where user is an admin
-    user_group_ids = []   #ZS: Group IDs where user is a regular user
+    # Get the groups where a user is an admin or a member and
+    # return lists corresponding to those two sets of groups
+    admin_group_ids = []  # Group IDs where user is an admin
+    user_group_ids = []  # Group IDs where user is a regular user
     groups_list = Redis.hgetall("groups")
-    for key in groups_list:
-        group_ob = json.loads(groups_list[key])
-        group_admins = set(group_ob['admins'])
-        group_users = set(group_ob['users'])
-        if user_id in group_admins:
-            admin_group_ids.append(group_ob['id'])
-        elif user_id in group_users:
-            user_group_ids.append(group_ob['id'])
-        else:
+    for group_id, group_details in groups_list.items():
+        try:
+            _details = json.loads(group_details)
+            group_admins = set([this_admin if this_admin else None for this_admin in _details['admins']])
+            group_members = set([this_member if this_member else None for this_member in _details['members']])
+            if user_id in group_admins:
+                admin_group_ids.append(group_id)
+            elif user_id in group_members:
+                user_group_ids.append(group_id)
+            else:
+                continue
+        except:
             continue
 
-    return admin_group_ids, user_group_ids
+    admin_groups = []
+    user_groups = []
+    for the_id in admin_group_ids:
+        admin_groups.append(get_group_info(the_id))
+    for the_id in user_group_ids:
+        user_groups.append(get_group_info(the_id))
+
+    return admin_groups, user_groups
+
 
 def get_group_info(group_id):
     group_json = Redis.hget("groups", group_id)
@@ -105,23 +141,26 @@ def get_group_info(group_id):
 
     return group_info
 
-def create_group(admin_member_ids, user_member_ids = [], group_name = ""):
+
+def create_group(admin_user_ids, member_user_ids=[],
+                 group_name="Default Group Name"):
     group_id = str(uuid.uuid4())
     new_group = {
-        "id"    : group_id,
-        "admins": admin_member_ids,
-        "users" : user_member_ids,
-        "name"  : group_name,
+        "id": group_id,
+        "admins": admin_user_ids,
+        "members": member_user_ids,
+        "name": group_name,
         "created_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p'),
         "changed_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p')
     }
 
-    Redis.hset("groups", group_id, new_group)
+    Redis.hset("groups", group_id, json.dumps(new_group))
 
     return new_group
 
+
 def delete_group(user_id, group_id):
-    #ZS: If user is an admin of a group, remove it from the groups hash
+    # ZS: If user is an admin of a group, remove it from the groups hash
     group_info = get_group_info(group_id)
     if user_id in group_info["admins"]:
         Redis.hdel("groups", group_id)
@@ -129,13 +168,19 @@ def delete_group(user_id, group_id):
     else:
         None
 
-def add_users_to_group(user_id, group_id, user_emails = [], admins = False): #ZS "admins" is just to indicate whether the users should be added to the groups admins or regular users set
+
+# ZS "admins" is just to indicate whether the users should be added to
+# the groups admins or regular users set
+def add_users_to_group(user_id, group_id, user_emails=[], admins=False):
     group_info = get_group_info(group_id)
-    if user_id in group_info["admins"]: #ZS: Just to make sure that the user is an admin for the group, even though they shouldn't be able to reach this point unless they are
+    # ZS: Just to make sure that the user is an admin for the group,
+    # even though they shouldn't be able to reach this point unless
+    # they are
+    if user_id in group_info["admins"]:
         if admins:
             group_users = set(group_info["admins"])
         else:
-            group_users = set(group_info["users"])
+            group_users = set(group_info["members"])
 
         for email in user_emails:
             user_id = get_user_id("email_address", email)
@@ -144,27 +189,98 @@ def add_users_to_group(user_id, group_id, user_emails = [], admins = False): #ZS
         if admins:
             group_info["admins"] = list(group_users)
         else:
-            group_info["users"] = list(group_users)
+            group_info["members"] = list(group_users)
 
-        group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p')
+        group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime(
+            '%b %d %Y %I:%M%p')
         Redis.hset("groups", group_id, json.dumps(group_info))
         return group_info
     else:
         return None
 
-def remove_users_from_group(user_id, users_to_remove_ids, group_id, user_type = "users"): #ZS: User type is because I assume admins can remove other admins
+
+# ZS: User type is because I assume admins can remove other admins
+def remove_users_from_group(user_id,
+                            users_to_remove_ids,
+                            group_id,
+                            user_type="members"):
     group_info = get_group_info(group_id)
+
     if user_id in group_info["admins"]:
+        users_to_remove_set = set(users_to_remove_ids)
+        # ZS: Make sure an admin can't remove themselves from a group,
+        # since I imagine we don't want groups to be able to become
+        # admin-less
+        if user_type == "admins" and user_id in users_to_remove_set:
+            users_to_remove_set.remove(user_id)
         group_users = set(group_info[user_type])
-        group_users -= set(users_to_remove_ids)
+        group_users -= users_to_remove_set
         group_info[user_type] = list(group_users)
-        group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p')
+        group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime(
+            '%b %d %Y %I:%M%p')
         Redis.hset("groups", group_id, json.dumps(group_info))
 
+
 def change_group_name(user_id, group_id, new_name):
     group_info = get_group_info(group_id)
     if user_id in group_info["admins"]:
         group_info["name"] = new_name
+        Redis.hset("groups", group_id, json.dumps(group_info))
         return group_info
     else:
-        return None
\ No newline at end of file
+        return None
+
+
+def get_resources():
+    resource_list = Redis.hgetall("resources")
+    return resource_list
+
+
+def get_resource_id(dataset, trait_id=None):
+    resource_id = False
+    if dataset.type == "Publish":
+        if trait_id:
+            resource_id = hmac_creation("{}:{}:{}".format(
+                'dataset-publish', dataset.id, trait_id))
+    elif dataset.type == "ProbeSet":
+        resource_id = hmac_creation(
+            "{}:{}".format('dataset-probeset', dataset.id))
+    elif dataset.type == "Geno":
+        resource_id = hmac_creation(
+            "{}:{}".format('dataset-geno', dataset.id))
+
+    return resource_id
+
+
+@deprecated
+def get_resource_info(resource_id):
+    resource_info = Redis.hget("resources", resource_id)
+    if resource_info:
+        return json.loads(resource_info)
+    else:
+        return None
+
+
+def add_resource(resource_info, update=True):
+    if 'trait' in resource_info['data']:
+        resource_id = hmac_creation('{}:{}:{}'.format(
+            str(resource_info['type']), str(
+                resource_info['data']['dataset']),
+            str(resource_info['data']['trait'])))
+    else:
+        resource_id = hmac_creation('{}:{}'.format(
+            str(resource_info['type']), str(resource_info['data']['dataset'])))
+
+    if update or not Redis.hexists("resources", resource_id):
+        Redis.hset("resources", resource_id, json.dumps(resource_info))
+
+    return resource_info
+
+
+def add_access_mask(resource_id, group_id, access_mask):
+    the_resource = get_resource_info(resource_id)
+    the_resource['group_masks'][group_id] = access_mask
+
+    Redis.hset("resources", resource_id, json.dumps(the_resource))
+
+    return the_resource
diff --git a/wqflask/utility/startup_config.py b/wqflask/utility/startup_config.py
index 817284dd..778fb64d 100644
--- a/wqflask/utility/startup_config.py
+++ b/wqflask/utility/startup_config.py
@@ -1,39 +1,44 @@
 
 from wqflask import app
-from utility.tools import WEBSERVER_MODE, show_settings, get_setting_int, get_setting, get_setting_bool
 
-import utility.logger
-logger = utility.logger.getLogger(__name__ )
+from utility.tools import WEBSERVER_MODE
+from utility.tools import show_settings
+from utility.tools import get_setting_int
+from utility.tools import get_setting
+from utility.tools import get_setting_bool
 
-BLUE  = '\033[94m'
+
+BLUE = '\033[94m'
 GREEN = '\033[92m'
-BOLD  = '\033[1m'
-ENDC  = '\033[0m'
+BOLD = '\033[1m'
+ENDC = '\033[0m'
+
 
 def app_config():
     app.config['SESSION_TYPE'] = 'filesystem'
     if not app.config.get('SECRET_KEY'):
         import os
         app.config['SECRET_KEY'] = str(os.urandom(24))
-
     mode = WEBSERVER_MODE
-    if mode == "DEV" or mode == "DEBUG":
+    if mode in ["DEV", "DEBUG"]:
         app.config['TEMPLATES_AUTO_RELOAD'] = True
-        # if mode == "DEBUG":
-        #     app.config['EXPLAIN_TEMPLATE_LOADING'] = True <--- use overriding app param instead
+        if mode == "DEBUG":
+            from flask_debugtoolbar import DebugToolbarExtension
+            app.debug = True
+            toolbar = DebugToolbarExtension(app)
+
     print("==========================================")
+
     show_settings()
 
     port = get_setting_int("SERVER_PORT")
 
     if get_setting_bool("USE_GN_SERVER"):
-        print("GN2 API server URL is ["+BLUE+get_setting("GN_SERVER_URL")+ENDC+"]")
+        print(f"GN2 API server URL is [{BLUE}GN_SERVER_URL{ENDC}]")
         import requests
         page = requests.get(get_setting("GN_SERVER_URL"))
         if page.status_code != 200:
             raise Exception("API server not found!")
-
-    # import utility.elasticsearch_tools as es
-    # es.test_elasticsearch_connection()
-
-    print("GN2 is running. Visit %s[http://localhost:%s/%s](%s)" % (BLUE,str(port),ENDC,get_setting("WEBSERVER_URL")))
+    print(f"GN2 is running. Visit {BLUE}"
+          f"[http://localhost:{str(port)}/{ENDC}]"
+          f"({get_setting('WEBSERVER_URL')})")
diff --git a/wqflask/utility/svg.py b/wqflask/utility/svg.py
index db13b9d1..eddb97da 100644
--- a/wqflask/utility/svg.py
+++ b/wqflask/utility/svg.py
@@ -25,54 +25,56 @@
 # Last updated by GeneNetwork Core Team 2010/10/20
 
 #!/usr/bin/env python
-##Copyright (c) 2002, Fedor Baart & Hans de Wit (Stichting Farmaceutische Kengetallen)
-##All rights reserved.
+# Copyright (c) 2002, Fedor Baart & Hans de Wit (Stichting Farmaceutische Kengetallen)
+# All rights reserved.
 ##
-##Redistribution and use in source and binary forms, with or without modification,
-##are permitted provided that the following conditions are met:
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
 ##
-##Redistributions of source code must retain the above copyright notice, this
-##list of conditions and the following disclaimer.
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
 ##
-##Redistributions in binary form must reproduce the above copyright notice,
-##this list of conditions and the following disclaimer in the documentation and/or
-##other materials provided with the distribution.
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution.
 ##
-##Neither the name of the Stichting Farmaceutische Kengetallen nor the names of
-##its contributors may be used to endorse or promote products derived from this
-##software without specific prior written permission.
+# Neither the name of the Stichting Farmaceutische Kengetallen nor the names of
+# its contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
 ##
-##THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-##AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-##IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-##DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-##FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-##DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-##SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-##CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-##OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-##OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Thanks to Gerald Rosennfellner for his help and useful comments.
 
-##Thanks to Gerald Rosennfellner for his help and useful comments.
-
-__doc__="""Use SVGdraw to generate your SVGdrawings.
+import sys
+import exceptions
+__doc__ = """Use SVGdraw to generate your SVGdrawings.
 
 SVGdraw uses an object model drawing and a method toXML to create SVG graphics
 by using easy to use classes and methods usualy you start by creating a drawing eg
 
     d=drawing()
-    #then you create a SVG root element
+    # then you create a SVG root element
     s=svg()
-    #then you add some elements eg a circle and add it to the svg root element
+    # then you add some elements eg a circle and add it to the svg root element
     c=circle()
-    #you can supply attributes by using named arguments.
+    # you can supply attributes by using named arguments.
     c=circle(fill='red',stroke='blue')
-    #or by updating the attributes attribute:
+    # or by updating the attributes attribute:
     c.attributes['stroke-width']=1
     s.addElement(c)
-    #then you add the svg root element to the drawing
+    # then you add the svg root element to the drawing
     d.setSVG(s)
-    #and finaly you xmlify the drawing
+    # and finaly you xmlify the drawing
     d.toXml()
 
 
@@ -82,7 +84,7 @@ This module was created using the SVG specification of www.w3c.org and the
 O'Reilly (www.oreilly.com) python books as information sources. A svg viewer
 is available from www.adobe.com"""
 
-__version__="1.0"
+__version__ = "1.0"
 
 # there are two possibilities to generate svg:
 # via a dom implementation and directly using <element>text</element> strings
@@ -93,33 +95,34 @@ __version__="1.0"
 # Note that PyXML is required for using the dom implementation.
 # It is also possible to use the standard minidom. But I didn't try that one.
 # Anyway the text based approach is about 60 times faster than using the full dom implementation.
-use_dom_implementation=0
+use_dom_implementation = 0
 
 
-import exceptions
-if use_dom_implementation<>0:
+if use_dom_implementation != 0:
     try:
         from xml.dom import implementation
         from xml.dom.ext import PrettyPrint
     except:
-        raise exceptions.ImportError, "PyXML is required for using the dom implementation"
-#The implementation is used for the creating the XML document.
-#The prettyprint module is used for converting the xml document object to a xml file
+        raise exceptions.ImportError(
+            "PyXML is required for using the dom implementation")
+# The implementation is used for the creating the XML document.
+# The prettyprint module is used for converting the xml document object to a xml file
+
+assert sys.version_info[0] >= 2
+if sys.version_info[1] < 2:
+    True = 1
+    False = 0
+    file = open
+
+sys.setrecursionlimit = 50
+# The recursion limit is set conservative so mistakes like s=svg() s.addElement(s)
+# won't eat up too much processor time.
+
+# the following code is pasted form xml.sax.saxutils
+# it makes it possible to run the code without the xml sax package installed
+# To make it possible to have <rubbish> in your text elements, it is necessary to escape the texts
+
 
-import sys
-assert sys.version_info[0]>=2
-if sys.version_info[1]<2:
-    True=1
-    False=0
-    file=open
-
-sys.setrecursionlimit=50
-#The recursion limit is set conservative so mistakes like s=svg() s.addElement(s)
-#won't eat up too much processor time.
-
-#the following code is pasted form xml.sax.saxutils
-#it makes it possible to run the code without the xml sax package installed
-#To make it possible to have <rubbish> in your text elements, it is necessary to escape the texts
 def _escape(data, entities={}):
     """Escape &, <, and > in a string of data.
 
@@ -127,13 +130,14 @@ def _escape(data, entities={}):
     the optional entities parameter.  The keys and values must all be
     strings; each key will be replaced with its corresponding value.
     """
-    #data = data.replace("&", "&amp;")
+    # data = data.replace("&", "&amp;")
     data = data.replace("<", "&lt;")
     data = data.replace(">", "&gt;")
-    for chars, entity in entities.items():
+    for chars, entity in list(entities.items()):
         data = data.replace(chars, entity)
     return data
 
+
 def _quoteattr(data, entities={}):
     """Escape and quote an attribute value.
 
@@ -156,96 +160,125 @@ def _quoteattr(data, entities={}):
     return data
 
 
-
 def _xypointlist(a):
     """formats a list of xy pairs"""
-    s=''
-    for e in a: #this could be done more elegant
-        s+=str(e)[1:-1] +'  '
+    s = ''
+    for e in a:  # this could be done more elegant
+        s += str(e)[1:-1] + '  '
     return s
 
+
 def _viewboxlist(a):
     """formats a tuple"""
-    s=''
+    s = ''
     for e in a:
-        s+=str(e)+' '
+        s += str(e) + ' '
     return s
 
+
 def _pointlist(a):
     """formats a list of numbers"""
     return str(a)[1:-1]
 
+
 class pathdata:
     """class used to create a pathdata object which can be used for a path.
     although most methods are pretty straightforward it might be useful to look at the SVG specification."""
-    #I didn't test the methods below.
-    def __init__(self,x=None,y=None):
-        self.path=[]
+    # I didn't test the methods below.
+
+    def __init__(self, x=None, y=None):
+        self.path = []
         if x is not None and y is not None:
-            self.path.append('M '+str(x)+' '+str(y))
+            self.path.append('M ' + str(x) + ' ' + str(y))
+
     def closepath(self):
         """ends the path"""
         self.path.append('z')
-    def move(self,x,y):
+
+    def move(self, x, y):
         """move to absolute"""
-        self.path.append('M '+str(x)+' '+str(y))
-    def relmove(self,x,y):
+        self.path.append('M ' + str(x) + ' ' + str(y))
+
+    def relmove(self, x, y):
         """move to relative"""
-        self.path.append('m '+str(x)+' '+str(y))
-    def line(self,x,y):
+        self.path.append('m ' + str(x) + ' ' + str(y))
+
+    def line(self, x, y):
         """line to absolute"""
-        self.path.append('L '+str(x)+' '+str(y))
-    def relline(self,x,y):
+        self.path.append('L ' + str(x) + ' ' + str(y))
+
+    def relline(self, x, y):
         """line to relative"""
-        self.path.append('l '+str(x)+' '+str(y))
-    def hline(self,x):
+        self.path.append('l ' + str(x) + ' ' + str(y))
+
+    def hline(self, x):
         """horizontal line to absolute"""
-        self.path.append('H'+str(x))
-    def relhline(self,x):
+        self.path.append('H' + str(x))
+
+    def relhline(self, x):
         """horizontal line to relative"""
-        self.path.append('h'+str(x))
-    def vline(self,y):
+        self.path.append('h' + str(x))
+
+    def vline(self, y):
         """verical line to absolute"""
-        self.path.append('V'+str(y))
-    def relvline(self,y):
+        self.path.append('V' + str(y))
+
+    def relvline(self, y):
         """vertical line to relative"""
-        self.path.append('v'+str(y))
-    def bezier(self,x1,y1,x2,y2,x,y):
+        self.path.append('v' + str(y))
+
+    def bezier(self, x1, y1, x2, y2, x, y):
         """bezier with xy1 and xy2 to xy absolut"""
-        self.path.append('C'+str(x1)+','+str(y1)+' '+str(x2)+','+str(y2)+' '+str(x)+','+str(y))
-    def relbezier(self,x1,y1,x2,y2,x,y):
+        self.path.append('C' + str(x1) + ',' + str(y1) + ' ' + str(x2)
+                         + ',' + str(y2) + ' ' + str(x) + ',' + str(y))
+
+    def relbezier(self, x1, y1, x2, y2, x, y):
         """bezier with xy1 and xy2 to xy relative"""
-        self.path.append('c'+str(x1)+','+str(y1)+' '+str(x2)+','+str(y2)+' '+str(x)+','+str(y))
-    def smbezier(self,x2,y2,x,y):
+        self.path.append('c' + str(x1) + ',' + str(y1) + ' ' + str(x2)
+                         + ',' + str(y2) + ' ' + str(x) + ',' + str(y))
+
+    def smbezier(self, x2, y2, x, y):
         """smooth bezier with xy2 to xy absolut"""
-        self.path.append('S'+str(x2)+','+str(y2)+' '+str(x)+','+str(y))
-    def relsmbezier(self,x2,y2,x,y):
+        self.path.append('S' + str(x2) + ',' + str(y2) + \
+                         ' ' + str(x) + ',' + str(y))
+
+    def relsmbezier(self, x2, y2, x, y):
         """smooth bezier with xy2 to xy relative"""
-        self.path.append('s'+str(x2)+','+str(y2)+' '+str(x)+','+str(y))
-    def qbezier(self,x1,y1,x,y):
+        self.path.append('s' + str(x2) + ',' + str(y2) + \
+                         ' ' + str(x) + ',' + str(y))
+
+    def qbezier(self, x1, y1, x, y):
         """quadratic bezier with xy1 to xy absolut"""
-        self.path.append('Q'+str(x1)+','+str(y1)+' '+str(x)+','+str(y))
-    def relqbezier(self,x1,y1,x,y):
+        self.path.append('Q' + str(x1) + ',' + str(y1) + \
+                         ' ' + str(x) + ',' + str(y))
+
+    def relqbezier(self, x1, y1, x, y):
         """quadratic bezier with xy1 to xy relative"""
-        self.path.append('q'+str(x1)+','+str(y1)+' '+str(x)+','+str(y))
-    def smqbezier(self,x,y):
+        self.path.append('q' + str(x1) + ',' + str(y1) + \
+                         ' ' + str(x) + ',' + str(y))
+
+    def smqbezier(self, x, y):
         """smooth quadratic bezier to xy absolut"""
-        self.path.append('T'+str(x)+','+str(y))
-    def relsmqbezier(self,x,y):
+        self.path.append('T' + str(x) + ',' + str(y))
+
+    def relsmqbezier(self, x, y):
         """smooth quadratic bezier to xy relative"""
-        self.path.append('t'+str(x)+','+str(y))
-    def ellarc(self,rx,ry,xrot,laf,sf,x,y):
+        self.path.append('t' + str(x) + ',' + str(y))
+
+    def ellarc(self, rx, ry, xrot, laf, sf, x, y):
         """elliptival arc with rx and ry rotating with xrot using large-arc-flag and sweep-flag  to xy absolut"""
-        self.path.append('A'+str(rx)+','+str(ry)+' '+str(xrot)+' '+str(laf)+' '+str(sf)+' '+str(x)+' '+str(y))
-    def relellarc(self,rx,ry,xrot,laf,sf,x,y):
+        self.path.append('A' + str(rx) + ',' + str(ry) + ' ' + str(xrot)
+                         + ' ' + str(laf) + ' ' + str(sf) + ' ' + str(x) + ' ' + str(y))
+
+    def relellarc(self, rx, ry, xrot, laf, sf, x, y):
         """elliptival arc with rx and ry rotating with xrot using large-arc-flag and sweep-flag  to xy relative"""
-        self.path.append('a'+str(rx)+','+str(ry)+' '+str(xrot)+' '+str(laf)+' '+str(sf)+' '+str(x)+' '+str(y))
+        self.path.append('a' + str(rx) + ',' + str(ry) + ' ' + str(xrot)
+                         + ' ' + str(laf) + ' ' + str(sf) + ' ' + str(x) + ' ' + str(y))
+
     def __repr__(self):
         return ' '.join(self.path)
 
 
-
-
 class SVGelement:
     """SVGelement(type,attributes,elements,text,namespace,**args)
     Creates a arbitrary svg element and is intended to be subclassed not used on its own.
@@ -256,62 +289,67 @@ class SVGelement:
     namespace. Note the elements==None, if elements = None:self.elements=[] construction.
     This is done because if you default to elements=[] every object has a reference
     to the same empty list."""
-    def __init__(self,type='',attributes=None,elements=None,text='',namespace='',cdata=None, **args):
-        self.type=type
-        if attributes==None:
-            self.attributes={}
+
+    def __init__(self, type='', attributes=None, elements=None, text='', namespace='', cdata=None, **args):
+        self.type = type
+        if attributes == None:
+            self.attributes = {}
         else:
-            self.attributes=attributes
-        if elements==None:
-            self.elements=[]
+            self.attributes = attributes
+        if elements == None:
+            self.elements = []
         else:
-            self.elements=elements
-        self.text=text
-        self.namespace=namespace
-        self.cdata=cdata
-        for arg in args.keys():
+            self.elements = elements
+        self.text = text
+        self.namespace = namespace
+        self.cdata = cdata
+        for arg in list(args.keys()):
             arg2 = arg.replace("__", ":")
             arg2 = arg2.replace("_", "-")
-            self.attributes[arg2]=args[arg]
-    def addElement(self,SVGelement):
+            self.attributes[arg2] = args[arg]
+
+    def addElement(self, SVGelement):
         """adds an element to a SVGelement
 
         SVGelement.addElement(SVGelement)
         """
         self.elements.append(SVGelement)
 
-    def toXml(self,level,f):
-        f.write('\t'*level)
-        f.write('<'+self.type)
-        for attkey in self.attributes.keys():
-            f.write(' '+_escape(str(attkey))+'='+_quoteattr(str(self.attributes[attkey])))
+    def toXml(self, level, f):
+        f.write('\t' * level)
+        f.write('<' + self.type)
+        for attkey in list(self.attributes.keys()):
+            f.write(' ' + _escape(str(attkey)) + '='
+                    + _quoteattr(str(self.attributes[attkey])))
         if self.namespace:
-            f.write(' xmlns="'+ _escape(str(self.namespace))+'" xmlns:xlink="http://www.w3.org/1999/xlink"')
+            f.write(' xmlns="' + _escape(str(self.namespace))
+                    + '" xmlns:xlink="http://www.w3.org/1999/xlink"')
         if self.elements or self.text or self.cdata:
             f.write('>')
         if self.elements:
             f.write('\n')
         for element in self.elements:
-            element.toXml(level+1,f)
+            element.toXml(level + 1, f)
         if self.cdata:
-            f.write('\n'+'\t'*(level+1)+'<![CDATA[')
+            f.write('\n' + '\t' * (level + 1) + '<![CDATA[')
             for line in self.cdata.splitlines():
-                f.write('\n'+'\t'*(level+2)+line)
-            f.write('\n'+'\t'*(level+1)+']]>\n')
+                f.write('\n' + '\t' * (level + 2) + line)
+            f.write('\n' + '\t' * (level + 1) + ']]>\n')
         if self.text:
-            if type(self.text)==type(''): #If the text is only text
+            if isinstance(self.text, type('')):  # If the text is only text
                 f.write(_escape(str(self.text)))
-            else:                         #If the text is a spannedtext class
+            else:  # If the text is a spannedtext class
                 f.write(str(self.text))
         if self.elements:
-            f.write('\t'*level+'</'+self.type+'>\n')
+            f.write('\t' * level + '</' + self.type + '>\n')
         elif self.text:
-            f.write('</'+self.type+'>\n')
+            f.write('</' + self.type + '>\n')
         elif self.cdata:
-            f.write('\t'*level+'</'+self.type+'>\n')
+            f.write('\t' * level + '</' + self.type + '>\n')
         else:
             f.write('/>\n')
 
+
 class tspan(SVGelement):
     """ts=tspan(text='',**args)
 
@@ -323,19 +361,22 @@ class tspan(SVGelement):
     st.addtspan(ts)
     t=text(3,5,st)
     """
-    def __init__(self,text=None,**args):
-        SVGelement.__init__(self,'tspan',**args)
-        if self.text<>None:
-            self.text=text
+
+    def __init__(self, text=None, **args):
+        SVGelement.__init__(self, 'tspan', **args)
+        if self.text != None:
+            self.text = text
+
     def __repr__(self):
-        s="<tspan"
-        for key,value in self.attributes.items():
-            s+= ' %s="%s"' % (key,value)
-        s+='>'
-        s+=self.text
-        s+='</tspan>'
+        s = "<tspan"
+        for key, value in list(self.attributes.items()):
+            s += ' %s="%s"' % (key, value)
+        s += '>'
+        s += self.text
+        s += '</tspan>'
         return s
 
+
 class tref(SVGelement):
     """tr=tref(link='',**args)
 
@@ -346,16 +387,19 @@ class tref(SVGelement):
     st.addtref(tr)
     t=text(3,5,st)
     """
-    def __init__(self,link,**args):
-        SVGelement.__init__(self,'tref',{'xlink:href':link},**args)
+
+    def __init__(self, link, **args):
+        SVGelement.__init__(self, 'tref', {'xlink:href': link}, **args)
+
     def __repr__(self):
-        s="<tref"
+        s = "<tref"
 
-        for key,value in self.attributes.items():
-            s+= ' %s="%s"' % (key,value)
-        s+='/>'
+        for key, value in list(self.attributes.items()):
+            s += ' %s="%s"' % (key, value)
+        s += '/>'
         return s
 
+
 class spannedtext:
     """st=spannedtext(textlist=[])
 
@@ -374,72 +418,74 @@ class spannedtext:
     st.addtext('This text is not bold')
     t=text(3,5,st)
     """
-    def __init__(self,textlist=None):
-        if textlist==None:
-            self.textlist=[]
+
+    def __init__(self, textlist=None):
+        if textlist == None:
+            self.textlist = []
         else:
-            self.textlist=textlist
-    def addtext(self,text=''):
+            self.textlist = textlist
+
+    def addtext(self, text=''):
         self.textlist.append(text)
-    def addtspan(self,tspan):
+
+    def addtspan(self, tspan):
         self.textlist.append(tspan)
-    def addtref(self,tref):
+
+    def addtref(self, tref):
         self.textlist.append(tref)
+
     def __repr__(self):
-        s=""
+        s = ""
         for element in self.textlist:
-            s+=str(element)
+            s += str(element)
         return s
 
+
 class rect(SVGelement):
     """r=rect(width,height,x,y,fill,stroke,stroke_width,**args)
 
     a rectangle is defined by a width and height and a xy pair
     """
-    def __init__(self,x=None,y=None,width=None,height=None,fill=None,stroke=None,stroke_width=None,**args):
-        if width==None or height==None:
-            if width<>None:
-                raise ValueError, 'height is required'
-            if height<>None:
-                raise ValueError, 'width is required'
-            else:
-                raise ValueError, 'both height and width are required'
-        SVGelement.__init__(self,'rect',{'width':width,'height':height},**args)
-        if x<>None:
-            self.attributes['x']=x
-        if y<>None:
-            self.attributes['y']=y
-        if fill<>None:
-            self.attributes['fill']=fill
-        if stroke<>None:
-            self.attributes['stroke']=stroke
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
+
+    def __init__(self, x=None, y=None, width=None, height=None, fill=None, stroke=None, stroke_width=None, **args):
+        if width == None or height == None:
+            raise ValueError('both height and width are required')
+
+        SVGelement.__init__(
+            self, 'rect', {'width': width, 'height': height}, **args)
+        if x != None:
+            self.attributes['x'] = x
+        if y != None:
+            self.attributes['y'] = y
+        if fill != None:
+            self.attributes['fill'] = fill
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
+
 
 class ellipse(SVGelement):
     """e=ellipse(rx,ry,x,y,fill,stroke,stroke_width,**args)
 
     an ellipse is defined as a center and a x and y radius.
     """
-    def __init__(self,cx=None,cy=None,rx=None,ry=None,fill=None,stroke=None,stroke_width=None,**args):
-        if rx==None or ry== None:
-            if rx<>None:
-                raise ValueError, 'rx is required'
-            if ry<>None:
-                raise ValueError, 'ry is required'
-            else:
-                raise ValueError, 'both rx and ry are required'
-        SVGelement.__init__(self,'ellipse',{'rx':rx,'ry':ry},**args)
-        if cx<>None:
-            self.attributes['cx']=cx
-        if cy<>None:
-            self.attributes['cy']=cy
-        if fill<>None:
-            self.attributes['fill']=fill
-        if stroke<>None:
-            self.attributes['stroke']=stroke
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
+
+    def __init__(self, cx=None, cy=None, rx=None, ry=None, fill=None, stroke=None, stroke_width=None, **args):
+        if rx == None or ry == None:
+            raise ValueError('both rx and ry are required')
+
+        SVGelement.__init__(self, 'ellipse', {'rx': rx, 'ry': ry}, **args)
+        if cx != None:
+            self.attributes['cx'] = cx
+        if cy != None:
+            self.attributes['cy'] = cy
+        if fill != None:
+            self.attributes['fill'] = fill
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
 
 
 class circle(SVGelement):
@@ -447,20 +493,22 @@ class circle(SVGelement):
 
     The circle creates an element using a x, y and radius values eg
     """
-    def __init__(self,cx=None,cy=None,r=None,fill=None,stroke=None,stroke_width=None,**args):
-        if r==None:
-            raise ValueError, 'r is required'
-        SVGelement.__init__(self,'circle',{'r':r},**args)
-        if cx<>None:
-            self.attributes['cx']=cx
-        if cy<>None:
-            self.attributes['cy']=cy
-        if fill<>None:
-            self.attributes['fill']=fill
-        if stroke<>None:
-            self.attributes['stroke']=stroke
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
+
+    def __init__(self, cx=None, cy=None, r=None, fill=None, stroke=None, stroke_width=None, **args):
+        if r == None:
+            raise ValueError('r is required')
+        SVGelement.__init__(self, 'circle', {'r': r}, **args)
+        if cx != None:
+            self.attributes['cx'] = cx
+        if cy != None:
+            self.attributes['cy'] = cy
+        if fill != None:
+            self.attributes['fill'] = fill
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
+
 
 class point(circle):
     """p=point(x,y,color)
@@ -468,72 +516,83 @@ class point(circle):
     A point is defined as a circle with a size 1 radius. It may be more efficient to use a
     very small rectangle if you use many points because a circle is difficult to render.
     """
-    def __init__(self,x,y,fill='black',**args):
-        circle.__init__(self,x,y,1,fill,**args)
+
+    def __init__(self, x, y, fill='black', **args):
+        circle.__init__(self, x, y, 1, fill, **args)
+
 
 class line(SVGelement):
     """l=line(x1,y1,x2,y2,stroke,stroke_width,**args)
 
     A line is defined by a begin x,y pair and an end x,y pair
     """
-    def __init__(self,x1=None,y1=None,x2=None,y2=None,stroke=None,stroke_width=None,**args):
-        SVGelement.__init__(self,'line',**args)
-        if x1<>None:
-            self.attributes['x1']=x1
-        if y1<>None:
-            self.attributes['y1']=y1
-        if x2<>None:
-            self.attributes['x2']=x2
-        if y2<>None:
-            self.attributes['y2']=y2
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
-        if stroke<>None:
-            self.attributes['stroke']=stroke
+
+    def __init__(self, x1=None, y1=None, x2=None, y2=None, stroke=None, stroke_width=None, **args):
+        SVGelement.__init__(self, 'line', **args)
+        if x1 != None:
+            self.attributes['x1'] = x1
+        if y1 != None:
+            self.attributes['y1'] = y1
+        if x2 != None:
+            self.attributes['x2'] = x2
+        if y2 != None:
+            self.attributes['y2'] = y2
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+
 
 class polyline(SVGelement):
     """pl=polyline([[x1,y1],[x2,y2],...],fill,stroke,stroke_width,**args)
 
     a polyline is defined by a list of xy pairs
     """
-    def __init__(self,points,fill=None,stroke=None,stroke_width=None,**args):
-        SVGelement.__init__(self,'polyline',{'points':_xypointlist(points)},**args)
-        if fill<>None:
-            self.attributes['fill']=fill
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
-        if stroke<>None:
-            self.attributes['stroke']=stroke
+
+    def __init__(self, points, fill=None, stroke=None, stroke_width=None, **args):
+        SVGelement.__init__(self, 'polyline', {
+                            'points': _xypointlist(points)}, **args)
+        if fill != None:
+            self.attributes['fill'] = fill
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+
 
 class polygon(SVGelement):
     """pl=polyline([[x1,y1],[x2,y2],...],fill,stroke,stroke_width,**args)
 
     a polygon is defined by a list of xy pairs
     """
-    def __init__(self,points,fill=None,stroke=None,stroke_width=None,**args):
-        SVGelement.__init__(self,'polygon',{'points':_xypointlist(points)},**args)
-        if fill<>None:
-            self.attributes['fill']=fill
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
-        if stroke<>None:
-            self.attributes['stroke']=stroke
+
+    def __init__(self, points, fill=None, stroke=None, stroke_width=None, **args):
+        SVGelement.__init__(
+            self, 'polygon', {'points': _xypointlist(points)}, **args)
+        if fill != None:
+            self.attributes['fill'] = fill
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+
 
 class path(SVGelement):
     """p=path(path,fill,stroke,stroke_width,**args)
 
     a path is defined by a path object and optional width, stroke and fillcolor
     """
-    def __init__(self,pathdata,fill=None,stroke=None,stroke_width=None,id=None,**args):
-        SVGelement.__init__(self,'path',{'d':str(pathdata)},**args)
-        if stroke<>None:
-            self.attributes['stroke']=stroke
-        if fill<>None:
-            self.attributes['fill']=fill
-        if stroke_width<>None:
-            self.attributes['stroke-width']=stroke_width
-        if id<>None:
-            self.attributes['id']=id
+
+    def __init__(self, pathdata, fill=None, stroke=None, stroke_width=None, id=None, **args):
+        SVGelement.__init__(self, 'path', {'d': str(pathdata)}, **args)
+        if stroke != None:
+            self.attributes['stroke'] = stroke
+        if fill != None:
+            self.attributes['fill'] = fill
+        if stroke_width != None:
+            self.attributes['stroke-width'] = stroke_width
+        if id != None:
+            self.attributes['id'] = id
 
 
 class text(SVGelement):
@@ -541,20 +600,21 @@ class text(SVGelement):
 
     a text element can bge used for displaying text on the screen
     """
-    def __init__(self,x=None,y=None,text=None,font_size=None,font_family=None,text_anchor=None,**args):
-        SVGelement.__init__(self,'text',**args)
-        if x<>None:
-            self.attributes['x']=x
-        if y<>None:
-            self.attributes['y']=y
-        if font_size<>None:
-            self.attributes['font-size']=font_size
-        if font_family<>None:
-            self.attributes['font-family']=font_family
-        if text<>None:
-            self.text=text
-        if text_anchor<>None:
-            self.attributes['text-anchor']=text_anchor
+
+    def __init__(self, x=None, y=None, text=None, font_size=None, font_family=None, text_anchor=None, **args):
+        SVGelement.__init__(self, 'text', **args)
+        if x != None:
+            self.attributes['x'] = x
+        if y != None:
+            self.attributes['y'] = y
+        if font_size != None:
+            self.attributes['font-size'] = font_size
+        if font_family != None:
+            self.attributes['font-family'] = font_family
+        if text != None:
+            self.text = text
+        if text_anchor != None:
+            self.attributes['text-anchor'] = text_anchor
 
 
 class textpath(SVGelement):
@@ -562,10 +622,12 @@ class textpath(SVGelement):
 
     a textpath places a text on a path which is referenced by a link.
     """
-    def __init__(self,link,text=None,**args):
-        SVGelement.__init__(self,'textPath',{'xlink:href':link},**args)
-        if text<>None:
-            self.text=text
+
+    def __init__(self, link, text=None, **args):
+        SVGelement.__init__(self, 'textPath', {'xlink:href': link}, **args)
+        if text != None:
+            self.text = text
+
 
 class pattern(SVGelement):
     """p=pattern(x,y,width,height,patternUnits,**args)
@@ -574,18 +636,20 @@ class pattern(SVGelement):
     graphic object which can be replicated ("tiled") at fixed intervals
     in x and y to cover the areas to be painted.
     """
-    def __init__(self,x=None,y=None,width=None,height=None,patternUnits=None,**args):
-        SVGelement.__init__(self,'pattern',**args)
-        if x<>None:
-            self.attributes['x']=x
-        if y<>None:
-            self.attributes['y']=y
-        if width<>None:
-            self.attributes['width']=width
-        if height<>None:
-            self.attributes['height']=height
-        if patternUnits<>None:
-            self.attributes['patternUnits']=patternUnits
+
+    def __init__(self, x=None, y=None, width=None, height=None, patternUnits=None, **args):
+        SVGelement.__init__(self, 'pattern', **args)
+        if x != None:
+            self.attributes['x'] = x
+        if y != None:
+            self.attributes['y'] = y
+        if width != None:
+            self.attributes['width'] = width
+        if height != None:
+            self.attributes['height'] = height
+        if patternUnits != None:
+            self.attributes['patternUnits'] = patternUnits
+
 
 class title(SVGelement):
     """t=title(text,**args)
@@ -593,10 +657,12 @@ class title(SVGelement):
     a title is a text element. The text is displayed in the title bar
     add at least one to the root svg element
     """
-    def __init__(self,text=None,**args):
-        SVGelement.__init__(self,'title',**args)
-        if text<>None:
-            self.text=text
+
+    def __init__(self, text=None, **args):
+        SVGelement.__init__(self, 'title', **args)
+        if text != None:
+            self.text = text
+
 
 class description(SVGelement):
     """d=description(text,**args)
@@ -604,10 +670,12 @@ class description(SVGelement):
     a description can be added to any element and is used for a tooltip
     Add this element before adding other elements.
     """
-    def __init__(self,text=None,**args):
-        SVGelement.__init__(self,'desc',**args)
-        if text<>None:
-            self.text=text
+
+    def __init__(self, text=None, **args):
+        SVGelement.__init__(self, 'desc', **args)
+        if text != None:
+            self.text = text
+
 
 class lineargradient(SVGelement):
     """lg=lineargradient(x1,y1,x2,y2,id,**args)
@@ -615,18 +683,20 @@ class lineargradient(SVGelement):
     defines a lineargradient using two xy pairs.
     stop elements van be added to define the gradient colors.
     """
-    def __init__(self,x1=None,y1=None,x2=None,y2=None,id=None,**args):
-        SVGelement.__init__(self,'linearGradient',**args)
-        if x1<>None:
-            self.attributes['x1']=x1
-        if y1<>None:
-            self.attributes['y1']=y1
-        if x2<>None:
-            self.attributes['x2']=x2
-        if y2<>None:
-            self.attributes['y2']=y2
-        if id<>None:
-            self.attributes['id']=id
+
+    def __init__(self, x1=None, y1=None, x2=None, y2=None, id=None, **args):
+        SVGelement.__init__(self, 'linearGradient', **args)
+        if x1 != None:
+            self.attributes['x1'] = x1
+        if y1 != None:
+            self.attributes['y1'] = y1
+        if x2 != None:
+            self.attributes['x2'] = x2
+        if y2 != None:
+            self.attributes['y2'] = y2
+        if id != None:
+            self.attributes['id'] = id
+
 
 class radialgradient(SVGelement):
     """rg=radialgradient(cx,cy,r,fx,fy,id,**args)
@@ -634,38 +704,43 @@ class radialgradient(SVGelement):
     defines a radial gradient using a outer circle which are defined by a cx,cy and r and by using a focalpoint.
     stop elements van be added to define the gradient colors.
     """
-    def __init__(self,cx=None,cy=None,r=None,fx=None,fy=None,id=None,**args):
-        SVGelement.__init__(self,'radialGradient',**args)
-        if cx<>None:
-            self.attributes['cx']=cx
-        if cy<>None:
-            self.attributes['cy']=cy
-        if r<>None:
-            self.attributes['r']=r
-        if fx<>None:
-            self.attributes['fx']=fx
-        if fy<>None:
-            self.attributes['fy']=fy
-        if id<>None:
-            self.attributes['id']=id
+
+    def __init__(self, cx=None, cy=None, r=None, fx=None, fy=None, id=None, **args):
+        SVGelement.__init__(self, 'radialGradient', **args)
+        if cx != None:
+            self.attributes['cx'] = cx
+        if cy != None:
+            self.attributes['cy'] = cy
+        if r != None:
+            self.attributes['r'] = r
+        if fx != None:
+            self.attributes['fx'] = fx
+        if fy != None:
+            self.attributes['fy'] = fy
+        if id != None:
+            self.attributes['id'] = id
+
 
 class stop(SVGelement):
     """st=stop(offset,stop_color,**args)
 
     Puts a stop color at the specified radius
     """
-    def __init__(self,offset,stop_color=None,**args):
-        SVGelement.__init__(self,'stop',{'offset':offset},**args)
-        if stop_color<>None:
-            self.attributes['stop-color']=stop_color
+
+    def __init__(self, offset, stop_color=None, **args):
+        SVGelement.__init__(self, 'stop', {'offset': offset}, **args)
+        if stop_color != None:
+            self.attributes['stop-color'] = stop_color
+
 
 class style(SVGelement):
     """st=style(type,cdata=None,**args)
 
     Add a CDATA element to this element for defing in line stylesheets etc..
     """
-    def __init__(self,type,cdata=None,**args):
-        SVGelement.__init__(self,'style',{'type':type},cdata=cdata, **args)
+
+    def __init__(self, type, cdata=None, **args):
+        SVGelement.__init__(self, 'style', {'type': type}, cdata=cdata, **args)
 
 
 class image(SVGelement):
@@ -673,27 +748,26 @@ class image(SVGelement):
 
     adds an image to the drawing. Supported formats are .png, .jpg and .svg.
     """
-    def __init__(self,url,x=None,y=None,width=None,height=None,**args):
-        if width==None or height==None:
-            if width<>None:
-                raise ValueError, 'height is required'
-            if height<>None:
-                raise ValueError, 'width is required'
-            else:
-                raise ValueError, 'both height and width are required'
-        SVGelement.__init__(self,'image',{'xlink:href':url,'width':width,'height':height},**args)
-        if x<>None:
-            self.attributes['x']=x
-        if y<>None:
-            self.attributes['y']=y
+
+    def __init__(self, url, x=None, y=None, width=None, height=None, **args):
+        if width == None or height == None:
+            raise ValueError('both height and width are required')
+        SVGelement.__init__(
+            self, 'image', {'xlink:href': url, 'width': width, 'height': height}, **args)
+        if x != None:
+            self.attributes['x'] = x
+        if y != None:
+            self.attributes['y'] = y
+
 
 class cursor(SVGelement):
     """c=cursor(url,**args)
 
     defines a custom cursor for a element or a drawing
     """
-    def __init__(self,url,**args):
-        SVGelement.__init__(self,'cursor',{'xlink:href':url},**args)
+
+    def __init__(self, url, **args):
+        SVGelement.__init__(self, 'cursor', {'xlink:href': url}, **args)
 
 
 class marker(SVGelement):
@@ -702,20 +776,22 @@ class marker(SVGelement):
     defines a marker which can be used as an endpoint for a line or other pathtypes
     add an element to it which should be used as a marker.
     """
-    def __init__(self,id=None,viewBox=None,refx=None,refy=None,markerWidth=None,markerHeight=None,**args):
-        SVGelement.__init__(self,'marker',**args)
-        if id<>None:
-            self.attributes['id']=id
-        if viewBox<>None:
-            self.attributes['viewBox']=_viewboxlist(viewBox)
-        if refx<>None:
-            self.attributes['refX']=refx
-        if refy<>None:
-            self.attributes['refY']=refy
-        if markerWidth<>None:
-            self.attributes['markerWidth']=markerWidth
-        if markerHeight<>None:
-            self.attributes['markerHeight']=markerHeight
+
+    def __init__(self, id=None, viewBox=None, refx=None, refy=None, markerWidth=None, markerHeight=None, **args):
+        SVGelement.__init__(self, 'marker', **args)
+        if id != None:
+            self.attributes['id'] = id
+        if viewBox != None:
+            self.attributes['viewBox'] = _viewboxlist(viewBox)
+        if refx != None:
+            self.attributes['refX'] = refx
+        if refy != None:
+            self.attributes['refY'] = refy
+        if markerWidth != None:
+            self.attributes['markerWidth'] = markerWidth
+        if markerHeight != None:
+            self.attributes['markerHeight'] = markerHeight
+
 
 class group(SVGelement):
     """g=group(id,**args)
@@ -723,10 +799,12 @@ class group(SVGelement):
     a group is defined by an id and is used to contain elements
     g.addElement(SVGelement)
     """
-    def __init__(self,id=None,**args):
-        SVGelement.__init__(self,'g',**args)
-        if id<>None:
-            self.attributes['id']=id
+
+    def __init__(self, id=None, **args):
+        SVGelement.__init__(self, 'g', **args)
+        if id != None:
+            self.attributes['id'] = id
+
 
 class symbol(SVGelement):
     """sy=symbol(id,viewbox,**args)
@@ -737,20 +815,23 @@ class symbol(SVGelement):
     sy.addElement(SVGelement)
     """
 
-    def __init__(self,id=None,viewBox=None,**args):
-        SVGelement.__init__(self,'symbol',**args)
-        if id<>None:
-            self.attributes['id']=id
-        if viewBox<>None:
-            self.attributes['viewBox']=_viewboxlist(viewBox)
+    def __init__(self, id=None, viewBox=None, **args):
+        SVGelement.__init__(self, 'symbol', **args)
+        if id != None:
+            self.attributes['id'] = id
+        if viewBox != None:
+            self.attributes['viewBox'] = _viewboxlist(viewBox)
+
 
 class defs(SVGelement):
     """d=defs(**args)
 
     container for defining elements
     """
-    def __init__(self,**args):
-        SVGelement.__init__(self,'defs',**args)
+
+    def __init__(self, **args):
+        SVGelement.__init__(self, 'defs', **args)
+
 
 class switch(SVGelement):
     """sw=switch(**args)
@@ -759,8 +840,9 @@ class switch(SVGelement):
     requiredFeatures, requiredExtensions and systemLanguage.
     Refer to the SVG specification for details.
     """
-    def __init__(self,**args):
-        SVGelement.__init__(self,'switch',**args)
+
+    def __init__(self, **args):
+        SVGelement.__init__(self, 'switch', **args)
 
 
 class use(SVGelement):
@@ -768,17 +850,18 @@ class use(SVGelement):
 
     references a symbol by linking to its id and its position, height and width
     """
-    def __init__(self,link,x=None,y=None,width=None,height=None,**args):
-        SVGelement.__init__(self,'use',{'xlink:href':link},**args)
-        if x<>None:
-            self.attributes['x']=x
-        if y<>None:
-            self.attributes['y']=y
 
-        if width<>None:
-            self.attributes['width']=width
-        if height<>None:
-            self.attributes['height']=height
+    def __init__(self, link, x=None, y=None, width=None, height=None, **args):
+        SVGelement.__init__(self, 'use', {'xlink:href': link}, **args)
+        if x != None:
+            self.attributes['x'] = x
+        if y != None:
+            self.attributes['y'] = y
+
+        if width != None:
+            self.attributes['width'] = width
+        if height != None:
+            self.attributes['height'] = height
 
 
 class link(SVGelement):
@@ -787,17 +870,21 @@ class link(SVGelement):
     a link  is defined by a hyperlink. add elements which have to be linked
     a.addElement(SVGelement)
     """
-    def __init__(self,link='',**args):
-        SVGelement.__init__(self,'a',{'xlink:href':link},**args)
+
+    def __init__(self, link='', **args):
+        SVGelement.__init__(self, 'a', {'xlink:href': link}, **args)
+
 
 class view(SVGelement):
     """v=view(id,**args)
 
     a view can be used to create a view with different attributes"""
-    def __init__(self,id=None,**args):
-        SVGelement.__init__(self,'view',**args)
-        if id<>None:
-            self.attributes['id']=id
+
+    def __init__(self, id=None, **args):
+        SVGelement.__init__(self, 'view', **args)
+        if id != None:
+            self.attributes['id'] = id
+
 
 class script(SVGelement):
     """sc=script(type,type,cdata,**args)
@@ -805,78 +892,94 @@ class script(SVGelement):
     adds a script element which contains CDATA to the SVG drawing
 
     """
-    def __init__(self,type,cdata=None,**args):
-        SVGelement.__init__(self,'script',{'type':type},cdata=cdata,**args)
+
+    def __init__(self, type, cdata=None, **args):
+        SVGelement.__init__(
+            self, 'script', {'type': type}, cdata=cdata, **args)
+
 
 class animate(SVGelement):
     """an=animate(attribute,from,to,during,**args)
 
     animates an attribute.
     """
-    def __init__(self,attribute,fr=None,to=None,dur=None,**args):
-        SVGelement.__init__(self,'animate',{'attributeName':attribute},**args)
-        if fr<>None:
-            self.attributes['from']=fr
-        if to<>None:
-            self.attributes['to']=to
-        if dur<>None:
-            self.attributes['dur']=dur
+
+    def __init__(self, attribute, fr=None, to=None, dur=None, **args):
+        SVGelement.__init__(
+            self, 'animate', {'attributeName': attribute}, **args)
+        if fr != None:
+            self.attributes['from'] = fr
+        if to != None:
+            self.attributes['to'] = to
+        if dur != None:
+            self.attributes['dur'] = dur
+
 
 class animateMotion(SVGelement):
     """an=animateMotion(pathdata,dur,**args)
 
     animates a SVGelement over the given path in dur seconds
     """
-    def __init__(self,pathdata,dur,**args):
-        SVGelement.__init__(self,'animateMotion',**args)
-        if pathdata<>None:
-            self.attributes['path']=str(pathdata)
-        if dur<>None:
-            self.attributes['dur']=dur
+
+    def __init__(self, pathdata, dur, **args):
+        SVGelement.__init__(self, 'animateMotion', **args)
+        if pathdata != None:
+            self.attributes['path'] = str(pathdata)
+        if dur != None:
+            self.attributes['dur'] = dur
+
 
 class animateTransform(SVGelement):
     """antr=animateTransform(type,from,to,dur,**args)
 
     transform an element from and to a value.
     """
-    def __init__(self,type=None,fr=None,to=None,dur=None,**args):
-        SVGelement.__init__(self,'animateTransform',{'attributeName':'transform'},**args)
-        #As far as I know the attributeName is always transform
-        if type<>None:
-            self.attributes['type']=type
-        if fr<>None:
-            self.attributes['from']=fr
-        if to<>None:
-            self.attributes['to']=to
-        if dur<>None:
-            self.attributes['dur']=dur
+
+    def __init__(self, type=None, fr=None, to=None, dur=None, **args):
+        SVGelement.__init__(self, 'animateTransform', {
+                            'attributeName': 'transform'}, **args)
+        # As far as I know the attributeName is always transform
+        if type != None:
+            self.attributes['type'] = type
+        if fr != None:
+            self.attributes['from'] = fr
+        if to != None:
+            self.attributes['to'] = to
+        if dur != None:
+            self.attributes['dur'] = dur
+
+
 class animateColor(SVGelement):
     """ac=animateColor(attribute,type,from,to,dur,**args)
 
     Animates the color of a element
     """
-    def __init__(self,attribute,type=None,fr=None,to=None,dur=None,**args):
-        SVGelement.__init__(self,'animateColor',{'attributeName':attribute},**args)
-        if type<>None:
-            self.attributes['type']=type
-        if fr<>None:
-            self.attributes['from']=fr
-        if to<>None:
-            self.attributes['to']=to
-        if dur<>None:
-            self.attributes['dur']=dur
+
+    def __init__(self, attribute, type=None, fr=None, to=None, dur=None, **args):
+        SVGelement.__init__(self, 'animateColor', {
+                            'attributeName': attribute}, **args)
+        if type != None:
+            self.attributes['type'] = type
+        if fr != None:
+            self.attributes['from'] = fr
+        if to != None:
+            self.attributes['to'] = to
+        if dur != None:
+            self.attributes['dur'] = dur
+
+
 class set(SVGelement):
     """st=set(attribute,to,during,**args)
 
     sets an attribute to a value for a
     """
-    def __init__(self,attribute,to=None,dur=None,**args):
-        SVGelement.__init__(self,'set',{'attributeName':attribute},**args)
-        if to<>None:
-            self.attributes['to']=to
-        if dur<>None:
-            self.attributes['dur']=dur
 
+    def __init__(self, attribute, to=None, dur=None, **args):
+        SVGelement.__init__(self, 'set', {'attributeName': attribute}, **args)
+        if to != None:
+            self.attributes['to'] = to
+        if dur != None:
+            self.attributes['dur'] = dur
 
 
 class svg(SVGelement):
@@ -894,15 +997,17 @@ class svg(SVGelement):
     d.setSVG(s)
     d.toXml()
     """
-    def __init__(self,viewBox=None, width=None, height=None,**args):
-        SVGelement.__init__(self,'svg',**args)
-        if viewBox<>None:
-            self.attributes['viewBox']=_viewboxlist(viewBox)
-        if width<>None:
-            self.attributes['width']=width
-        if height<>None:
-            self.attributes['height']=height
-        self.namespace="http://www.w3.org/2000/svg"
+
+    def __init__(self, viewBox=None, width=None, height=None, **args):
+        SVGelement.__init__(self, 'svg', **args)
+        if viewBox != None:
+            self.attributes['viewBox'] = _viewboxlist(viewBox)
+        if width != None:
+            self.attributes['width'] = width
+        if height != None:
+            self.attributes['height'] = height
+        self.namespace = "http://www.w3.org/2000/svg"
+
 
 class drawing:
     """d=drawing()
@@ -916,29 +1021,32 @@ class drawing:
     """
 
     def __init__(self, entity={}):
-        self.svg=None
+        self.svg = None
         self.entity = entity
-    def setSVG(self,svg):
-        self.svg=svg
-        #Voeg een element toe aan de grafiek toe.
-    if use_dom_implementation==0:
-        def toXml(self, filename='',compress=False):
-            import cStringIO
-            xml=cStringIO.StringIO()
+
+    def setSVG(self, svg):
+        self.svg = svg
+        # Voeg een element toe aan de grafiek toe.
+    if use_dom_implementation == 0:
+        def toXml(self, filename='', compress=False):
+            import io
+            xml = io.StringIO()
             xml.write("<?xml version='1.0' encoding='UTF-8'?>\n")
-            xml.write("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"")
+            xml.write(
+                "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"")
             if self.entity:
                 xml.write(" [\n")
-                for item in self.entity.keys():
-                    xml.write("<!ENTITY %s \"%s\">\n" % (item, self.entity[item]))
+                for item in list(self.entity.keys()):
+                    xml.write("<!ENTITY %s \"%s\">\n" %
+                              (item, self.entity[item]))
                 xml.write("]")
             xml.write(">\n")
-            self.svg.toXml(0,xml)
+            self.svg.toXml(0, xml)
             if not filename:
                 if compress:
                     import gzip
-                    f=cStringIO.StringIO()
-                    zf=gzip.GzipFile(fileobj=f,mode='wb')
+                    f = io.StringIO()
+                    zf = gzip.GzipFile(fileobj=f, mode='wb')
                     zf.write(xml.getvalue())
                     zf.close()
                     f.seek(0)
@@ -946,57 +1054,62 @@ class drawing:
                 else:
                     return xml.getvalue()
             else:
-                if filename[-4:]=='svgz':
+                if filename[-4:] == 'svgz':
                     import gzip
-                    f=gzip.GzipFile(filename=filename,mode="wb", compresslevel=9)
+                    f = gzip.GzipFile(filename=filename,
+                                      mode="wb", compresslevel=9)
                     f.write(xml.getvalue())
                     f.close()
                 else:
-                    f=file(filename,'w')
+                    f = file(filename, 'w')
                     f.write(xml.getvalue())
                     f.close()
 
     else:
-        def toXml(self,filename='',compress=False):
+        def toXml(self, filename='', compress=False):
             """drawing.toXml()        ---->to the screen
             drawing.toXml(filename)---->to the file
             writes a svg drawing to the screen or to a file
             compresses if filename ends with svgz or if compress is true
             """
-            doctype = implementation.createDocumentType('svg',"-//W3C//DTD SVG 1.0//EN""",'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd ')
+            doctype = implementation.createDocumentType(
+                'svg', "-//W3C//DTD SVG 1.0//EN""", 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd ')
 
             global root
-            #root is defined global so it can be used by the appender. Its also possible to use it as an arugument but
-            #that is a bit messy.
-            root=implementation.createDocument(None,None,doctype)
-            #Create the xml document.
+            # root is defined global so it can be used by the appender. Its also possible to use it as an arugument but
+            # that is a bit messy.
+            root = implementation.createDocument(None, None, doctype)
+            # Create the xml document.
             global appender
-            def appender(element,elementroot):
+
+            def appender(element, elementroot):
                 """This recursive function appends elements to an element and sets the attributes
                 and type. It stops when alle elements have been appended"""
                 if element.namespace:
-                    e=root.createElementNS(element.namespace,element.type)
+                    e = root.createElementNS(element.namespace, element.type)
                 else:
-                    e=root.createElement(element.type)
+                    e = root.createElement(element.type)
                 if element.text:
-                    textnode=root.createTextNode(element.text)
+                    textnode = root.createTextNode(element.text)
                     e.appendChild(textnode)
-                for attribute in element.attributes.keys():   #in element.attributes is supported from python 2.2
-                    e.setAttribute(attribute,str(element.attributes[attribute]))
+                # in element.attributes is supported from python 2.2
+                for attribute in list(element.attributes.keys()):
+                    e.setAttribute(attribute, str(
+                        element.attributes[attribute]))
                 if element.elements:
                     for el in element.elements:
-                        e=appender(el,e)
+                        e = appender(el, e)
                 elementroot.appendChild(e)
                 return elementroot
-            root=appender(self.svg,root)
+            root = appender(self.svg, root)
             if not filename:
-                import cStringIO
-                xml=cStringIO.StringIO()
-                PrettyPrint(root,xml)
+                import io
+                xml = io.StringIO()
+                PrettyPrint(root, xml)
                 if compress:
                     import gzip
-                    f=cStringIO.StringIO()
-                    zf=gzip.GzipFile(fileobj=f,mode='wb')
+                    f = io.StringIO()
+                    zf = gzip.GzipFile(fileobj=f, mode='wb')
                     zf.write(xml.getvalue())
                     zf.close()
                     f.seek(0)
@@ -1005,64 +1118,68 @@ class drawing:
                     return xml.getvalue()
             else:
                 try:
-                    if filename[-4:]=='svgz':
+                    if filename[-4:] == 'svgz':
                         import gzip
-                        import cStringIO
-                        xml=cStringIO.StringIO()
-                        PrettyPrint(root,xml)
-                        f=gzip.GzipFile(filename=filename,mode='wb',compresslevel=9)
+                        import io
+                        xml = io.StringIO()
+                        PrettyPrint(root, xml)
+                        f = gzip.GzipFile(filename=filename,
+                                          mode='wb', compresslevel=9)
                         f.write(xml.getvalue())
                         f.close()
                     else:
-                        f=open(filename,'w')
-                        PrettyPrint(root,f)
+                        f = open(filename, 'w')
+                        PrettyPrint(root, f)
                         f.close()
                 except:
-                    print "Cannot write SVG file: " + filename
+                    print(("Cannot write SVG file: " + filename))
+
     def validate(self):
         try:
             import xml.parsers.xmlproc.xmlval
         except:
-            raise exceptions.ImportError,'PyXml is required for validating SVG'
-        svg=self.toXml()
-        xv=xml.parsers.xmlproc.xmlval.XMLValidator()
+            raise exceptions.ImportError(
+                'PyXml is required for validating SVG')
+        svg = self.toXml()
+        xv = xml.parsers.xmlproc.xmlval.XMLValidator()
         try:
             xv.feed(svg)
         except:
             raise Exception("SVG is not well formed, see messages above")
         else:
-            print "SVG well formed"
-if __name__=='__main__':
+            print("SVG well formed")
 
 
-    d=drawing()
-    s=svg((0,0,100,100))
-    r=rect(-100,-100,300,300,'cyan')
+if __name__ == '__main__':
+
+    d = drawing()
+    s = svg((0, 0, 100, 100))
+    r = rect(-100, -100, 300, 300, 'cyan')
     s.addElement(r)
 
-    t=title('SVGdraw Demo')
+    t = title('SVGdraw Demo')
     s.addElement(t)
-    g=group('animations')
-    e=ellipse(0,0,5,2)
+    g = group('animations')
+    e = ellipse(0, 0, 5, 2)
     g.addElement(e)
-    c=circle(0,0,1,'red')
+    c = circle(0, 0, 1, 'red')
     g.addElement(c)
-    pd=pathdata(0,-10)
+    pd = pathdata(0, -10)
     for i in range(6):
-        pd.relsmbezier(10,5,0,10)
-        pd.relsmbezier(-10,5,0,10)
-    an=animateMotion(pd,10)
-    an.attributes['rotate']='auto-reverse'
-    an.attributes['repeatCount']="indefinite"
+        pd.relsmbezier(10, 5, 0, 10)
+        pd.relsmbezier(-10, 5, 0, 10)
+    an = animateMotion(pd, 10)
+    an.attributes['rotate'] = 'auto-reverse'
+    an.attributes['repeatCount'] = "indefinite"
     g.addElement(an)
     s.addElement(g)
-    for i in range(20,120,20):
-        u=use('#animations',i,0)
+    for i in range(20, 120, 20):
+        u = use('#animations', i, 0)
         s.addElement(u)
-    for i in range(0,120,20):
-        for j in range(5,105,10):
-            c=circle(i,j,1,'red','black',.5)
+    for i in range(0, 120, 20):
+        for j in range(5, 105, 10):
+            c = circle(i, j, 1, 'red', 'black', .5)
             s.addElement(c)
     d.setSVG(s)
 
-    print d.toXml()
+    print((d.toXml()))
diff --git a/wqflask/utility/temp_data.py b/wqflask/utility/temp_data.py
index 5bf700c9..07c5a318 100644
--- a/wqflask/utility/temp_data.py
+++ b/wqflask/utility/temp_data.py
@@ -1,9 +1,9 @@
-from __future__ import print_function, division, absolute_import
 from redis import Redis
 
 import simplejson as json
 
-class TempData(object):
+
+class TempData:
 
     def __init__(self, temp_uuid):
         self.temp_uuid = temp_uuid
@@ -12,7 +12,7 @@ class TempData(object):
 
     def store(self, field, value):
         self.redis.hset(self.key, field, value)
-        self.redis.expire(self.key, 60*15)  # Expire in 15 minutes
+        self.redis.expire(self.key, 60 * 15)  # Expire in 15 minutes
 
     def get_all(self):
         return self.redis.hgetall(self.key)
@@ -20,6 +20,6 @@ class TempData(object):
 
 if __name__ == "__main__":
     redis = Redis()
-    for key in redis.keys():
+    for key in list(redis.keys()):
         for field in redis.hkeys(key):
             print("{}.{}={}".format(key, field, redis.hget(key, field)))
diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py
index 89d88516..0efe8ca9 100644
--- a/wqflask/utility/tools.py
+++ b/wqflask/utility/tools.py
@@ -9,16 +9,18 @@ from wqflask import app
 
 # Use the standard logger here to avoid a circular dependency
 import logging
-logger = logging.getLogger(__name__ )
+logger = logging.getLogger(__name__)
 
 OVERRIDES = {}
 
+
 def app_set(command_id, value):
     """Set application wide value"""
-    app.config.setdefault(command_id,value)
+    app.config.setdefault(command_id, value)
     return value
 
-def get_setting(command_id,guess=None):
+
+def get_setting(command_id, guess=None):
     """Resolve a setting from the environment or the global settings in
     app.config, with valid_path is a function checking whether the
     path points to an expected directory and returns the full path to
@@ -45,7 +47,7 @@ def get_setting(command_id,guess=None):
     def value(command):
         if command:
             # sys.stderr.write("Found "+command+"\n")
-            app_set(command_id,command)
+            app_set(command_id, command)
             return command
         else:
             return None
@@ -54,7 +56,7 @@ def get_setting(command_id,guess=None):
     # print("Looking for "+command_id+"\n")
     command = value(os.environ.get(command_id))
     if command is None or command == "":
-        command = OVERRIDES.get(command_id) # currently not in use
+        command = OVERRIDES.get(command_id)  # currently not in use
         if command is None:
             # ---- Check whether setting exists in app
             command = value(app.config.get(command_id))
@@ -62,16 +64,19 @@ def get_setting(command_id,guess=None):
                 command = value(guess)
                 if command is None or command == "":
                     # print command
-                    raise Exception(command_id+' setting unknown or faulty (update default_settings.py?).')
+                    raise Exception(
+                        command_id + ' setting unknown or faulty (update default_settings.py?).')
     # print("Set "+command_id+"="+str(command))
     return command
 
+
 def get_setting_bool(id):
     v = get_setting(id)
-    if v not in [0,False,'False','FALSE',None]:
-      return True
+    if v not in [0, False, 'False', 'FALSE', None]:
+        return True
     return False
 
+
 def get_setting_int(id):
     v = get_setting(id)
     if isinstance(v, str):
@@ -80,69 +85,83 @@ def get_setting_int(id):
         return 0
     return v
 
+
 def valid_bin(bin):
     if os.path.islink(bin) or valid_file(bin):
         return bin
     return None
 
+
 def valid_file(fn):
     if os.path.isfile(fn):
         return fn
     return None
 
+
 def valid_path(dir):
     if os.path.isdir(dir):
         return dir
     return None
 
+
 def js_path(module=None):
     """
     Find the JS module in the two paths
     """
-    try_gn   = get_setting("JS_GN_PATH")+"/"+module
+    try_gn = get_setting("JS_GN_PATH") + "/" + module
     if valid_path(try_gn):
         return try_gn
-    try_guix = get_setting("JS_GUIX_PATH")+"/"+module
+    try_guix = get_setting("JS_GUIX_PATH") + "/" + module
     if valid_path(try_guix):
         return try_guix
-    raise "No JS path found for "+module+" (if not in Guix check JS_GN_PATH)"
+    raise "No JS path found for " + module + \
+        " (if not in Guix check JS_GN_PATH)"
+
 
 def reaper_command(guess=None):
-    return get_setting("REAPER_COMMAND",guess)
+    return get_setting("REAPER_COMMAND", guess)
+
 
 def gemma_command(guess=None):
-    return assert_bin(get_setting("GEMMA_COMMAND",guess))
+    return assert_bin(get_setting("GEMMA_COMMAND", guess))
+
 
 def gemma_wrapper_command(guess=None):
-    return assert_bin(get_setting("GEMMA_WRAPPER_COMMAND",guess))
+    return assert_bin(get_setting("GEMMA_WRAPPER_COMMAND", guess))
+
 
 def plink_command(guess=None):
-    return assert_bin(get_setting("PLINK_COMMAND",guess))
+    return assert_bin(get_setting("PLINK_COMMAND", guess))
+
 
 def flat_file_exists(subdir):
     base = get_setting("GENENETWORK_FILES")
-    return valid_path(base+"/"+subdir)
+    return valid_path(base + "/" + subdir)
+
 
 def flat_files(subdir=None):
     base = get_setting("GENENETWORK_FILES")
     if subdir:
-        return assert_dir(base+"/"+subdir)
+        return assert_dir(base + "/" + subdir)
     return assert_dir(base)
 
+
 def assert_bin(fn):
     if not valid_bin(fn):
-        raise Exception("ERROR: can not find binary "+fn)
+        raise Exception("ERROR: can not find binary " + fn)
     return fn
 
+
 def assert_dir(dir):
     if not valid_path(dir):
-        raise Exception("ERROR: can not find directory "+dir)
+        raise Exception("ERROR: can not find directory " + dir)
     return dir
 
+
 def assert_writable_dir(dir):
     try:
         fn = dir + "/test.txt"
-        fh = open( fn, 'w' )
+        fh = open(fn, 'w')
         fh.write("I am writing this text to the file\n")
         fh.close()
         os.remove(fn)
@@ -150,16 +169,19 @@ def assert_writable_dir(dir):
         raise Exception('Unable to write test.txt to directory ' + dir)
     return dir
 
+
 def assert_file(fn):
     if not valid_file(fn):
-        raise Exception('Unable to find file '+fn)
+        raise Exception('Unable to find file ' + fn)
     return fn
 
+
 def mk_dir(dir):
     if not valid_path(dir):
         os.makedirs(dir)
     return assert_dir(dir)
 
+
 def locate(name, subdir=None):
     """
     Locate a static flat file in the GENENETWORK_FILES environment.
@@ -168,19 +190,22 @@ def locate(name, subdir=None):
     """
     base = get_setting("GENENETWORK_FILES")
     if subdir:
-        base = base+"/"+subdir
+        base = base + "/" + subdir
     if valid_path(base):
         lookfor = base + "/" + name
         if valid_file(lookfor):
-            logger.info("Found: file "+lookfor+"\n")
+            logger.info("Found: file " + lookfor + "\n")
             return lookfor
         else:
-            raise Exception("Can not locate "+lookfor)
-    if subdir: sys.stderr.write(subdir)
-    raise Exception("Can not locate "+name+" in "+base)
+            raise Exception("Can not locate " + lookfor)
+    if subdir:
+        sys.stderr.write(subdir)
+    raise Exception("Can not locate " + name + " in " + base)
+
 
 def locate_phewas(name, subdir=None):
-    return locate(name,'/phewas/'+subdir)
+    return locate(name, '/phewas/' + subdir)
+
 
 def locate_ignore_error(name, subdir=None):
     """
@@ -191,75 +216,80 @@ def locate_ignore_error(name, subdir=None):
     """
     base = get_setting("GENENETWORK_FILES")
     if subdir:
-        base = base+"/"+subdir
+        base = base + "/" + subdir
     if valid_path(base):
         lookfor = base + "/" + name
         if valid_file(lookfor):
-            logger.debug("Found: file "+name+"\n")
+            logger.debug("Found: file " + name + "\n")
             return lookfor
-    logger.info("WARNING: file "+name+" not found\n")
+    logger.info("WARNING: file " + name + " not found\n")
     return None
 
+
 def tempdir():
     """
     Get UNIX TMPDIR by default
     """
-    return valid_path(get_setting("TMPDIR","/tmp"))
+    return valid_path(get_setting("TMPDIR", "/tmp"))
+
 
-BLUE  = '\033[94m'
+BLUE = '\033[94m'
 GREEN = '\033[92m'
-BOLD  = '\033[1m'
-ENDC  = '\033[0m'
+BOLD = '\033[1m'
+ENDC = '\033[0m'
+
 
 def show_settings():
     from utility.tools import LOG_LEVEL
 
-    print("Set global log level to "+BLUE+LOG_LEVEL+ENDC)
+    print(("Set global log level to " + BLUE + LOG_LEVEL + ENDC))
     log_level = getattr(logging, LOG_LEVEL.upper())
     logging.basicConfig(level=log_level)
 
     logger.info(OVERRIDES)
-    logger.info(BLUE+"Mr. Mojo Risin 2"+ENDC)
-    print "runserver.py: ****** Webserver configuration - k,v pairs from app.config ******"
-    keylist = app.config.keys()
+    logger.info(BLUE + "Mr. Mojo Risin 2" + ENDC)
+    keylist = list(app.config.keys())
+    print("runserver.py: ****** Webserver configuration - k,v pairs from app.config ******")
     keylist.sort()
     for k in keylist:
         try:
-            print("%s: %s%s%s%s" % (k,BLUE,BOLD,get_setting(k),ENDC))
+            print(("%s: %s%s%s%s" % (k, BLUE, BOLD, get_setting(k), ENDC)))
         except:
-            print("%s: %s%s%s%s" % (k,GREEN,BOLD,app.config[k],ENDC))
+            print(("%s: %s%s%s%s" % (k, GREEN, BOLD, app.config[k], ENDC)))
 
 
 # Cached values
-GN_VERSION         = get_setting('GN_VERSION')
-HOME               = get_setting('HOME')
-SERVER_PORT        = get_setting('SERVER_PORT')
-WEBSERVER_MODE     = get_setting('WEBSERVER_MODE')
-GN2_BASE_URL       = get_setting('GN2_BASE_URL')
-GN2_BRANCH_URL     = get_setting('GN2_BRANCH_URL')
-GN_SERVER_URL      = get_setting('GN_SERVER_URL')
-SERVER_PORT        = get_setting_int('SERVER_PORT')
-SQL_URI            = get_setting('SQL_URI')
-LOG_LEVEL          = get_setting('LOG_LEVEL')
-LOG_LEVEL_DEBUG    = get_setting_int('LOG_LEVEL_DEBUG')
-LOG_SQL            = get_setting_bool('LOG_SQL')
-LOG_SQL_ALCHEMY    = get_setting_bool('LOG_SQL_ALCHEMY')
-LOG_BENCH          = get_setting_bool('LOG_BENCH')
-LOG_FORMAT         = "%(message)s"    # not yet in use
-USE_REDIS          = get_setting_bool('USE_REDIS')
-USE_GN_SERVER      = get_setting_bool('USE_GN_SERVER')
-
-GENENETWORK_FILES  = get_setting('GENENETWORK_FILES')
-JS_GUIX_PATH       = get_setting('JS_GUIX_PATH')
+GN_VERSION = get_setting('GN_VERSION')
+HOME = get_setting('HOME')
+SERVER_PORT = get_setting('SERVER_PORT')
+WEBSERVER_MODE = get_setting('WEBSERVER_MODE')
+GN2_BASE_URL = get_setting('GN2_BASE_URL')
+GN2_BRANCH_URL = get_setting('GN2_BRANCH_URL')
+GN_SERVER_URL = get_setting('GN_SERVER_URL')
+GN_PROXY_URL = get_setting('GN_PROXY_URL')
+GN3_LOCAL_URL = get_setting('GN3_LOCAL_URL')
+SERVER_PORT = get_setting_int('SERVER_PORT')
+SQL_URI = get_setting('SQL_URI')
+LOG_LEVEL = get_setting('LOG_LEVEL')
+LOG_LEVEL_DEBUG = get_setting_int('LOG_LEVEL_DEBUG')
+LOG_SQL = get_setting_bool('LOG_SQL')
+LOG_SQL_ALCHEMY = get_setting_bool('LOG_SQL_ALCHEMY')
+LOG_BENCH = get_setting_bool('LOG_BENCH')
+LOG_FORMAT = "%(message)s"    # not yet in use
+USE_REDIS = get_setting_bool('USE_REDIS')
+USE_GN_SERVER = get_setting_bool('USE_GN_SERVER')
+
+GENENETWORK_FILES = get_setting('GENENETWORK_FILES')
+JS_GUIX_PATH = get_setting('JS_GUIX_PATH')
 assert_dir(JS_GUIX_PATH)
-JS_GN_PATH         = get_setting('JS_GN_PATH')
+JS_GN_PATH = get_setting('JS_GN_PATH')
 # assert_dir(JS_GN_PATH)
 
 GITHUB_CLIENT_ID = get_setting('GITHUB_CLIENT_ID')
 GITHUB_CLIENT_SECRET = get_setting('GITHUB_CLIENT_SECRET')
 if GITHUB_CLIENT_ID != 'UNKNOWN' and GITHUB_CLIENT_SECRET:
     GITHUB_AUTH_URL = "https://github.com/login/oauth/authorize?client_id=" + \
-                      GITHUB_CLIENT_ID+"&client_secret="+GITHUB_CLIENT_SECRET
+                      GITHUB_CLIENT_ID + "&client_secret=" + GITHUB_CLIENT_SECRET
     GITHUB_API_URL = get_setting('GITHUB_API_URL')
 
 ORCID_CLIENT_ID = get_setting('ORCID_CLIENT_ID')
@@ -267,11 +297,12 @@ ORCID_CLIENT_SECRET = get_setting('ORCID_CLIENT_SECRET')
 ORCID_AUTH_URL = None
 if ORCID_CLIENT_ID != 'UNKNOWN' and ORCID_CLIENT_SECRET:
     ORCID_AUTH_URL = "https://orcid.org/oauth/authorize?response_type=code&scope=/authenticate&show_login=true&client_id=" + \
-                      ORCID_CLIENT_ID+"&client_secret="+ORCID_CLIENT_SECRET
+        ORCID_CLIENT_ID + "&client_secret=" + ORCID_CLIENT_SECRET + \
+        "&redirect_uri=" + GN2_BRANCH_URL + "n/login/orcid_oauth2"
     ORCID_TOKEN_URL = get_setting('ORCID_TOKEN_URL')
 
-# ELASTICSEARCH_HOST = get_setting('ELASTICSEARCH_HOST')
-# ELASTICSEARCH_PORT = get_setting('ELASTICSEARCH_PORT')
+ELASTICSEARCH_HOST = get_setting('ELASTICSEARCH_HOST')
+ELASTICSEARCH_PORT = get_setting('ELASTICSEARCH_PORT')
 # import utility.elasticsearch_tools as es
 # es.test_elasticsearch_connection()
 
@@ -279,28 +310,29 @@ SMTP_CONNECT = get_setting('SMTP_CONNECT')
 SMTP_USERNAME = get_setting('SMTP_USERNAME')
 SMTP_PASSWORD = get_setting('SMTP_PASSWORD')
 
-REAPER_COMMAND     = app_set("REAPER_COMMAND",reaper_command())
-GEMMA_COMMAND      = app_set("GEMMA_COMMAND",gemma_command())
+REAPER_COMMAND = app_set("REAPER_COMMAND", reaper_command())
+GEMMA_COMMAND = app_set("GEMMA_COMMAND", gemma_command())
 assert(GEMMA_COMMAND is not None)
-PLINK_COMMAND      = app_set("PLINK_COMMAND",plink_command())
+PLINK_COMMAND = app_set("PLINK_COMMAND", plink_command())
 GEMMA_WRAPPER_COMMAND = gemma_wrapper_command()
-TEMPDIR            = tempdir() # defaults to UNIX TMPDIR
+TEMPDIR = tempdir()  # defaults to UNIX TMPDIR
 assert_dir(TEMPDIR)
 
 # ---- Handle specific JS modules
 JS_GUIX_PATH = get_setting("JS_GUIX_PATH")
 assert_dir(JS_GUIX_PATH)
-assert_dir(JS_GUIX_PATH+'/cytoscape-panzoom')
+assert_dir(JS_GUIX_PATH + '/cytoscape-panzoom')
 
 CSS_PATH = JS_GUIX_PATH  # The CSS is bundled together with the JS
 # assert_dir(JS_PATH)
 
-JS_TWITTER_POST_FETCHER_PATH = get_setting("JS_TWITTER_POST_FETCHER_PATH",js_path("javascript-twitter-post-fetcher"))
+JS_TWITTER_POST_FETCHER_PATH = get_setting(
+    "JS_TWITTER_POST_FETCHER_PATH", js_path("javascript-twitter-post-fetcher"))
 assert_dir(JS_TWITTER_POST_FETCHER_PATH)
-assert_file(JS_TWITTER_POST_FETCHER_PATH+"/js/twitterFetcher_min.js")
+assert_file(JS_TWITTER_POST_FETCHER_PATH + "/js/twitterFetcher_min.js")
 
-JS_CYTOSCAPE_PATH = get_setting("JS_CYTOSCAPE_PATH",js_path("cytoscape"))
+JS_CYTOSCAPE_PATH = get_setting("JS_CYTOSCAPE_PATH", js_path("cytoscape"))
 assert_dir(JS_CYTOSCAPE_PATH)
-assert_file(JS_CYTOSCAPE_PATH+'/cytoscape.min.js')
+assert_file(JS_CYTOSCAPE_PATH + '/cytoscape.min.js')
 
 # assert_file(PHEWAS_FILES+"/auwerx/PheWAS_pval_EMMA_norm.RData")
diff --git a/wqflask/utility/type_checking.py b/wqflask/utility/type_checking.py
index f15b17e2..00f14ba9 100644
--- a/wqflask/utility/type_checking.py
+++ b/wqflask/utility/type_checking.py
@@ -7,6 +7,7 @@ def is_float(value):
     except:
         return False
 
+
 def is_int(value):
     try:
         int(value)
@@ -14,6 +15,7 @@ def is_int(value):
     except:
         return False
 
+
 def is_str(value):
     if value is None:
         return False
@@ -23,20 +25,23 @@ def is_str(value):
     except:
         return False
 
-def get_float(vars,name,default=None):
-    if name in vars:
-        if is_float(vars[name]):
-            return float(vars[name])
+
+def get_float(vars_obj, name, default=None):
+    if name in vars_obj:
+        if is_float(vars_obj[name]):
+            return float(vars_obj[name])
     return default
 
-def get_int(vars,name,default=None):
-    if name in vars:
-        if is_int(vars[name]):
-            return float(vars[name])
+
+def get_int(vars_obj, name, default=None):
+    if name in vars_obj:
+        if is_int(vars_obj[name]):
+            return float(vars_obj[name])
     return default
 
-def get_string(vars,name,default=None):
-    if name in vars:
-        if not vars[name] is None:
-            return str(vars[name])
+
+def get_string(vars_obj, name, default=None):
+    if name in vars_obj:
+        if not vars_obj[name] is None:
+            return str(vars_obj[name])
     return default
diff --git a/wqflask/utility/webqtlUtil.py b/wqflask/utility/webqtlUtil.py
index 53661ae4..0cb71567 100644
--- a/wqflask/utility/webqtlUtil.py
+++ b/wqflask/utility/webqtlUtil.py
@@ -33,44 +33,46 @@ from math import *
 from base import webqtlConfig
 
 # NL, 07/27/2010. moved from webqtlForm.py
-#Dict of Parents and F1 information, In the order of [F1, Mat, Pat]
-ParInfo ={
-'BXH':['BHF1', 'HBF1',  'C57BL/6J', 'C3H/HeJ'],
-'AKXD':['AKF1', 'KAF1', 'AKR/J', 'DBA/2J'],
-'BXD':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
-'C57BL-6JxC57BL-6NJF2':['', '', 'C57BL/6J', 'C57BL/6NJ'],
-'BXD300':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
-'B6BTBRF2':['B6BTBRF1', 'BTBRB6F1', 'C57BL/6J', 'BTBRT<+>tf/J'],
-'BHHBF2':['B6HF2','HB6F2','C57BL/6J','C3H/HeJ'],
-'BHF2':['B6HF2','HB6F2','C57BL/6J','C3H/HeJ'],
-'B6D2F2':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
-'BDF2-1999':['B6D2F2', 'D2B6F2', 'C57BL/6J', 'DBA/2J'],
-'BDF2-2005':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
-'CTB6F2':['CTB6F2','B6CTF2','C57BL/6J','Castaneous'],
-'CXB':['CBF1', 'BCF1', 'C57BL/6ByJ', 'BALB/cByJ'],
-'AXBXA':['ABF1', 'BAF1', 'C57BL/6J', 'A/J'],
-'AXB':['ABF1', 'BAF1', 'C57BL/6J', 'A/J'],
-'BXA':['BAF1', 'ABF1', 'C57BL/6J', 'A/J'],
-'LXS':['LSF1', 'SLF1', 'ISS', 'ILS'],
-'HXBBXH':['SHR_BNF1', 'BN_SHRF1', 'BN-Lx/Cub', 'SHR/OlaIpcv'],
-'BayXSha':['BayXShaF1', 'ShaXBayF1', 'Bay-0','Shahdara'],
-'ColXBur':['ColXBurF1', 'BurXColF1', 'Col-0','Bur-0'],
-'ColXCvi':['ColXCviF1', 'CviXColF1', 'Col-0','Cvi'],
-'SXM':['SMF1', 'MSF1', 'Steptoe','Morex'],
-'HRDP':['SHR_BNF1', 'BN_SHRF1', 'BN-Lx/Cub', 'SHR/OlaIpcv']
+# Dict of Parents and F1 information, In the order of [F1, Mat, Pat]
+ParInfo = {
+    'BXH': ['BHF1', 'HBF1', 'C57BL/6J', 'C3H/HeJ'],
+    'AKXD': ['AKF1', 'KAF1', 'AKR/J', 'DBA/2J'],
+    'BXD': ['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
+    'C57BL-6JxC57BL-6NJF2': ['', '', 'C57BL/6J', 'C57BL/6NJ'],
+    'BXD300': ['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
+    'B6BTBRF2': ['B6BTBRF1', 'BTBRB6F1', 'C57BL/6J', 'BTBRT<+>tf/J'],
+    'BHHBF2': ['B6HF2', 'HB6F2', 'C57BL/6J', 'C3H/HeJ'],
+    'BHF2': ['B6HF2', 'HB6F2', 'C57BL/6J', 'C3H/HeJ'],
+    'B6D2F2': ['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
+    'BDF2-1999': ['B6D2F2', 'D2B6F2', 'C57BL/6J', 'DBA/2J'],
+    'BDF2-2005': ['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'],
+    'CTB6F2': ['CTB6F2', 'B6CTF2', 'C57BL/6J', 'Castaneous'],
+    'CXB': ['CBF1', 'BCF1', 'C57BL/6ByJ', 'BALB/cByJ'],
+    'AXBXA': ['ABF1', 'BAF1', 'C57BL/6J', 'A/J'],
+    'AXB': ['ABF1', 'BAF1', 'C57BL/6J', 'A/J'],
+    'BXA': ['BAF1', 'ABF1', 'C57BL/6J', 'A/J'],
+    'LXS': ['LSF1', 'SLF1', 'ISS', 'ILS'],
+    'HXBBXH': ['SHR_BNF1', 'BN_SHRF1', 'BN-Lx/Cub', 'SHR/OlaIpcv'],
+    'BayXSha': ['BayXShaF1', 'ShaXBayF1', 'Bay-0', 'Shahdara'],
+    'ColXBur': ['ColXBurF1', 'BurXColF1', 'Col-0', 'Bur-0'],
+    'ColXCvi': ['ColXCviF1', 'CviXColF1', 'Col-0', 'Cvi'],
+    'SXM': ['SMF1', 'MSF1', 'Steptoe', 'Morex'],
+    'HRDP': ['SHR_BNF1', 'BN_SHRF1', 'BN-Lx/Cub', 'SHR/OlaIpcv']
 }
 
 #########################################
 #      Accessory Functions
 #########################################
 
-def genRandStr(prefix = "", length=8, chars=string.letters+string.digits):
+
+def genRandStr(prefix="", length=8, chars=string.ascii_letters + string.digits):
     from random import choice
     _str = prefix[:]
     for i in range(length):
         _str += choice(chars)
     return _str
 
+
 def ListNotNull(lst):
     '''Obsolete - Use built in function any (or all or whatever)
 
@@ -83,15 +85,17 @@ def ListNotNull(lst):
             return 1
     return None
 
-def readLineCSV(line): ### dcrowell July 2008
+
+def readLineCSV(line):  # dcrowell July 2008
     """Parses a CSV string of text and returns a list containing each element as a string.
     Used by correlationPage"""
     returnList = line.split('","')
-    returnList[-1]=returnList[-1][:-2]
-    returnList[0]=returnList[0][1:]
+    returnList[-1] = returnList[-1][:-2]
+    returnList[0] = returnList[0][1:]
     return returnList
 
-def cmpEigenValue(A,B):
+
+def cmpEigenValue(A, B):
     try:
         if A[0] > B[0]:
             return -1
@@ -102,12 +106,13 @@ def cmpEigenValue(A,B):
     except:
         return 0
 
+
 def hasAccessToConfidentialPhenotypeTrait(privilege, userName, authorized_users):
     access_to_confidential_phenotype_trait = 0
     if webqtlConfig.USERDICT[privilege] > webqtlConfig.USERDICT['user']:
         access_to_confidential_phenotype_trait = 1
     else:
-        AuthorizedUsersList=map(string.strip, string.split(authorized_users, ','))
-        if AuthorizedUsersList.__contains__(userName):
+        AuthorizedUsersList = [x.strip() for x in authorized_users.split(',')]
+        if userName in AuthorizedUsersList:
             access_to_confidential_phenotype_trait = 1
-    return access_to_confidential_phenotype_trait
\ No newline at end of file
+    return access_to_confidential_phenotype_trait