def __vendor_enzymes(self, name): vendor = Session.query(Vendor).filter_by(name=unicode(name)).first() # this might be better off with a regular SQL statement all_enzymes = Session.query(VendorEnzyme, Enzyme.name, Enzyme.cutseq, Enzyme.methylation_sensitivity,\ func.sum(VendorEnzyme.stock_units).label('total_stock_units') ).join(Enzyme).filter(VendorEnzyme.vendor_id == vendor.id).group_by(VendorEnzyme.enzyme_id).all() return all_enzymes
def reader_history(self, id=None, admin=True): box2 = self.__setup_box2_context_by_code(id) c.admin = admin != 'False' logs = Session.query(Box2Log).filter_by(box2_id=box2.id)\ .order_by('time_effective desc')\ .options(joinedload_all(Box2Log.circuit))\ .all() statuses = Session.query(DRStatusLog).filter_by(box2_id=box2.id)\ .order_by('time_effective desc')\ .options(joinedload_all(DRStatusLog.reporter))\ .all() fixes = Session.query(DRFixLog).filter_by(box2_id=box2.id)\ .order_by('time_effective desc')\ .all() log_pairs = [(logs[i].time_effective, [logs[i],(logs[i+1] if i < len(logs)-1 else None)]) for i in range(len(logs))] for pair in log_pairs: pair[1].append((sorted(box2log_mv.labeleditems(pair[1][0]).items()), sorted(box2log_mv.labeleditems(pair[1][1]).items()))) status_pairs = [(status.time_effective, status) for status in statuses] fix_pairs = [(fix.time_effective, fix) for fix in fixes] changes = log_pairs + status_pairs + fix_pairs c.changes = sorted(changes, key=operator.itemgetter(0)) c.changes.reverse() return render('/admin/reader_history.html')
def apply_template_to_plate(qlplate, dbplate): """ Determine if a plate has an applicable template, either by explicit setting or by implicit naming. :param qlplate: The QLP file to read :param dbplate: The DB plate to update """ # new-style: if plate file has plate_template_id in it, # just bind if qlplate.plate_template_id: template = Session.query(PlateTemplate).get(int(qlplate.plate_template_id)) if template: inherit_template_attributes(dbplate, template) return True # otherwise, check the name dirname = dbplate.qlbplate.file.dirname basename = dbplate.qlbplate.file.basename complete_name = basename[:-4] # -- .qlp # duplicate prefixes are possible; use most recent templates = Session.query(PlateTemplate).order_by('prefix desc, id desc').all() for template in templates: if complete_name.startswith(template.prefix): inherit_template_attributes(dbplate, template) return True return False
def apply_setup_to_plate(qlplate, dbplate): """ Determine if a plate has an applicable template, either by explicit setting or by implicit naming. :param qlplate: The QLP file to read :param dbplate: The DB plate to update """ if qlplate.plate_setup_id: setup = Session.query(PlateSetup).get(int(qlplate.plate_setup_id)) if setup: inherit_setup_attributes(dbplate, setup) return True dirname = dbplate.qlbplate.file.dirname basename = dbplate.qlbplate.file.basename complete_name = basename[:-4] # -- .qlp setups = Session.query(PlateSetup).order_by('prefix desc').all() for setup in setups: if complete_name.startswith(setup.prefix): inherit_setup_attributes(dbplate, setup) return True return False
def make_plate_name(plate, experiment_name=None): """ Given a plate and assigned project, operator and experiment, generate a name that conforms to the QTools naming standard. Name will be project_operator_experiment. :param plate: :param experiment_name: :return: """ # this is the hard way, before the relation is saved. if plate.project_id: project = Session.query(Project).get(plate.project_id) if project: if project.code: project_code = project.code else: project_code = project.name else: project_code = '' else: project_code = '' operator = Session.query(Person).get(plate.operator_id) if operator: user_code = operator.name_code else: user_code = '' fields = [project_code, user_code, experiment_name] return '_'.join([field for field in fields if field])
def by_well_tag(self): well_tag_field = fl.well_tag_field(str(self.form_result['well_tag'])) c.group_by_plate = self.form_result['group_by_plate'] c.tag_id = self.form_result['well_tag'] c.tag_name = Session.query(WellTag).get(c.tag_id).name c.form = h.LiteralFormSelectPatch( value = {'well_tag': well_tag_field['value'], 'group_by_plate': [u'1' if c.group_by_plate else u'0']}, option = {'well_tag': [('--','--')]+well_tag_field['options'], 'group_by_plate': [(u'1', '')]} ) well_tags = Session.query(WellTag).\ filter_by(id=c.tag_id).\ options(joinedload_all(WellTag.tag_wells, QLBWell.plate, QLBPlate.file, innerjoin=True), joinedload_all(WellTag.tag_wells, QLBWell.plate, QLBPlate.plate, innerjoin=True)).\ all() c.label_names = [] if not len(well_tags): c.wells = [] c.well_groups = [] elif c.group_by_plate: wells = sorted(well_tags[0].wells, key=lambda well: (well.plate_id, well.well_name)) well_groups = [(plate, list(wells)) for plate, wells in itertools.groupby(wells, lambda well: well.plate)] c.well_groups = sorted(well_groups, key=lambda tup: tup[0].host_datetime) c.well_groups.reverse() else: c.wells = sorted(well_tags[0].wells, key=lambda well: well.host_datetime) c.wells.reverse() return render('/box2/by_well_tag.html')
def command(self): app = self.load_wsgi_app() root = app.config['qlb.dg_root'] top_folders = app.config['qlb.top_dg_folders'] source = DGLogSource(root, top_folders) min_file_dict = dict(Session.query(DropletGeneratorRun.dirname, func.max(DropletGeneratorRun.basename).label('last_file')).\ group_by(DropletGeneratorRun.dirname).all()) min_file_prefix = '2011-03-21' dgs = Session.query(DropletGenerator).all() dg_ids = [dg.id for dg in dgs] for dirname, basename in source.path_iter(min_file_name=min_file_prefix, min_file_dict=min_file_dict): print dirname, basename dg_run = read_dg_log(source.full_path(dirname, basename)) if not dg_run: continue dg_run.dirname = dirname dg_run.basename = basename if dg_run.droplet_generator_id in dg_ids: Session.add(dg_run) Session.commit()
def runs(self, id=None): c.dg = Session.query(DropletGenerator).get(int(id)) if not c.dg: abort(404) reprocess_config_id = request.params.get('rp_id', None) if reprocess_config_id: reprocess_config_id = int(reprocess_config_id) runs = Session.query(DropletGeneratorRun).filter( and_(DropletGeneratorRun.droplet_generator_id == c.dg.id, DropletGeneratorRun.run_number != None)).all() run_dict = dict([(run.run_number, run) for run in runs]) wells = Session.query(WellMetric, QLBWell.id, QLBWell.sample_name, QLBWell.dg_run_number, QLBWell.consumable_channel_num)\ .join(QLBWell)\ .join(PlateMetric)\ .filter(and_(QLBWell.droplet_generator_id == id, QLBWell.dg_run_number != None, PlateMetric.reprocess_config_id == reprocess_config_id))\ .order_by(QLBWell.dg_run_number, QLBWell.consumable_channel_num).all() sorted_runs = sorted(groupinto(wells, lambda tup: (tup[3])), key=operator.itemgetter(0)) c.runs = [(run_id, run_dict[run_id], sorted(info, key=operator.itemgetter(4))) for run_id, info in sorted_runs if run_dict.get(run_id, None)] #raise Exception, c.runs return render('/product/dg/runs.html')
def plate_query(): # writing it this way because the .join seems to muck up # filter_by statements downstream box2s = [tup[0] for tup in Session.query(Box2.id).all()] query = Session.query(Plate).filter(Plate.box2_id.in_(box2s)) return query
def save(self): if self.form_result['plate_setup_id']: ps = Session.query(PlateSetup).get(self.form_result['plate_setup_id']) prefix = ps.prefix elif self.form_result['plate_template_id']: pt = Session.query(PlateTemplate).get(self.form_result['plate_template_id']) prefix = pt.prefix else: prefix = 'output' response.headers['Content-Type'] = 'application/quantalife-template' h.set_download_response_header(request, response, "%s.qlt" % prefix) response.headers['Pragma'] = 'no-cache' # build a plate # TODO: add default fields plate = ExperimentMetadataQLPlate(channel_names=['FAM','VIC'], host_datetime=datetime.now(), host_machine='QTools', host_user='******', plate_template_id=self.form_result['plate_template_id'], plate_setup_id=self.form_result['plate_setup_id']) for cell in sorted(self.form_result['cells'], key=lambda c: c['cell_name']): well = ExperimentMetadataQLWell(name=cell['cell_name'], num_channels=2, sample=cell['sample'], experiment_comment=cell['experiment_comment'], experiment_name=cell['experiment_name'], experiment_type=cell['experiment_type'], temperature=cell['temperature'], enzyme=cell['enzyme'], enzyme_conc=cell['enzyme_conc'], additive=cell['additive'], additive_conc=cell['additive_conc'], expected_cpd=cell['expected_cpd'], expected_cpul=cell['expected_cpul'], target_copy_num=cell['target_copy_num'], ref_copy_num=cell['ref_copy_num'], dg_cartridge=cell['cartridge'], supermix=cell['supermix']) well.channels[0].target = cell['fam_target'] well.channels[0].type = cell['fam_type'] well.channels[1].target = cell['vic_target'] well.channels[1].type = cell['vic_type'] plate.wells[str(cell['cell_name'])] = well # generate QLT # TODO: rowcol order writer = QLTWriter(rowcol_order=self.form_result['rowcol_order'], fgcolorfunc=self.__qlt_fgcolorfunc, bgcolorfunc=self.__qlt_bgcolorfunc) qlt = writer.getbytes(plate) return qlt
def _list_base(self): groove_test = Session.query(Project).filter_by(name="GrooveTest").first() query = Session.query(PlateSetup).filter_by(project_id=groove_test.id).order_by("time_updated desc, name") c.paginator = paginate.Page(query, page=int(request.params.get("page", 1)), items_per_page=20) c.pager_kwargs = {} c.plate_type_field = groove_plate_type_field() return render("/product/groove/list.html")
def _algcommand_base(self): ags = Session.query(AnalysisGroup).filter_by(active=True).order_by(AnalysisGroup.name).all() rps = Session.query(ReprocessConfig).filter_by(active=True).order_by(ReprocessConfig.name).all() c.analysis_groups = {'value': '', 'options': [(ag.id, ag.name) for ag in ags]} c.reprocess_configs = {'value': '', 'options': [(rp.id, rp.name) for rp in rps]} return render('/product/algorithms/select.html')
def analyzed_channel_query(plate_list, channel_num): if not plate_list: # intentional empty? return Session.query(QLBWellChannel).filter(QLBWellChannel.id < 0) query = Session.query(QLBWellChannel).join(QLBWell, QLBPlate, Plate, Box2).\ filter(QLBWellChannel.channel_num == channel_num).\ filter(QLBWell.file_id != -1).\ filter(Plate.id.in_([p.id for p in plate_list])).\ options(joinedload_all(QLBWellChannel.well, QLBWell.plate, QLBPlate.plate, innerjoin=True)) return query
def __load_groove_setup(self, id=None): if not id: return None project = Session.query(Project).filter_by(name="GrooveTest").first() setup = Session.query(PlateSetup).get(int(id)) if not setup: return None if setup.project_id != project.id: return None return setup
def command(self): self.load_wsgi_app() plate_id = self.args[0] plate_setup_id = self.args[1] plate = Session.query(Plate).get(plate_id) plate_setup = Session.query(PlateSetup).get(plate_setup_id) if plate and plate_setup: inherit_setup_attributes(plate, plate_setup) trigger_plate_rescan(plate) # in case metrics need recalc Session.commit() print "Plate linked." else: print "Plate or setup not found (%s, %s)" % (plate_id, plate_setup_id)
def validation_download(self): plate_template = Session.query(PlateTemplate).get(self.form_result['plate_template_id']) plate_type = Session.query(PlateType).filter_by(code=self.form_result['plate_type_code']).first() plate_template.plate_type_id = plate_type.id Session.commit() response.headers['Content-Type'] = 'application/quantalife-template' h.set_download_response_header(request, response, "%s.qlt" % plate_template.prefix) response.headers['Pragma'] = 'no-cache' # yeah, this is somewhat dangerous... template_path = "%s/%s" % (config['qlb.setup_template_store'], os.path.basename(self.form_result['template_name'])) return forward(FileApp(template_path, response.headerlist))
def command(self): self.load_wsgi_app() # TODO: this might be better with keywords plate_id = self.args[0] plate_template_id = self.args[1] plate = Session.query(Plate).get(plate_id) plate_template = Session.query(PlateTemplate).get(plate_template_id) if plate and plate_template: inherit_template_attributes(plate, plate_template) trigger_plate_rescan(plate) # in case metrics need recalc Session.commit() print "Plate linked." else: print "Plate or template not found: (%s,%s)" % (plate_id, plate_template_id)
def box2_field(selected=None, empty='--', prod_only=False, exclude_fluidics_modules=False,order_by='name',order_desc=False): if ( order_desc ): box_q = Session.query(Box2).order_by( getattr(Box2,order_by).desc() ) else: box_q = Session.query(Box2).order_by( getattr(Box2,order_by) ) if prod_only or wowo('contractor'): box_q = box_q.filter(Box2.prod_query()) if exclude_fluidics_modules: box_q = box_q.filter(Box2.whole_readers_only_query()) boxes = box_q.all() return {'value': selected or '', 'options': [('',empty)]+ [(box.id, box.name) for box in boxes]}
def save(self, id=None): """ """ if id is None: abort(404) assay_q = Session.query(Assay) assay = assay_q.filter_by(id=id).first() if assay is None: abort(404) reload_sequences = False for k, v in self.form_result.items(): if k in ("primer_fwd", "primer_rev", "chromosome", "probe_pos", "amplicon_width", "snp_rsid"): if getattr(assay, k) != v: reload_sequences = True if k not in ("id"): setattr(assay, k, v) # blow away previous sequences; on view, this will update. if reload_sequences: cached_sequences = assay.cached_sequences for i in range(len(cached_sequences)): cs = cached_sequences[-1] snps = cs.snps for j in range(len(snps)): snp = snps.pop() Session.delete(snp) cached_sequences.pop() Session.delete(cs) self.__update_tms(assay) Session.commit() session.save() redirect(url(controller="assay", action="view", id=assay.id))
def command(self): app = self.load_wsgi_app() min_id = 0 if len(self.args) > 1: min_id = self.args[0] storage = QLStorageSource(app.config) qlbplates = Session.query(QLBPlate).filter(QLBPlate.id > min_id).order_by('id').all() for qlbplate in qlbplates: try: path = storage.qlbplate_path(qlbplate) except Exception: print "Could not find plate: %s (%s)" % (qlbplate.plate.name if qlbplate.plate else 'Name unknown', qlbplate.id) continue try: qlplate = get_plate(path) except Exception: print "Could not read plate: %s (%s)" % (qlbplate.plate.name if qlbplate.plate else 'Name Unknown', qlbplate.id) continue if qlplate.is_fam_vic: qlbplate.dyeset = QLBPlate.DYESET_FAM_VIC elif qlplate.is_fam_hex: qlbplate.dyeset = QLBPlate.DYESET_FAM_HEX elif qlplate.is_eva_green: qlbplate.dyeset = QLBPlate.DYESET_EVA else: qlbplate.dyeset = QLBPlate.DYESET_UNKNOWN print "Assigned dye %s - %s (%s)" % (qlbplate.dyeset, qlbplate.plate.name if qlbplate.plate else 'Name Unknown', qlbplate.id) Session.commit()
def model_distinct_field(column, additional=None, selected=None, blank=''): """ Creates a select-compatible dropdown based on the distinct values of the model in the DB. Side effect is a DB query, so be careful. TODO: might be a good idea to separate the selection logic from the lookup logic here. :param column: The Model attribute to display :param additional: Additional values to have in the dropdown, if they are not present in any DB records. :param selected: Which value should be selected. :param blank: The value to display if the backing value is null/blank. :return A dict with keys (value, options): the selected value and the option dict. """ if not additional: additional = [] # get model from attribute values = [tup[0] for tup in Session.query(column).distinct().all()] for val in additional: if val not in values: values.append(val) values.sort(key=lambda v: v.lower()) field = {'value': (selected if selected in values else '') or '', 'options': [('', blank)]+ [(v, v) for v in values]} return field
def scan_plates(plate_source, image_source): """ Scan for new/changed plates in the plate source. Store database records in the database, and thumbnail images in locations specified by image_source. THIS IS THE METHOD YOU CALL TO LOOK FOR NEW PLATES. """ count = 0 file_lists = defaultdict(list) # get QLPs -- needs read status filter? mtime_dict = dict([("%s/%s" % (dirname, basename), (id, mtime)) for id, dirname, basename, mtime in Session.query(QLBFile.id, QLBFile.dirname, QLBFile.basename, QLBFile.mtime).\ filter(QLBFile.type == 'processed').\ all()]) for volume, path in plate_source.volume_path_iter(): count += 1 path_id = plate_source.path_id(volume, path) file_source = plate_source.file_source(volume) __scan_plate(file_source, image_source, path_id, path, mtime_dict, file_lists) return file_lists
def person_field(selected=None, active_only=True): person_q = Session.query(Person).order_by(Person.first_name) if active_only: person_q = person_q.filter_by(active=True) people = person_q.all() return {'value': selected or '', 'options': [('','--')]+[(person.id, "%s %s" % (person.first_name, person.last_name)) for person in people]}
def __display(self, rowcol_order=ROWCOL_ORDER_COL): c.assay_field = fl.sequence_group_name_field(blank=True, include_without_amplicons=True, empty='') c.class_decorator = icon_class_decorator c.re_field = fl.instock_enzyme_field() c.form = h.LiteralForm( value = {'rowcol_order': str(rowcol_order)}, option = {'rowcol_order': [(ROWCOL_ORDER_ROW, 'By Row (Left->Right)'), (ROWCOL_ORDER_COL, 'By Column (Top->Bottom)')]} ) if getattr(c, 'plate_setup_id', None): c.plate_setup = Session.query(PlateSetup).get(c.plate_setup_id) elif getattr(c, 'plate_template_id', None): c.plate_template = Session.query(PlateTemplate).get(c.plate_template_id) return render('/template/design.html')
def register_algorithm(self): storage = QSAlgorithmSource(config) existing_folders = [tup[0] for tup in Session.query(ReprocessConfig.original_folder).all()] errors = dict() src_dir = self.form_result['src_dir'] if src_dir in existing_folders: errors['src_dir'] = 'This algorithm has already been registered.' elif not storage.source_path_exists(src_dir): errors['src_dir'] = 'This algorithm is not accessible in the file system.' if self.form_result['peak_detection_version'] == (0,0): # this is arbitrary peak_detection_version = (0, QUANTASOFT_DIR_VERSION_RE.search(src_dir).group(1).split('_')[-1]) else: peak_detection_version = self.form_result['peak_detection_version'] if self.form_result['peak_quantitation_version'] == (0,0): peak_quantitation_version = (0, QUANTASOFT_DIR_VERSION_RE.search(src_dir).group(1).split('_')[-1]) else: peak_quantitation_version = self.form_result['peak_quantitation_version'] if errors: resp = self._algorithms_base() defaults = AlgorithmRegisterForm.from_python(self.form_result) return h.render_bootstrap_form(resp, defaults=defaults, errors=errors, error_formatters=h.tw_bootstrap_error_formatters) try: rp = ReprocessConfig(name=src_dir.split(os.path.sep)[0], code=self.form_result['code'], peak_detection_major=peak_detection_version[0], peak_detection_minor=peak_detection_version[1], peak_quant_major=peak_quantitation_version[0], peak_quant_minor=peak_quantitation_version[1], trigger_fixed_width=100, active=True, cluster_mode=ReprocessConfig.CLUSTER_MODE_CLUSTER, original_folder=src_dir) storage.add_reprocessor(src_dir, self.form_result['code']) Session.add(rp) Session.commit() session['flash'] = 'New algorithm reprocessor created.' session.save() return redirect(url(controller='product', action='algorithms')) except shutil.Error: session['flash'] = 'Could not copy source algorithm to destination.' session['flash_class'] = 'error' session.save() return redirect(url(controller='product', action='algorithms')) except IOError: session['flash'] = "Could not access the algorithm's file system." session['flash_class'] = 'error' session.save() return redirect(url(controller='product', action='algorithms'))
def enzyme_conc_new(self): enzyme_field = fl.enzyme_field() assay_field = fl.assay_field(blank=True, empty="", selected=request.params.get("assay_id", None)) author_field = fl.person_field() c.plate = None if request.params.get("plate_id", None): plate = Session.query(Plate).get(int(request.params.get("plate_id"))) if plate: c.plate = plate c.form = h.LiteralFormSelectPatch( value={ "enzyme_id": enzyme_field["value"], "assay_id": assay_field["value"], "author_id": author_field["value"], }, option={ "enzyme_id": enzyme_field["options"], "assay_id": assay_field["options"], "author_id": author_field["options"], }, ) return render("/assay/enzyme/new.html")
def enzyme_conc_edit(self, id=None): if id is None: abort(404) conc = Session.query(EnzymeConcentration).get(id) if not conc: abort(404) c.conc = conc enzyme_field = fl.enzyme_field(selected=unicode(conc.enzyme_id)) assay_field = fl.assay_field(blank=True, selected=unicode(conc.assay.id)) author_field = fl.person_field(selected=unicode(conc.author_id)) c.plate = None c.form = h.LiteralFormSelectPatch( value={ "enzyme_id": enzyme_field["value"], "assay_id": assay_field["value"], "author_id": author_field["value"], "minimum_conc": conc.minimum_conc, "maximum_conc": conc.maximum_conc, "source_plate_id": conc.source_plate_id, "notes": conc.notes, }, option={ "enzyme_id": enzyme_field["options"], "assay_id": assay_field["options"], "author_id": author_field["options"], }, ) return render("/assay/enzyme/edit.html")
def __set_dg_context(self, dg_id, run_id): c.dg_run = Session.query(DropletGeneratorRun).filter( and_(DropletGeneratorRun.droplet_generator_id == dg_id, DropletGeneratorRun.run_number == run_id))\ .options(joinedload_all(DropletGeneratorRun.droplet_generator, innerjoin=True)).first() if not c.dg_run: abort(404)
def gmap(self): addresses = self.form_result['addresses'] address_row_map = defaultdict(list) for a in addresses: address_row_map[a['address']].append(a['row']) if addresses: known_address_tuples = Session.query(MapCache.address, MapCache)\ .filter(MapCache.address.in_([a['address'] for a in addresses])).all() known_address_json = [] for a, k in known_address_tuples: if not k.verified: continue rows = address_row_map[a] for r in rows: known_address_json.append([r, a, k.lat, k.lon]) c.known_address_json = json.dumps(known_address_json) unknown_address_json = [] known_addresses = [a for a, k in known_address_tuples] for a in addresses: if a['address'] not in known_addresses: unknown_address_json.append((a['row'], a['address'])) c.unknown_address_json = json.dumps(sorted(unknown_address_json)) # todo make config c.api_key = 'AIzaSyCJmLePQj0ZLMbxVvJorxcL65AKUp8OH9w' c.origin = config['qtools.map.origin'] return render('/map/gmap.html')
def batch_plate_template_download(self, id=None): plate = self.__load_batch_plate(id) box2 = Session.query(Box2).get(self.form_result['box2_id']) if not plate or not box2: abort(404) code = plate.batch.plate_type.code if self.form_result['qc_plate']: plate.qc_plate = self.form_result['qc_plate'] Session.commit() # TODO FIXFIX or incorporate into model if plate.qc_plate: serial = 'QC' else: serial = box2.name.split(' ')[-1] # only mfgco supported right now if code == 'mfgco': qlt_file = "%s/carryover.qlt" % config['qlb.setup_template_store'] elif code == 'fvtitr': qlt_file = "%s/fvbatch_QC.qlt" % config['qlb.setup_template_store'] else: abort(404) response.headers['Content-Type'] = 'application/quantalife-template' h.set_download_response_header(request, response, "%s_%s.qlt" % (serial, plate.name)) response.headers['Pragma'] = 'no-cache' response.headers['Cache-Control'] = 'no-cache' return forward(FileApp(qlt_file, response.headerlist))