diff options
author | Arthur Centeno | 2021-04-09 20:38:21 +0000 |
---|---|---|
committer | Arthur Centeno | 2021-04-09 20:38:21 +0000 |
commit | e2b04a322f26670782fe7f7c39bcebc508fdabdd (patch) | |
tree | a51c32bae4d544cc0beea19f455ccc52f0544a4c /wqflask/utility | |
parent | 187cd40bd3273b50d2813bfccf98bfadbb8c14ff (diff) | |
parent | ef51e08753defdfc7f3e67f8788cd1362d2cf631 (diff) | |
download | genenetwork2-e2b04a322f26670782fe7f7c39bcebc508fdabdd.tar.gz |
Merge branch 'testing' of github.com:genenetwork/genenetwork2 into acenteno
Diffstat (limited to 'wqflask/utility')
-rw-r--r-- | wqflask/utility/Plot.py | 127 | ||||
-rw-r--r-- | wqflask/utility/__init__.py | 4 | ||||
-rw-r--r-- | wqflask/utility/after.py | 4 | ||||
-rw-r--r-- | wqflask/utility/authentication_tools.py | 145 | ||||
-rw-r--r-- | wqflask/utility/benchmark.py | 6 | ||||
-rw-r--r-- | wqflask/utility/chunks.py | 65 | ||||
-rw-r--r-- | wqflask/utility/corr_result_helpers.py | 26 | ||||
-rw-r--r-- | wqflask/utility/db_tools.py | 12 | ||||
-rw-r--r-- | wqflask/utility/elasticsearch_tools.py | 2 | ||||
-rw-r--r-- | wqflask/utility/formatting.py | 29 | ||||
-rw-r--r-- | wqflask/utility/gen_geno_ob.py | 6 | ||||
-rw-r--r-- | wqflask/utility/genofile_parser.py | 1 | ||||
-rw-r--r-- | wqflask/utility/helper_functions.py | 17 | ||||
-rw-r--r-- | wqflask/utility/hmac.py | 17 | ||||
-rw-r--r-- | wqflask/utility/logger.py | 26 | ||||
-rw-r--r-- | wqflask/utility/pillow_utils.py | 27 | ||||
-rw-r--r-- | wqflask/utility/redis_tools.py | 271 | ||||
-rw-r--r-- | wqflask/utility/startup_config.py | 4 | ||||
-rw-r--r-- | wqflask/utility/svg.py | 692 | ||||
-rw-r--r-- | wqflask/utility/temp_data.py | 3 | ||||
-rw-r--r-- | wqflask/utility/tools.py | 44 | ||||
-rw-r--r-- | wqflask/utility/type_checking.py | 24 | ||||
-rw-r--r-- | wqflask/utility/webqtlUtil.py | 24 |
23 files changed, 960 insertions, 616 deletions
diff --git a/wqflask/utility/Plot.py b/wqflask/utility/Plot.py index cce8435d..61f408d2 100644 --- a/wqflask/utility/Plot.py +++ b/wqflask/utility/Plot.py @@ -24,32 +24,35 @@ # # 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__ ) +# ---- 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] == '.': @@ -77,7 +80,7 @@ def frange(start, end=None, inc=1.0): # 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 @@ -88,7 +91,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,7 +119,8 @@ 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 @@ -152,7 +156,7 @@ def plotBar(canvas, data, barColor=pid.blue, axesColor=pid.black, labelColor=pid 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) @@ -163,67 +167,91 @@ def plotBar(canvas, data, barColor=pid.blue, axesColor=pid.black, labelColor=pid 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) + im_drawer.rectangle( + xy=((xc+2, yc), (xc+barWidth-2, yTopOffset+plotHeight)), + outline=barColor, fill=barColor) #draw drawing region - canvas.drawRect(xLeftOffset, yTopOffset, xLeftOffset+plotWidth, yTopOffset+plotHeight) + im_drawer.rectangle( + xy=((xLeftOffset, yTopOffset), (xLeftOffset+plotWidth, yTopOffset+plotHeight)) + ) #draw scale - scaleFont=pid.Font(ttf="cour",size=11,bold=1) + scaleFont=ImageFont.truetype(font=COUR_FILE, size=11) 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) + im_drawer.line( + xy=((xc, yTopOffset+plotHeight), (xc, yTopOffset+plotHeight+5)), + fill=axesColor) strX = cformat(d=x, rank=0) - canvas.drawString(strX,xc-canvas.stringWidth(strX,font=scaleFont)/2,yTopOffset+plotHeight+14,font=scaleFont) + 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 - canvas.drawLine(xLeftOffset,yc,xLeftOffset-5,yc, color=axesColor) + im_drawer.line(xy=((xLeftOffset, yc), (xLeftOffset-5, yc)), fill=axesColor) strY = "%d" %y - canvas.drawString(strY,xLeftOffset-canvas.stringWidth(strY,font=scaleFont)-6,yc+5,font=scaleFont) + 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=pid.Font(ttf="tahoma",size=17,bold=0) + 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): +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) + 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)] + 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 if max != 0: @@ -235,7 +263,7 @@ def detScale(min=0,max=0): min -= 0.1*a a=max-min b=floor(log10(a)) - c=pow(10.0,b) + c=pow(10.0, b) low=c*floor(min/c) high=c*ceil(max/c) n = round((high-low)/c) @@ -253,7 +281,7 @@ def detScale(min=0,max=0): 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))) @@ -262,21 +290,26 @@ def redfunc(x): 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)] + 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)); + 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) j = 0 @@ -292,4 +325,4 @@ def _test(): if __name__=="__main__": - _test()
\ No newline at end of file + _test() diff --git a/wqflask/utility/__init__.py b/wqflask/utility/__init__.py index d9856eed..204ff59a 100644 --- a/wqflask/utility/__init__.py +++ b/wqflask/utility/__init__.py @@ -19,7 +19,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 +30,6 @@ 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..06091ecb 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 @@ -13,4 +11,4 @@ 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..672b36d5 --- /dev/null +++ b/wqflask/utility/authentication_tools.py @@ -0,0 +1,145 @@ +import json +import requests + +from flask import g +from base import webqtlConfig + + +from utility.redis_tools import (get_redis_conn, + get_resource_info, + get_resource_id, + add_resource) +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) + + # ZS: If resource isn't already in redis, add it with default + # privileges + if not resource_info: + resource_info = add_new_resource(dataset, trait_id) + + # ZS: 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 = "http://localhost:8080/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 = "http://localhost:8080/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 + + +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) + + if g.user_session.user_id in Redis.smembers("super_users"): + return "owner" + + resource_info = get_resource_info(resource_id) + if resource_info: + if g.user_session.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..ea5a0ab6 100644 --- a/wqflask/utility/benchmark.py +++ b/wqflask/utility/benchmark.py @@ -1,5 +1,3 @@ -from __future__ import print_function, division, absolute_import - import collections import inspect import time @@ -38,9 +36,9 @@ class Bench(object): @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(): + 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..9a7db102 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 @@ -31,66 +29,3 @@ def divide_into_chunks(the_list, number_chunks): 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/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..a5580811 100644 --- a/wqflask/utility/elasticsearch_tools.py +++ b/wqflask/utility/elasticsearch_tools.py @@ -59,7 +59,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 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..81085ffe 100644 --- a/wqflask/utility/gen_geno_ob.py +++ b/wqflask/utility/gen_geno_ob.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, division, print_function - import utility.logger logger = utility.logger.getLogger(__name__ ) @@ -175,7 +173,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 + self.genotype.append("U") diff --git a/wqflask/utility/genofile_parser.py b/wqflask/utility/genofile_parser.py index af306731..0b736176 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 diff --git a/wqflask/utility/helper_functions.py b/wqflask/utility/helper_functions.py index e7c04fef..7eb7f013 100644 --- a/wqflask/utility/helper_functions.py +++ b/wqflask/utility/helper_functions.py @@ -1,7 +1,5 @@ -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 @@ -11,10 +9,9 @@ from flask import Flask, g import logging 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 "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: @@ -24,7 +21,7 @@ def get_species_dataset_trait(self, start_vars): logger.debug("After creating 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) @@ -34,9 +31,8 @@ def get_species_dataset_trait(self, start_vars): #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 = [] @@ -49,10 +45,11 @@ def get_trait_db_obs(self, trait_db_list): 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, + trait_ob = create_trait(dataset=dataset_ob, name=trait_name, cellid=None) - self.trait_list.append((trait_ob, dataset_ob)) + if trait_ob: + self.trait_list.append((trait_ob, dataset_ob)) def get_species_groups(): diff --git a/wqflask/utility/hmac.py b/wqflask/utility/hmac.py index d8a0eace..29891677 100644 --- a/wqflask/utility/hmac.py +++ b/wqflask/utility/hmac.py @@ -1,16 +1,18 @@ -from __future__ import print_function, division, absolute_import - import hmac import hashlib +from flask import url_for + from wqflask import app + 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 +20,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 +38,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..e904eb94 100644 --- a/wqflask/utility/logger.py +++ b/wqflask/utility/logger.py @@ -42,10 +42,10 @@ 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) @@ -54,7 +54,7 @@ class GNLogger: level=num to filter on LOG_LEVEL_DEBUG. """ - self.collect(self.logger.debug,*args) + self.collect(self.logger.debug, *args) def debug20(self,*args): """Call logging.debug for multiple args. Use level=num to filter on @@ -63,15 +63,15 @@ 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): """Call logging.info for multiple args""" - self.collect(self.logger.info,*args) + self.collect(self.logger.info, *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): @@ -79,13 +79,13 @@ LOG_LEVEL_DEBUG (NYI). 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) + self.collect(self.logger.error, *l) 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): """Call logging.debug for multiple args lazily and handle @@ -95,15 +95,15 @@ 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): """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: @@ -119,7 +119,7 @@ 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) def collectf(self,fun,*args): @@ -134,7 +134,7 @@ 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 diff --git a/wqflask/utility/pillow_utils.py b/wqflask/utility/pillow_utils.py new file mode 100644 index 00000000..c486abba --- /dev/null +++ b/wqflask/utility/pillow_utils.py @@ -0,0 +1,27 @@ +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..8052035f 100644 --- a/wqflask/utility/redis_tools.py +++ b/wqflask/utility/redis_tools.py @@ -1,17 +1,22 @@ -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 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 +24,14 @@ def is_redis_available(): return False return True + +def load_json_from_redis(item_list, 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 +39,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 +50,42 @@ 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 get_users_like_unique_column(column_name, column_value): + """Like previous function, but this only checks if the input is a + subset of a field and can return multiple results + + """ + matched_users = [] + + if column_value != "": + user_list = Redis.hgetall("users") + if column_name != "user_id": + for key in user_list: + user_ob = json.loads(user_list[key]) + if "user_id" not in user_ob: + set_user_attribute(key, "user_id", key) + user_ob["user_id"] = key + if column_name in user_ob: + if column_value in user_ob[column_name]: + matched_users.append(user_ob) + else: + matched_users.append(load_json_from_redis(user_list, column_value)) + + return matched_users + + 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 +95,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 + # 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 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: + try: + group_ob = json.loads(groups_list[key]) + group_admins = set([this_admin.encode('utf-8') if this_admin else None for this_admin in group_ob['admins']]) + group_members = set([this_member.encode('utf-8') if this_member else None for this_member in group_ob['members']]) + if user_id in group_admins: + admin_group_ids.append(group_ob['id']) + elif user_id in group_members: + user_group_ids.append(group_ob['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 +162,71 @@ def get_group_info(group_id): return group_info -def create_group(admin_member_ids, user_member_ids = [], group_name = ""): + +def get_group_by_unique_column(column_name, column_value): + """ Get group by column; not sure if there's a faster way to do this """ + + matched_groups = [] + + all_group_list = Redis.hgetall("groups") + for key in all_group_list: + group_info = json.loads(all_group_list[key]) + # ZS: Since these fields are lists, search in the list + if column_name == "admins" or column_name == "members": + if column_value in group_info[column_name]: + matched_groups.append(group_info) + else: + if group_info[column_name] == column_value: + matched_groups.append(group_info) + + return matched_groups + + +def get_groups_like_unique_column(column_name, column_value): + """Like previous function, but this only checks if the input is a + subset of a field and can return multiple results + + """ + matched_groups = [] + + if column_value != "": + group_list = Redis.hgetall("groups") + if column_name != "group_id": + for key in group_list: + group_info = json.loads(group_list[key]) + # ZS: Since these fields are lists, search in the list + if column_name == "admins" or column_name == "members": + if column_value in group_info[column_name]: + matched_groups.append(group_info) + else: + if column_name in group_info: + if column_value in group_info[column_name]: + matched_groups.append(group_info) + else: + matched_groups.append(load_json_from_redis(group_list, column_value)) + + return matched_groups + + +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 +234,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 +255,105 @@ 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 + + +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 + + +def change_resource_owner(resource_id, new_owner_id): + the_resource = get_resource_info(resource_id) + the_resource['owner_id'] = new_owner_id + + Redis.delete("resource") + Redis.hset("resources", resource_id, json.dumps(the_resource)) diff --git a/wqflask/utility/startup_config.py b/wqflask/utility/startup_config.py index 817284dd..f1aaebb6 100644 --- a/wqflask/utility/startup_config.py +++ b/wqflask/utility/startup_config.py @@ -27,7 +27,7 @@ def app_config(): 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(("GN2 API server URL is ["+BLUE+get_setting("GN_SERVER_URL")+ENDC+"]")) import requests page = requests.get(get_setting("GN_SERVER_URL")) if page.status_code != 200: @@ -36,4 +36,4 @@ def app_config(): # 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(("GN2 is running. Visit %s[http://localhost:%s/%s](%s)" % (BLUE, str(port), ENDC, get_setting("WEBSERVER_URL")))) diff --git a/wqflask/utility/svg.py b/wqflask/utility/svg.py index db13b9d1..b92cc2d1 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("&", "&") + # data = data.replace("&", "&") data = data.replace("<", "<") data = data.replace(">", ">") - 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,121 @@ 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)) + 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): + + def relmove(self, x, y): """move to relative""" self.path.append('m '+str(x)+' '+str(y)) - def line(self,x,y): + + def line(self, x, y): """line to absolute""" self.path.append('L '+str(x)+' '+str(y)) - def relline(self,x,y): + + def relline(self, x, y): """line to relative""" self.path.append('l '+str(x)+' '+str(y)) - def hline(self,x): + + def hline(self, x): """horizontal line to absolute""" self.path.append('H'+str(x)) - def relhline(self,x): + + def relhline(self, x): """horizontal line to relative""" self.path.append('h'+str(x)) - def vline(self,y): + + def vline(self, y): """verical line to absolute""" self.path.append('V'+str(y)) - def relvline(self,y): + + def relvline(self, y): """vertical line to relative""" self.path.append('v'+str(y)) - def bezier(self,x1,y1,x2,y2,x,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): + + 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): + + 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): + + 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): + + def smqbezier(self, x, y): """smooth quadratic bezier to xy absolut""" self.path.append('T'+str(x)+','+str(y)) - def relsmqbezier(self,x,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): + + 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,52 +285,56 @@ 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): + 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]))) + 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[') for line in self.cdata.splitlines(): 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') @@ -312,6 +345,7 @@ class SVGelement: else: f.write('/>\n') + class tspan(SVGelement): """ts=tspan(text='',**args) @@ -323,19 +357,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 +383,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,46 +414,49 @@ 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: + + 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: + if y!=None: self.attributes['y']=y - if fill<>None: + if fill!=None: self.attributes['fill']=fill - if stroke<>None: + if stroke!=None: self.attributes['stroke']=stroke - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width class ellipse(SVGelement): @@ -423,22 +466,18 @@ class ellipse(SVGelement): """ 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: + 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: + if cy!=None: self.attributes['cy']=cy - if fill<>None: + if fill!=None: self.attributes['fill']=fill - if stroke<>None: + if stroke!=None: self.attributes['stroke']=stroke - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width @@ -449,17 +488,17 @@ class circle(SVGelement): """ 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: + raise ValueError('r is required') + SVGelement.__init__(self, 'circle', {'r':r}, **args) + if cx!=None: self.attributes['cx']=cx - if cy<>None: + if cy!=None: self.attributes['cy']=cy - if fill<>None: + if fill!=None: self.attributes['fill']=fill - if stroke<>None: + if stroke!=None: self.attributes['stroke']=stroke - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width class point(circle): @@ -469,7 +508,7 @@ class point(circle): 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) + circle.__init__(self, x, y, 1, fill, **args) class line(SVGelement): """l=line(x1,y1,x2,y2,stroke,stroke_width,**args) @@ -477,18 +516,18 @@ class line(SVGelement): 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: + SVGelement.__init__(self, 'line', **args) + if x1!=None: self.attributes['x1']=x1 - if y1<>None: + if y1!=None: self.attributes['y1']=y1 - if x2<>None: + if x2!=None: self.attributes['x2']=x2 - if y2<>None: + if y2!=None: self.attributes['y2']=y2 - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width - if stroke<>None: + if stroke!=None: self.attributes['stroke']=stroke class polyline(SVGelement): @@ -497,12 +536,12 @@ class polyline(SVGelement): 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: + SVGelement.__init__(self, 'polyline', {'points':_xypointlist(points)}, **args) + if fill!=None: self.attributes['fill']=fill - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width - if stroke<>None: + if stroke!=None: self.attributes['stroke']=stroke class polygon(SVGelement): @@ -511,12 +550,12 @@ class polygon(SVGelement): 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: + SVGelement.__init__(self, 'polygon', {'points':_xypointlist(points)}, **args) + if fill!=None: self.attributes['fill']=fill - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width - if stroke<>None: + if stroke!=None: self.attributes['stroke']=stroke class path(SVGelement): @@ -525,14 +564,14 @@ class path(SVGelement): 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: + SVGelement.__init__(self, 'path', {'d':str(pathdata)}, **args) + if stroke!=None: self.attributes['stroke']=stroke - if fill<>None: + if fill!=None: self.attributes['fill']=fill - if stroke_width<>None: + if stroke_width!=None: self.attributes['stroke-width']=stroke_width - if id<>None: + if id!=None: self.attributes['id']=id @@ -542,18 +581,18 @@ 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: + SVGelement.__init__(self, 'text', **args) + if x!=None: self.attributes['x']=x - if y<>None: + if y!=None: self.attributes['y']=y - if font_size<>None: + if font_size!=None: self.attributes['font-size']=font_size - if font_family<>None: + if font_family!=None: self.attributes['font-family']=font_family - if text<>None: + if text!=None: self.text=text - if text_anchor<>None: + if text_anchor!=None: self.attributes['text-anchor']=text_anchor @@ -563,8 +602,8 @@ 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: + SVGelement.__init__(self, 'textPath', {'xlink:href':link}, **args) + if text!=None: self.text=text class pattern(SVGelement): @@ -575,16 +614,16 @@ class pattern(SVGelement): 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: + SVGelement.__init__(self, 'pattern', **args) + if x!=None: self.attributes['x']=x - if y<>None: + if y!=None: self.attributes['y']=y - if width<>None: + if width!=None: self.attributes['width']=width - if height<>None: + if height!=None: self.attributes['height']=height - if patternUnits<>None: + if patternUnits!=None: self.attributes['patternUnits']=patternUnits class title(SVGelement): @@ -594,8 +633,8 @@ class title(SVGelement): add at least one to the root svg element """ def __init__(self,text=None,**args): - SVGelement.__init__(self,'title',**args) - if text<>None: + SVGelement.__init__(self, 'title', **args) + if text!=None: self.text=text class description(SVGelement): @@ -605,8 +644,8 @@ class description(SVGelement): Add this element before adding other elements. """ def __init__(self,text=None,**args): - SVGelement.__init__(self,'desc',**args) - if text<>None: + SVGelement.__init__(self, 'desc', **args) + if text!=None: self.text=text class lineargradient(SVGelement): @@ -616,16 +655,16 @@ class lineargradient(SVGelement): 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: + SVGelement.__init__(self, 'linearGradient', **args) + if x1!=None: self.attributes['x1']=x1 - if y1<>None: + if y1!=None: self.attributes['y1']=y1 - if x2<>None: + if x2!=None: self.attributes['x2']=x2 - if y2<>None: + if y2!=None: self.attributes['y2']=y2 - if id<>None: + if id!=None: self.attributes['id']=id class radialgradient(SVGelement): @@ -635,18 +674,18 @@ class radialgradient(SVGelement): 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: + SVGelement.__init__(self, 'radialGradient', **args) + if cx!=None: self.attributes['cx']=cx - if cy<>None: + if cy!=None: self.attributes['cy']=cy - if r<>None: + if r!=None: self.attributes['r']=r - if fx<>None: + if fx!=None: self.attributes['fx']=fx - if fy<>None: + if fy!=None: self.attributes['fy']=fy - if id<>None: + if id!=None: self.attributes['id']=id class stop(SVGelement): @@ -655,8 +694,8 @@ class stop(SVGelement): 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: + SVGelement.__init__(self, 'stop', {'offset':offset}, **args) + if stop_color!=None: self.attributes['stop-color']=stop_color class style(SVGelement): @@ -665,7 +704,7 @@ class style(SVGelement): 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) + SVGelement.__init__(self, 'style', {'type':type}, cdata=cdata, **args) class image(SVGelement): @@ -675,16 +714,11 @@ class image(SVGelement): """ 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: + 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: + if y!=None: self.attributes['y']=y class cursor(SVGelement): @@ -693,7 +727,7 @@ class cursor(SVGelement): defines a custom cursor for a element or a drawing """ def __init__(self,url,**args): - SVGelement.__init__(self,'cursor',{'xlink:href':url},**args) + SVGelement.__init__(self, 'cursor', {'xlink:href':url}, **args) class marker(SVGelement): @@ -703,18 +737,18 @@ class marker(SVGelement): 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: + SVGelement.__init__(self, 'marker', **args) + if id!=None: self.attributes['id']=id - if viewBox<>None: + if viewBox!=None: self.attributes['viewBox']=_viewboxlist(viewBox) - if refx<>None: + if refx!=None: self.attributes['refX']=refx - if refy<>None: + if refy!=None: self.attributes['refY']=refy - if markerWidth<>None: + if markerWidth!=None: self.attributes['markerWidth']=markerWidth - if markerHeight<>None: + if markerHeight!=None: self.attributes['markerHeight']=markerHeight class group(SVGelement): @@ -724,8 +758,8 @@ class group(SVGelement): g.addElement(SVGelement) """ def __init__(self,id=None,**args): - SVGelement.__init__(self,'g',**args) - if id<>None: + SVGelement.__init__(self, 'g', **args) + if id!=None: self.attributes['id']=id class symbol(SVGelement): @@ -738,10 +772,10 @@ class symbol(SVGelement): """ def __init__(self,id=None,viewBox=None,**args): - SVGelement.__init__(self,'symbol',**args) - if id<>None: + SVGelement.__init__(self, 'symbol', **args) + if id!=None: self.attributes['id']=id - if viewBox<>None: + if viewBox!=None: self.attributes['viewBox']=_viewboxlist(viewBox) class defs(SVGelement): @@ -750,7 +784,7 @@ class defs(SVGelement): container for defining elements """ def __init__(self,**args): - SVGelement.__init__(self,'defs',**args) + SVGelement.__init__(self, 'defs', **args) class switch(SVGelement): """sw=switch(**args) @@ -760,7 +794,7 @@ class switch(SVGelement): Refer to the SVG specification for details. """ def __init__(self,**args): - SVGelement.__init__(self,'switch',**args) + SVGelement.__init__(self, 'switch', **args) class use(SVGelement): @@ -769,15 +803,15 @@ 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: + SVGelement.__init__(self, 'use', {'xlink:href':link}, **args) + if x!=None: self.attributes['x']=x - if y<>None: + if y!=None: self.attributes['y']=y - if width<>None: + if width!=None: self.attributes['width']=width - if height<>None: + if height!=None: self.attributes['height']=height @@ -788,15 +822,15 @@ class link(SVGelement): a.addElement(SVGelement) """ def __init__(self,link='',**args): - SVGelement.__init__(self,'a',{'xlink:href':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: + SVGelement.__init__(self, 'view', **args) + if id!=None: self.attributes['id']=id class script(SVGelement): @@ -806,7 +840,7 @@ class script(SVGelement): """ def __init__(self,type,cdata=None,**args): - SVGelement.__init__(self,'script',{'type':type},cdata=cdata,**args) + SVGelement.__init__(self, 'script', {'type':type}, cdata=cdata, **args) class animate(SVGelement): """an=animate(attribute,from,to,during,**args) @@ -814,12 +848,12 @@ class animate(SVGelement): animates an attribute. """ def __init__(self,attribute,fr=None,to=None,dur=None,**args): - SVGelement.__init__(self,'animate',{'attributeName':attribute},**args) - if fr<>None: + SVGelement.__init__(self, 'animate', {'attributeName':attribute}, **args) + if fr!=None: self.attributes['from']=fr - if to<>None: + if to!=None: self.attributes['to']=to - if dur<>None: + if dur!=None: self.attributes['dur']=dur class animateMotion(SVGelement): @@ -828,10 +862,10 @@ class animateMotion(SVGelement): animates a SVGelement over the given path in dur seconds """ def __init__(self,pathdata,dur,**args): - SVGelement.__init__(self,'animateMotion',**args) - if pathdata<>None: + SVGelement.__init__(self, 'animateMotion', **args) + if pathdata!=None: self.attributes['path']=str(pathdata) - if dur<>None: + if dur!=None: self.attributes['dur']=dur class animateTransform(SVGelement): @@ -840,15 +874,15 @@ class animateTransform(SVGelement): 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: + 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: + if fr!=None: self.attributes['from']=fr - if to<>None: + if to!=None: self.attributes['to']=to - if dur<>None: + if dur!=None: self.attributes['dur']=dur class animateColor(SVGelement): """ac=animateColor(attribute,type,from,to,dur,**args) @@ -856,14 +890,14 @@ class animateColor(SVGelement): 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: + SVGelement.__init__(self, 'animateColor', {'attributeName':attribute}, **args) + if type!=None: self.attributes['type']=type - if fr<>None: + if fr!=None: self.attributes['from']=fr - if to<>None: + if to!=None: self.attributes['to']=to - if dur<>None: + if dur!=None: self.attributes['dur']=dur class set(SVGelement): """st=set(attribute,to,during,**args) @@ -871,10 +905,10 @@ class set(SVGelement): 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: + SVGelement.__init__(self, 'set', {'attributeName':attribute}, **args) + if to!=None: self.attributes['to']=to - if dur<>None: + if dur!=None: self.attributes['dur']=dur @@ -895,12 +929,12 @@ class svg(SVGelement): d.toXml() """ def __init__(self,viewBox=None, width=None, height=None,**args): - SVGelement.__init__(self,'svg',**args) - if viewBox<>None: + SVGelement.__init__(self, 'svg', **args) + if viewBox!=None: self.attributes['viewBox']=_viewboxlist(viewBox) - if width<>None: + if width!=None: self.attributes['width']=width - if height<>None: + if height!=None: self.attributes['height']=height self.namespace="http://www.w3.org/2000/svg" @@ -918,27 +952,27 @@ class drawing: def __init__(self, entity={}): self.svg=None self.entity = entity - def setSVG(self,svg): + def setSVG(self, svg): self.svg=svg - #Voeg een element toe aan de grafiek toe. + # Voeg een element toe aan de grafiek toe. if use_dom_implementation==0: def toXml(self, filename='',compress=False): - import cStringIO - xml=cStringIO.StringIO() + 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\"") if self.entity: xml.write(" [\n") - for item in self.entity.keys(): + 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) @@ -948,11 +982,11 @@ class drawing: else: 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() @@ -963,40 +997,40 @@ class drawing: 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) if 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])) + for attribute in list(element.attributes.keys()): #in element.attributes is supported from python 2.2 + 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) @@ -1007,23 +1041,23 @@ class drawing: try: 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' + raise exceptions.ImportError('PyXml is required for validating SVG') svg=self.toXml() xv=xml.parsers.xmlproc.xmlval.XMLValidator() try: @@ -1031,38 +1065,38 @@ class drawing: except: raise Exception("SVG is not well formed, see messages above") else: - print "SVG well formed" + print("SVG well formed") if __name__=='__main__': d=drawing() - s=svg((0,0,100,100)) - r=rect(-100,-100,300,300,'cyan') + s=svg((0, 0, 100, 100)) + r=rect(-100, -100, 300, 300, 'cyan') s.addElement(r) t=title('SVGdraw Demo') s.addElement(t) g=group('animations') - e=ellipse(0,0,5,2) + 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) + 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..4144ae00 100644 --- a/wqflask/utility/temp_data.py +++ b/wqflask/utility/temp_data.py @@ -1,4 +1,3 @@ -from __future__ import print_function, division, absolute_import from redis import Redis import simplejson as json @@ -20,6 +19,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..65df59c3 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -15,7 +15,7 @@ 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): @@ -45,7 +45,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 @@ -68,7 +68,7 @@ def get_setting(command_id,guess=None): def get_setting_bool(id): v = get_setting(id) - if v not in [0,False,'False','FALSE',None]: + if v not in [0, False, 'False', 'FALSE', None]: return True return False @@ -108,16 +108,16 @@ def js_path(module=None): 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") @@ -180,7 +180,7 @@ def locate(name, subdir=None): 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): """ @@ -204,7 +204,7 @@ def tempdir(): """ Get UNIX TMPDIR by default """ - return valid_path(get_setting("TMPDIR","/tmp")) + return valid_path(get_setting("TMPDIR", "/tmp")) BLUE = '\033[94m' GREEN = '\033[92m' @@ -214,20 +214,20 @@ 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() + 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 @@ -267,11 +267,11 @@ 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,10 +279,10 @@ 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 assert_dir(TEMPDIR) @@ -295,11 +295,11 @@ 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") -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') diff --git a/wqflask/utility/type_checking.py b/wqflask/utility/type_checking.py index f15b17e2..6b029317 100644 --- a/wqflask/utility/type_checking.py +++ b/wqflask/utility/type_checking.py @@ -23,20 +23,20 @@ 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..5681fadf 100644 --- a/wqflask/utility/webqtlUtil.py +++ b/wqflask/utility/webqtlUtil.py @@ -41,22 +41,22 @@ ParInfo ={ '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'], +'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'], +'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'], +'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'] } @@ -64,7 +64,7 @@ ParInfo ={ # 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): @@ -91,7 +91,7 @@ def readLineCSV(line): ### dcrowell July 2008 returnList[0]=returnList[0][1:] return returnList -def cmpEigenValue(A,B): +def cmpEigenValue(A, B): try: if A[0] > B[0]: return -1 @@ -107,7 +107,7 @@ def hasAccessToConfidentialPhenotypeTrait(privilege, userName, authorized_users) 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 |