From 0f982e66b7093602c346eab653b3a358437c7cd2 Mon Sep 17 00:00:00 2001 From: kedhammar Date: Mon, 21 Oct 2024 15:13:38 +0200 Subject: [PATCH 1/7] fix quote bug --- status/instruments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/instruments.py b/status/instruments.py index ff491c8e..f11e7630 100644 --- a/status/instruments.py +++ b/status/instruments.py @@ -43,7 +43,7 @@ def recover_logs(handler, search_string=None, inst_type="bravo"): for row in handler.application.biomek_errs_db.view("dates/timestamp", startkey=date_earlier, endkey=date_later): date = datetime.datetime.strptime(row.key, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=tz.tzutc()).astimezone(tz.tzlocal()) - inst = f"{instruments_list[row.value["inst_id"]]}({row.value["inst_id"]})" + inst = f"{instruments_list[row.value['inst_id']]}({row.value['inst_id']})" method = row.value.get("method", 'diff') errs = row.value["errors"] valid_rows.append({"timestamp": f"{date}", "instrument_name": inst, "method": method, "message": errs}) From d9b221d70c1d67a3ed307b6183c199821ca7fbd1 Mon Sep 17 00:00:00 2001 From: kedhammar Date: Mon, 21 Oct 2024 15:13:38 +0200 Subject: [PATCH 2/7] ruff 109 safe fixes --- setup.py | 6 +- status/applications.py | 1 + status/authorization.py | 7 +- status/barcode.py | 13 +-- status/bioinfo_analysis.py | 11 ++- status/clone_project.py | 6 +- status/controls.py | 5 +- status/data_deliveries_plot.py | 3 +- status/deliveries.py | 21 +++-- status/flowcell.py | 9 +- status/flowcells.py | 37 ++++----- status/instruments.py | 7 +- status/invoicing.py | 17 ++-- status/ngisweden_stats.py | 1 + status/ont_plot.py | 3 +- status/pricing.py | 33 +++----- status/production.py | 4 +- status/projects.py | 57 ++++++------- status/queues.py | 19 ++--- status/reads_plot.py | 3 +- status/running_notes.py | 39 +++------ status/sample_requirements.py | 24 ++---- status/sensorpush.py | 2 +- status/sequencing.py | 10 +-- status/suggestion_box.py | 1 + status/testing.py | 4 +- status/user_preferences.py | 2 +- status/util.py | 18 ++-- status/worksets.py | 13 +-- status_app.py | 132 +++++++++++++++--------------- tests/test_integration.py | 16 ++-- tests/test_pricing_integration.py | 19 +++-- 32 files changed, 252 insertions(+), 291 deletions(-) diff --git a/setup.py b/setup.py index ca454a0e..e98c780f 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,12 @@ #!/usr/bin/env python """Setup file and install script SciLife python scripts. """ -from setuptools import setup, find_packages +from setuptools import find_packages, setup try: - with open("requirements.txt", "r") as f: + with open("requirements.txt") as f: install_requires = [x.strip() for x in f.readlines()] -except IOError: +except OSError: install_requires = [] setup( diff --git a/status/applications.py b/status/applications.py index 57167e61..93637960 100644 --- a/status/applications.py +++ b/status/applications.py @@ -2,6 +2,7 @@ """ import json from collections import Counter + from status.util import SafeHandler diff --git a/status/authorization.py b/status/authorization.py index 4536e84d..690ec71a 100644 --- a/status/authorization.py +++ b/status/authorization.py @@ -1,8 +1,9 @@ -import tornado.web -import tornado.auth import json -from status.util import UnsafeHandler, GoogleUser +import tornado.auth +import tornado.web + +from status.util import GoogleUser, UnsafeHandler class LoginHandler(tornado.web.RequestHandler, tornado.auth.GoogleOAuth2Mixin): diff --git a/status/barcode.py b/status/barcode.py index 1e6ae200..4a60d3b0 100644 --- a/status/barcode.py +++ b/status/barcode.py @@ -1,9 +1,10 @@ """Handlers related to test for barcode printing """ +import re import subprocess + from status.util import SafeHandler -import re class BarcodeHandler(SafeHandler): @@ -156,7 +157,7 @@ def make_barcode(label, print_bc): xpositionText = "440" # moves the text position because the bc is longer textHeight = "38" formattedLabel.append( - "^FO{0},27^AFN,{1},{2}^FN1^FS".format(xpositionText, textHeight, ch_size) + f"^FO{xpositionText},27^AFN,{textHeight},{ch_size}^FN1^FS" ) # AF = assign font F, field number 1 (FN1), print text at position field origin (FO) rel. to home formattedLabel.append( "^FO80,17^BCN,70,N,N^FN2^FS" @@ -172,14 +173,14 @@ def make_barcode(label, print_bc): yposition = "30" # Scalable font ^A0N,32,32 should fit roughly 42 chars on our current labels formattedLabel.append( - "^FO20,{0}^A0N,{1},{1}^FB640,1,0,C,0^FN1^FS".format(yposition, ch_size) + f"^FO20,{yposition}^A0N,{ch_size},{ch_size}^FB640,1,0,C,0^FN1^FS" ) # FO = x,y relative field origin; A0N = scalable font height,width; FB = make into one line field block and center formattedLabel.append("^XZ") # end format formattedLabel.append("^XA") # start of label format formattedLabel.append("^XFFORMAT^FS") # label home posision - formattedLabel.append("^FN1^FD{}^FS".format(label)) # this is readable + formattedLabel.append(f"^FN1^FD{label}^FS") # this is readable if print_bc: - formattedLabel.append("^FN2^FD{}^FS".format(label)) # this is the barcode + formattedLabel.append(f"^FN2^FD{label}^FS") # this is the barcode formattedLabel.append("^XZ") return formattedLabel @@ -204,5 +205,5 @@ def print_barcode(barcodeFile): sp.stdin.write(barcodeFile.encode("utf-8")) print("lp command is called for printing.") stdout, stderr = sp.communicate() # Will wait for sp to finish - print("lp stdout: {0}".format(stdout)) + print(f"lp stdout: {stdout}") sp.stdin.close() diff --git a/status/bioinfo_analysis.py b/status/bioinfo_analysis.py index 12b67e0f..fba36a67 100644 --- a/status/bioinfo_analysis.py +++ b/status/bioinfo_analysis.py @@ -1,8 +1,9 @@ -import json import datetime -import dateutil +import json import traceback +import dateutil + from status.util import SafeHandler @@ -77,12 +78,10 @@ def post(self, project_id): # couchdb bulk update try: save_result = self.application.bioinfo_db.update(to_save) - except Exception as err: + except Exception: self.set_status(400) self.finish( - "

Could not save bioinfo data. Please try again later.

{}
".format( - traceback.format_exc() - ) + f"

Could not save bioinfo data. Please try again later.

