From 5ebe36d5ff685e6b663b14c130606aa60b0123c2 Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 3 Sep 2021 14:58:05 +0000 Subject: Fix issue where values written to phenotype file for R/qtl sometimes had trailing decimal values by grounding to 3 places past the decimal --- wqflask/wqflask/marker_regression/rqtl_mapping.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py index 09afb8d1..cd578870 100644 --- a/wqflask/wqflask/marker_regression/rqtl_mapping.py +++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py @@ -89,7 +89,7 @@ def write_phenotype_file(trait_name: str, for i, sample in enumerate(samples): this_row = [sample] if vals[i] != "x": - this_row.append(vals[i]) + this_row.append(str(round(float(vals[i]), 3))) else: this_row.append("NA") for cofactor in cofactor_data: @@ -126,7 +126,7 @@ def cofactors_to_dict(cofactors: str, dataset_ob, samples) -> Dict: sample_data = trait_ob.data for index, sample in enumerate(samples): if sample in sample_data: - sample_value = sample_data[sample].value + sample_value = str(round(float(sample_data[sample].value), 3)) cofactor_dict[cofactor_name].append(sample_value) else: cofactor_dict[cofactor_name].append("NA") -- cgit v1.2.3 From 8af212bc7eac5b39e8e6838df446a4003633a55e Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 3 Sep 2021 14:59:14 +0000 Subject: Fix issue that caused javascript to not work on the R/qtl mapping result page when permutations weren't used (because it wrongly expected the permutation histogram to always exist) --- wqflask/wqflask/templates/mapping_results.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index 81eb1ba1..d446745d 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -529,7 +529,7 @@ }); {% endif %} - {% if mapping_method != "gemma" and mapping_method != "plink" %} + {% if mapping_method != "gemma" and mapping_method != "plink" and nperm > 0 and permChecked == "ON" %} $('#download_perm').click(function(){ perm_info_dict = { perm_data: js_data.perm_results, -- cgit v1.2.3 From f4297bc9e4c49f58e0759d02d3e7aea392ba5615 Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 3 Sep 2021 15:01:34 +0000 Subject: Allow categorical_var_list to be passed as a template variable --- wqflask/wqflask/show_trait/show_trait.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py index 3f93bae0..c4d1ae1c 100644 --- a/wqflask/wqflask/show_trait/show_trait.py +++ b/wqflask/wqflask/show_trait/show_trait.py @@ -178,11 +178,11 @@ class ShowTrait: self.sample_group_types['samples_primary'] = self.dataset.group.name sample_lists = [group.sample_list for group in self.sample_groups] - categorical_var_list = [] + self.categorical_var_list = [] self.numerical_var_list = [] if not self.temp_trait: # ZS: Only using first samplelist, since I think mapping only uses those samples - categorical_var_list = get_categorical_variables( + self.categorical_var_list = get_categorical_variables( self.this_trait, self.sample_groups[0]) self.numerical_var_list = get_numerical_variables( self.this_trait, self.sample_groups[0]) @@ -287,8 +287,8 @@ class ShowTrait: hddn['study_samplelists'] = json.dumps(study_samplelist_json) hddn['num_perm'] = 0 hddn['categorical_vars'] = "" - if categorical_var_list: - hddn['categorical_vars'] = ",".join(categorical_var_list) + if self.categorical_var_list: + hddn['categorical_vars'] = ",".join(self.categorical_var_list) hddn['manhattan_plot'] = "" hddn['control_marker'] = "" if not self.temp_trait: @@ -323,7 +323,7 @@ class ShowTrait: has_num_cases=self.has_num_cases, attributes=self.sample_groups[0].attributes, categorical_attr_exists=self.categorical_attr_exists, - categorical_vars=",".join(categorical_var_list), + categorical_vars=",".join(self.categorical_var_list), num_values=self.num_values, qnorm_values=self.qnorm_vals, zscore_values=self.z_scores, -- cgit v1.2.3 From f81a5629ab6ea7e39893af00e59c3ac6d79d7892 Mon Sep 17 00:00:00 2001 From: zsloan Date: Sun, 5 Sep 2021 17:03:51 +0000 Subject: Fixed issue that caused sample data to not be fetched correctly; there's something wrong with the 'get_probeset_data' function (not sure why this function exists) --- wqflask/wqflask/correlation/correlation_gn3_api.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wqflask/wqflask/correlation/correlation_gn3_api.py b/wqflask/wqflask/correlation/correlation_gn3_api.py index d0d4bcba..a18bceaf 100644 --- a/wqflask/wqflask/correlation/correlation_gn3_api.py +++ b/wqflask/wqflask/correlation/correlation_gn3_api.py @@ -150,10 +150,7 @@ def fetch_sample_data(start_vars, this_trait, this_dataset, target_dataset): sample_data = process_samples( start_vars, this_dataset.group.all_samples_ordered()) - if target_dataset.type == "ProbeSet": - target_dataset.get_probeset_data(list(sample_data.keys())) - else: - target_dataset.get_trait_data(list(sample_data.keys())) + target_dataset.get_trait_data(list(sample_data.keys())) this_trait = retrieve_sample_data(this_trait, this_dataset) this_trait_data = { "trait_sample_data": sample_data, -- cgit v1.2.3 From 25a5fe8027a00a64513855630a4365480cf567d7 Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 7 Sep 2021 18:21:34 +0000 Subject: Add timer to loading page to track how long the process has been running --- wqflask/wqflask/templates/loading.html | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/wqflask/wqflask/templates/loading.html b/wqflask/wqflask/templates/loading.html index 1edde31e..ccf810b0 100644 --- a/wqflask/wqflask/templates/loading.html +++ b/wqflask/wqflask/templates/loading.html @@ -12,6 +12,8 @@ {% if start_vars.tool_used == "Mapping" %}

Computing the Maps


+ Time Elapsed: +
Trait Metadata
species = {{ start_vars.species[0] | upper }}{{ start_vars.species[1:] }} @@ -101,9 +103,6 @@ -- cgit v1.2.3 From d243e3a69b26d60709fe10ab0b70a0e1d53ba50d Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 7 Sep 2021 18:22:44 +0000 Subject: Add trait hash and datetime to mapping figure --- .../marker_regression/display_mapping_results.py | 68 ++++++++++++++-------- wqflask/wqflask/marker_regression/run_mapping.py | 1 + .../new/javascript/show_trait_mapping_tools.js | 10 ++-- wqflask/wqflask/templates/mapping_results.html | 1 + wqflask/wqflask/views.py | 1 + 5 files changed, 51 insertions(+), 30 deletions(-) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index 3986c441..5f5fe6a3 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -24,6 +24,7 @@ # # Last updated by Zach 12/14/2010 +import datetime import string from math import * from PIL import Image @@ -271,6 +272,7 @@ class DisplayMappingResults: # Needing for form submission when doing single chr # mapping or remapping after changing options self.sample_vals = start_vars['sample_vals'] + self.vals_hash= start_vars['vals_hash'] self.sample_vals_dict = json.loads(self.sample_vals) self.transform = start_vars['transform'] @@ -651,7 +653,7 @@ class DisplayMappingResults: btminfo.append( 'Mapping using genotype data as a trait will result in infinity LRS at one locus. In order to display the result properly, all LRSs higher than 100 are capped at 100.') - def plotIntMapping(self, canvas, offset=(80, 120, 90, 100), zoom=1, startMb=None, endMb=None, showLocusForm=""): + def plotIntMapping(self, canvas, offset=(80, 120, 110, 100), zoom=1, startMb=None, endMb=None, showLocusForm=""): im_drawer = ImageDraw.Draw(canvas) # calculating margins xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset @@ -661,7 +663,7 @@ class DisplayMappingResults: if self.legendChecked: yTopOffset += 10 if self.covariates != "" and self.controlLocus and self.doControl != "false": - yTopOffset += 20 + yTopOffset += 25 if len(self.transform) > 0: yTopOffset += 5 else: @@ -1195,43 +1197,47 @@ class DisplayMappingResults: dataset_label = "%s - %s" % (self.dataset.group.name, self.dataset.fullname) - string1 = 'Dataset: %s' % (dataset_label) + + current_datetime = datetime.datetime.now() + string1 = 'UTC Timestamp: %s' % (current_datetime.strftime("%b %d %Y %H:%M:%S")) + string2 = 'Dataset: %s' % (dataset_label) + string3 = 'Trait Hash: %s' % (self.vals_hash) if self.genofile_string == "": - string2 = 'Genotype File: %s.geno' % self.dataset.group.name + string4 = 'Genotype File: %s.geno' % self.dataset.group.name else: - string2 = 'Genotype File: %s' % self.genofile_string + string4 = 'Genotype File: %s' % self.genofile_string - string4 = '' + string6 = '' if self.mapping_method == "gemma" or self.mapping_method == "gemma_bimbam": if self.use_loco == "True": - string3 = 'Using GEMMA mapping method with LOCO and ' + string5 = 'Using GEMMA mapping method with LOCO and ' else: - string3 = 'Using GEMMA mapping method with ' + string5 = 'Using GEMMA mapping method with ' if self.covariates != "": - string3 += 'the cofactors below:' + string5 += 'the cofactors below:' cofactor_names = ", ".join( [covar.split(":")[0] for covar in self.covariates.split(",")]) - string4 = cofactor_names + string6 = cofactor_names else: - string3 += 'no cofactors' + string5 += 'no cofactors' elif self.mapping_method == "rqtl_plink" or self.mapping_method == "rqtl_geno": - string3 = 'Using R/qtl mapping method with ' + string5 = 'Using R/qtl mapping method with ' if self.covariates != "": - string3 += 'the cofactors below:' + string5 += 'the cofactors below:' cofactor_names = ", ".join( [covar.split(":")[0] for covar in self.covariates.split(",")]) - string4 = cofactor_names + string6 = cofactor_names elif self.controlLocus and self.doControl != "false": - string3 += '%s as control' % self.controlLocus + string5 += '%s as control' % self.controlLocus else: - string3 += 'no cofactors' + string5 += 'no cofactors' else: - string3 = 'Using Haldane mapping function with ' + string5 = 'Using Haldane mapping function with ' if self.controlLocus and self.doControl != "false": - string3 += '%s as control' % self.controlLocus + string5 += '%s as control' % self.controlLocus else: - string3 += 'no control for other QTLs' + string5 += 'no control for other QTLs' y_constant = 10 if self.this_trait.name: @@ -1260,7 +1266,9 @@ class DisplayMappingResults: d = 4 + max( im_drawer.textsize(identification, font=labelFont)[0], im_drawer.textsize(string1, font=labelFont)[0], - im_drawer.textsize(string2, font=labelFont)[0]) + im_drawer.textsize(string2, font=labelFont)[0], + im_drawer.textsize(string3, font=labelFont)[0], + im_drawer.textsize(string4, font=labelFont)[0]) im_drawer.text( text=identification, xy=(xLeftOffset, y_constant * fontZoom), font=labelFont, @@ -1269,7 +1277,9 @@ class DisplayMappingResults: else: d = 4 + max( im_drawer.textsize(string1, font=labelFont)[0], - im_drawer.textsize(string2, font=labelFont)[0]) + im_drawer.textsize(string2, font=labelFont)[0], + im_drawer.textsize(string3, font=labelFont)[0], + im_drawer.textsize(string4, font=labelFont)[0]) if len(self.transform) > 0: transform_text = "Transform - " @@ -1296,14 +1306,22 @@ class DisplayMappingResults: text=string2, xy=(xLeftOffset, y_constant * fontZoom), font=labelFont, fill=labelColor) y_constant += 15 - if string3 != '': + im_drawer.text( + text=string3, xy=(xLeftOffset, y_constant * fontZoom), + font=labelFont, fill=labelColor) + y_constant += 15 + im_drawer.text( + text=string4, xy=(xLeftOffset, y_constant * fontZoom), + font=labelFont, fill=labelColor) + y_constant += 15 + if string4 != '': im_drawer.text( - text=string3, xy=(xLeftOffset, y_constant * fontZoom), + text=string5, xy=(xLeftOffset, y_constant * fontZoom), font=labelFont, fill=labelColor) y_constant += 15 - if string4 != '': + if string5 != '': im_drawer.text( - text=string4, xy=(xLeftOffset, y_constant * fontZoom), + text=string6, xy=(xLeftOffset, y_constant * fontZoom), font=labelFont, fill=labelColor) def drawGeneBand(self, canvas, gifmap, plotXScale, offset=(40, 120, 80, 10), zoom=1, startMb=None, endMb=None): diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index ebad7d36..2f90b475 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -75,6 +75,7 @@ class RunMapping: self.vals = [] self.samples = [] self.sample_vals = start_vars['sample_vals'] + self.vals_hash = start_vars['vals_hash'] sample_val_dict = json.loads(self.sample_vals) samples = sample_val_dict.keys() if (len(genofile_samplelist) != 0): diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js index 09e9d024..b75d658e 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js +++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js @@ -141,11 +141,11 @@ $('input[name=display_all]').change((function(_this) { })(this)); //ZS: This is a list of inputs to be passed to the loading page, since not all inputs on the trait page are relevant to mapping -var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', 'sample_vals', - 'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', 'num_bootstrap', 'bootCheck', 'bootstrap_results', - 'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'control_marker', 'do_control', 'genofile', - 'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', 'haplotypeAnalystCheck', - 'mapmethod_rqtl_geno', 'mapmodel_rqtl_geno', 'temp_trait', 'group', 'species', 'reaper_version', 'primary_samples'] +var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form_url', 'method', 'transform', 'trimmed_markers', 'selected_chr', 'chromosomes', 'mapping_scale', + 'sample_vals', 'vals_hash', 'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', + 'num_bootstrap', 'bootCheck', 'bootstrap_results', 'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'control_marker', + 'do_control', 'genofile', 'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', + 'haplotypeAnalystCheck', 'mapmethod_rqtl_geno', 'mapmodel_rqtl_geno', 'temp_trait', 'group', 'species', 'reaper_version', 'primary_samples'] $(".rqtl-geno-tab, #rqtl_geno_compute").on("click", (function(_this) { return function() { diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index d446745d..162ae810 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -34,6 +34,7 @@ + diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 11a9380c..707b18e1 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -1051,6 +1051,7 @@ def mapping_results_page(): 'samples', 'vals', 'sample_vals', + 'vals_hash', 'first_run', 'output_files', 'geno_db_exists', -- cgit v1.2.3 From 1f2e32a91727abab77ecdf501fcc5040b17dfece Mon Sep 17 00:00:00 2001 From: zsloan Date: Thu, 9 Sep 2021 17:07:06 +0000 Subject: Replaced trait name with trait display name in display_mapping_results so the group codes will be includes in phenotype IDs --- wqflask/wqflask/marker_regression/display_mapping_results.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index 5f5fe6a3..e9ba7dff 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -1249,18 +1249,18 @@ class DisplayMappingResults: if self.this_trait.symbol: identification += "Trait: %s - %s" % ( - self.this_trait.name, self.this_trait.symbol) + self.this_trait.display_name, self.this_trait.symbol) elif self.dataset.type == "Publish": if self.this_trait.post_publication_abbreviation: identification += "Trait: %s - %s" % ( - self.this_trait.name, self.this_trait.post_publication_abbreviation) + self.this_trait.display_name, self.this_trait.post_publication_abbreviation) elif self.this_trait.pre_publication_abbreviation: identification += "Trait: %s - %s" % ( - self.this_trait.name, self.this_trait.pre_publication_abbreviation) + self.this_trait.display_name, self.this_trait.pre_publication_abbreviation) else: - identification += "Trait: %s" % (self.this_trait.name) + identification += "Trait: %s" % (self.this_trait.display_name) else: - identification += "Trait: %s" % (self.this_trait.name) + identification += "Trait: %s" % (self.this_trait.display_name) identification += " with %s samples" % (self.n_samples) d = 4 + max( -- cgit v1.2.3 From 5020158b3ab7cf14a5809af65d2c616d32714a22 Mon Sep 17 00:00:00 2001 From: zsloan Date: Thu, 9 Sep 2021 17:07:47 +0000 Subject: Change trait name to display name in the metadata at the top of the page (so group codes will be includes in phenotype IDs --- wqflask/wqflask/templates/mapping_results.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index 162ae810..7f865056 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -68,7 +68,7 @@

Map Viewer: Whole Genome


Population: {{ dataset.group.species|capitalize }} {{ dataset.group.name }}
Database: {{ dataset.fullname }}
- {% if dataset.type == "ProbeSet" %}Trait ID:{% else %}Record ID:{% endif %} {{ this_trait.name }}
+ {% if dataset.type == "ProbeSet" %}Trait ID:{% else %}Record ID:{% endif %} {{ this_trait.display_name }}
{% if dataset.type == "ProbeSet" %} Gene Symbol: {{ this_trait.symbol }}
Location: Chr {{ this_trait.chr }} @ {{ this_trait.mb }} Mb
-- cgit v1.2.3 From f51569c80a4e00ad7dcd99ed9bf3ed6d9aaf4051 Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 10 Sep 2021 18:54:44 +0000 Subject: Removed encoding, since it's apparently not needed since the Python 3 switchover (and was causing there to be no matches between user IDs and groups) --- wqflask/utility/redis_tools.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py index ff125bd2..99295c67 100644 --- a/wqflask/utility/redis_tools.py +++ b/wqflask/utility/redis_tools.py @@ -135,10 +135,8 @@ def get_user_groups(user_id): for key in groups_list: 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']]) + group_admins = set([this_admin if this_admin else None for this_admin in group_ob['admins']]) + group_members = set([this_member 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: -- cgit v1.2.3 From d76e1ec30195074cf8dfd0f8396285d31faa8984 Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 10 Sep 2021 19:02:10 +0000 Subject: Fix issue with the way the template was checking if genofile_string was set; it was receiving an empty string, so the previous logic made it think there was a genofile string when there wasn't one --- wqflask/wqflask/templates/mapping_results.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index 7f865056..7a222d0c 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -73,7 +73,7 @@ Gene Symbol: {{ this_trait.symbol }}
Location: Chr {{ this_trait.chr }} @ {{ this_trait.mb }} Mb
{% endif %} - {% if genofile_string is defined %} + {% if genofile_string != "" %} Genotypes: {{ genofile_string.split(":")[1] }} {% endif %}
-- cgit v1.2.3 From f414cd4109229546bfb8c56fea95b6729121f0b3 Mon Sep 17 00:00:00 2001 From: jgart Date: Thu, 9 Sep 2021 22:28:02 -0500 Subject: Add Jupyter Notebook Launcher to Tools dropdown menu --- wqflask/wqflask/templates/base.html | 1 + 1 file changed, 1 insertion(+) diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html index 049ebe6d..14e6bc88 100644 --- a/wqflask/wqflask/templates/base.html +++ b/wqflask/wqflask/templates/base.html @@ -87,6 +87,7 @@
  • Systems Genetics PheWAS
  • Genome Browser
  • BXD Power Calculator
  • +
  • Jupyter Notebook Launcher
  • Interplanetary File System
  • -- cgit v1.2.3 From 38a8544553506651a263b0134ab5372c6a62c629 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 13 Sep 2021 18:58:10 +0000 Subject: Temporarily point the View in GN1 button to gn1-lily.genenetwork.org since some features aren't working on gn1.genenetwork.org yet --- wqflask/wqflask/templates/show_trait_details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html index 53e16aa0..36d3c15a 100644 --- a/wqflask/wqflask/templates/show_trait_details.html +++ b/wqflask/wqflask/templates/show_trait_details.html @@ -233,7 +233,7 @@ {% endif %} {% endif %} - + {% if admin_status == "owner" or admin_status == "edit-admins" or admin_status == "edit-access" %} {% if this_trait.dataset.type == 'Publish' %} -- cgit v1.2.3 From 6a94f7a3a4893f087af53c2d39685d9dcb4b733d Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 13 Sep 2021 19:41:19 +0000 Subject: Change Genotype File text to only show the meaningful genotype deescription --- wqflask/wqflask/marker_regression/display_mapping_results.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index e9ba7dff..a9ebeb64 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -1206,7 +1206,7 @@ class DisplayMappingResults: if self.genofile_string == "": string4 = 'Genotype File: %s.geno' % self.dataset.group.name else: - string4 = 'Genotype File: %s' % self.genofile_string + string4 = 'Genotype File: %s' % self.genofile_string.split(":")[1] string6 = '' if self.mapping_method == "gemma" or self.mapping_method == "gemma_bimbam": -- cgit v1.2.3 From 75132a5382d32d9332f743aca0e406ae6137d7e5 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 13 Sep 2021 19:49:05 +0000 Subject: Include some extra metadata in the mapping page details (in addition to the figure itself) --- wqflask/wqflask/marker_regression/display_mapping_results.py | 4 ++-- wqflask/wqflask/templates/mapping_results.html | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index a9ebeb64..77d6e2db 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -1198,8 +1198,8 @@ class DisplayMappingResults: self.dataset.fullname) - current_datetime = datetime.datetime.now() - string1 = 'UTC Timestamp: %s' % (current_datetime.strftime("%b %d %Y %H:%M:%S")) + self.current_datetime = datetime.datetime.now().strftime("%b %d %Y %H:%M:%S") + string1 = 'UTC Timestamp: %s' % (self.current_datetime) string2 = 'Dataset: %s' % (dataset_label) string3 = 'Trait Hash: %s' % (self.vals_hash) diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index 7a222d0c..f2d11e89 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -69,14 +69,15 @@ Population: {{ dataset.group.species|capitalize }} {{ dataset.group.name }}
    Database: {{ dataset.fullname }}
    {% if dataset.type == "ProbeSet" %}Trait ID:{% else %}Record ID:{% endif %} {{ this_trait.display_name }}
    + Trait Hash: {{ vals_hash }}
    {% if dataset.type == "ProbeSet" %} Gene Symbol: {{ this_trait.symbol }}
    Location: Chr {{ this_trait.chr }} @ {{ this_trait.mb }} Mb
    {% endif %} {% if genofile_string != "" %} - Genotypes: {{ genofile_string.split(":")[1] }} + Genotypes: {{ genofile_string.split(":")[1] }}
    {% endif %} -
    + Current Date/Time: {{ current_datetime }}

    Download Full Results -- cgit v1.2.3 From 2ef7cad06cc1dcde61c91d2eafef002d25cb194e Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 13 Sep 2021 19:58:43 +0000 Subject: Add trait name and trait hash to exported mapping results --- wqflask/wqflask/marker_regression/run_mapping.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 2f90b475..b101b948 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -422,8 +422,9 @@ class RunMapping: total_markers = len(self.qtl_results) with Bench("Exporting Results"): - export_mapping_results(self.dataset, self.this_trait, self.qtl_results, self.mapping_results_path, - self.mapping_scale, self.score_type, self.transform, self.covariates, self.n_samples) + export_mapping_results(self.dataset, self.this_trait, self.qtl_results, + self.mapping_results_path, self.mapping_scale, self.score_type, + self.transform, self.covariates, self.n_samples, self.vals_hash) with Bench("Trimming Markers for Figure"): if len(self.qtl_results) > 30000: @@ -541,13 +542,15 @@ class RunMapping: return trimmed_genotype_data -def export_mapping_results(dataset, trait, markers, results_path, mapping_scale, score_type, transform, covariates, n_samples): +def export_mapping_results(dataset, trait, markers, results_path, mapping_scale, score_type, transform, covariates, n_samples, vals_hash): with open(results_path, "w+") as output_file: output_file.write( "Time/Date: " + datetime.datetime.now().strftime("%x / %X") + "\n") output_file.write( "Population: " + dataset.group.species.title() + " " + dataset.group.name + "\n") output_file.write("Data Set: " + dataset.fullname + "\n") + output_file.write("Trait: " + trait.display_name + "\n") + output_file.write("Trait Hash: " + vals_hash + "\n") output_file.write("N Samples: " + str(n_samples) + "\n") if len(transform) > 0: transform_text = "Transform - " -- cgit v1.2.3 From 91d04e5b573107aead1da8482dd9184d9869b82a Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 13 Sep 2021 20:03:45 +0000 Subject: Change mapping export filename to use the trait hash --- wqflask/wqflask/marker_regression/run_mapping.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index b101b948..361c413b 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -104,9 +104,7 @@ class RunMapping: if "results_path" in start_vars: self.mapping_results_path = start_vars['results_path'] else: - mapping_results_filename = self.dataset.group.name + "_" + \ - ''.join(random.choice(string.ascii_uppercase + string.digits) - for _ in range(6)) + mapping_results_filename = "_".join([self.dataset.group.name, self.vals_hash]) self.mapping_results_path = "{}{}.csv".format( webqtlConfig.GENERATED_IMAGE_DIR, mapping_results_filename) -- cgit v1.2.3 From 24e0de14969edb220a03e22d1c9b7e6ed33f6b82 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 13 Sep 2021 20:04:30 +0000 Subject: Change mapping export filename to use the path passed from run_mapping, instead of the generic mapping_results.csv --- wqflask/wqflask/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 707b18e1..54314a20 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -1170,7 +1170,7 @@ def export_mapping_results(): results_csv = open(file_path, "r").read() response = Response(results_csv, mimetype='text/csv', - headers={"Content-Disposition": "attachment;filename=mapping_results.csv"}) + headers={"Content-Disposition": "attachment;filename=" + os.path.basename(file_path)}) return response -- cgit v1.2.3 From c0fbbb42a79baa823b517ee8f537cec1edc057c8 Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 14 Sep 2021 18:09:36 +0000 Subject: Replace / with _ in the file hashes in rqtl_mapping.py, since they get translated to directories --- wqflask/wqflask/marker_regression/rqtl_mapping.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py index cd578870..a148b49c 100644 --- a/wqflask/wqflask/marker_regression/rqtl_mapping.py +++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py @@ -61,6 +61,7 @@ def get_hash_of_textio(the_file: TextIO) -> str: the_file.seek(0) hash_of_file = hashlib.md5(the_file.read().encode()).hexdigest() + hash_of_file = hash_of_file.replace("/", "_") # Replace / with _ to prevent issue with filenames being translated to directories return hash_of_file -- cgit v1.2.3 From 8d54d1871e1319f7db46132d3eed61a817d5dc4c Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 14 Sep 2021 18:14:33 +0000 Subject: Replace / with _ in the mapping results filename, due to / causing issues with being translated to directories --- wqflask/wqflask/marker_regression/run_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 361c413b..1df53fef 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -104,7 +104,7 @@ class RunMapping: if "results_path" in start_vars: self.mapping_results_path = start_vars['results_path'] else: - mapping_results_filename = "_".join([self.dataset.group.name, self.vals_hash]) + mapping_results_filename = "_".join([self.dataset.group.name, self.vals_hash]).replace("/", "_") self.mapping_results_path = "{}{}.csv".format( webqtlConfig.GENERATED_IMAGE_DIR, mapping_results_filename) -- cgit v1.2.3 From b6c0885007d516b257d1027b97df66c11b8672dd Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Thu, 16 Sep 2021 13:26:53 +0300 Subject: wqflask: views: Redirect to the correct URL after phenotype update --- wqflask/wqflask/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 54314a20..85aa6b17 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -633,7 +633,7 @@ def update_phenotype(): json_data=json.dumps(diff_data))) flash(f"Diff-data: \n{diff_data}\nhas been uploaded", "success") return redirect(f"/trait/{data_.get('dataset-name')}" - f"/edit/phenotype-id/{data_.get('phenotype-id')}") + f"/edit/inbredset-id/{data_.get('inbred-set-id')}") @app.route("/probeset/update", methods=["POST"]) -- cgit v1.2.3 From 719b256996facb1f4bee2a0288bce1f18168f99b Mon Sep 17 00:00:00 2001 From: zsloan Date: Thu, 16 Sep 2021 17:59:49 +0000 Subject: Added back the option to edit privileges on trait pages, since the metadata edit button had replaced it --- wqflask/wqflask/templates/show_trait_details.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html index 36d3c15a..6a541c8c 100644 --- a/wqflask/wqflask/templates/show_trait_details.html +++ b/wqflask/wqflask/templates/show_trait_details.html @@ -242,6 +242,9 @@ {% if this_trait.dataset.type == 'ProbeSet' %} {% endif %} + {% if admin_status == "owner" or admin_status == "edit-admins" or admin_status == "edit-access" %} + + {% endif %} {% endif %} -- cgit v1.2.3 From a9509a01191883e61cd5013453d18e89db022df2 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 20 Sep 2021 17:34:26 +0000 Subject: Removed the reaper_version selection option, since original qtlreaper is no longer supported --- wqflask/wqflask/templates/show_trait_mapping_tools.html | 9 --------- 1 file changed, 9 deletions(-) diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html index 5365140d..c6b6c0e1 100755 --- a/wqflask/wqflask/templates/show_trait_mapping_tools.html +++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html @@ -95,15 +95,6 @@ {% elif mapping_method == "QTLReaper" %}
    -
    - -
    - -
    -
    -- cgit v1.2.3 From 2ad5b87f1c9bc5ce5bd3f54f7d83f18123ce3c3e Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 20 Sep 2021 17:37:18 +0000 Subject: Returned the GN1 url to gn1.genenetwork.org since it's apparently working well enough again now that some issues have been fixed --- wqflask/wqflask/templates/show_trait_details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html index 6a541c8c..2a21dd24 100644 --- a/wqflask/wqflask/templates/show_trait_details.html +++ b/wqflask/wqflask/templates/show_trait_details.html @@ -233,7 +233,7 @@ {% endif %} {% endif %} - + {% if admin_status == "owner" or admin_status == "edit-admins" or admin_status == "edit-access" %} {% if this_trait.dataset.type == 'Publish' %} -- cgit v1.2.3 From 92df90d68c3d3067f6856c6894be92c7c5dbcaa6 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 22 Sep 2021 17:41:53 +0000 Subject: Remove references to reaper_version and code for running old qtlreaper --- .../marker_regression/display_mapping_results.py | 3 +- .../wqflask/marker_regression/qtlreaper_mapping.py | 95 ---------------------- wqflask/wqflask/marker_regression/run_mapping.py | 59 +++++--------- .../new/javascript/show_trait_mapping_tools.js | 2 +- wqflask/wqflask/views.py | 1 - 5 files changed, 24 insertions(+), 136 deletions(-) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index 77d6e2db..6254b9b9 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -357,8 +357,7 @@ class DisplayMappingResults: if 'use_loco' in list(start_vars.keys()) and self.mapping_method == "gemma": self.use_loco = start_vars['use_loco'] - if 'reaper_version' in list(start_vars.keys()) and self.mapping_method == "reaper": - self.reaper_version = start_vars['reaper_version'] + if self.mapping_method == "reaper": if 'output_files' in start_vars: self.output_files = ",".join( [(the_file if the_file is not None else "") for the_file in start_vars['output_files']]) diff --git a/wqflask/wqflask/marker_regression/qtlreaper_mapping.py b/wqflask/wqflask/marker_regression/qtlreaper_mapping.py index 4d6715ba..801674e1 100644 --- a/wqflask/wqflask/marker_regression/qtlreaper_mapping.py +++ b/wqflask/wqflask/marker_regression/qtlreaper_mapping.py @@ -178,101 +178,6 @@ def parse_reaper_output(gwa_filename, permu_filename, bootstrap_filename): return marker_obs, permu_vals, bootstrap_vals -def run_original_reaper(this_trait, dataset, samples_before, trait_vals, json_data, num_perm, bootCheck, num_bootstrap, do_control, control_marker, manhattan_plot): - genotype = dataset.group.read_genotype_file(use_reaper=True) - - if manhattan_plot != True: - genotype = genotype.addinterval() - - trimmed_samples = [] - trimmed_values = [] - for i in range(0, len(samples_before)): - try: - trimmed_values.append(float(trait_vals[i])) - trimmed_samples.append(str(samples_before[i])) - except: - pass - - perm_output = [] - bootstrap_results = [] - - if num_perm < 100: - suggestive = 0 - significant = 0 - else: - perm_output = genotype.permutation( - strains=trimmed_samples, trait=trimmed_values, nperm=num_perm) - suggestive = perm_output[int(num_perm * 0.37 - 1)] - significant = perm_output[int(num_perm * 0.95 - 1)] - # highly_significant = perm_output[int(num_perm*0.99-1)] #ZS: Currently not used, but leaving it here just in case - - json_data['suggestive'] = suggestive - json_data['significant'] = significant - - if control_marker != "" and do_control == "true": - reaper_results = genotype.regression(strains=trimmed_samples, - trait=trimmed_values, - control=str(control_marker)) - if bootCheck: - control_geno = [] - control_geno2 = [] - _FIND = 0 - for _chr in genotype: - for _locus in _chr: - if _locus.name == control_marker: - control_geno2 = _locus.genotype - _FIND = 1 - break - if _FIND: - break - if control_geno2: - _prgy = list(genotype.prgy) - for _strain in trimmed_samples: - _idx = _prgy.index(_strain) - control_geno.append(control_geno2[_idx]) - - bootstrap_results = genotype.bootstrap(strains=trimmed_samples, - trait=trimmed_values, - control=control_geno, - nboot=num_bootstrap) - else: - reaper_results = genotype.regression(strains=trimmed_samples, - trait=trimmed_values) - - if bootCheck: - bootstrap_results = genotype.bootstrap(strains=trimmed_samples, - trait=trimmed_values, - nboot=num_bootstrap) - - json_data['chr'] = [] - json_data['pos'] = [] - json_data['lod.hk'] = [] - json_data['markernames'] = [] - # if self.additive: - # self.json_data['additive'] = [] - - # Need to convert the QTL objects that qtl reaper returns into a json serializable dictionary - qtl_results = [] - for qtl in reaper_results: - reaper_locus = qtl.locus - # ZS: Convert chr to int - converted_chr = reaper_locus.chr - if reaper_locus.chr != "X" and reaper_locus.chr != "X/Y": - converted_chr = int(reaper_locus.chr) - json_data['chr'].append(converted_chr) - json_data['pos'].append(reaper_locus.Mb) - json_data['lod.hk'].append(qtl.lrs) - json_data['markernames'].append(reaper_locus.name) - # if self.additive: - # self.json_data['additive'].append(qtl.additive) - locus = {"name": reaper_locus.name, "chr": reaper_locus.chr, - "cM": reaper_locus.cM, "Mb": reaper_locus.Mb} - qtl = {"lrs_value": qtl.lrs, "chr": converted_chr, "Mb": reaper_locus.Mb, - "cM": reaper_locus.cM, "name": reaper_locus.name, "additive": qtl.additive, "dominance": qtl.dominance} - qtl_results.append(qtl) - return qtl_results, json_data, perm_output, suggestive, significant, bootstrap_results - - def natural_sort(marker_list): """ Function to naturally sort numbers + strings, adopted from user Mark Byers here: https://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 1df53fef..290c4a14 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -271,47 +271,32 @@ class RunMapping: self.bootCheck = False self.num_bootstrap = 0 - self.reaper_version = start_vars['reaper_version'] - self.control_marker = start_vars['control_marker'] self.do_control = start_vars['do_control'] logger.info("Running qtlreaper") - if self.reaper_version == "new": - self.first_run = True - self.output_files = None - # ZS: check if first run so existing result files can be used if it isn't (for example zooming on a chromosome, etc) - if 'first_run' in start_vars: - self.first_run = False - if 'output_files' in start_vars: - self.output_files = start_vars['output_files'].split( - ",") - - results, self.perm_output, self.suggestive, self.significant, self.bootstrap_results, self.output_files = qtlreaper_mapping.run_reaper(self.this_trait, - self.dataset, - self.samples, - self.vals, - self.json_data, - self.num_perm, - self.bootCheck, - self.num_bootstrap, - self.do_control, - self.control_marker, - self.manhattan_plot, - self.first_run, - self.output_files) - else: - results, self.json_data, self.perm_output, self.suggestive, self.significant, self.bootstrap_results = qtlreaper_mapping.run_original_reaper(self.this_trait, - self.dataset, - self.samples, - self.vals, - self.json_data, - self.num_perm, - self.bootCheck, - self.num_bootstrap, - self.do_control, - self.control_marker, - self.manhattan_plot) + self.first_run = True + self.output_files = None + # ZS: check if first run so existing result files can be used if it isn't (for example zooming on a chromosome, etc) + if 'first_run' in start_vars: + self.first_run = False + if 'output_files' in start_vars: + self.output_files = start_vars['output_files'].split( + ",") + + results, self.perm_output, self.suggestive, self.significant, self.bootstrap_results, self.output_files = qtlreaper_mapping.run_reaper(self.this_trait, + self.dataset, + self.samples, + self.vals, + self.json_data, + self.num_perm, + self.bootCheck, + self.num_bootstrap, + self.do_control, + self.control_marker, + self.manhattan_plot, + self.first_run, + self.output_files) elif self.mapping_method == "plink": self.score_type = "-logP" self.manhattan_plot = True diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js index b75d658e..e42fe8c4 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js +++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js @@ -145,7 +145,7 @@ var mapping_input_list = ['temp_uuid', 'trait_id', 'dataset', 'tool_used', 'form 'sample_vals', 'vals_hash', 'score_type', 'suggestive', 'significant', 'num_perm', 'permCheck', 'perm_output', 'perm_strata', 'categorical_vars', 'num_bootstrap', 'bootCheck', 'bootstrap_results', 'LRSCheck', 'covariates', 'maf', 'use_loco', 'manhattan_plot', 'control_marker', 'do_control', 'genofile', 'pair_scan', 'startMb', 'endMb', 'graphWidth', 'lrsMax', 'additiveCheck', 'showSNP', 'showGenes', 'viewLegend', - 'haplotypeAnalystCheck', 'mapmethod_rqtl_geno', 'mapmodel_rqtl_geno', 'temp_trait', 'group', 'species', 'reaper_version', 'primary_samples'] + 'haplotypeAnalystCheck', 'mapmethod_rqtl_geno', 'mapmodel_rqtl_geno', 'temp_trait', 'group', 'species', 'primary_samples'] $(".rqtl-geno-tab, #rqtl_geno_compute").on("click", (function(_this) { return function() { diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 85aa6b17..980b9362 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -1097,7 +1097,6 @@ def mapping_results_page(): 'mapmethod_rqtl_geno', 'mapmodel_rqtl_geno', 'temp_trait', - 'reaper_version', 'n_samples', 'transform' ) -- cgit v1.2.3 From 7cb23fe9c03e4f8051340e2a8f32645e88acce3a Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 22 Sep 2021 17:52:37 +0000 Subject: Added type='button' to the Delete Collection button within collections/view, since without it it attempts to submit the form encapsulating the button (export in this case) --- wqflask/wqflask/templates/collections/view.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/collections/view.html b/wqflask/wqflask/templates/collections/view.html index 9ec98ab1..a3090bcf 100644 --- a/wqflask/wqflask/templates/collections/view.html +++ b/wqflask/wqflask/templates/collections/view.html @@ -49,7 +49,7 @@ - +
    -- cgit v1.2.3 From 9bd85361d58eb67ef9e59eff6031ed9fd00a3411 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 22 Sep 2021 18:30:13 +0000 Subject: Only show most search page options if results exist; otherwise provide a link back to the home page --- wqflask/wqflask/templates/search_result_page.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html index 7ec335d5..c499aa8f 100644 --- a/wqflask/wqflask/templates/search_result_page.html +++ b/wqflask/wqflask/templates/search_result_page.html @@ -53,6 +53,7 @@ A total of {{ results|count }} records were found.

    + {% if results|count > 0 %} {% if go_term is not none %}

    The associated genes include:

    {% for word in search_terms %}{{ word.search_term[0] }}{% endfor %}

    {% endif %} @@ -133,8 +134,11 @@
    {% endif %} + {% else %} +
    + + {% endif %}
    -
    @@ -171,6 +175,7 @@ return params; }; + {% if results|count > 0 %} //ZS: Need to make sort by symbol, also need to make sure blank symbol fields at the bottom and symbols starting with numbers below letters trait_table = $('#trait_table').DataTable( { 'drawCallback': function( settings ) { @@ -412,6 +417,7 @@ var table = $('#trait_table').DataTable(); table.colReorder.reset() }); + {% endif %} submit_special = function(url) { $("#trait_submission_form").attr("action", url); -- cgit v1.2.3 From cbb9905aa4406551973bfe47dcdb00f6b8ce9628 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 22 Sep 2021 18:39:38 +0000 Subject: Fixed issue where the control marker parameter was being passed incorrectly to GN3 (should be just 'control' but was previously passed as 'control_marker') --- wqflask/wqflask/marker_regression/rqtl_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py index a148b49c..1dca1b1b 100644 --- a/wqflask/wqflask/marker_regression/rqtl_mapping.py +++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py @@ -39,7 +39,7 @@ def run_rqtl(trait_name, vals, samples, dataset, mapping_scale, model, method, n } if do_control == "true" and control_marker: - post_data["control_marker"] = control_marker + post_data["control"] = control_marker if not manhattan_plot: post_data["interval"] = True -- cgit v1.2.3 From cb9422ec5fc985530fcb4fb44d2729e460424d60 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 22 Sep 2021 18:44:01 +0000 Subject: Removed the Control for (marker) option from R/qtl for now since Danny mentioned it isn't working correctly --- wqflask/wqflask/templates/show_trait_mapping_tools.html | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html index c6b6c0e1..3af94ed6 100755 --- a/wqflask/wqflask/templates/show_trait_mapping_tools.html +++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html @@ -253,21 +253,6 @@
    {% endif %} -
    - -
    - - - -
    -
    -
    -- cgit v1.2.3 From 3494a9af7f82691f419ba1e3bd616be5ce68a00a Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 27 Sep 2021 13:07:11 +0300 Subject: Remove lengthy stack trace for 404, 400, 408 status codes The stack trace causes the log file to grow into unmanageable sizes over time. --- wqflask/wqflask/views.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 980b9362..1139ad43 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -160,18 +160,26 @@ def shutdown_session(exception=None): @app.errorhandler(Exception) -def handle_bad_request(e): +def handle_generic_exceptions(e): + import werkzeug err_msg = str(e) - logger.error(err_msg) - logger.error(request.url) - # get the stack trace and send it to the logger - exc_type, exc_value, exc_traceback = sys.exc_info() - logger.error(traceback.format_exc()) now = datetime.datetime.utcnow() time_str = now.strftime('%l:%M%p UTC %b %d, %Y') - formatted_lines = [request.url - + " (" + time_str + ")"] + traceback.format_exc().splitlines() - + # get the stack trace and send it to the logger + exc_type, exc_value, exc_traceback = sys.exc_info() + formatted_lines = {f"{request.url} ({time_str}) " + f" {traceback.format_exc().splitlines()}"} + + _message_templates = { + werkzeug.exceptions.NotFound: ("404: Not Found: " + f"{time_str}: {request.url}"), + werkzeug.exceptions.BadRequest: ("400: Bad Request: " + f"{time_str}: {request.url}"), + werkzeug.exceptions.RequestTimeout: ("408: Request Timeout: " + f"{time_str}: {request.url}")} + # Default to the lengthy stack trace! + logger.error(_message_templates.get(exc_type, + formatted_lines)) # Handle random animations # Use a cookie to have one animation on refresh animation = request.cookies.get(err_msg[:32]) -- cgit v1.2.3 From 8135bd22898130ae6f58aa74cb80c83ab334d0d4 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 27 Sep 2021 13:08:49 +0300 Subject: Remove variable-- named after a python keyword-- called "list" --- wqflask/wqflask/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 1139ad43..007b0f9e 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -184,9 +184,8 @@ def handle_generic_exceptions(e): # Use a cookie to have one animation on refresh animation = request.cookies.get(err_msg[:32]) if not animation: - list = [fn for fn in os.listdir( - "./wqflask/static/gif/error") if fn.endswith(".gif")] - animation = random.choice(list) + animation = random.choice([fn for fn in os.listdir( + "./wqflask/static/gif/error") if fn.endswith(".gif")]) resp = make_response(render_template("error.html", message=err_msg, stack=formatted_lines, error_image=animation, version=GN_VERSION)) -- cgit v1.2.3 From 16947a15bd955be7da45bb5f078870649b1b63e5 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 27 Sep 2021 13:09:24 +0300 Subject: Apply pep-8 formatting --- wqflask/wqflask/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 007b0f9e..b297da08 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -188,7 +188,9 @@ def handle_generic_exceptions(e): "./wqflask/static/gif/error") if fn.endswith(".gif")]) resp = make_response(render_template("error.html", message=err_msg, - stack=formatted_lines, error_image=animation, version=GN_VERSION)) + stack=formatted_lines, + error_image=animation, + version=GN_VERSION)) # logger.error("Set cookie %s with %s" % (err_msg, animation)) resp.set_cookie(err_msg[:32], animation) -- cgit v1.2.3 From 266d4c4a425ca0a215c8d789e2978d213d5ff37d Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 21 Sep 2021 21:25:13 +0300 Subject: Rename "admin_login_required" to "edit_access_required" --- wqflask/wqflask/decorators.py | 2 +- wqflask/wqflask/views.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wqflask/wqflask/decorators.py b/wqflask/wqflask/decorators.py index f0978fd3..f6e3eb8a 100644 --- a/wqflask/wqflask/decorators.py +++ b/wqflask/wqflask/decorators.py @@ -3,7 +3,7 @@ from flask import g from functools import wraps -def admin_login_required(f): +def edit_access_required(f): """Use this for endpoints where admins are required""" @wraps(f) def wrap(*args, **kwargs): diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index b297da08..5067ca0e 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -85,7 +85,7 @@ from wqflask.export_traits import export_search_results_csv from wqflask.gsearch import GSearch from wqflask.update_search_results import GSearch as UpdateGSearch from wqflask.docs import Docs, update_text -from wqflask.decorators import admin_login_required +from wqflask.decorators import edit_access_required from wqflask.db_info import InfoPage from utility import temp_data @@ -420,7 +420,7 @@ def submit_trait_form(): @app.route("/trait//edit/inbredset-id/") -@admin_login_required +@edit_access_required def edit_phenotype(name, inbredset_id): conn = MySQLdb.Connect(db=current_app.config.get("DB_NAME"), user=current_app.config.get("DB_USER"), @@ -477,7 +477,7 @@ def edit_phenotype(name, inbredset_id): @app.route("/trait/edit/probeset-name/") -@admin_login_required +@edit_access_required def edit_probeset(dataset_name): conn = MySQLdb.Connect(db=current_app.config.get("DB_NAME"), user=current_app.config.get("DB_USER"), @@ -520,7 +520,7 @@ def edit_probeset(dataset_name): @app.route("/trait/update", methods=["POST"]) -@admin_login_required +@edit_access_required def update_phenotype(): conn = MySQLdb.Connect(db=current_app.config.get("DB_NAME"), user=current_app.config.get("DB_USER"), @@ -646,7 +646,7 @@ def update_phenotype(): @app.route("/probeset/update", methods=["POST"]) -@admin_login_required +@edit_access_required def update_probeset(): conn = MySQLdb.Connect(db=current_app.config.get("DB_NAME"), user=current_app.config.get("DB_USER"), @@ -1381,7 +1381,7 @@ def get_sample_data_as_csv(trait_name: int, phenotype_id: int): @app.route("/admin/data-sample/diffs/") -@admin_login_required +@edit_access_required def display_diffs_admin(): TMPDIR = current_app.config.get("TMPDIR") DIFF_DIR = f"{TMPDIR}/sample-data/diffs" -- cgit v1.2.3 From 7f317126d7d422b073cb4e4a8698757fe1e763f3 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 21 Sep 2021 21:36:32 +0300 Subject: Replace hard-coded e-mails with gn-proxy queries * wqflask/wqflask/decorators.py (edit_access_required.wrap): Query the proxy to see the access rights of a given user. --- wqflask/wqflask/decorators.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/wqflask/wqflask/decorators.py b/wqflask/wqflask/decorators.py index f6e3eb8a..54aa6795 100644 --- a/wqflask/wqflask/decorators.py +++ b/wqflask/wqflask/decorators.py @@ -1,14 +1,36 @@ """This module contains gn2 decorators""" from flask import g +from typing import Dict from functools import wraps +from utility.hmac import hmac_creation + +import json +import requests def edit_access_required(f): """Use this for endpoints where admins are required""" @wraps(f) def wrap(*args, **kwargs): - if g.user_session.record.get(b"user_email_address") not in [ - b"labwilliams@gmail.com"]: + resource_id: str = "" + if kwargs.get("inbredset_id"): # data type: dataset-publish + resource_id = hmac_creation("dataset-publish:" + f"{kwargs.get('inbredset_id')}:" + f"{kwargs.get('name')}") + if kwargs.get("dataset_name"): # data type: dataset-probe + resource_id = hmac_creation("dataset-probeset:" + f"{kwargs.get('dataset_name')}") + response: Dict = {} + try: + _user_id = g.user_session.record.get(b"user_id", + "").decode("utf-8") + response = json.loads( + requests.get("http://localhost:8080/" + "available?resource=" + f"{resource_id}&user={_user_id}").content) + except: + response = {} + if "edit" not in response.get("data", []): return "You need to be admin", 401 return f(*args, **kwargs) return wrap -- cgit v1.2.3 From ac14326be6695f185f843d29bf3ff016f5eb3016 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 22 Sep 2021 14:30:09 +0300 Subject: new_security: login_user.html: Delete commented out block --- .../wqflask/templates/new_security/login_user.html | 26 ---------------------- 1 file changed, 26 deletions(-) diff --git a/wqflask/wqflask/templates/new_security/login_user.html b/wqflask/wqflask/templates/new_security/login_user.html index 095036f0..88eab6bc 100644 --- a/wqflask/wqflask/templates/new_security/login_user.html +++ b/wqflask/wqflask/templates/new_security/login_user.html @@ -114,31 +114,5 @@ label.error,div.error{ {% endblock %} {% block js %} - - - {% include "new_security/_scripts.html" %} {% endblock %} -- cgit v1.2.3 From 84a0cce8a341b8b45b3b0037379818c32d5614b2 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 22 Sep 2021 14:32:03 +0300 Subject: Remove "_scripts.html" and all it's references --- wqflask/wqflask/templates/new_security/_scripts.html | 1 - wqflask/wqflask/templates/new_security/forgot_password.html | 1 - wqflask/wqflask/templates/new_security/forgot_password_step2.html | 1 - wqflask/wqflask/templates/new_security/password_reset.html | 1 - wqflask/wqflask/templates/new_security/register_user.html | 1 - wqflask/wqflask/templates/new_security/registered.html | 1 - wqflask/wqflask/templates/new_security/thank_you.html | 1 - wqflask/wqflask/templates/new_security/verification_still_needed.html | 1 - 8 files changed, 8 deletions(-) delete mode 100644 wqflask/wqflask/templates/new_security/_scripts.html diff --git a/wqflask/wqflask/templates/new_security/_scripts.html b/wqflask/wqflask/templates/new_security/_scripts.html deleted file mode 100644 index 5fefe305..00000000 --- a/wqflask/wqflask/templates/new_security/_scripts.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/wqflask/wqflask/templates/new_security/forgot_password.html b/wqflask/wqflask/templates/new_security/forgot_password.html index e5c42a45..60a221da 100644 --- a/wqflask/wqflask/templates/new_security/forgot_password.html +++ b/wqflask/wqflask/templates/new_security/forgot_password.html @@ -48,6 +48,5 @@ {% endblock %} {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} diff --git a/wqflask/wqflask/templates/new_security/forgot_password_step2.html b/wqflask/wqflask/templates/new_security/forgot_password_step2.html index b4bf41c7..1835fd4c 100644 --- a/wqflask/wqflask/templates/new_security/forgot_password_step2.html +++ b/wqflask/wqflask/templates/new_security/forgot_password_step2.html @@ -20,7 +20,6 @@ {% endblock %} {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} diff --git a/wqflask/wqflask/templates/new_security/password_reset.html b/wqflask/wqflask/templates/new_security/password_reset.html index 684c12b1..e21f075c 100644 --- a/wqflask/wqflask/templates/new_security/password_reset.html +++ b/wqflask/wqflask/templates/new_security/password_reset.html @@ -73,7 +73,6 @@ {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} diff --git a/wqflask/wqflask/templates/new_security/register_user.html b/wqflask/wqflask/templates/new_security/register_user.html index 3ae4488b..c2895517 100644 --- a/wqflask/wqflask/templates/new_security/register_user.html +++ b/wqflask/wqflask/templates/new_security/register_user.html @@ -100,7 +100,6 @@ {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} diff --git a/wqflask/wqflask/templates/new_security/registered.html b/wqflask/wqflask/templates/new_security/registered.html index f2f58ec1..29889a97 100644 --- a/wqflask/wqflask/templates/new_security/registered.html +++ b/wqflask/wqflask/templates/new_security/registered.html @@ -19,7 +19,6 @@ {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} diff --git a/wqflask/wqflask/templates/new_security/thank_you.html b/wqflask/wqflask/templates/new_security/thank_you.html index 0ff7ee8d..d4f5e574 100644 --- a/wqflask/wqflask/templates/new_security/thank_you.html +++ b/wqflask/wqflask/templates/new_security/thank_you.html @@ -18,7 +18,6 @@ {% endblock %} {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} diff --git a/wqflask/wqflask/templates/new_security/verification_still_needed.html b/wqflask/wqflask/templates/new_security/verification_still_needed.html index dc0f9e68..1f91fd8d 100644 --- a/wqflask/wqflask/templates/new_security/verification_still_needed.html +++ b/wqflask/wqflask/templates/new_security/verification_still_needed.html @@ -21,7 +21,6 @@ {% endblock %} {% block js %} - {% include "new_security/_scripts.html" %} {% endblock %} -- cgit v1.2.3 From 6e0ea75ca427721aed0a5f394b501b2cde9bf769 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Thu, 23 Sep 2021 13:17:55 +0300 Subject: Add script for creating/ updating groups during authorisation --- scripts/authentication/group.py | 130 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 scripts/authentication/group.py diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py new file mode 100644 index 00000000..b89bc3ec --- /dev/null +++ b/scripts/authentication/group.py @@ -0,0 +1,130 @@ +"""A script for adding users to a specific group. + +Example: + +Assuming there are no groups and 'test@bonfacemunyoki.com' does not +exist in Redis: + +.. code-block:: bash + python group.py -g "editors" -m "test@bonfacemunyoki.com" + +results in:: + + Successfully created the group: 'editors' + Data: '{"admins": [], "members": []}' + +If 'me@bonfacemunyoki.com' exists in 'users' in Redis and we run: + +.. code-block:: bash + python group.py -g "editors" -m "me@bonfacemunyoki.com" + +now results in:: + + No new group was created. + Updated Data: {'admins': [], 'members': ['me@bonfacemunyoki.com']} + +""" + +import argparse +import redis +import json + +from typing import Dict, List, Optional, Set +from glom import glom # type: ignore + + +def create_group_data(users: Dict, target_group: str, + members: Optional[str] = None, + admins: Optional[str] = None) -> Dict: + """Return a dictionary that contains the following keys: "key", + "field", and "value" that can be used in a redis hash as follows: + HSET key field value + + Parameters: + + - `users`: a list of users for example: + + {'8ad942fe-490d-453e-bd37-56f252e41603': + '{"email_address": "me@test.com", + "full_name": "John Doe", + "organization": "Genenetwork", + "password": {"algorithm": "pbkdf2", + "hashfunc": "sha256", + "salt": "gJrd1HnPSSCmzB5veMPaVk2ozzDlS1Z7Ggcyl1+pciA=", + "iterations": 100000, "keylength": 32, + "created_timestamp": "2021-09-22T11:32:44.971912", + "password": "edcdaa60e84526c6"}, + "user_id": "8ad942fe", "confirmed": 1, + "registration_info": { + "timestamp": "2021-09-22T11:32:45.028833", + "ip_address": "127.0.0.1", + "user_agent": "Mozilla/5.0"}}'} + + - `target_group`: the group name that will be stored inside the + "groups" hash in Redis. + + - `members`: a comma-separated list of values that contain members + of the `target_group` e.g. "me@test1.com, me@test2.com, + me@test3.com" + + - `admins`: a comma-separated list of values that contain + administrators of the `target_group` e.g. "me@test1.com, + me@test2.com, me@test3.com" + + """ + _members = "".join(members.split()).split(",") if members else [] + _admins: List = "".join(admins.split()).split(",") if admins else [] + + user_emails: Set = {glom(json.loads(user_details), "email_address") + for _, user_details in users.items()} + + return {"key": "groups", + "field": target_group, + "value": json.dumps({ + "admins": [admin for admin in _admins + if admin in user_emails], + "members": [member for member in _members + if member in user_emails] + })} + + +if __name__ == "__main__": + # Initialising the parser CLI arguments + parser = argparse.ArgumentParser() + parser.add_argument("-g", "--group-name", + help="This is the name of the GROUP mask") + parser.add_argument("-m", "--members", + help="Members of the GROUP mask") + parser.add_argument("-a", "--admins", + help="Admins of the GROUP mask") + args = parser.parse_args() + + if not args.group_name: + exit("\nExiting. Please specify a group name to use!\n") + + members = args.members if args.members else None + admins = args.admins if args.admins else None + REDIS_CONN = redis.Redis() + USERS = {key.decode(): val.decode() + for key, val in REDIS_CONN.hgetall("users").items()} + + if not any([members, admins]): + exit("\nExiting. Please provide a value for " + "MEMBERS(-m) or ADMINS(-a)!\n") + + data = create_group_data( + users=USERS, + target_group=args.group_name, + members=members, + admins=admins) + created_p = REDIS_CONN.hset(data.get("key", ""), + data.get("field", ""), + data.get("value", "")) + + groups = json.loads(REDIS_CONN.hget("groups", + args.group_name)) # type: ignore + if created_p: + exit(f"\nSuccessfully created the group: '{args.group_name}'\n" + f"Data: {groups}\n") + exit("\nNo new group was created.\n" + f"Updated Data: {groups}\n") -- cgit v1.2.3 From c585945c5516092b362efecc16325ad9ecc54291 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Thu, 23 Sep 2021 15:39:32 +0300 Subject: Add script that adds "editors" group to all resources in Redis --- scripts/authentication/resource.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 scripts/authentication/resource.py diff --git a/scripts/authentication/resource.py b/scripts/authentication/resource.py new file mode 100644 index 00000000..75ef9e93 --- /dev/null +++ b/scripts/authentication/resource.py @@ -0,0 +1,25 @@ +"""A script that adds the group: 'editors' to every +resource. 'editors' should have the right to edit both metadata and +data. + +To use this script, simply run: + +.. code-block:: python + python resource.py + +""" +import json +import redis + + +if __name__ == "__main__": + REDIS_CONN = redis.Redis() + resources = REDIS_CONN.hgetall("resources_clone") + for resource_id, resource in resources.items(): + deserialized_resource = json.loads(resource) + deserialized_resource["group_masks"] = { + "editors": {"metadata": "edit", + "data": "edit"}} + REDIS_CONN.hset("resources_clone", + resource_id, + json.dumps(deserialized_resource)) -- cgit v1.2.3 From edb6fe1b9dd98d84deb0925a2d83726e739d8677 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 27 Sep 2021 16:28:12 +0300 Subject: wqflask: resource_manager: Remove logger --- wqflask/wqflask/resource_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/wqflask/wqflask/resource_manager.py b/wqflask/wqflask/resource_manager.py index b28c1b04..c54dd0b3 100644 --- a/wqflask/wqflask/resource_manager.py +++ b/wqflask/wqflask/resource_manager.py @@ -8,8 +8,6 @@ from wqflask import app from utility.authentication_tools import check_owner_or_admin from utility.redis_tools import get_resource_info, get_group_info, get_groups_like_unique_column, get_user_id, get_user_by_unique_column, get_users_like_unique_column, add_access_mask, add_resource, change_resource_owner -from utility.logger import getLogger -logger = getLogger(__name__) @app.route("/resources/manage", methods=('GET', 'POST')) -- cgit v1.2.3 From df487791c91a5aa1a9a3b4e1a6c9ce17a58eafe6 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 4 Oct 2021 12:21:16 +0300 Subject: Modify resource editing script to enable data backups & restoration --- scripts/authentication/resource.py | 101 ++++++++++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/scripts/authentication/resource.py b/scripts/authentication/resource.py index 75ef9e93..8fcf09d7 100644 --- a/scripts/authentication/resource.py +++ b/scripts/authentication/resource.py @@ -1,25 +1,100 @@ -"""A script that adds the group: 'editors' to every -resource. 'editors' should have the right to edit both metadata and -data. +"""A script that: -To use this script, simply run: +- Optionally restores data from a json file. + +- By default, without any args provided, adds the group: 'editors' to +every resource. 'editors' should have the right to edit both metadata +and data. + +- Optionally creates a back-up every time you edit a resource. + + +To restore a back-up: + +.. code-block:: python + python resource.py --restore + +To add editors to every resource without creating a back-up: .. code-block:: python python resource.py +To add editors to every resource while creating a back-up before any +destructive edits: + +.. code-block:: python + python resource.py --enable-backup + """ +import argparse import json import redis +import os + +from datetime import datetime + + +def recover_hash(name: str, file_path: str, set_function) -> bool: + """Recover back-ups using the `set_function` + + Parameters: + + - `name`: Redis hash where `file_path` will be restored + + - `file_path`: File path where redis hash is sourced from + + - `set_function`: Function used to do the Redis backup for + example: HSET + + """ + try: + with open(file_path, "r") as f: + resources = json.load(f) + for resource_id, resource in resources.items(): + set_function(name=name, + key=resource_id, + value=resource) + return True + except Exception as e: + print(e) + return False if __name__ == "__main__": - REDIS_CONN = redis.Redis() - resources = REDIS_CONN.hgetall("resources_clone") - for resource_id, resource in resources.items(): - deserialized_resource = json.loads(resource) - deserialized_resource["group_masks"] = { - "editors": {"metadata": "edit", - "data": "edit"}} - REDIS_CONN.hset("resources_clone", + # Initialising the parser CLI arguments + parser = argparse.ArgumentParser() + parser.add_argument("--restore", + help="Restore from a given backup") + parser.add_argument("--enable-backup", action="store_true", + help="Create a back up before edits") + args = parser.parse_args() + + if args.restore: + if recover_hash(name="resources", + file_path=args.back_up, + set_function=redis.Redis(decode_responses=True).hset): + exit(f"\n Done restoring {args.back_up}!\n") + else: + exit(f"\n There was an error restoring {args.back_up}!\n") + + REDIS_CONN = redis.Redis(decode_responses=True) + RESOURCES = REDIS_CONN.hgetall("resources") + BACKUP_DIR = os.path.join(os.getenv("HOME"), "redis") + if args.enable_backup: + FILENAME = ("resources-" + f"{datetime.now().strftime('%Y-%m-%d-%I:%M:%S-%p')}" + ".json") + if not os.path.exists(BACKUP_DIR): + os.mkdir(BACKUP_DIR) + with open(os.path.join(BACKUP_DIR, FILENAME), "w") as f: + json.dump(RESOURCES, f, indent=4) + print(f"\nDone backing upto {FILENAME}") + + for resource_id, resource in RESOURCES.items(): + _resource = json.loads(resource) # str -> dict conversion + _resource["group_masks"] = {"editors": {"metadata": "edit", + "data": "edit"}} + REDIS_CONN.hset("resources", resource_id, - json.dumps(deserialized_resource)) + json.dumps(_resource)) + exit("Done updating `resources`\n") -- cgit v1.2.3 From c5215d1ed224480a274476933beded9d2ba7f7dc Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 4 Oct 2021 13:40:06 +0300 Subject: Decode redis response by default --- scripts/authentication/group.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index b89bc3ec..265e8664 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -104,9 +104,8 @@ if __name__ == "__main__": members = args.members if args.members else None admins = args.admins if args.admins else None - REDIS_CONN = redis.Redis() - USERS = {key.decode(): val.decode() - for key, val in REDIS_CONN.hgetall("users").items()} + REDIS_CONN = redis.Redis(decode_responses=True) + USERS = REDIS_CONN.hgetall("users") if not any([members, admins]): exit("\nExiting. Please provide a value for " -- cgit v1.2.3 From 8fae92c83d49042da68638319385df02061df44b Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 4 Oct 2021 13:45:59 +0300 Subject: scripts: group.py: Remove "glom" dependency --- scripts/authentication/group.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index 265e8664..02f782b3 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -30,7 +30,6 @@ import redis import json from typing import Dict, List, Optional, Set -from glom import glom # type: ignore def create_group_data(users: Dict, target_group: str, @@ -74,10 +73,12 @@ def create_group_data(users: Dict, target_group: str, """ _members = "".join(members.split()).split(",") if members else [] _admins: List = "".join(admins.split()).split(",") if admins else [] - - user_emails: Set = {glom(json.loads(user_details), "email_address") - for _, user_details in users.items()} - + user_emails: Set = set() + for _, user_details in users.items(): + _details = json.loads(user_details) + if _details.get("email_address"): + user_emails.add(_details.get("email_address")) + print(user_emails) return {"key": "groups", "field": target_group, "value": json.dumps({ -- cgit v1.2.3 From 7c1dd1211f96ca1021debc27a80d1700e70b9c6b Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Mon, 4 Oct 2021 13:49:12 +0300 Subject: scripts: group.py: Modify exit message when displaying updated data --- scripts/authentication/group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index 02f782b3..cc0b037e 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -125,6 +125,6 @@ if __name__ == "__main__": args.group_name)) # type: ignore if created_p: exit(f"\nSuccessfully created the group: '{args.group_name}'\n" - f"Data: {groups}\n") + f"`HGETALL groups {args.group_name}`: {groups}\n") exit("\nNo new group was created.\n" - f"Updated Data: {groups}\n") + f"`HGETALL groups {args.group_name}`: {groups}\n") -- cgit v1.2.3 From 609865fc42b7436d8c34cdcefd159c3352c5d91c Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 4 Oct 2021 20:58:14 +0000 Subject: Add group link for user member groups --- wqflask/wqflask/templates/admin/group_manager.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/wqflask/templates/admin/group_manager.html b/wqflask/wqflask/templates/admin/group_manager.html index c0b99e75..692a7abc 100644 --- a/wqflask/wqflask/templates/admin/group_manager.html +++ b/wqflask/wqflask/templates/admin/group_manager.html @@ -81,7 +81,7 @@ {{ loop.index }} - {{ group.name }} + {{ group.name }} {{ group.admins|length + group.members|length }} {{ group.created_timestamp }} {{ group.changed_timestamp }} -- cgit v1.2.3 From 5b116de4aaf796be138ee0ad06c2242b3f3c33c7 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 4 Oct 2021 21:02:37 +0000 Subject: Changed get_user_groups to pull both the ID and details in the for loop from group_list by using group_list.items() --- wqflask/utility/redis_tools.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py index 99295c67..de9dde46 100644 --- a/wqflask/utility/redis_tools.py +++ b/wqflask/utility/redis_tools.py @@ -127,20 +127,20 @@ def check_verification_code(code): def get_user_groups(user_id): - # ZS: Get the groups where a user is an admin or a member and + # 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 + admin_group_ids = [] # Group IDs where user is an admin + user_group_ids = [] # Group IDs where user is a regular user groups_list = Redis.hgetall("groups") - for key in groups_list: + for group_id, group_details in groups_list.items(): try: - group_ob = json.loads(groups_list[key]) - group_admins = set([this_admin if this_admin else None for this_admin in group_ob['admins']]) - group_members = set([this_member if this_member else None for this_member in group_ob['members']]) + _details = json.loads(group_details) + group_admins = set([this_admin if this_admin else None for this_admin in _details['admins']]) + group_members = set([this_member if this_member else None for this_member in _details['members']]) if user_id in group_admins: - admin_group_ids.append(group_ob['id']) + admin_group_ids.append(group_id) elif user_id in group_members: - user_group_ids.append(group_ob['id']) + user_group_ids.append(group_id) else: continue except: -- cgit v1.2.3 From 35a970adba5ee1d60769a81b446122a60eac9494 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 4 Oct 2021 21:03:52 +0000 Subject: Changed the group.py script to replace user e-mails with IDs and to include id, name, changed_timestamp, and created_timestamp in group details --- scripts/authentication/group.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index cc0b037e..a5f75aad 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -26,11 +26,13 @@ now results in:: """ import argparse +import datetime import redis import json from typing import Dict, List, Optional, Set +REDIS_CONN = redis.Redis(decode_responses=True) def create_group_data(users: Dict, target_group: str, members: Optional[str] = None, @@ -71,21 +73,26 @@ def create_group_data(users: Dict, target_group: str, me@test2.com, me@test3.com" """ - _members = "".join(members.split()).split(",") if members else [] + + _members: List = "".join(members.split()).split(",") if members else [] _admins: List = "".join(admins.split()).split(",") if admins else [] - user_emails: Set = set() - for _, user_details in users.items(): + + user_ids: Dict = dict() + for user_id, user_details in users.items(): _details = json.loads(user_details) if _details.get("email_address"): - user_emails.add(_details.get("email_address")) - print(user_emails) + user_ids[_details.get("email_address")] = user_id + print(user_ids) return {"key": "groups", "field": target_group, "value": json.dumps({ - "admins": [admin for admin in _admins - if admin in user_emails], - "members": [member for member in _members - if member in user_emails] + "id": target_group, + "name": target_group, + "admins": [user_ids[admin] for admin in _admins + if admin in user_ids], + "members": [user_ids[member] for member in _members + if member in user_ids], + "changed_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') })} @@ -105,7 +112,6 @@ if __name__ == "__main__": members = args.members if args.members else None admins = args.admins if args.admins else None - REDIS_CONN = redis.Redis(decode_responses=True) USERS = REDIS_CONN.hgetall("users") if not any([members, admins]): @@ -117,6 +123,12 @@ if __name__ == "__main__": target_group=args.group_name, members=members, admins=admins) + + if not REDIS_CONN.hget("groups", data.get("field", "")): + updated_data = json.loads(data["value"]) + updated_data["created_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + data["value"] = json.dumps(updated_data) + created_p = REDIS_CONN.hset(data.get("key", ""), data.get("field", ""), data.get("value", "")) -- cgit v1.2.3 From 4c6a7e46dd7afe311c0bed38c4a69ddadf3cb416 Mon Sep 17 00:00:00 2001 From: zsloan Date: Mon, 4 Oct 2021 21:09:15 +0000 Subject: Moved REDIS_CONN back into if __name__ == '__main__' since it doesn't need to be globally accessed anymore (I think I intiially moved it because I was calling it in create_group_data, but that ended up being unnecessary --- scripts/authentication/group.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index a5f75aad..76c7fb4f 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -32,8 +32,6 @@ import json from typing import Dict, List, Optional, Set -REDIS_CONN = redis.Redis(decode_responses=True) - def create_group_data(users: Dict, target_group: str, members: Optional[str] = None, admins: Optional[str] = None) -> Dict: @@ -112,6 +110,8 @@ if __name__ == "__main__": members = args.members if args.members else None admins = args.admins if args.admins else None + + REDIS_CONN = redis.Redis(decode_responses=True) USERS = REDIS_CONN.hgetall("users") if not any([members, admins]): -- cgit v1.2.3 From 2236508f24c8c266a6a9dff28a1307bb3d0dd31e Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 5 Oct 2021 11:07:09 +0300 Subject: tests: test_run_mapping: Add missing positional argument "vals_hash" --- wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py index c220a072..31f56c07 100644 --- a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py +++ b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py @@ -181,7 +181,8 @@ class TestRunMapping(unittest.TestCase): with mock.patch("wqflask.marker_regression.run_mapping.datetime.datetime", new=datetime_mock): export_mapping_results(dataset=self.dataset, trait=self.trait, markers=markers, results_path="~/results", mapping_scale="physic", score_type="-log(p)", - transform="qnorm", covariates="Dataset1:Trait1,Dataset2:Trait2", n_samples="100") + transform="qnorm", covariates="Dataset1:Trait1,Dataset2:Trait2", n_samples="100", + vals_hash="") write_calls = [ mock.call('Time/Date: 09/01/19 / 10:12:12\n'), -- cgit v1.2.3 From 321632bf70c72ed987ba7c4f605dd92deaa62380 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 5 Oct 2021 11:10:04 +0300 Subject: tests: test_run_mapping: Add missing attribute to "self.trait" --- wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py index 31f56c07..26903eed 100644 --- a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py +++ b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py @@ -47,7 +47,7 @@ class TestRunMapping(unittest.TestCase): self.chromosomes = AttributeSetter({"chromosomes": chromosomes}) self.trait = AttributeSetter( - {"symbol": "IGFI", "chr": "X1", "mb": 123313}) + {"symbol": "IGFI", "chr": "X1", "mb": 123313, "display_name": "Test Name"}) def tearDown(self): self.dataset = AttributeSetter( -- cgit v1.2.3 From e97719eea27ede1b3e943e6d21d18e5d383679f0 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 5 Oct 2021 11:12:29 +0300 Subject: tests: test_run_mapping: Fix failing assert when getting perm strata --- wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py index 26903eed..3e9e4ef3 100644 --- a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py +++ b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py @@ -233,25 +233,20 @@ class TestRunMapping(unittest.TestCase): "c1": "c1_value", "c2": "c2_value", "w1": "w1_value" - }, "S2": { "w1": "w2_value", "w2": "w2_value" - }, "S3": { "c1": "c1_value", "c2": "c2_value" - }, - }}) - results = get_perm_strata(this_trait={}, sample_list=sample_list, categorical_vars=categorical_vars, used_samples=used_samples) - self.assertEqual(results, [2, 1]) + self.assertEqual(results, [1, 1]) def test_get_chr_length(self): """test for getting chromosome length""" -- cgit v1.2.3 From 1f5be42d8f090fd4fe77a9275b12a9c9b1383d09 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 5 Oct 2021 11:19:52 +0300 Subject: tests: test_run_mapping: Add missing calls After adding the missing attribute to "self.trait", we need to also need to update some missing calls. --- wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py index 3e9e4ef3..3747aeb8 100644 --- a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py +++ b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py @@ -188,6 +188,8 @@ class TestRunMapping(unittest.TestCase): mock.call('Time/Date: 09/01/19 / 10:12:12\n'), mock.call('Population: Human GP1_\n'), mock.call( 'Data Set: dataser_1\n'), + mock.call('Trait: Test Name\n'), + mock.call('Trait Hash: \n'), mock.call('N Samples: 100\n'), mock.call( 'Transform - Quantile Normalized\n'), mock.call('Gene Symbol: IGFI\n'), mock.call( -- cgit v1.2.3 From a4ec2505fb9dd6f0480c9b452fd623e038c07939 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 5 Oct 2021 11:28:33 +0300 Subject: tests: test_run_mapping: Add missing "name" attribute to tests --- .../unit/wqflask/marker_regression/test_gemma_mapping.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py index 4003d68f..58a44b2a 100644 --- a/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py +++ b/wqflask/tests/unit/wqflask/marker_regression/test_gemma_mapping.py @@ -81,10 +81,12 @@ class TestGemmaMapping(unittest.TestCase): def test_gen_pheno_txt_file(self): """add tests for generating pheno txt file""" with mock.patch("builtins.open", mock.mock_open())as mock_open: - gen_pheno_txt_file(this_dataset={}, genofile_name="", vals=[ - "x", "w", "q", "we", "R"], trait_filename="fitr.re") + gen_pheno_txt_file( + this_dataset=AttributeSetter({"name": "A"}), + genofile_name="", vals=[ + "x", "w", "q", "we", "R"]) mock_open.assert_called_once_with( - '/home/user/data/gn2/fitr.re.txt', 'w') + '/home/user/data/gn2/PHENO_KiAEKlCvM6iGTM9Kh_TAlQ.txt', 'w') filehandler = mock_open() values = ["x", "w", "q", "we", "R"] write_calls = [mock.call('NA\n'), mock.call('w\n'), mock.call( @@ -112,7 +114,7 @@ class TestGemmaMapping(unittest.TestCase): create_trait.side_effect = create_trait_side_effect group = MockGroup({"name": "group_X", "samplelist": samplelist}) - this_dataset = AttributeSetter({"group": group}) + this_dataset = AttributeSetter({"group": group, "name": "A"}) flat_files.return_value = "Home/Genenetwork" with mock.patch("builtins.open", mock.mock_open())as mock_open: @@ -132,7 +134,7 @@ class TestGemmaMapping(unittest.TestCase): flat_files.assert_called_once_with('mapping') mock_open.assert_called_once_with( - 'Home/Genenetwork/group_X_covariates.txt', 'w') + 'Home/Genenetwork/COVAR_anFZ_LfZYV0Ulywo+7tRCw.txt', 'w') filehandler = mock_open() filehandler.write.assert_has_calls([mock.call( '-9\t'), mock.call('-9\t'), mock.call('-9\t'), mock.call('-9\t'), mock.call('\n')]) -- cgit v1.2.3 From 7a15d24a6598f30801dd897ddc72d3773641e7bd Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Tue, 5 Oct 2021 11:32:17 +0300 Subject: doc: docker-container.org: Remove python2 gn2 docker set-up command --- doc/docker-container.org | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/docker-container.org b/doc/docker-container.org index ef0d71fc..79b8272f 100644 --- a/doc/docker-container.org +++ b/doc/docker-container.org @@ -28,13 +28,6 @@ which will be added to a base mariaDB image. First create the gn2 tar archive by running: #+begin_src sh -# For the Python 2 version: -env GUIX_PACKAGE_PATH="/home/bonface/projects/guix-bioinformatics:/home/bonface/projects/guix-past/modules" \ - ./pre-inst-env guix pack --no-grafts\ - -S /gn2-profile=/ \ - screen python2-genenetwork2 - -# For the Python 3 version: env GUIX_PACKAGE_PATH="/home/bonface/projects/guix-bioinformatics:/home/bonface/projects/guix-past/modules" \ ./pre-inst-env guix pack --no-grafts\ -S /gn2-profile=/ \ -- cgit v1.2.3 From 949789a00d8e6e901cc18b939737cd42e14c0236 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 16:12:22 +0300 Subject: scripts: group: Use a unique key to identify a group --- scripts/authentication/group.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index 76c7fb4f..eea13efe 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -29,6 +29,7 @@ import argparse import datetime import redis import json +import uuid from typing import Dict, List, Optional, Set @@ -71,26 +72,31 @@ def create_group_data(users: Dict, target_group: str, me@test2.com, me@test3.com" """ + # Emails + _members: Set = set("".join(members.split()).split(",") + if members else []) + _admins: Set = set("".join(admins.split()).split(",") + if admins else []) - _members: List = "".join(members.split()).split(",") if members else [] - _admins: List = "".join(admins.split()).split(",") if admins else [] + # Unique IDs + member_ids: Set = set() + admin_ids: Set = set() - user_ids: Dict = dict() for user_id, user_details in users.items(): _details = json.loads(user_details) - if _details.get("email_address"): - user_ids[_details.get("email_address")] = user_id - print(user_ids) + if _details.get("email_address") in _members: + member_ids.add(user_id) + if _details.get("email_address") in _admins: + admin_ids.add(user_id) + + timestamp: str = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') return {"key": "groups", - "field": target_group, + "field": str(uuid.uuid4()), "value": json.dumps({ - "id": target_group, "name": target_group, - "admins": [user_ids[admin] for admin in _admins - if admin in user_ids], - "members": [user_ids[member] for member in _members - if member in user_ids], - "changed_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + "admins": list(admin_ids), + "members": list(member_ids), + "changed_timestamp": timestamp, })} -- cgit v1.2.3 From 931c7eb07cc995118ba808df760fd74de036853f Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 16:15:31 +0300 Subject: scripts: group: Remove unused import --- scripts/authentication/group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index eea13efe..d3f9a1e4 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -31,7 +31,8 @@ import redis import json import uuid -from typing import Dict, List, Optional, Set +from typing import Dict, Optional, Set + def create_group_data(users: Dict, target_group: str, members: Optional[str] = None, -- cgit v1.2.3 From 870edaf2cf8ce8588ee7c58d08fc1f307f7198ec Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 16:19:04 +0300 Subject: scripts: group: Remove empty `""` value for data.get data.get("field") will default to None if there is no value; and None is falsy. --- scripts/authentication/group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index d3f9a1e4..1919d9db 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -131,10 +131,10 @@ if __name__ == "__main__": members=members, admins=admins) - if not REDIS_CONN.hget("groups", data.get("field", "")): updated_data = json.loads(data["value"]) updated_data["created_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') data["value"] = json.dumps(updated_data) + if not REDIS_CONN.hget("groups", data.get("field")): created_p = REDIS_CONN.hset(data.get("key", ""), data.get("field", ""), -- cgit v1.2.3 From c1b23a1b01071c252ddae6dbea14500e4c248d84 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 21:01:54 +0300 Subject: workflows: main.yml: Disable link checking --- .github/workflows/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f279a7e5..8e2c7966 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,11 +55,11 @@ jobs: GENENETWORK_FILES=/genotype_files/ bin/genenetwork2 \ etc/default_settings.py -c -m unittest discover -v - - name: Test for Broken Links - run: | - env GN2_PROFILE=/gn2-profile \ - TMPDIR=/tmp\ - WEBSERVER_MODE=DEBUG LOG_LEVEL=DEBUG \ - GENENETWORK_FILES=/genotype_files/ bin/genenetwork2 \ - etc/default_settings.py -c \ - $PWD/test/requests/links_scraper/genelinks.py + # - name: Test for Broken Links + # run: | + # env GN2_PROFILE=/gn2-profile \ + # TMPDIR=/tmp\ + # WEBSERVER_MODE=DEBUG LOG_LEVEL=DEBUG \ + # GENENETWORK_FILES=/genotype_files/ bin/genenetwork2 \ + # etc/default_settings.py -c \ + # $PWD/test/requests/links_scraper/genelinks.py -- cgit v1.2.3 From 40dddc1a78a7808b480d26594ced689cdcc08c24 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 21:23:08 +0300 Subject: scripts: group: Fix indentation --- scripts/authentication/group.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index 1919d9db..7e73be15 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -131,10 +131,10 @@ if __name__ == "__main__": members=members, admins=admins) - updated_data = json.loads(data["value"]) - updated_data["created_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') - data["value"] = json.dumps(updated_data) if not REDIS_CONN.hget("groups", data.get("field")): + updated_data = json.loads(data["value"]) + updated_data["created_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + data["value"] = json.dumps(updated_data) created_p = REDIS_CONN.hset(data.get("key", ""), data.get("field", ""), -- cgit v1.2.3 From 67222a6cb11995eb5a4af58f63cc9385ccfb9226 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 21:24:16 +0300 Subject: scripts: group: Break up long line --- scripts/authentication/group.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index 7e73be15..ed17f260 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -133,7 +133,8 @@ if __name__ == "__main__": if not REDIS_CONN.hget("groups", data.get("field")): updated_data = json.loads(data["value"]) - updated_data["created_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + timestamp = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + updated_data["created_timestamp"] = timestamp data["value"] = json.dumps(updated_data) created_p = REDIS_CONN.hset(data.get("key", ""), -- cgit v1.2.3 From dc378d26c003a8f0503ad69235d1685d66e4d611 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 21:26:03 +0300 Subject: scripts: group: Update docstrings for "create_group_data" --- scripts/authentication/group.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index ed17f260..08a4a2bc 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -41,6 +41,9 @@ def create_group_data(users: Dict, target_group: str, "field", and "value" that can be used in a redis hash as follows: HSET key field value + The "field" return value is a unique-id that is used to + distinguish the groups. + Parameters: - `users`: a list of users for example: -- cgit v1.2.3 From d5f6670836cbed804a00e02ec0258d0c87564006 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 21:40:35 +0300 Subject: scripts: group: Replace args.group_name with data["field"] --- scripts/authentication/group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/authentication/group.py b/scripts/authentication/group.py index 08a4a2bc..c8c2caad 100644 --- a/scripts/authentication/group.py +++ b/scripts/authentication/group.py @@ -145,7 +145,7 @@ if __name__ == "__main__": data.get("value", "")) groups = json.loads(REDIS_CONN.hget("groups", - args.group_name)) # type: ignore + data.get("field"))) # type: ignore if created_p: exit(f"\nSuccessfully created the group: '{args.group_name}'\n" f"`HGETALL groups {args.group_name}`: {groups}\n") -- cgit v1.2.3 From 70f8ed53f85cfb42ca81ed6c3b4c9cf1060940e5 Mon Sep 17 00:00:00 2001 From: BonfaceKilz Date: Wed, 6 Oct 2021 21:44:51 +0300 Subject: scripts: resource: Add option for specifying a groups uuid --- scripts/authentication/resource.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/authentication/resource.py b/scripts/authentication/resource.py index 8fcf09d7..4996f34c 100644 --- a/scripts/authentication/resource.py +++ b/scripts/authentication/resource.py @@ -63,12 +63,16 @@ def recover_hash(name: str, file_path: str, set_function) -> bool: if __name__ == "__main__": # Initialising the parser CLI arguments parser = argparse.ArgumentParser() + parser.add_argument("--group-id", + help="Add the group id to all resources") parser.add_argument("--restore", help="Restore from a given backup") parser.add_argument("--enable-backup", action="store_true", help="Create a back up before edits") args = parser.parse_args() + if not args.group_id: + exit("Please specify the group-id!\n") if args.restore: if recover_hash(name="resources", file_path=args.back_up, @@ -92,8 +96,8 @@ if __name__ == "__main__": for resource_id, resource in RESOURCES.items(): _resource = json.loads(resource) # str -> dict conversion - _resource["group_masks"] = {"editors": {"metadata": "edit", - "data": "edit"}} + _resource["group_masks"] = {args.group_id: {"metadata": "edit", + "data": "edit"}} REDIS_CONN.hset("resources", resource_id, json.dumps(_resource)) -- cgit v1.2.3 From 7805a48172ada364d3783db043dbcf637445a7fe Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 8 Oct 2021 22:07:43 +0000 Subject: Adding convert_dol_genotypes.py to scripts; everything is hard-coded in it since I was only writing it to generate a specific file and it probably won't be re-used --- scripts/convert_dol_genotypes.py | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 scripts/convert_dol_genotypes.py diff --git a/scripts/convert_dol_genotypes.py b/scripts/convert_dol_genotypes.py new file mode 100644 index 00000000..353f1b53 --- /dev/null +++ b/scripts/convert_dol_genotypes.py @@ -0,0 +1,68 @@ +# This is just to convert the Rqtl2 format genotype files for DOL into a .geno file +# Everything is hard-coded since I doubt this will be re-used and I just wanted to generate the file quickly + +import os + +geno_dir = "/home/zas1024/gn2-zach/DO_genotypes/" +markers_file = "/home/zas1024/gn2-zach/DO_genotypes/SNP_Map.txt" +gn_geno_path = "/home/zas1024/gn2-zach/DO_genotypes/DOL.geno" + +marker_data = {} +with open(markers_file, "r") as markers_fh: + for i, line in enumerate(markers_fh): + if i == 0: + continue + else: + line_items = line.split("\t") + this_marker = {} + this_marker['chr'] = line_items[2] if line_items[2] != "0" else "M" + this_marker['pos'] = f'{float(line_items[3])/1000000:.6f}' + marker_data[line_items[1]] = this_marker + +sample_names = [] +for filename in os.listdir(geno_dir): + if "gm4qtl2_geno" in filename: + with open(geno_dir + "/" + filename, "r") as rqtl_geno_fh: + for i, line in enumerate(rqtl_geno_fh): + line_items = line.split(",") + if i < 3: + continue + elif not len(sample_names) and i == 3: + sample_names = [item.replace("TLB", "TB") for item in line_items[1:]] + elif i > 3: + marker_data[line_items[0]]['genotypes'] = ["X" if item.strip() == "-" else item.strip() for item in line_items[1:]] + +def sort_func(e): + try: + return int(e['chr']) + except: + if e['chr'] == "X": + return 20 + elif e['chr'] == "Y": + return 21 + elif e['chr'] == "M": + return 22 + +marker_list = [] +for key, value in marker_data.items(): + if 'genotypes' in value: + this_marker = { + 'chr': value['chr'], + 'locus': key, + 'pos': value['pos'], + 'genotypes': value['genotypes'] + } + marker_list.append(this_marker) + +marker_list.sort(key=sort_func) + +with open(gn_geno_path, "w") as gn_geno_fh: + gn_geno_fh.write("\t".join((["Chr", "Locus", "cM", "Mb"] + sample_names))) + for marker in marker_list: + row_contents = [ + marker['chr'], + marker['locus'], + marker['pos'], + marker['pos'] + ] + marker['genotypes'] + gn_geno_fh.write("\t".join(row_contents) + "\n") -- cgit v1.2.3 From b37a9c6c495d142852d0cee54d83f5c9e815e37b Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 8 Oct 2021 22:19:07 +0000 Subject: Fixed the sort to account for both chr and pos in a kind of hack-y way + added some comments + changed EOL to LF because the file suddenly started including EOL characters --- scripts/convert_dol_genotypes.py | 142 ++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 68 deletions(-) diff --git a/scripts/convert_dol_genotypes.py b/scripts/convert_dol_genotypes.py index 353f1b53..81b3bd6d 100644 --- a/scripts/convert_dol_genotypes.py +++ b/scripts/convert_dol_genotypes.py @@ -1,68 +1,74 @@ -# This is just to convert the Rqtl2 format genotype files for DOL into a .geno file -# Everything is hard-coded since I doubt this will be re-used and I just wanted to generate the file quickly - -import os - -geno_dir = "/home/zas1024/gn2-zach/DO_genotypes/" -markers_file = "/home/zas1024/gn2-zach/DO_genotypes/SNP_Map.txt" -gn_geno_path = "/home/zas1024/gn2-zach/DO_genotypes/DOL.geno" - -marker_data = {} -with open(markers_file, "r") as markers_fh: - for i, line in enumerate(markers_fh): - if i == 0: - continue - else: - line_items = line.split("\t") - this_marker = {} - this_marker['chr'] = line_items[2] if line_items[2] != "0" else "M" - this_marker['pos'] = f'{float(line_items[3])/1000000:.6f}' - marker_data[line_items[1]] = this_marker - -sample_names = [] -for filename in os.listdir(geno_dir): - if "gm4qtl2_geno" in filename: - with open(geno_dir + "/" + filename, "r") as rqtl_geno_fh: - for i, line in enumerate(rqtl_geno_fh): - line_items = line.split(",") - if i < 3: - continue - elif not len(sample_names) and i == 3: - sample_names = [item.replace("TLB", "TB") for item in line_items[1:]] - elif i > 3: - marker_data[line_items[0]]['genotypes'] = ["X" if item.strip() == "-" else item.strip() for item in line_items[1:]] - -def sort_func(e): - try: - return int(e['chr']) - except: - if e['chr'] == "X": - return 20 - elif e['chr'] == "Y": - return 21 - elif e['chr'] == "M": - return 22 - -marker_list = [] -for key, value in marker_data.items(): - if 'genotypes' in value: - this_marker = { - 'chr': value['chr'], - 'locus': key, - 'pos': value['pos'], - 'genotypes': value['genotypes'] - } - marker_list.append(this_marker) - -marker_list.sort(key=sort_func) - -with open(gn_geno_path, "w") as gn_geno_fh: - gn_geno_fh.write("\t".join((["Chr", "Locus", "cM", "Mb"] + sample_names))) - for marker in marker_list: - row_contents = [ - marker['chr'], - marker['locus'], - marker['pos'], - marker['pos'] - ] + marker['genotypes'] - gn_geno_fh.write("\t".join(row_contents) + "\n") +# This is just to convert the Rqtl2 format genotype files for DOL into a .geno file +# Everything is hard-coded since I doubt this will be re-used and I just wanted to generate the file quickly + +import os + +geno_dir = "/home/zas1024/gn2-zach/DO_genotypes/" +markers_file = "/home/zas1024/gn2-zach/DO_genotypes/SNP_Map.txt" +gn_geno_path = "/home/zas1024/gn2-zach/DO_genotypes/DOL.geno" + +# Iterate through the SNP_Map.txt file to get marker positions +marker_data = {} +with open(markers_file, "r") as markers_fh: + for i, line in enumerate(markers_fh): + if i == 0: + continue + else: + line_items = line.split("\t") + this_marker = {} + this_marker['chr'] = line_items[2] if line_items[2] != "0" else "M" + this_marker['pos'] = f'{float(line_items[3])/1000000:.6f}' + marker_data[line_items[1]] = this_marker + +# Iterate through R/qtl2 format genotype files and pull out the samplelist and genotypes for each marker +sample_names = [] +for filename in os.listdir(geno_dir): + if "gm4qtl2_geno" in filename: + with open(geno_dir + "/" + filename, "r") as rqtl_geno_fh: + for i, line in enumerate(rqtl_geno_fh): + line_items = line.split(",") + if i < 3: + continue + elif not len(sample_names) and i == 3: + sample_names = [item.replace("TLB", "TB") for item in line_items[1:]] + elif i > 3: + marker_data[line_items[0]]['genotypes'] = ["X" if item.strip() == "-" else item.strip() for item in line_items[1:]] + +# Generate list of marker obs to iterate through when writing to .geno file +marker_list = [] +for key, value in marker_data.items(): + if 'genotypes' in value: + this_marker = { + 'chr': value['chr'], + 'locus': key, + 'pos': value['pos'], + 'genotypes': value['genotypes'] + } + marker_list.append(this_marker) + +def sort_func(e): + """For ensuring that X/Y chromosomes/mitochondria are sorted to the end correctly""" + try: + return float((e['chr']))*1000 + float(e['pos']) + except: + if e['chr'] == "X": + return 20000 + float(e['pos']) + elif e['chr'] == "Y": + return 21000 + float(e['pos']) + elif e['chr'] == "M": + return 22000 + float(e['pos']) + +# Sort markers by chromosome +marker_list.sort(key=sort_func) + +# Write lines to .geno file +with open(gn_geno_path, "w") as gn_geno_fh: + gn_geno_fh.write("\t".join((["Chr", "Locus", "cM", "Mb"] + sample_names))) + for marker in marker_list: + row_contents = [ + marker['chr'], + marker['locus'], + marker['pos'], + marker['pos'] + ] + marker['genotypes'] + gn_geno_fh.write("\t".join(row_contents) + "\n") -- cgit v1.2.3 From e473a210491620477898ba69f33f69f14fdf5893 Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 8 Oct 2021 22:49:20 +0000 Subject: Fix issue where outliers weren't being highlighted for rows drawn by Scroller (so all rows beyond a certain point) --- wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js | 2 ++ wqflask/wqflask/templates/show_trait.html | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js index 4de1b0ac..0a060cdc 100644 --- a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js +++ b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js @@ -130,6 +130,7 @@ var primary_table = $('#samples_primary').DataTable( { $(row).addClass("value_se"); if (data.outlier) { $(row).addClass("outlier"); + $(row).attr("style", "background-color: orange;"); } $('td', row).eq(1).addClass("column_name-Index") $('td', row).eq(2).addClass("column_name-Sample") @@ -189,6 +190,7 @@ if (js_data.sample_lists.length > 1){ $(row).addClass("value_se"); if (data.outlier) { $(row).addClass("outlier"); + $(row).attr("style", "background-color: orange;"); } $('td', row).eq(1).addClass("column_name-Index") $('td', row).eq(2).addClass("column_name-Sample") diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index 3dbf5f57..f3fa1332 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -254,8 +254,6 @@ } ); {% endif %} - $('#samples_primary, #samples_other').find("tr.outlier").css('background-color', 'orange') - $('.edit_sample_checkbox:checkbox').change(function() { if ($(this).is(":checked")) { if (!$(this).closest('tr').hasClass('selected')) { -- cgit v1.2.3 From 9b28d111ad156f3862286e88bc220e02d5e1312b Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 8 Oct 2021 23:31:19 +0000 Subject: Fixed some issues with scale and score_type in mapping export + include mapping method in export filename --- wqflask/wqflask/marker_regression/run_mapping.py | 25 ++++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 290c4a14..80094057 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -104,7 +104,7 @@ class RunMapping: if "results_path" in start_vars: self.mapping_results_path = start_vars['results_path'] else: - mapping_results_filename = "_".join([self.dataset.group.name, self.vals_hash]).replace("/", "_") + mapping_results_filename = "_".join([self.dataset.group.name, self.mapping_method, self.vals_hash]).replace("/", "_") self.mapping_results_path = "{}{}.csv".format( webqtlConfig.GENERATED_IMAGE_DIR, mapping_results_filename) @@ -405,8 +405,8 @@ class RunMapping: total_markers = len(self.qtl_results) with Bench("Exporting Results"): - export_mapping_results(self.dataset, self.this_trait, self.qtl_results, - self.mapping_results_path, self.mapping_scale, self.score_type, + export_mapping_results(self.dataset, self.this_trait, self.qtl_results, self.mapping_results_path, + self.mapping_method, self.mapping_scale, self.score_type, self.transform, self.covariates, self.n_samples, self.vals_hash) with Bench("Trimming Markers for Figure"): @@ -525,7 +525,11 @@ class RunMapping: return trimmed_genotype_data -def export_mapping_results(dataset, trait, markers, results_path, mapping_scale, score_type, transform, covariates, n_samples, vals_hash): +def export_mapping_results(dataset, trait, markers, results_path, mapping_method, mapping_scale, score_type, transform, covariates, n_samples, vals_hash): + if mapping_scale == "physic": + scale_string = "Mb" + else: + scale_string = "cM" with open(results_path, "w+") as output_file: output_file.write( "Time/Date: " + datetime.datetime.now().strftime("%x / %X") + "\n") @@ -535,6 +539,7 @@ def export_mapping_results(dataset, trait, markers, results_path, mapping_scale, output_file.write("Trait: " + trait.display_name + "\n") output_file.write("Trait Hash: " + vals_hash + "\n") output_file.write("N Samples: " + str(n_samples) + "\n") + output_file.write("Mapping Tool: " + str(mapping_method) + "\n") if len(transform) > 0: transform_text = "Transform - " if transform == "qnorm": @@ -564,10 +569,7 @@ def export_mapping_results(dataset, trait, markers, results_path, mapping_scale, output_file.write("Name,Chr,") if score_type.lower() == "-logP": score_type = "-logP" - if 'Mb' in markers[0]: - output_file.write("Mb," + score_type) - if 'cM' in markers[0]: - output_file.write("Cm," + score_type) + output_file.write(scale_string + "," + score_type) if "additive" in list(markers[0].keys()): output_file.write(",Additive") if "dominance" in list(markers[0].keys()): @@ -575,11 +577,8 @@ def export_mapping_results(dataset, trait, markers, results_path, mapping_scale, output_file.write("\n") for i, marker in enumerate(markers): output_file.write(marker['name'] + "," + str(marker['chr']) + ",") - if 'Mb' in marker: - output_file.write(str(marker['Mb']) + ",") - if 'cM' in marker: - output_file.write(str(marker['cM']) + ",") - if "lod_score" in marker.keys(): + output_file.write(str(marker[scale_string]) + ",") + if score_type == "-logP": output_file.write(str(marker['lod_score'])) else: output_file.write(str(marker['lrs_value'])) -- cgit v1.2.3 From a212ad123f902b6a9c74bcac1d98bc274cebbdda Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 12 Oct 2021 17:36:02 +0000 Subject: Fixed export_mapping_results test in test_run_mapping.py --- .../wqflask/marker_regression/test_run_mapping.py | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py index 3747aeb8..868b0b0b 100644 --- a/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py +++ b/wqflask/tests/unit/wqflask/marker_regression/test_run_mapping.py @@ -43,7 +43,7 @@ class TestRunMapping(unittest.TestCase): }) } self.dataset = AttributeSetter( - {"fullname": "dataser_1", "group": self.group, "type": "ProbeSet"}) + {"fullname": "dataset_1", "group": self.group, "type": "ProbeSet"}) self.chromosomes = AttributeSetter({"chromosomes": chromosomes}) self.trait = AttributeSetter( @@ -180,37 +180,36 @@ class TestRunMapping(unittest.TestCase): with mock.patch("wqflask.marker_regression.run_mapping.datetime.datetime", new=datetime_mock): export_mapping_results(dataset=self.dataset, trait=self.trait, markers=markers, - results_path="~/results", mapping_scale="physic", score_type="-log(p)", - transform="qnorm", covariates="Dataset1:Trait1,Dataset2:Trait2", n_samples="100", - vals_hash="") + results_path="~/results", mapping_method="gemma", mapping_scale="physic", + score_type="-logP", transform="qnorm", + covariates="Dataset1:Trait1,Dataset2:Trait2", + n_samples="100", vals_hash="") write_calls = [ mock.call('Time/Date: 09/01/19 / 10:12:12\n'), mock.call('Population: Human GP1_\n'), mock.call( - 'Data Set: dataser_1\n'), + 'Data Set: dataset_1\n'), mock.call('Trait: Test Name\n'), mock.call('Trait Hash: \n'), - mock.call('N Samples: 100\n'), mock.call( - 'Transform - Quantile Normalized\n'), + mock.call('N Samples: 100\n'), + mock.call('Mapping Tool: gemma\n'), + mock.call('Transform - Quantile Normalized\n'), mock.call('Gene Symbol: IGFI\n'), mock.call( 'Location: X1 @ 123313 Mb\n'), mock.call('Cofactors (dataset - trait):\n'), mock.call('Trait1 - Dataset1\n'), mock.call('Trait2 - Dataset2\n'), mock.call('\n'), mock.call('Name,Chr,'), - mock.call('Mb,-log(p)'), mock.call('Cm,-log(p)'), + mock.call('Mb,-logP'), mock.call(',Additive'), mock.call(',Dominance'), mock.call('\n'), mock.call('MK1,C1,'), - mock.call('12000,'), mock.call('1,'), - mock.call('3'), mock.call(',VA'), - mock.call(',TT'), mock.call('\n'), - mock.call('MK2,C2,'), mock.call('10000,'), - mock.call('15,'), mock.call('7'), + mock.call('12000,'), mock.call('3'), + mock.call(',VA'), mock.call(',TT'), + mock.call('\n'), mock.call('MK2,C2,'), + mock.call('10000,'), mock.call('7'), mock.call('\n'), mock.call('MK1,C3,'), - mock.call('1,'), mock.call('45,'), - mock.call('7'), mock.call(',VE'), - mock.call(',Tt') - + mock.call('1,'), mock.call('7'), + mock.call(',VE'), mock.call(',Tt') ] mock_open.assert_called_once_with("~/results", "w+") filehandler = mock_open() -- cgit v1.2.3