class ProtocolStep(Entity): """Steps key in the Protocol object""" _TAG = 'step' name = StringAttributeDescriptor("name") type = EntityDescriptor('process-type', Processtype) permittedcontainers = NestedStringListDescriptor('container-type', 'container-types') queue_fields = NestedAttributeListDescriptor('queue-field', 'queue-fields') step_fields = NestedAttributeListDescriptor('step-field', 'step-fields') sample_fields = NestedAttributeListDescriptor('sample-field', 'sample-fields') step_properties = NestedAttributeListDescriptor('step-property', 'step-properties') epp_triggers = NestedAttributeListDescriptor('epp-trigger', 'epp-triggers')
class Project(Entity): "Project concerning a number of samples; associated with a researcher." _URI = 'projects' _TAG = 'project' _PREFIX = 'prj' name = StringDescriptor('name') open_date = StringDescriptor('open-date') close_date = StringDescriptor('close-date') invoice_date = StringDescriptor('invoice-date') researcher = EntityDescriptor('researcher', Researcher) udf = UdfDictionaryDescriptor() udt = UdtDictionaryDescriptor() files = EntityListDescriptor(nsmap('file:file'), File) externalids = ExternalidListDescriptor()
class ProtocolStep(Entity): """Steps key in the Protocol object""" _TAG = 'step' name = StringAttributeDescriptor("name") type = EntityDescriptor('process-type', Processtype) permittedcontainers = NestedStringListDescriptor('container-type', 'permitted-containers') permitted_control_types = NestedEntityListDescriptor( 'control-type', ControlType, 'permitted-control-types') required_reagent_kits = NestedEntityListDescriptor( 'reagent-kit', ReagentKit, 'required-reagent-kits') queue_fields = NestedAttributeListDescriptor('queue-field', 'queue-fields') step_fields = NestedAttributeListDescriptor('step-field', 'step-fields') sample_fields = NestedAttributeListDescriptor('sample-field', 'sample-fields') step_properties = NestedAttributeListDescriptor('step-property', 'step-properties') epp_triggers = NestedAttributeListDescriptor('epp-trigger', 'epp-triggers')
class Container(Entity): "Container for analyte artifacts." _URI = 'containers' _PREFIX = 'con' name = StringDescriptor('name') type = EntityDescriptor('type', Containertype) occupied_wells = IntegerDescriptor('occupied-wells') placements = PlacementDictionaryDescriptor('placement') udf = UdfDictionaryDescriptor() udt = UdtDictionaryDescriptor() state = StringDescriptor('state') def get_placements(self): """Get the dictionary of locations and artifacts using the more efficient batch call.""" result = self.placements.copy() self.lims.get_batch(list(result.values())) return result
class Researcher(Entity): "Person; client scientist or lab personnel. Associated with a lab." _URI = 'researchers' _PREFIX = 'res' first_name = StringDescriptor('first-name') last_name = StringDescriptor('last-name') phone = StringDescriptor('phone') fax = StringDescriptor('fax') email = StringDescriptor('email') initials = StringDescriptor('initials') lab = EntityDescriptor('lab', Lab) udf = UdfDictionaryDescriptor() udt = UdtDictionaryDescriptor() externalids = ExternalidListDescriptor() # credentials XXX @property def name(self): return "%s %s" % (self.first_name, self.last_name)
class Step(Entity): "Step, as defined by the genologics API." _URI = 'steps' _PREFIX = 'stp' current_state = StringAttributeDescriptor('current-state') _reagent_lots = EntityDescriptor('reagent-lots', StepReagentLots) actions = EntityDescriptor('actions', StepActions) placements = EntityDescriptor('placements', StepPlacements) details = EntityDescriptor('details', StepDetails) step_pools = EntityDescriptor('pools', StepPools) program_status = EntityDescriptor('program-status', StepProgramStatus) reagents = EntityDescriptor('reagents', StepReagents) def advance(self): self.get() self.root = self.lims.post(uri="{0}/advance".format(self.uri), data=self.lims.tostring( ElementTree.ElementTree(self.root))) @property def reagent_lots(self): return self._reagent_lots.reagent_lots
class Artifact(Entity): "Any process input or output; analyte or file." _URI = 'artifacts' _TAG = 'artifact' _PREFIX = 'art' name = StringDescriptor('name') type = StringDescriptor('type') output_type = StringDescriptor('output-type') parent_process = EntityDescriptor('parent-process', Process) volume = StringDescriptor('volume') concentration = StringDescriptor('concentration') qc_flag = StringDescriptor('qc-flag') location = LocationDescriptor('location') working_flag = BooleanDescriptor('working-flag') samples = EntityListDescriptor('sample', Sample) udf = UdfDictionaryDescriptor() files = EntityListDescriptor(nsmap('file:file'), File) reagent_labels = ReagentLabelList() # artifact_flags XXX # artifact_groups XXX def input_artifact_list(self): """Returns the input artifact ids of the parrent process.""" input_artifact_list = [] try: for tuple in self.parent_process.input_output_maps: if tuple[1]['limsid'] == self.id: input_artifact_list.append(tuple[0]['uri']) # ['limsid']) except: pass return input_artifact_list def get_state(self): "Parse out the state value from the URI." parts = urlparse(self.uri) params = parse_qs(parts.query) try: return params['state'][0] except (KeyError, IndexError): return None @property def container(self): "The container where the artifact is located, or None" try: return self.location[0] except: return None def stateless(self): "returns the artefact independently of it's state" parts = urlparse(self.uri) if 'state' in parts[4]: stateless_uri = urlunparse( [parts[0], parts[1], parts[2], parts[3], '', '']) return Artifact(self.lims, uri=stateless_uri) else: return self # XXX set_state ? state = property(get_state) stateless = property(stateless) def _get_workflow_stages_and_statuses(self): self.get() result = [] rootnode = self.root.find('workflow-stages') for node in rootnode.findall('workflow-stage'): result.append((Stage(self.lims, uri=node.attrib['uri']), node.attrib['status'], node.attrib['name'])) return result workflow_stages_and_statuses = property(_get_workflow_stages_and_statuses)
class Process(Entity): "Process (instance of Processtype) executed producing ouputs from inputs." _URI = 'processes' _PREFIX = 'prc' type = EntityDescriptor('type', Processtype) date_run = StringDescriptor('date-run') technician = EntityDescriptor('technician', Researcher) protocol_name = StringDescriptor('protocol-name') input_output_maps = InputOutputMapList() udf = UdfDictionaryDescriptor() udt = UdtDictionaryDescriptor() files = EntityListDescriptor(nsmap('file:file'), File) process_parameter = StringDescriptor('process-parameter') instrument = EntityDescriptor('instrument', Instrument) # process_parameters XXX def outputs_per_input(self, inart, ResultFile=False, SharedResultFile=False, Analyte=False): """Getting all the output artifacts related to a particual input artifact""" inouts = [ io for io in self.input_output_maps if io[0]['limsid'] == inart ] if ResultFile: inouts = [ io for io in inouts if io[1]['output-type'] == 'ResultFile' ] elif SharedResultFile: inouts = [ io for io in inouts if io[1]['output-type'] == 'SharedResultFile' ] elif Analyte: inouts = [io for io in inouts if io[1]['output-type'] == 'Analyte'] outs = [io[1]['uri'] for io in inouts] return outs def input_per_sample(self, sample): """gettiung all the input artifacts dereved from the specifyed sample""" ins_all = self.all_inputs() ins = [] for inp in ins_all: for samp in inp.samples: if samp.name == sample and inp not in ins: ins.append(inp) return ins def all_inputs(self, unique=True, resolve=False): """Retrieving all input artifacts from input_output_maps if unique is true, no duplicates are returned. """ # if the process has no input, that is not standard and we want to know about it try: ids = [io[0]['limsid'] for io in self.input_output_maps] except TypeError: logger.error("Process ", self, " has no input artifacts") raise TypeError if unique: ids = list(frozenset(ids)) if resolve: return self.lims.get_batch( [Artifact(self.lims, id=id) for id in ids if id is not None]) else: return [Artifact(self.lims, id=id) for id in ids if id is not None] def all_outputs(self, unique=True, resolve=False): """Retrieving all output artifacts from input_output_maps if unique is true, no duplicates are returned. """ # Given how ids is structured, io[1] might be None : some process don't have an output. ids = [ io[1]['limsid'] for io in self.input_output_maps if io[1] is not None ] if unique: ids = list(frozenset(ids)) if resolve: return self.lims.get_batch( [Artifact(self.lims, id=id) for id in ids if id is not None]) else: return [Artifact(self.lims, id=id) for id in ids if id is not None] def shared_result_files(self): """Retreve all resultfiles of output-generation-type PerAllInputs.""" artifacts = self.all_outputs(unique=True) return [a for a in artifacts if a.output_type == 'SharedResultFile'] def result_files(self): """Retreve all resultfiles of output-generation-type perInput.""" artifacts = self.all_outputs(unique=True) return [a for a in artifacts if a.output_type == 'ResultFile'] def analytes(self): """Retreving the output Analytes of the process, if existing. If the process is not producing any output analytes, the input analytes are returned. Input/Output is returned as a information string. Makes aggregate processes and normal processes look the same.""" info = 'Output' artifacts = self.all_outputs(unique=True) analytes = [a for a in artifacts if a.type == 'Analyte'] if len(analytes) == 0: artifacts = self.all_inputs(unique=True) analytes = [a for a in artifacts if a.type == 'Analyte'] info = 'Input' return analytes, info def parent_processes(self): """Retrieving all parent processes through the input artifacts""" return [i_a.parent_process for i_a in self.all_inputs(unique=True)] def output_containers(self): """Retrieve all unique output containers""" cs = [] for o_a in self.all_outputs(unique=True): if o_a.container: cs.append(o_a.container) return list(frozenset(cs)) @property def step(self): """Retrive the Step coresponding to this process. They share the same id""" return Step(self.lims, id=self.id)
class Stage(Entity): """Holds Protocol/Workflow""" name = StringAttributeDescriptor('name') index = IntegerAttributeDescriptor('index') protocol = EntityDescriptor('protocol', Protocol) step = EntityDescriptor('step', ProtocolStep)
super(ReagentType, self).__init__(lims, uri, id) assert self.uri is not None self.root = lims.get(self.uri) self.sequence = None for t in self.root.findall('special-type'): if t.attrib.get("name") == "Index": for child in t.findall("attribute"): if child.attrib.get("name") == "Sequence": self.sequence = child.attrib.get("value") class Queue(Entity): """Queue of a given step. Will recursively get all the pages of artifacts, and therefore, can be quite slow to load""" _URI = "queues" _TAG = "queue" _PREFIX = "que" artifacts = MultiPageNestedEntityListDescriptor("artifact", Artifact, "artifacts") Sample.artifact = EntityDescriptor('artifact', Artifact) StepActions.step = EntityDescriptor('step', Step) Stage.workflow = EntityDescriptor('workflow', Workflow) Artifact.workflow_stages = NestedEntityListDescriptor('workflow-stage', Stage, 'workflow-stages') Step.configuration = EntityDescriptor('configuration', ProtocolStep) StepProgramStatus.configuration = EntityDescriptor('configuration', ProtocolStep) Researcher.roles = NestedEntityListDescriptor('role', Role, 'credentials')