{traceback.format_exc()}
" ) return None neg_save_res = [] diff --git a/status/clone_project.py b/status/clone_project.py index e4e840ed..3c479a14 100644 --- a/status/clone_project.py +++ b/status/clone_project.py @@ -1,11 +1,11 @@ import requests -from status.util import SafeHandler - from genologics import lims +from genologics.config import BASEURI, PASSWORD, USERNAME from genologics.entities import Project -from genologics.config import BASEURI, USERNAME, PASSWORD + +from status.util import SafeHandler class CloneProjectHandler(SafeHandler): diff --git a/status/controls.py b/status/controls.py index 1cd34e65..1eef1ba5 100644 --- a/status/controls.py +++ b/status/controls.py @@ -1,9 +1,10 @@ """ Handler related to Controls page """ +from genologics.config import BASEURI + from status.util import SafeHandler -from genologics import lims -from genologics.config import BASEURI, USERNAME, PASSWORD + class ControlsHandler(SafeHandler): diff --git a/status/data_deliveries_plot.py b/status/data_deliveries_plot.py index fae2b271..481cd225 100644 --- a/status/data_deliveries_plot.py +++ b/status/data_deliveries_plot.py @@ -1,5 +1,6 @@ -import json import datetime +import json + from status.util import SafeHandler diff --git a/status/deliveries.py b/status/deliveries.py index 4093f25d..ab5b9ff1 100644 --- a/status/deliveries.py +++ b/status/deliveries.py @@ -1,11 +1,12 @@ from collections import OrderedDict -from status.util import SafeHandler -from status.running_notes import LatestRunningNoteHandler - -from genologics.config import BASEURI, USERNAME, PASSWORD from genologics import lims -from genologics.entities import Udfconfig, Project as LIMSProject +from genologics.config import BASEURI, PASSWORD, USERNAME +from genologics.entities import Project as LIMSProject +from genologics.entities import Udfconfig + +from status.running_notes import LatestRunningNoteHandler +from status.util import SafeHandler lims = lims.Lims(BASEURI, USERNAME, PASSWORD) @@ -21,13 +22,13 @@ def post(self): lims_project = LIMSProject(lims, id=project_id) if not lims_project: self.set_status(400) - self.write("lims project not found: {}".format(project_id)) + self.write(f"lims project not found: {project_id}") return project_name = lims_project.name stepname = ["Project Summary 1.3"] processes = lims.get_processes(type=stepname, projectname=project_name) if processes == []: - error = "{} for {} is not available in LIMS.".format(stepname, project_name) + error = f"{stepname} for {project_name} is not available in LIMS." self.set_status(400) self.write(error) return @@ -290,9 +291,7 @@ def get(self): else: project_data = { - "error": "could not find project information for {}".format( - project_id - ) + "error": f"could not find project information for {project_id}" } ongoing_deliveries[project_id].update(project_data) @@ -300,7 +299,7 @@ def get(self): lims_responsibles = ["unassigned"] + sorted( Udfconfig(lims, id="1128").presets ) - except Exception as e: + except Exception: lims_responsibles = ["unassigned"] + sorted(responsible_list) template = self.application.loader.load("deliveries.html") self.write( diff --git a/status/flowcell.py b/status/flowcell.py index 2313e9b1..dfa73430 100644 --- a/status/flowcell.py +++ b/status/flowcell.py @@ -1,10 +1,11 @@ -from status.util import SafeHandler +import os +import re from datetime import datetime from typing import Optional + import pandas as pd -import re -import os +from status.util import SafeHandler thresholds = { "HiSeq X": 320, @@ -453,7 +454,7 @@ def get(self, name): reports_dir = self.application.minknow_path report_path = os.path.join(reports_dir, f"report_{name}.html") - self.write(open(report_path, "r").read()) + self.write(open(report_path).read()) class ElementFlowcellHandler(SafeHandler): def get(self, name): diff --git a/status/flowcells.py b/status/flowcells.py index 8ea00c4d..bfcd750f 100644 --- a/status/flowcells.py +++ b/status/flowcells.py @@ -1,21 +1,20 @@ """Set of handlers related with Flowcells """ -import json import datetime -import re +import json import logging - -from dateutil.relativedelta import relativedelta +import re from collections import OrderedDict -from genologics import lims -from genologics.config import BASEURI, USERNAME, PASSWORD import pandas as pd +from dateutil.relativedelta import relativedelta +from genologics import lims +from genologics.config import BASEURI, PASSWORD, USERNAME -from status.util import SafeHandler from status.flowcell import fetch_ont_run_stats, thresholds from status.running_notes import LatestRunningNoteHandler +from status.util import SafeHandler application_log = logging.getLogger("tornado.application") @@ -142,7 +141,7 @@ def list_ont_flowcells(self): view_mux_scans=view_mux_scans, view_pore_count_history=view_pore_count_history, ) - except Exception as e: + except Exception: unfetched_runs.append(row.key) application_log.exception(f"Failed to fetch run {row.key}") @@ -156,8 +155,8 @@ def list_ont_flowcells(self): # Convert back to dictionary and return ont_flowcells = df.to_dict(orient="index") - except Exception as e: - application_log.exception(f"Failed to compile ONT flowcell dataframe") + except Exception: + application_log.exception("Failed to compile ONT flowcell dataframe") return ont_flowcells, unfetched_runs @@ -300,9 +299,7 @@ def search_flowcell_names(self, search_string=""): if search_string in row_key.lower(): splitted_fc = row_key.split("_") fc = { - "url": "/flowcells/{}_{}".format( - splitted_fc[0], splitted_fc[-1] - ), + "url": f"/flowcells/{splitted_fc[0]}_{splitted_fc[-1]}", "name": row_key, } flowcells.append(fc) @@ -325,9 +322,7 @@ def search_flowcell_names(self, search_string=""): if search_string in row_key.lower(): splitted_fc = row_key.split("_") fc = { - "url": "/flowcells/{}_{}".format( - splitted_fc[0], splitted_fc[-1] - ), + "url": f"/flowcells/{splitted_fc[0]}_{splitted_fc[-1]}", "name": row_key, } flowcells.append(fc) @@ -424,12 +419,12 @@ def get(self, flowcell): self.set_header("Content-type", "application/json") try: p = get_container_from_id(flowcell) - except (KeyError, IndexError) as e: + except (KeyError, IndexError): self.write("{}") else: try: links = json.loads(p.udf["Links"]) if "Links" in p.udf else {} - except KeyError as e: + except KeyError: links = {} # Sort by descending date, then hopefully have deviations on top @@ -454,7 +449,7 @@ def post(self, flowcell): else: try: p = get_container_from_id(flowcell) - except (KeyError, IndexError) as e: + except (KeyError, IndexError): self.status(400) self.write("Flowcell not found") else: @@ -505,8 +500,8 @@ def get(self, query): "info/summary", descending=True ) - for row in xfc_view[query : "{}Z".format(query)]: - if not row.key in data: + for row in xfc_view[query : f"{query}Z"]: + if row.key not in data: data[row.key] = [] # To add correct threshold values fc_long_name = row.value["fcp"].split(":")[0] diff --git a/status/instruments.py b/status/instruments.py index f11e7630..ce09e51b 100644 --- a/status/instruments.py +++ b/status/instruments.py @@ -1,9 +1,10 @@ -from status.util import SafeHandler - import datetime +import json + from dateutil import tz from dateutil.relativedelta import relativedelta -import json + +from status.util import SafeHandler def recover_logs(handler, search_string=None, inst_type="bravo"): diff --git a/status/invoicing.py b/status/invoicing.py index 903ec95d..fff149ff 100644 --- a/status/invoicing.py +++ b/status/invoicing.py @@ -1,17 +1,16 @@ -import json import datetime -import markdown -import os +import json import logging +import os + +import markdown import pandas as pd import requests -from dateutil.relativedelta import relativedelta - import tornado.web -from weasyprint import HTML, CSS +from weasyprint import CSS, HTML -from status.util import SafeHandler from status.pricing import AgreementsDBHandler +from status.util import SafeHandler logging.getLogger("fontTools").setLevel(logging.ERROR) logging.getLogger("weasyprint").setLevel(logging.ERROR) @@ -159,8 +158,8 @@ def get(self): return self.write("Error: Multiple projects specified!") def post(self): - from io import BytesIO import zipfile as zp + from io import BytesIO if not self.get_current_user().is_proj_coord: self.set_status(401) @@ -249,7 +248,7 @@ def post(self): self.set_header("Content-Type", "application/zip") self.set_header( - "Content-Disposition", "attachment; filename={}".format(fileName) + "Content-Disposition", f"attachment; filename={fileName}" ) self.write(buff.getvalue()) buff.close() diff --git a/status/ngisweden_stats.py b/status/ngisweden_stats.py index c5cf161e..de3b57ed 100644 --- a/status/ngisweden_stats.py +++ b/status/ngisweden_stats.py @@ -1,5 +1,6 @@ from status.util import SafeHandler + class NGISwedenHandler(SafeHandler): """Handles the yield_plot page diff --git a/status/ont_plot.py b/status/ont_plot.py index bab7113f..ffbb2ff8 100644 --- a/status/ont_plot.py +++ b/status/ont_plot.py @@ -1,8 +1,9 @@ -import json import datetime +import json from status.util import SafeHandler + class ONTFlowcellYieldHandler(SafeHandler): """Handles the api call to ont data diff --git a/status/pricing.py b/status/pricing.py index 2053a2cc..e6381bc7 100644 --- a/status/pricing.py +++ b/status/pricing.py @@ -1,8 +1,9 @@ -import json import datetime -import markdown +import json +import markdown import tornado.web + from status.util import SafeHandler @@ -214,8 +215,8 @@ def _validate_unique(self, items, type): id, "unique", ( - "Key combination {}:{} is included multiple " - "times in the {} sheet. ".format(keys, t, type) + f"Key combination {keys}:{t} is included multiple " + f"times in the {type} sheet. " ), ) self.validation_result = False @@ -237,10 +238,8 @@ def _validate_not_null(self, items, type): id, "not_null", ( - "{} cannot be empty for {}." - " Violated for item with id {}.".format( - not_null_key, type, id - ) + f"{not_null_key} cannot be empty for {type}." + f" Violated for item with id {id}." ), ) self.validation_result = False @@ -266,9 +265,9 @@ def _validate_conserved(self, new_items, current_items, type): id, "conserved", ( - "{} column not found in new {} row with " - "id {}. This column should be kept " - "conserved.".format(conserved_key, type, id) + f"{conserved_key} column not found in new {type} row with " + f"id {id}. This column should be kept " + "conserved." ), ) self.validation_result = False @@ -278,15 +277,9 @@ def _validate_conserved(self, new_items, current_items, type): id, "conserved", ( - "{} should be conserved for {}. " - "Violated for item with id {}. " - 'Found "{}" for new and "{}" for current. '.format( - conserved_key, - type, - id, - new_item[conserved_key], - current_items[str(id)][conserved_key], - ) + f"{conserved_key} should be conserved for {type}. " + f"Violated for item with id {id}. " + f'Found "{new_item[conserved_key]}" for new and "{current_items[str(id)][conserved_key]}" for current. ' ), ) self.validation_result = False diff --git a/status/production.py b/status/production.py index 0ff0c6cc..be919765 100644 --- a/status/production.py +++ b/status/production.py @@ -1,10 +1,10 @@ """ Handlers related to data production. """ from datetime import datetime -from dateutil import parser +from dateutil import parser -from status.util import dthandler, SafeHandler +from status.util import SafeHandler class ProductionCronjobsHandler(SafeHandler): diff --git a/status/projects.py b/status/projects.py index a5141591..6927d0fc 100644 --- a/status/projects.py +++ b/status/projects.py @@ -1,25 +1,22 @@ """ Handlers for sequencing project information. """ -import json -import tornado.web -import dateutil.parser -import datetime -import requests import base64 -import logging +import datetime import itertools - +import json +import logging from collections import OrderedDict -from dateutil.relativedelta import relativedelta +import dateutil.parser +import requests +import tornado.web +from dateutil.relativedelta import relativedelta from genologics import lims -from genologics.entities import Project, Artifact -from genologics.config import BASEURI, USERNAME, PASSWORD +from genologics.config import BASEURI, PASSWORD, USERNAME +from genologics.entities import Artifact, Project from zenpy import ZenpyException -from status.util import dthandler, SafeHandler -from status.running_notes import LatestRunningNoteHandler - +from status.util import SafeHandler, dthandler lims = lims.Lims(BASEURI, USERNAME, PASSWORD) application_log = logging.getLogger("tornado.application") @@ -140,9 +137,7 @@ def project_summary_data(self, row): if "pending_reviews" in row.value: links = ", ".join( [ - '{2} requested review from {3}'.format( - BASEURI, rid[0], rid[1], rid[2] - ) + f'{rid[1]} requested review from {rid[2]}' for rid in row.value["pending_reviews"] ] ) @@ -197,7 +192,7 @@ def project_summary_data(self, row): if "queued" not in row.value and diff > 14: row.value[ "days_in_reception_control" - ] = '{}'.format(diff) + ] = f'{diff}' else: row.value["days_in_reception_control"] = diff @@ -421,7 +416,7 @@ def list_projects(self, filter_projects="all"): "ongoing" in filter_projects and queuedflag and queued_condition - and not "close_date" in p_info + and "close_date" not in p_info ): filtered_projects.append(row) elif ( @@ -434,7 +429,7 @@ def list_projects(self, filter_projects="all"): # pending projects elif ( "pending" in filter_projects or filter_projects == "all" - ) and not "open_date" in p_info: + ) and "open_date" not in p_info: filtered_projects.append(row) final_projects = OrderedDict() @@ -667,7 +662,7 @@ def sample_data(self, sample_data, project, sample): "CaliperImageHandler", project, sample, - "libval{0}".format(lib_prep), + f"libval{lib_prep}", ) if "frag_an_image" in libval: # Go grab the image from the sftp server @@ -677,7 +672,7 @@ def sample_data(self, sample_data, project, sample): "FragAnImageHandler", project, sample, - "libval{0}".format(lib_prep), + f"libval{lib_prep}", ) if "details" in sample_data: @@ -785,8 +780,8 @@ class ImagesDownloadHandler(SafeHandler): """ def post(self, project, type): - from io import BytesIO import zipfile as zp + from io import BytesIO name = "" if "frag_an" in type: @@ -810,7 +805,7 @@ def post(self, project, type): # can be triggered by the data.get().get() calls. raise tornado.web.HTTPError(404, reason="No caliper image found") - fileName = "{}_{}_images.zip".format(project, name) + fileName = f"{project}_{name}_images.zip" f = BytesIO() num_files = 0 with zp.ZipFile(f, "w") as zf: @@ -865,7 +860,7 @@ def post(self, project, type): ) self.set_header("Content-Type", "application/zip") self.set_header( - "Content-Disposition", "attachment; filename={}".format(fileName) + "Content-Disposition", f"attachment; filename={fileName}" ) self.write(f.getvalue()) f.close() @@ -989,7 +984,7 @@ def get(self, p_id): # Search for all tickets with the given project name total_tickets = OrderedDict() for ticket in self.application.zendesk.search( - query='fieldvalue:"{}"'.format(p_name) + query=f'fieldvalue:"{p_name}"' ): total_tickets[ticket.id] = ticket.to_dict() for comment in self.application.zendesk.tickets.comments( @@ -1037,12 +1032,8 @@ def get(self, projectid): self.application.settings["charon"]["url"], projectid ) except KeyError: - url = "https://charon.scilifelab.se/api/v1/summary?projectid={}".format( - projectid - ) - project_url = "https://charon.scilifelab.se/api/v1/project/{}".format( - projectid - ) + url = f"https://charon.scilifelab.se/api/v1/summary?projectid={projectid}" + project_url = f"https://charon.scilifelab.se/api/v1/project/{projectid}" headers = {} r = requests.get(url, headers=headers) if r.status_code == requests.status_codes.codes.OK: @@ -1050,9 +1041,7 @@ def get(self, projectid): else: self.set_status(400) self.finish( - "There was a problem connecting to charon, please try it again later. {}".format( - r.reason - ) + f"There was a problem connecting to charon, please try it again later. {r.reason}" ) diff --git a/status/queues.py b/status/queues.py index 20b27029..c18e0752 100644 --- a/status/queues.py +++ b/status/queues.py @@ -1,10 +1,9 @@ import ast import json import logging -import psycopg2 +import psycopg2 from dateutil.parser import parse - from genologics_sql import queries as geno_queries from genologics_sql import utils as geno_utils @@ -95,10 +94,8 @@ def get(self): "from artifact art, stagetransition st, container ct, containerplacement ctp, sample s, artifact_sample_map asm, entity_udf_view e where " "art.artifactid=st.artifactid and st.stageid in (select stageid from stage where membershipid in (select sectionid from workflowsection where protocolid=8)) " "and st.workflowrunid>0 and st.completedbyid is null and ctp.processartifactid=st.artifactid and ctp.containerid=ct.containerid and s.processid=asm.processid " - "and asm.artifactid=art.artifactid and art.name not in {} and s.projectid=e.attachtoid and e.udfname='Library construction method'" - "group by st.artifactid, art.name, st.lastmodifieddate, st.generatedbyid, ct.name, ctp.wellxposition, ctp.wellyposition, s.projectid, e.udfvalue;".format( - tuple(control_names) - ) + f"and asm.artifactid=art.artifactid and art.name not in {tuple(control_names)} and s.projectid=e.attachtoid and e.udfname='Library construction method'" + "group by st.artifactid, art.name, st.lastmodifieddate, st.generatedbyid, ct.name, ctp.wellxposition, ctp.wellyposition, s.projectid, e.udfvalue;" ) methods = queues.keys() @@ -402,8 +399,8 @@ def get(self): if "NovaSeq" not in method: non_novaseq_rerun_query = ( "select udfname, udfvalue from artifact_udf_view where udfname = 'Rerun' " - "and artifactid={}" - ).format(record[0]) + f"and artifactid={record[0]}" + ) cursor.execute(non_novaseq_rerun_query) rerun_res = cursor.fetchone() is_rerun = False @@ -526,10 +523,8 @@ def get(self): query = ( "select art.artifactid, art.name, st.lastmodifieddate, st.generatedbyid " "from artifact art, stagetransition st where art.artifactid=st.artifactid and " - "st.stageid in (select stageid from stage where stepid={}) and " - "st.completedbyid is null and st.workflowrunid>0 and art.name not in {};".format( - queues[method], tuple(control_names) - ) + f"st.stageid in (select stageid from stage where stepid={queues[method]}) and " + f"st.completedbyid is null and st.workflowrunid>0 and art.name not in {tuple(control_names)};" ) cursor.execute(query) records = cursor.fetchall() diff --git a/status/reads_plot.py b/status/reads_plot.py index d121a0a9..c4c3238b 100644 --- a/status/reads_plot.py +++ b/status/reads_plot.py @@ -1,8 +1,9 @@ -import json import datetime +import json from status.util import SafeHandler + class DataFlowcellYieldHandler(SafeHandler): """Handles the api call to reads_plot data diff --git a/status/running_notes.py b/status/running_notes.py index d986f8f0..ebdc1f52 100644 --- a/status/running_notes.py +++ b/status/running_notes.py @@ -1,13 +1,12 @@ import datetime import json +import logging import re import smtplib import unicodedata -import logging - -from email.mime.text import MIMEText -from email.mime.multipart import MIMEMultipart from collections import OrderedDict +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText import markdown import nest_asyncio @@ -241,14 +240,12 @@ def notify_tagged_user( if tagtype == "userTag": notf_text = "tagged you" - slack_notf_text = "You have been tagged by *{}* in a running note".format( - tagger - ) - email_text = "You have been tagged by {} in a running note".format(tagger) + slack_notf_text = f"You have been tagged by *{tagger}* in a running note" + email_text = f"You have been tagged by {tagger} in a running note" else: notf_text = "created note" - slack_notf_text = "Running note created by *{}*".format(tagger) - email_text = "Running note created by {}".format(tagger) + slack_notf_text = f"Running note created by *{tagger}*" + email_text = f"Running note created by {tagger}" for user in userTags: if user in view_result: @@ -259,9 +256,7 @@ def notify_tagged_user( if option == "Slack" or option == "Both": nest_asyncio.apply() client = slack_sdk.WebClient(token=application.slack_token) - notification_text = "{} has {} in {}, {}!".format( - tagger, notf_text, project_id, project_name - ) + notification_text = f"{tagger} has {notf_text} in {project_id}, {project_name}!" blocks = [ { "type": "section", @@ -317,22 +312,12 @@ def notify_tagged_user( # default is email if option == "E-mail" or option == "Both": msg = MIMEMultipart("alternative") - msg["Subject"] = "[GenStat] Running Note:{}, {}".format( - project_id, project_name - ) + msg["Subject"] = f"[GenStat] Running Note:{project_id}, {project_name}" msg["From"] = "genomics-status" msg["To"] = view_result[user] - text = "{} in the project {}, {}! The note is as follows\n\ - >{} - {}{}\ - >{}".format( - email_text, - project_id, - project_name, - tagger, - time_in_format, - category, - note, - ) + text = f"{email_text} in the project {project_id}, {project_name}! The note is as follows\n\ + >{tagger} - {time_in_format}{category}\ + >{note}" html = '\ \ diff --git a/status/sample_requirements.py b/status/sample_requirements.py index f57e74dc..d099741b 100644 --- a/status/sample_requirements.py +++ b/status/sample_requirements.py @@ -1,7 +1,8 @@ -import json import datetime +import json import tornado.web + from status.util import SafeHandler @@ -335,8 +336,8 @@ def _validate_unique(self, items): id, "unique", ( - "Key combination {}:{} is included multiple " - "times. ".format(keys, t) + f"Key combination {keys}:{t} is included multiple " + "times. " ), ) self.validation_result = False @@ -357,10 +358,8 @@ def _validate_not_null(self, items): id, "not_null", ( - "{} cannot be empty." - " Violated for item with id {}.".format( - not_null_key, id - ) + f"{not_null_key} cannot be empty." + f" Violated for item with id {id}." ), ) self.validation_result = False @@ -395,14 +394,9 @@ def _validate_conserved(self, new_items, current_items): id, "conserved", ( - "{} should be conserved. " - "Violated for item with id {}. " - 'Found "{}" for new and "{}" for current. '.format( - conserved_key, - id, - new_item[conserved_key], - current_items[str(id)][conserved_key], - ) + f"{conserved_key} should be conserved. " + f"Violated for item with id {id}. " + f'Found "{new_item[conserved_key]}" for new and "{current_items[str(id)][conserved_key]}" for current. ' ), ) self.validation_result = False diff --git a/status/sensorpush.py b/status/sensorpush.py index d255e733..3ad583a3 100644 --- a/status/sensorpush.py +++ b/status/sensorpush.py @@ -1,8 +1,8 @@ """Set of handlers related with Sensorpush data """ -import json import datetime +import json from status.util import SafeHandler diff --git a/status/sequencing.py b/status/sequencing.py index 48a55617..bbe1f1c9 100644 --- a/status/sequencing.py +++ b/status/sequencing.py @@ -1,16 +1,16 @@ """ Handlers related to data sequencing statistics. """ +import json from collections import defaultdict -from io import BytesIO from datetime import datetime -import json +from io import BytesIO -from dateutil import parser import matplotlib.pyplot as plt -from matplotlib.backends.backend_agg import FigureCanvasAgg import numpy as np +from dateutil import parser +from matplotlib.backends.backend_agg import FigureCanvasAgg -from status.util import dthandler, SafeHandler +from status.util import SafeHandler, dthandler def make_instrument_series_handler(couchdb_view_name): diff --git a/status/suggestion_box.py b/status/suggestion_box.py index b6912311..55449ea1 100644 --- a/status/suggestion_box.py +++ b/status/suggestion_box.py @@ -3,6 +3,7 @@ from atlassian import Jira from ibmcloudant.cloudant_v1 import Document + from status.util import SafeHandler TITLE_TEMPLATE = "{deployment}{title} ({area})" diff --git a/status/testing.py b/status/testing.py index 21fb4bc6..3e10039f 100644 --- a/status/testing.py +++ b/status/testing.py @@ -1,9 +1,9 @@ """ Status Handlers used to test some functionalities while building layouts. """ -import random import json +import random -from status.util import dthandler, UnsafeHandler +from status.util import UnsafeHandler, dthandler class TestDataHandler(UnsafeHandler): diff --git a/status/user_preferences.py b/status/user_preferences.py index 6aeea8d9..353cf2bd 100644 --- a/status/user_preferences.py +++ b/status/user_preferences.py @@ -1,7 +1,7 @@ import json -from status.util import SafeHandler from status.projects import PresetsHandler as ph +from status.util import SafeHandler class UserPrefPageHandler(SafeHandler): diff --git a/status/util.py b/status/util.py index 90ddf78a..5316a95c 100644 --- a/status/util.py +++ b/status/util.py @@ -1,11 +1,11 @@ -import tornado.web import json -import requests import os import sys from datetime import datetime, timedelta -from dateutil import parser +import requests +import tornado.web +from dateutil import parser ######################### # Useful misc handlers # @@ -30,7 +30,7 @@ } -class User(object): +class User: """A minimal user class""" def __init__(self, name, email, roles): @@ -139,7 +139,7 @@ def write_error(self, status_code, **kwargs): # Return JSON if this is an API call if "/api/v1/" in self.request.uri: jsondict = { - "page_title": "Error {}: {}".format(status_code, reason), + "page_title": f"Error {status_code}: {reason}", "error_status": status_code, "error_reason": reason, "error_exception": self.application.gs_globals["exception_fulltext"], @@ -176,10 +176,10 @@ def get_multiqc(self, project_id): if project_name: multiqc_path = self.application.multiqc_path or "" for type in ["_", "_qc_", "_pipeline_"]: - multiqc_name = "{}{}multiqc_report.html".format(project_name, type) + multiqc_name = f"{project_name}{type}multiqc_report.html" multiqc_file_path = os.path.join(multiqc_path, multiqc_name) if os.path.exists(multiqc_file_path): - with open(multiqc_file_path, "r", encoding="utf-8") as multiqc_file: + with open(multiqc_file_path, encoding="utf-8") as multiqc_file: html = multiqc_file.read() multiqc_reports[type] = html return multiqc_reports @@ -369,7 +369,7 @@ def get(self): text_timestamp = os.stat(logfile).st_mtime delta = datetime.now() - datetime.fromtimestamp(int(text_timestamp)) except (OSError, KeyError, TypeError): - response["status"] = "Log File '{}' not found.".format(logfile) + response["status"] = f"Log File '{logfile}' not found." else: response["status"] = "Success" response["hours"] = int(delta.seconds / 3600) @@ -385,7 +385,7 @@ def get(self): ######################## -class GoogleUser(object): +class GoogleUser: """Stores the information that google returns from a user throuhgh its secured API.""" def __init__(self, user_token): diff --git a/status/worksets.py b/status/worksets.py index f273d716..07d1a48f 100644 --- a/status/worksets.py +++ b/status/worksets.py @@ -1,17 +1,18 @@ """Handlers for worksets""" +import datetime import json -from status.util import SafeHandler -from genologics import lims -from genologics.entities import Process -from genologics.config import BASEURI, USERNAME, PASSWORD from collections import OrderedDict -import datetime -from dateutil.relativedelta import relativedelta + from dateutil.parser import parse +from dateutil.relativedelta import relativedelta +from genologics import lims +from genologics.config import BASEURI, PASSWORD, USERNAME +from genologics.entities import Process from status.running_notes import LatestRunningNoteHandler +from status.util import SafeHandler class WorksetsDataHandler(SafeHandler): diff --git a/status_app.py b/status_app.py index 3d135180..020d36f1 100644 --- a/status_app.py +++ b/status_app.py @@ -1,24 +1,24 @@ """ Main genomics-status web application. """ import base64 +import json import subprocess import uuid -import yaml -import json -import requests - from collections import OrderedDict -from couchdb import Server - -from ibmcloudant import cloudant_v1, CouchDbSessionAuthenticator +from pathlib import Path +from urllib.parse import urlsplit +import requests import tornado.autoreload import tornado.httpserver import tornado.ioloop import tornado.web - +import yaml +from couchdb import Server +from ibmcloudant import CouchDbSessionAuthenticator, cloudant_v1 from tornado import template from tornado.options import define, options +from zenpy import Zenpy from status.applications import ( ApplicationDataHandler, @@ -26,15 +26,19 @@ ApplicationsDataHandler, ApplicationsHandler, ) -from status.barcode import BarcodeHandler -from status.controls import ControlsHandler -from status.clone_project import CloneProjectHandler, LIMSProjectCloningHandler -from status.user_management import UserManagementHandler, UserManagementDataHandler from status.authorization import LoginHandler, LogoutHandler, UnAuthorizedHandler +from status.barcode import BarcodeHandler from status.bioinfo_analysis import BioinfoAnalysisHandler +from status.clone_project import CloneProjectHandler, LIMSProjectCloningHandler +from status.controls import ControlsHandler from status.data_deliveries_plot import DataDeliveryHandler, DeliveryPlotHandler from status.deliveries import DeliveriesPageHandler -from status.flowcell import FlowcellHandler, ElementFlowcellHandler, ONTFlowcellHandler, ONTReportHandler +from status.flowcell import ( + ElementFlowcellHandler, + FlowcellHandler, + ONTFlowcellHandler, + ONTReportHandler, +) from status.flowcells import ( FlowcellDemultiplexHandler, FlowcellLinksDataHandler, @@ -48,37 +52,38 @@ ReadsTotalHandler, ) from status.instruments import ( - InstrumentLogsHandler, DataInstrumentLogsHandler, + InstrumentLogsHandler, InstrumentNamesHandler, ) from status.invoicing import ( - InvoicingPageHandler, + DeleteInvoiceHandler, + GenerateInvoiceHandler, InvoiceSpecDateHandler, + InvoicingOrderDetailsHandler, InvoicingPageDataHandler, - GenerateInvoiceHandler, - DeleteInvoiceHandler, + InvoicingPageHandler, SentInvoiceHandler, - InvoicingOrderDetailsHandler, ) -from status.lanes_ordered import LanesOrderedHandler, LanesOrderedDataHandler +from status.lanes_ordered import LanesOrderedDataHandler, LanesOrderedHandler from status.multiqc_report import MultiQCReportHandler from status.ngisweden_stats import NGISwedenHandler +from status.ont_plot import ONTFlowcellPlotHandler, ONTFlowcellYieldHandler from status.pricing import ( + AgreementDataHandler, + AgreementMarkSignHandler, + AgreementTemplateTextHandler, + GenerateQuoteHandler, + PricingDataHandler, PricingDateToVersionDataHandler, + PricingDraftDataHandler, PricingExchangeRatesDataHandler, - PricingQuoteHandler, - PricingValidateDraftDataHandler, + PricingPreviewHandler, PricingPublishDataHandler, + PricingQuoteHandler, PricingReassignLockDataHandler, PricingUpdateHandler, - PricingPreviewHandler, - PricingDataHandler, - PricingDraftDataHandler, - GenerateQuoteHandler, - AgreementTemplateTextHandler, - AgreementDataHandler, - AgreementMarkSignHandler, + PricingValidateDraftDataHandler, SaveQuoteHandler, ) from status.production import ( @@ -87,9 +92,14 @@ from status.projects import ( CaliperImageHandler, CharonProjectHandler, + FragAnImageHandler, + ImagesDownloadHandler, LinksDataHandler, PresetsHandler, + PresetsOnLoadHandler, + PrioProjectsTableHandler, ProjectDataHandler, + ProjectRNAMetaDataHandler, ProjectSamplesDataHandler, ProjectSamplesHandler, ProjectsDataHandler, @@ -97,39 +107,32 @@ ProjectsHandler, ProjectsSearchHandler, ProjectTicketsDataHandler, - RecCtrlDataHandler, ProjMetaCompareHandler, - ProjectRNAMetaDataHandler, - FragAnImageHandler, - PresetsOnLoadHandler, - ImagesDownloadHandler, - PrioProjectsTableHandler, + RecCtrlDataHandler, ) - from status.queues import ( - qPCRPoolsDataHandler, - qPCRPoolsHandler, + LibraryPoolingQueuesDataHandler, + LibraryPoolingQueuesHandler, SequencingQueuesDataHandler, SequencingQueuesHandler, - WorksetQueuesHandler, - WorksetQueuesDataHandler, - LibraryPoolingQueuesHandler, - LibraryPoolingQueuesDataHandler, - SmartSeq3ProgressPageHandler, SmartSeq3ProgressPageDataHandler, + SmartSeq3ProgressPageHandler, + WorksetQueuesDataHandler, + WorksetQueuesHandler, + qPCRPoolsDataHandler, + qPCRPoolsHandler, ) from status.reads_plot import DataFlowcellYieldHandler, FlowcellPlotHandler -from status.ont_plot import ONTFlowcellYieldHandler, ONTFlowcellPlotHandler -from status.running_notes import RunningNotesDataHandler, LatestStickyNoteHandler +from status.running_notes import LatestStickyNoteHandler, RunningNotesDataHandler from status.sample_requirements import ( - SampleRequirementsViewHandler, SampleRequirementsDataHandler, - SampleRequirementsUpdateHandler, SampleRequirementsDraftDataHandler, - SampleRequirementsValidateDraftDataHandler, SampleRequirementsPreviewHandler, - SampleRequirementsReassignLockDataHandler, SampleRequirementsPublishDataHandler, + SampleRequirementsReassignLockDataHandler, + SampleRequirementsUpdateHandler, + SampleRequirementsValidateDraftDataHandler, + SampleRequirementsViewHandler, ) from status.sensorpush import ( SensorpushDataHandler, @@ -137,28 +140,30 @@ SensorpushWarningsDataHandler, ) from status.sequencing import ( - InstrumentClusterDensityPlotHandler, - InstrumentErrorratePlotHandler, - InstrumentUnmatchedPlotHandler, - InstrumentYieldPlotHandler, InstrumentClusterDensityDataHandler, + InstrumentClusterDensityPlotHandler, InstrumentErrorrateDataHandler, + InstrumentErrorratePlotHandler, InstrumentUnmatchedDataHandler, + InstrumentUnmatchedPlotHandler, InstrumentYieldDataHandler, + InstrumentYieldPlotHandler, ) from status.statistics import ( - YearApplicationsProjectHandler, - YearApplicationsSamplesHandler, - YearAffiliationProjectsHandler, - YearDeliverytimeProjectsHandler, ApplicationOpenProjectsHandler, ApplicationOpenSamplesHandler, - WeekInstrumentTypeYieldHandler, StatsAggregationHandler, + WeekInstrumentTypeYieldHandler, + YearAffiliationProjectsHandler, + YearApplicationsProjectHandler, + YearApplicationsSamplesHandler, YearDeliverytimeApplicationHandler, + YearDeliverytimeProjectsHandler, ) from status.suggestion_box import SuggestionBoxDataHandler, SuggestionBoxHandler from status.testing import TestDataHandler +from status.user_management import UserManagementDataHandler, UserManagementHandler +from status.user_preferences import UserPrefPageHandler, UserPrefPageHandler_b5 from status.util import ( BaseHandler, DataHandler, @@ -166,21 +171,16 @@ MainHandler, UpdatedDocumentsDatahandler, ) -from status.user_preferences import UserPrefPageHandler, UserPrefPageHandler_b5 from status.worksets import ( - WorksetHandler, - WorksetsHandler, + ClosedWorksetsHandler, WorksetDataHandler, + WorksetHandler, WorksetLinksHandler, WorksetsDataHandler, WorksetSearchHandler, - ClosedWorksetsHandler, + WorksetsHandler, ) -from zenpy import Zenpy -from urllib.parse import urlsplit -from pathlib import Path - class Application(tornado.web.Application): def __init__(self, settings): @@ -425,7 +425,7 @@ def __init__(self, settings): self.running_notes_db = couch["running_notes"] else: print(settings.get("couch_server", None)) - raise IOError("Cannot connect to couchdb") + raise OSError("Cannot connect to couchdb") cloudant = cloudant_v1.CloudantV1(authenticator=CouchDbSessionAuthenticator(settings.get("username"), settings.get("password"))) cloudant.set_service_url(settings.get("couch_url")) diff --git a/tests/test_integration.py b/tests/test_integration.py index c26e292f..1c084a1b 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1,17 +1,17 @@ #!/usr/bin/env python -from nose.tools import assert_true import json -import requests -import re import os +import re +import requests import yaml +from nose.tools import assert_true file_dir_path = os.path.dirname(__file__) TEST_ITEMS = os.path.join(file_dir_path, "test_items.yaml") -class TestGet(object): +class TestGet: def setUp(self): """Server Settings""" self.url = "http://localhost:9761" @@ -28,7 +28,7 @@ def test_all_pages(self): assert_true( len(error_pages) == 0, - msg=("Pages resulted in error: {0} ".format(error_pages)), + msg=(f"Pages resulted in error: {error_pages} "), ) def test_api_without_regexp(self): @@ -53,7 +53,7 @@ def test_api_without_regexp(self): assert_true( len(error_pages) == 0, - msg=("Requests resulted in error: {0} ".format(error_pages)), + msg=(f"Requests resulted in error: {error_pages} "), ) def test_api_test(self): @@ -78,7 +78,7 @@ def test_api_misc(self): error_pages = list(filter(lambda u: not requests.get(u).ok, urls)) assert_true( len(error_pages) == 0, - msg=("Misc requests resulted in error {0} ".format(error_pages)), + msg=(f"Misc requests resulted in error {error_pages} "), ) non_error_url = filter(lambda u: u not in error_pages, urls) @@ -89,5 +89,5 @@ def test_api_misc(self): ) assert_true( len(empty_json) == 0, - msg=("Misc requests are empty: {0} ".format(empty_json)), + msg=(f"Misc requests are empty: {empty_json} "), ) diff --git a/tests/test_pricing_integration.py b/tests/test_pricing_integration.py index c634e79a..44ad3a9b 100644 --- a/tests/test_pricing_integration.py +++ b/tests/test_pricing_integration.py @@ -1,16 +1,17 @@ +import json import time import unittest + import requests -import json from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import ( - ElementNotInteractableException, ElementClickInterceptedException, + ElementNotInteractableException, ) +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait class TestPricingQuote(unittest.TestCase): @@ -71,7 +72,7 @@ def test_addproduct(self): e = self.driver.find_element( By.CSS_SELECTOR, - ".quote-product-list input[data-product-id='{}']".format(id), + f".quote-product-list input[data-product-id='{id}']", ) self.assertEqual( e.get_attribute("value"), "1", msg="One item of this product is added" @@ -84,7 +85,7 @@ def test_addproduct(self): e = self.driver.find_element( By.CSS_SELECTOR, - ".quote-product-list input[data-product-id='{}']".format(id), + f".quote-product-list input[data-product-id='{id}']", ) self.assertEqual( e.get_attribute("value"), "1", msg="Two items of this product are added" @@ -138,7 +139,7 @@ def test_exchangerates(self): time.sleep(1.0) self.driver.find_element( By.CSS_SELECTOR, - ".status_available:nth-child({}) td:nth-child(1) > a > i".format(i + 1), + f".status_available:nth-child({i + 1}) td:nth-child(1) > a > i", ).click() time.sleep(1.0) From a5f191413c63f7a069e6daebd084b60fb74e99f2 Mon Sep 17 00:00:00 2001 From: kedhammar Date: Mon, 21 Oct 2024 15:13:38 +0200 Subject: [PATCH 3/7] ruff 12 unsafe fixes --- status/authorization.py | 2 +- status/deliveries.py | 2 +- status/projects.py | 3 +-- status/statistics.py | 13 ++++++------- status_app.py | 1 - 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/status/authorization.py b/status/authorization.py index 690ec71a..9d62b53b 100644 --- a/status/authorization.py +++ b/status/authorization.py @@ -35,7 +35,7 @@ def get(self): if url is None: url = "/" else: - url = "/unauthorized?email={0}&contact={1}".format( + url = "/unauthorized?email={}&contact={}".format( user.emails[0], self.application.settings["contact_person"] ) self.redirect(url) diff --git a/status/deliveries.py b/status/deliveries.py index ab5b9ff1..ceeebcca 100644 --- a/status/deliveries.py +++ b/status/deliveries.py @@ -52,7 +52,7 @@ def post(self): for row in view[project_id]: doc_id = row.value break - if doc_id == None: + if doc_id is None: self.set_status(400) self.write("Status DB has not been updated: project not found") return diff --git a/status/projects.py b/status/projects.py index 6927d0fc..71ff7da3 100644 --- a/status/projects.py +++ b/status/projects.py @@ -1028,12 +1028,11 @@ def get(self, projectid): self.application.settings["charon"]["api_token"] ) } - project_url = "{}/api/v1/project/{}".format( + "{}/api/v1/project/{}".format( self.application.settings["charon"]["url"], projectid ) except KeyError: url = f"https://charon.scilifelab.se/api/v1/summary?projectid={projectid}" - project_url = f"https://charon.scilifelab.se/api/v1/project/{projectid}" headers = {} r = requests.get(url, headers=headers) if r.status_code == requests.status_codes.codes.OK: diff --git a/status/statistics.py b/status/statistics.py index 5553a96c..1a227adf 100644 --- a/status/statistics.py +++ b/status/statistics.py @@ -6,7 +6,6 @@ def get_clean_application_keys(handler): categories_v = handler.application.application_categories_db.view("general/app_cat") clean_keys = {} - category = None for row in categories_v: clean_keys[row.key] = row.value @@ -62,7 +61,7 @@ def general_cleaning(meta_key): class YearApplicationsProjectHandler(SafeHandler): def __init__(self, *args, **kwargs): - super(YearApplicationsProjectHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.cleaning = get_clean_application_keys(self) def get(self): @@ -80,7 +79,7 @@ def get(self): class YearApplicationsSamplesHandler(SafeHandler): def __init__(self, *args, **kwargs): - super(YearApplicationsSamplesHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.cleaning = get_clean_application_keys(self) def get(self): @@ -124,7 +123,7 @@ def get(self): class ApplicationOpenProjectsHandler(SafeHandler): def __init__(self, *args, **kwargs): - super(ApplicationOpenProjectsHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.cleaning = get_clean_application_keys(self) def get(self): @@ -142,7 +141,7 @@ def get(self): class ApplicationOpenSamplesHandler(SafeHandler): def __init__(self, *args, **kwargs): - super(ApplicationOpenSamplesHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.cleaning = get_clean_application_keys(self) def get(self): @@ -171,7 +170,7 @@ def get(self): class YearDeliverytimeApplicationHandler(UnsafeHandler): def __init__(self, *args, **kwargs): - super(YearDeliverytimeApplicationHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.cleaning = get_clean_application_keys(self) def get(self): @@ -189,7 +188,7 @@ def get(self): class StatsAggregationHandler(UnsafeHandler): def __init__(self, *args, **kwargs): - super(StatsAggregationHandler, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.project_aggregates = { "num_projects": ("genomics-dashboard/year_application_count", 2), "num_samples": ("genomics-dashboard/year_application_count_samples", 2), diff --git a/status_app.py b/status_app.py index 020d36f1..db662281 100644 --- a/status_app.py +++ b/status_app.py @@ -434,7 +434,6 @@ def __init__(self, settings): # Load columns and presets from genstat-defaults user in StatusDB genstat_id = "" - user_id = "" user = settings.get("username", None) for u in self.gs_users_db.view("authorized/users"): if u.get("key") == "genstat-defaults": From 7a4c35d628fe1bfa454ccad266c8d2ed17b4efc7 Mon Sep 17 00:00:00 2001 From: kedhammar Date: Mon, 21 Oct 2024 15:13:38 +0200 Subject: [PATCH 4/7] manual fix --- status/sample_requirements.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/status/sample_requirements.py b/status/sample_requirements.py index d099741b..b151cdd5 100644 --- a/status/sample_requirements.py +++ b/status/sample_requirements.py @@ -335,10 +335,7 @@ def _validate_unique(self, items): self._add_validation_msg( id, "unique", - ( - f"Key combination {keys}:{t} is included multiple " - "times. " - ), + (f"Key combination {keys}:{t} is included multiple " "times. "), ) self.validation_result = False key_val_set.add(t) @@ -383,9 +380,9 @@ def _validate_conserved(self, new_items, current_items): id, "conserved", ( - "{} column not found in new {} row with " - "id {}. This column should be kept " - "conserved.".format(conserved_key, id) + f"{conserved_key} column not found in new row with " + f"id {id}. This column should be kept " + "conserved." ), ) self.validation_result = False From 8bad19b1bb29be92e97a2fa802bd5e10447dc442 Mon Sep 17 00:00:00 2001 From: kedhammar Date: Wed, 23 Oct 2024 11:22:45 +0200 Subject: [PATCH 5/7] ruff fix necessitated by merge from master --- status_app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/status_app.py b/status_app.py index 6f55940a..f5c899e6 100644 --- a/status_app.py +++ b/status_app.py @@ -34,9 +34,9 @@ from status.data_deliveries_plot import DataDeliveryHandler, DeliveryPlotHandler from status.deliveries import DeliveriesPageHandler from status.flowcell import ( - FlowcellHandler, - ElementFlowcellHandler, ElementFlowcellDataHandler, + ElementFlowcellHandler, + FlowcellHandler, ONTFlowcellHandler, ONTReportHandler, ) From b22ed34e243b1f1e82b11c2d632649f943b9d6c6 Mon Sep 17 00:00:00 2001 From: Alfred Kedhammar <89784800+kedhammar@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:02:22 +0200 Subject: [PATCH 6/7] Remove unused string statement Co-authored-by: Anandashankar Anil --- status/projects.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/status/projects.py b/status/projects.py index 71ff7da3..edf3fa1e 100644 --- a/status/projects.py +++ b/status/projects.py @@ -1028,9 +1028,6 @@ def get(self, projectid): self.application.settings["charon"]["api_token"] ) } - "{}/api/v1/project/{}".format( - self.application.settings["charon"]["url"], projectid - ) except KeyError: url = f"https://charon.scilifelab.se/api/v1/summary?projectid={projectid}" headers = {} From 0ed5291fba66a8a83ae9350d45042368c02aa643 Mon Sep 17 00:00:00 2001 From: kedhammar Date: Thu, 24 Oct 2024 12:04:46 +0200 Subject: [PATCH 7/7] apply f-string --- status/authorization.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/status/authorization.py b/status/authorization.py index 9d62b53b..f4cb0dbe 100644 --- a/status/authorization.py +++ b/status/authorization.py @@ -35,9 +35,7 @@ def get(self): if url is None: url = "/" else: - url = "/unauthorized?email={}&contact={}".format( - user.emails[0], self.application.settings["contact_person"] - ) + url = f"/unauthorized?email={user.emails[0]}&contact={self.application.settings['contact_person']}" self.redirect(url) else: