def store_pools( self, customer: str, order: str, ordered: dt.datetime, ticket: int, pools: List[dict], ) -> List[models.Pool]: """Store pools in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_pools = [] for pool in pools: with self.status.session.no_autoflush: application_version = self.status.current_application_version(pool["application"]) if application_version is None: raise OrderError(f"Invalid application: {pool['application']}") new_pool = self.status.add_pool( customer=customer_obj, name=pool["name"], order=order, ordered=ordered, ticket=ticket, application_version=application_version, data_analysis=pool["data_analysis"], capture_kit=pool["capture_kit"], ) new_delivery = self.status.add_delivery(destination="caesar", pool=new_pool) self.status.add(new_delivery) new_pools.append(new_pool) self.status.add_commit(new_pools) return new_pools
def store_samples( self, customer: str, order: str, ordered: dt.datetime, ticket: int, samples: List[dict], ) -> List[models.Sample]: """Store samples in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_samples = [] with self.status.session.no_autoflush: for sample in samples: new_sample = self.status.add_sample( name=sample["name"], internal_id=sample["internal_id"], sex=sample["sex"] or "unknown", order=order, ordered=ordered, ticket=ticket, priority=sample["priority"], comment=sample["comment"], tumour=sample["tumour"], data_analysis=sample["data_analysis"], ) new_sample.customer = customer_obj application_tag = sample["application"] application_version = self.status.current_application_version(application_tag) if application_version is None: raise OrderError(f"Invalid application: {sample['application']}") new_sample.application_version = application_version new_samples.append(new_sample) self.status.add_commit(new_samples) return new_samples
def store_pools(self, customer: str, order: str, ordered: dt.datetime, ticket: int, pools: List[dict]) -> List[models.Pool]: """Store pools in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_pools = [] for pool in pools: with self.status.session.no_autoflush: application_version = self.status.latest_version( pool['application']) if application_version is None: raise OrderError( f"unknown application: {pool['application']}") new_pool = self.status.add_pool( customer=customer_obj, name=pool['name'], order=order, ordered=ordered, ticket=ticket, application_version=application_version, ) new_delivery = self.status.add_delivery(destination='caesar', pool=new_pool) self.status.add(new_delivery) new_pools.append(new_pool) self.status.add_commit(new_pools) return new_pools
def group_containers(samples): """Group samples by containers.""" tubes = {} plates = {} no_container = {} for sample_data in samples: if sample_data["container"] == "Tube": # detected tube: name after sample unless specified container_name = sample_data.get( "container_name") or sample_data["name"] if container_name in tubes: raise OrderError( f"{container_name}: conflicting sample/tube name") tubes[container_name] = [sample_data] elif sample_data["container"] == "96 well plate": # detected plate: require container name if sample_data["container_name"] not in plates: plates[sample_data["container_name"]] = [] plates[sample_data["container_name"]].append(sample_data) elif sample_data["container"] == "No container": # detected no-container: name after sample unless specified container_name = sample_data.get( "container_name") or sample_data["name"] if container_name in tubes: raise OrderError( f"{container_name}: conflicting sample/container name") tubes[container_name] = [sample_data] else: raise ValueError( f"unknown container type: {sample_data['container']}") return tubes, plates, no_container
def store_items_in_status(self, customer: str, order: str, ordered: dt.datetime, ticket: int, items: List[dict]) -> List[models.Sample]: """Store fastq samples in the status database including family connection and delivery""" production_customer = self.status.customer("cust000") customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_samples = [] with self.status.session.no_autoflush: for sample in items: new_sample = self.status.add_sample( comment=sample["comment"], internal_id=sample.get("internal_id"), name=sample["name"], order=order, ordered=ordered, priority=sample["priority"], sex=sample["sex"] or "unknown", ticket=ticket, tumour=sample["tumour"], ) new_sample.customer = customer_obj application_tag = sample["application"] application_version = self.status.current_application_version( application_tag) if application_version is None: raise OrderError( f"Invalid application: {sample['application']}") new_sample.application_version = application_version new_samples.append(new_sample) data_analysis: Pipeline = self._get_fastq_pipeline( application_version, new_sample.is_tumour) new_case = self.status.add_case( data_analysis=data_analysis, data_delivery=DataDelivery(sample["data_delivery"]), name=sample["name"], panels=["OMIM-AUTO"], priority="research", ) new_case.customer = production_customer self.status.add(new_case) new_relationship = self.status.relate_sample( family=new_case, sample=new_sample, status=StatusEnum.unknown) self.status.add(new_relationship) new_delivery = self.status.add_delivery(destination="caesar", sample=new_sample) self.status.add(new_delivery) self.status.add_commit(new_samples) return new_samples
def store_microbial_order( self, customer: str, order: str, ordered: dt.datetime, ticket: int, lims_project: str, samples: List[dict], comment: str = None, ) -> models.MicrobialOrder: """Store microbial samples in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") with self.status.session.no_autoflush: new_order = self.status.add_microbial_order( customer=customer_obj, name=order, ordered=ordered, internal_id=lims_project, ticket_number=ticket, comment=comment, ) for sample_data in samples: application_tag = sample_data["application"] application_version = self.status.current_application_version(application_tag) if application_version is None: raise OrderError(f"Invalid application: {sample_data['application']}") organism = self.status.organism(sample_data["organism_id"]) if not organism: organism = self.status.add_organism( internal_id=sample_data["organism_id"], name=sample_data["organism_id"], reference_genome=sample_data["reference_genome"], ) self.status.add_commit(organism) new_sample = self.status.add_microbial_sample( name=sample_data["name"], internal_id=sample_data["internal_id"], reference_genome=sample_data["reference_genome"], comment=sample_data["comment"], organism=organism, application_version=application_version, priority=sample_data["priority"], data_analysis=sample_data["data_analysis"], ) new_order.microbial_samples.append(new_sample) self.status.add_commit(new_order) return new_order
def store_fastq_samples( self, customer: str, order: str, ordered: dt.datetime, ticket: int, samples: List[dict], ) -> List[models.Sample]: """Store fast samples in the status database including family connection and delivery.""" production_customer = self.status.customer("cust000") customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_samples = [] with self.status.session.no_autoflush: for sample in samples: new_sample = self.status.add_sample( name=sample["name"], internal_id=sample["internal_id"], sex=sample["sex"] or "unknown", order=order, ordered=ordered, ticket=ticket, priority=sample["priority"], comment=sample["comment"], tumour=sample["tumour"], data_analysis=sample["data_analysis"], ) new_sample.customer = customer_obj application_tag = sample["application"] application_version = self.status.current_application_version(application_tag) if application_version is None: raise OrderError(f"Invalid application: {sample['application']}") new_sample.application_version = application_version new_samples.append(new_sample) if not new_sample.is_tumour: new_family = self.status.add_family( name=sample["name"], panels=["OMIM-AUTO"], priority="research" ) new_family.customer = production_customer self.status.add(new_family) new_relationship = self.status.relate_sample( family=new_family, sample=new_sample, status=sample["status"] or "unknown", ) self.status.add(new_relationship) new_delivery = self.status.add_delivery(destination="caesar", sample=new_sample) self.status.add(new_delivery) self.status.add_commit(new_samples) return new_samples
def store_items_in_status(self, customer: str, order: str, ordered: dt.datetime, ticket: int, items: List[dict]) -> List[models.Sample]: """Store samples in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_samples = [] with self.status.session.no_autoflush: for sample in items: new_sample = self.status.add_sample( comment=sample["comment"], internal_id=sample.get("internal_id"), name=sample["name"], order=order, ordered=ordered, priority=sample["priority"], sex="unknown", ticket=ticket, ) new_sample.customer = customer_obj application_tag = sample["application"] application_version = self.status.current_application_version( application_tag) if application_version is None: raise OrderError( f"Invalid application: {sample['application']}") new_sample.application_version = application_version new_samples.append(new_sample) new_case = self.status.add_case( data_analysis=Pipeline(sample["data_analysis"]), data_delivery=DataDelivery(sample["data_delivery"]), name=sample["name"], panels=None, priority=sample["priority"], ) new_case.customer = customer_obj self.status.add(new_case) new_relationship = self.status.relate_sample( family=new_case, sample=new_sample, status=StatusEnum.unknown) self.status.add(new_relationship) self.status.add_commit(new_samples) return new_samples
def submit(self, project: OrderType, data: dict, ticket: dict) -> dict: """Submit a batch of samples.""" try: ORDER_SCHEMES[project].validate(data) except (ValueError, TypeError) as error: raise OrderError(error.args[0]) # detect manual ticket assignment ticket_match = re.search(r'^#?([0-9]{6})$', data['name']) ticket_number = int(ticket_match.group()) if ticket_match else None if ticket_number: LOG.info(f"{ticket_number}: detected ticket in order name") data['ticket'] = ticket_number else: # open and assign ticket to order try: if self.osticket: message = f"New incoming samples, {ticket['name']}" data['ticket'] = self.osticket.open_ticket( name=ticket['name'], email=ticket['email'], subject=data['name'], message=message, ) LOG.info(f"{data['ticket']}: opened new ticket") else: data['ticket'] = None except TicketCreationError as error: LOG.warning(error.message) data['ticket'] = None order_func = getattr(self, f"submit_{project.value}") result = order_func(data) return result
def _validate_subject_sex(self, samples: [Of1508Sample], customer_id: str): """Validate that sex is consistent with existing samples, skips samples of unknown sex Args: samples (list[dict]): Samples to validate customer_id (str): Customer that the samples belong to Returns: Nothing """ sample: Of1508Sample for sample in samples: subject_id: str = sample.subject_id if not subject_id: continue new_gender: str = sample.sex if new_gender == "unknown": continue existing_samples: [ models.Sample ] = self.status.samples_by_subject_id(customer_id=customer_id, subject_id=subject_id) existing_sample: models.Sample for existing_sample in existing_samples: previous_gender = existing_sample.sex if previous_gender == "unknown": continue if previous_gender != new_gender: raise OrderError( f"Sample gender inconsistency for subject_id: {subject_id}: previous gender {previous_gender}, new gender {new_gender}" )
def _validate_customer_on_imported_samples(self, project, data): for sample in data.get("samples"): if sample.get("internal_id"): if project not in ( OrderType.MIP, OrderType.EXTERNAL, OrderType.BALSAMIC, OrderType.MIP_BALSAMIC, OrderType.MIP_RNA, ): raise OrderError( f"Only MIP, Balsamic and external orders can have imported " f"samples: " f"{sample.get('name')}" ) existing_sample = self.status.sample(sample.get("internal_id")) data_customer = self.status.customer(data["customer"]) if existing_sample.customer.customer_group_id != data_customer.customer_group_id: raise OrderError(f"Sample not available: {sample.get('name')}")
def prepare(cls, samples): """Convert API input to LIMS input data.""" lims_containers = [] tubes, plates, no_container = cls.group_containers(samples) # "96 well plate" = container type "1"; Tube = container type "2"; "No container" = container type "3" for container_type, containers in [("1", plates), ("2", tubes), ("3", no_container)]: for container_name, samples in containers.items(): new_container = { "name": container_name, "type": container_type, "samples": [] } # check that positions in plate are unique well_positions = {} for sample_data in samples: location = sample_data["well_position"] or None if location: if location in well_positions: first_sample = well_positions[location] message = ( f"duplicate well position: {location} | {first_sample}" f" - {sample_data['name']}") raise OrderError(message) well_positions[location] = sample_data["name"] if sample_data[ "container"] == "96 well plate" and location is None: message = f"missing 'well_position' for sample: {sample_data['name']}" raise ValueError(message) new_sample = { "name": sample_data["name"], "location": location or "1:1", "index_sequence": sample_data["index_sequence"], "udfs": {}, } for key, value in sample_data["udfs"].items(): if value is None: LOG.debug(f"{key}: skipping null value UDF") continue if key in PROP2UDF: if isinstance(value, bool): value = "yes" if value else "no" new_sample["udfs"][PROP2UDF[key]] = value else: LOG.debug(f"UDF not found: {key} - {value}") new_container["samples"].append(new_sample) lims_containers.append(new_container) return lims_containers
def _validate_case_names_are_available(self, customer_id: str, samples: List[RmlSample], ticket: int): """Validate that the names of all pools are unused for all samples""" customer_obj: models.Customer = self.status.customer(customer_id) sample: RmlSample for sample in samples: case_name: str = self.create_case_name(pool_name=sample.pool, ticket=ticket) if self.status.find_family(customer=customer_obj, name=case_name): raise OrderError( f"Case name {case_name} already in use for customer {customer_obj.name}" )
def _validate_case_names_are_unique(self, samples: List[OrderInSample], customer_id: str) -> None: """Validate that the names of all cases are unused for all samples""" customer_obj: models.Customer = self.status.customer(customer_id) sample: Of1508Sample for sample in samples: if self._rerun_of_existing_case(sample): continue if self.status.find_family(customer=customer_obj, name=sample.family_name): raise OrderError( f"Case name {sample.family_name} already in use")
def _validate_samples_available_to_customer(self, samples: List[OrderInSample], customer_id: str) -> None: """Validate that the customer have access to all samples""" sample: Of1508Sample for sample in samples: if not sample.internal_id: continue existing_sample: models.Sample = self.status.sample( sample.internal_id) data_customer: models.Customer = self.status.customer(customer_id) if existing_sample.customer.customer_group_id != data_customer.customer_group_id: raise OrderError(f"Sample not available: {sample.name}")
def prepare(cls, samples): """Convert API input to LIMS input data.""" lims_containers = [] tubes, plates = cls.group_containers(samples) # "96 well plate" = container type "1"; Tube = container type "2" for container_type, containers in [('1', plates), ('2', tubes)]: for container_name, samples in containers.items(): new_container = { 'name': container_name, 'type': container_type, 'samples': [], } # check that positions in plate are unique well_positions = {} for sample_data in samples: location = sample_data['well_position'] or None if location: if location in well_positions: first_sample = well_positions[location] message = ( f"duplicate well position: {location} | {first_sample}" f" - {sample_data['name']}") raise OrderError(message) well_positions[location] = sample_data['name'] if sample_data[ 'container'] == '96 well plate' and location is None: message = f"missing 'well_position' for sample: {sample_data['name']}" raise ValueError(message) new_sample = { 'name': sample_data['name'], 'location': location or '1:1', 'index_sequence': sample_data['index_sequence'], 'udfs': {} } for key, value in sample_data['udfs'].items(): if value is None: LOG.debug(f"{key}: skipping null value UDF") continue if key in PROP2UDF: if isinstance(value, bool): value = 'yes' if value else 'no' new_sample['udfs'][PROP2UDF[key]] = value else: LOG.debug(f"UDF not found: {key} - {value}") new_container['samples'].append(new_sample) lims_containers.append(new_container) return lims_containers
def store_samples(self, customer: str, order: str, ordered: dt.datetime, ticket: int, samples: List[dict]) -> List[models.Sample]: """Store samples in the status database.""" production_customer = self.status.customer('cust000') customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_samples = [] for sample in samples: with self.status.session.no_autoflush: new_sample = self.status.add_sample( name=sample['name'], internal_id=sample['internal_id'], sex=sample['sex'] or 'unknown', order=order, ordered=ordered, ticket=ticket, priority=sample['priority'], comment=sample['comment'], tumour=sample['tumour'], ) new_sample.customer = customer_obj with self.status.session.no_autoflush: new_sample.application_version = self.status.latest_version( sample['application']) new_samples.append(new_sample) if not new_sample.is_tumour: with self.status.session.no_autoflush: new_family = self.status.add_family(name=sample['name'], panels=['OMIM-AUTO'], priority='research') new_family.customer = production_customer self.status.add(new_family) new_relationship = self.status.relate_sample( family=new_family, sample=new_sample, status=sample['status'] or 'unknown', ) self.status.add(new_relationship) new_delivery = self.status.add_delivery(destination='caesar', sample=new_sample) self.status.add(new_delivery) self.status.add_commit(new_samples) return new_samples
def _validate_sample_names_are_available(self, samples: List[SarsCov2Sample], customer_id: str) -> None: """Validate that the names of all samples are unused for all samples""" customer_obj: models.Customer = self.status.customer(customer_id) sample: SarsCov2Sample for sample in samples: sample_name: str = sample.name if sample.control: continue if self.status.find_samples(customer=customer_obj, name=sample_name).first(): raise OrderError( f"Sample name {sample_name} already in use for customer {customer_obj.name}" )
def pools_to_status(data: dict) -> dict: """Convert input to pools.""" pools = {} for sample in data['samples']: if sample['pool'] not in pools: pools[sample['pool']] = set() pools[sample['pool']].add(sample['application']) status_data = { 'customer': data['customer'], 'order': data['name'], 'pools': [] } for pool_name, applications in pools.items(): if len(applications) != 1: raise OrderError( f"different application in pool: {pool_name} - {applications}" ) status_data['pools'].append({ 'name': pool_name, 'application': applications.pop(), }) return status_data
def order_to_status(order: OrderIn) -> dict: """Convert input to pools.""" status_data = { "customer": order.customer, "order": order.name, "comment": order.comment, "pools": [], } # group pools pools = {} for sample in order.samples: pool_name = sample.pool application = sample.application data_analysis = sample.data_analysis data_delivery = sample.data_delivery priority = sample.priority if pool_name not in pools: pools[pool_name] = {} pools[pool_name]["name"] = pool_name pools[pool_name]["applications"] = set() pools[pool_name]["priorities"] = set() pools[pool_name]["samples"] = [] pools[pool_name]["samples"].append(sample) pools[pool_name]["applications"].add(application) pools[pool_name]["priorities"].add(priority) # each pool must only have same of some values for pool in pools.values(): applications = pool["applications"] priorities = pool["priorities"] pool_name = pool["name"] if len(applications) > 1: raise OrderError( f"different applications in pool: {pool_name} - {applications}" ) if len(priorities) > 1: raise OrderError( f"different priorities in pool: {pool_name} - {priorities}" ) for pool in pools.values(): pool_name = pool["name"] applications = pool["applications"] application = applications.pop() pool_samples = pool["samples"] priorities = pool["priorities"] priority = priorities.pop() status_data["pools"].append({ "name": pool_name, "application": application, "data_analysis": data_analysis, "data_delivery": data_delivery, "priority": priority, "samples": [{ "comment": sample.comment, "control": sample.control, "name": sample.name, } for sample in pool_samples], }) return status_data
def store_cases( self, customer: str, order: str, ordered: dt.datetime, ticket: int, cases: List[dict], ) -> List[models.Family]: """Store cases and samples in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_families = [] for case in cases: case_obj = self.status.find_family(customer_obj, case["name"]) if case_obj: case_obj.panels = case["panels"] else: case_obj = self.status.add_family( name=case["name"], panels=case["panels"], priority=case["priority"] ) case_obj.customer = customer_obj new_families.append(case_obj) family_samples = {} for sample in case["samples"]: sample_obj = self.status.sample(sample["internal_id"]) if sample_obj: family_samples[sample["name"]] = sample_obj else: new_sample = self.status.add_sample( capture_kit=sample["capture_kit"], comment=sample["comment"], data_analysis=sample["data_analysis"], from_sample=sample["from_sample"], internal_id=sample["internal_id"], name=sample["name"], order=order, ordered=ordered, priority=case["priority"], sex=sample["sex"], ticket=ticket, time_point=sample["time_point"], tumour=sample["tumour"], ) new_sample.customer = customer_obj with self.status.session.no_autoflush: application_tag = sample["application"] new_sample.application_version = self.status.current_application_version( application_tag ) if new_sample.application_version is None: raise OrderError(f"Invalid application: {sample['application']}") family_samples[new_sample.name] = new_sample self.status.add(new_sample) new_delivery = self.status.add_delivery(destination="caesar", sample=new_sample) self.status.add(new_delivery) for sample in case["samples"]: mother_obj = family_samples[sample["mother"]] if sample.get("mother") else None father_obj = family_samples[sample["father"]] if sample.get("father") else None with self.status.session.no_autoflush: link_obj = self.status.link(case_obj.internal_id, sample["internal_id"]) if link_obj: link_obj.status = sample["status"] or link_obj.status link_obj.mother = mother_obj or link_obj.mother link_obj.father = father_obj or link_obj.father else: new_link = self.status.relate_sample( family=case_obj, sample=family_samples[sample["name"]], status=sample["status"], mother=mother_obj, father=father_obj, ) self.status.add(new_link) self.status.add_commit(new_families) return new_families
def submit(self, project: OrderType, data: dict, ticket: dict) -> dict: """Submit a batch of samples. Main entry point for the class towards interfaces that implements it. """ try: ORDER_SCHEMES[project].validate(data) except (ValueError, TypeError) as error: raise OrderError(error.args[0]) self._validate_customer_on_imported_samples(project, data) # detect manual ticket assignment ticket_match = re.fullmatch(r"#([0-9]{6})", data["name"]) if ticket_match: ticket_number = int(ticket_match.group(1)) LOG.info(f"{ticket_number}: detected ticket in order name") data["ticket"] = ticket_number else: # open and assign ticket to order try: if self.osticket: message = f"data:text/html;charset=utf-8,New incoming samples: " for sample in data.get("samples"): message += "<br />" + sample.get("name") if sample.get("family_name"): message += f", family: {sample.get('family_name')}" if sample.get("internal_id"): existing_sample = self.status.sample(sample.get("internal_id")) sample_customer = "" if existing_sample.customer_id != data["customer"]: sample_customer = " from " + existing_sample.customer.internal_id message += f" (already existing sample{sample_customer})" if sample.get("comment"): message += ", " + sample.get("comment") message += f"<br />" if data.get("comment"): message += f"<br />{data.get('comment')}." if ticket.get("name"): message += f"<br />{ticket.get('name')}" data["ticket"] = self.osticket.open_ticket( name=ticket["name"], email=ticket["email"], subject=data["name"], message=message, ) LOG.info(f"{data['ticket']}: opened new ticket") else: data["ticket"] = None except TicketCreationError as error: LOG.warning(error.message) data["ticket"] = None order_func = getattr(self, f"submit_{project.value}") result = order_func(data) return result
def store_families(self, customer: str, order: str, ordered: dt.datetime, ticket: int, families: List[dict]) -> List[models.Family]: """Store families and samples in the status database.""" customer_obj = self.status.customer(customer) if customer_obj is None: raise OrderError(f"unknown customer: {customer}") new_families = [] for family in families: family_obj = self.status.find_family(customer_obj, family['name']) if family_obj: family_obj.panels = family['panels'] else: family_obj = self.status.add_family( name=family['name'], panels=family['panels'], priority=family['priority'], ) family_obj.customer = customer_obj new_families.append(family_obj) family_samples = {} for sample in family['samples']: sample_obj = self.status.sample(sample['internal_id']) if sample_obj: sample_obj.name = sample['name'] sample_obj.sex = sample['sex'] sample_obj.comment = sample['comment'] family_samples[sample_obj.name] = sample_obj else: new_sample = self.status.add_sample( name=sample['name'], internal_id=sample['internal_id'], sex=sample['sex'], order=order, ordered=ordered, ticket=ticket, priority=family['priority'], comment=sample['comment'], ) new_sample.customer = customer_obj with self.status.session.no_autoflush: application_tag = sample['application'] new_sample.application_version = self.status.latest_version( application_tag) if new_sample.application_version is None: raise OrderError( f"unknown application tag: {sample['application']}" ) family_samples[new_sample.name] = new_sample self.status.add(new_sample) new_delivery = self.status.add_delivery( destination='caesar', sample=new_sample) self.status.add(new_delivery) for sample in family['samples']: mother_obj = family_samples[sample['mother']] if sample.get( 'mother') else None father_obj = family_samples[sample['father']] if sample.get( 'father') else None with self.status.session.no_autoflush: link_obj = self.status.link(family_obj.internal_id, sample['internal_id']) if link_obj: link_obj.status = sample['status'] or link_obj.status link_obj.mother = mother_obj or link_obj.mother link_obj.father = father_obj or link_obj.father else: new_link = self.status.relate_sample( family=family_obj, sample=family_samples[sample['name']], status=sample['status'], mother=mother_obj, father=father_obj, ) self.status.add(new_link) self.status.add_commit(new_families) return new_families
def pools_to_status(data: dict) -> dict: """Convert input to pools.""" status_data = {"customer": data["customer"], "order": data["name"], "pools": []} # group pools pools = {} for sample in data["samples"]: name = sample["pool"] application = sample["application"] data_analysis = sample["data_analysis"] capture_kit = sample.get("capture_kit") if name not in pools: pools[name] = {} pools[name]["name"] = name pools[name]["applications"] = set() pools[name]["capture_kits"] = set() pools[name]["applications"].add(application) if capture_kit: pools[name]["capture_kits"].add(capture_kit) # each pool must only have one application type for pool in pools.values(): applications = pool["applications"] pool_name = pool["name"] if len(applications) != 1: raise OrderError(f"different application in pool: {pool_name} - {applications}") # each pool must only have one capture kit for pool in pools.values(): capture_kits = pool["capture_kits"] pool_name = pool["name"] if len(capture_kits) > 1: raise OrderError(f"different capture kits in pool: {pool_name} - {capture_kits}") for pool in pools.values(): pool_name = pool["name"] applications = pool["applications"] application = applications.pop() capture_kits = pool["capture_kits"] capture_kit = None if len(capture_kits) == 1: capture_kit = capture_kits.pop() status_data["pools"].append( { "name": pool_name, "application": application, "data_analysis": data_analysis, "capture_kit": capture_kit, } ) return status_data