def migrate_interpretation_request_cancer_to_interpreted_genome_v6(
            json_dict, assembly, interpretation_service, reference_database_versions, software_versions,
            report_url, comments):
        """
        :type json_dict: dict
        :type assembly: Assembly
        :type interpretation_service: str
        :type reference_database_versions: dict
        :type software_versions: dict
        :type report_url: str
        :type comments: list
        :rtype: CancerInterpretationRequest_6_0_0
        """
        if CancerInterpretationRequest_5_0_0.validate(CancerInterpretationRequest_5_0_0.fromJsonDict(json_dict)):
            raise MigrationError(
                "Cannot transform a cancer interpretation request in version 5.0.0 into an interpreted genome")
        if CancerInterpretationRequest_6_0_0.validate(CancerInterpretationRequest_6_0_0.fromJsonDict(json_dict)):
            raise MigrationError(
                "Cannot transform a cancer interpretation request in version 6.0.0 into an interpreted genome")

        types = [
            InterpretedGenome_6_0_0,
            CancerInterpretedGenome_5_0_0,
            CancerInterpretationRequest_4_0_0
        ]
        migrations = [
            lambda x: x,
            MigrateReports500To600().migrate_cancer_interpreted_genome,
            lambda x: MigrateReports400To500().migrate_cancer_interpretation_request_to_cancer_interpreted_genome(
                old_instance=x, assembly=assembly, interpretation_service=interpretation_service,
                reference_database_versions=reference_database_versions, software_versions=software_versions,
                report_url=report_url, comments=comments)
        ]

        return MigrationHelpers.migrate(json_dict, types, migrations)
Esempio n. 2
0
    def migrate_cancer_interpretation_request_to_cancer_interpreted_genome(
            self,
            old_instance,
            assembly,
            interpretation_service,
            reference_database_versions,
            software_versions,
            report_url=None,
            comments=None):
        """
        NOTE: we migrate from a model where only one sample and one participant is supported, thus we do not need
        a list of samples or participants
        :type old_instance: reports_4_0_0.CancerInterpretationRequest
        :type assembly: reports_5_0_0.Assembly
        :type interpretation_service: str
        :type reference_database_versions: dict
        :type software_versions: dict
        :type report_url: str
        :type comments: list
        :rtype: reports_5_0_0.CancerInterpretedGenome
        """
        new_instance = self.convert_class(
            self.new_model.CancerInterpretedGenome,
            old_instance)  # :type: reports_5_0_0.CancerInterpretedGenome

        new_instance.interpretationRequestId = old_instance.reportRequestId
        new_instance.interpretationRequestVersion = old_instance.reportVersion
        new_instance.interpretationService = interpretation_service
        new_instance.referenceDatabasesVersions = reference_database_versions
        if not isinstance(software_versions, dict):
            software_versions = {}
        software_versions['tiering'] = old_instance.tieringVersion
        new_instance.softwareVersions = software_versions
        new_instance.reportUrl = report_url
        new_instance.comments = comments
        participant_id = old_instance.cancerParticipant.individualId
        tumor_samples = old_instance.cancerParticipant.tumourSamples
        if not tumor_samples:
            raise MigrationError(
                "There is no tumour sample to perform the migration")
        elif len(tumor_samples) > 1:
            raise MigrationError(
                "There are several tumour samples, cannot decide which to use '{}'"
                .format(str(tumor_samples)))
        sample_id = tumor_samples[0].sampleId
        new_instance.variants = self.convert_collection(
            old_instance.tieredVariants,
            self._migrate_reported_variant_cancer,
            assembly=assembly,
            participant_id=participant_id,
            sample_id=sample_id)

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.CancerInterpretedGenome)
    def migrate_cancer_exit_questionnaire(self, old_instance, assembly):
        """
        :type old_instance: reports_5_0_0.CancerExitQuestionnaire
        :type assembly: reports_5_0_0.Assembly
        :rtype: reports_6_0_0.CancerExitQuestionnaire
        """
        if assembly is None:
            raise MigrationError(
                "Parameter <assembly> is required to migrate cancer exit questionnaire to version 6"
            )

        new_c_eq = self.convert_class(
            target_klass=self.new_model.CancerExitQuestionnaire,
            instance=old_instance)
        new_c_eq.somaticVariantLevelQuestions = self.convert_collection(
            old_instance.somaticVariantLevelQuestions,
            self._migrate_somatic_variant_level_question,
            assembly=assembly)
        new_c_eq.germlineVariantLevelQuestions = self.convert_collection(
            old_instance.germlineVariantLevelQuestions,
            self._migrate_germline_variant_level_question,
            assembly=assembly)
        new_c_eq.otherActionableVariants = self.convert_collection(
            old_instance.otherActionableVariants,
            self._migrate_other_actionable_variant,
            assembly=assembly)
        return self.validate_object(
            object_to_validate=new_c_eq,
            object_type=self.new_model.CancerExitQuestionnaire)
    def migrate_interpreted_genome_rd(self, old_instance, assembly,
                                      interpretation_request_version):
        """
        :type old_instance: reports_4_0_0.InterpretedGenomeRD
        :type assembly: reports_5_0_0.Assembly
        :type interpretation_request_version: int
        :rtype: reports_5_0_0.InterpretedGenomeRD
        """
        if assembly is None or interpretation_request_version is None:
            raise MigrationError(
                "Parameters <assembly> and <interpretation_request_version> are required for models earlier than 5.0.0"
            )
        new_instance = self.convert_class(
            self.new_model.InterpretedGenomeRD,
            old_instance)  # type:self.new_model.InterpretedGenomeRD
        new_instance.interpretationRequestVersion = interpretation_request_version
        new_instance.interpretationService = old_instance.companyName
        new_instance.variants = self.convert_collection(
            old_instance.reportedVariants,
            self._migrate_reported_variant,
            assembly=assembly)

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.InterpretedGenomeRD)
    def migrate_action(self, old_instance):
        """
        NOTE: fields that cannot be filled are "actionType"
        :type old_instance: reports_4_0_0.Actions
        :rtype reports_5_0_0.Action
        :return:
        """
        new_instance = self.convert_class(self.new_model.Action, old_instance)

        new_instance.evidenceType = old_instance.actionType
        new_instance.actionType = None

        # rename evidence to references
        new_instance.references = old_instance.evidence

        # maps the action status
        if old_instance.status is not None:
            status = old_instance.status.lower().replace('-', '_')
            if status == reports_5_0_0.ActionStatus.clinical:
                new_instance.status = reports_5_0_0.ActionStatus.clinical
            elif status == reports_5_0_0.ActionStatus.pre_clinical:
                new_instance.status = reports_5_0_0.ActionStatus.pre_clinical
            elif status is not None and status != "":
                raise MigrationError("Action status does not match any known value '{}'".format(status))

        return self.validate_object(
            object_to_validate=new_instance, object_type=self.new_model.Action
        )
    def _migrate_reported_variant_cancer(self, old_instance, assembly,
                                         participant_id, sample_ids):
        ne_instance = old_instance.reportedVariantCancer
        new_instance = self.convert_class(
            self.new_model.ReportedVariantCancer,
            ne_instance)  # :type: reports_5_0_0.ReportedVariant
        new_instance.variantCoordinates = self.convert_class(
            reports_5_0_0.VariantCoordinates, ne_instance)
        new_instance.variantCoordinates.assembly = self._migrate_assembly(
            assembly)
        if old_instance.reportedVariantCancer.cDnaChange:
            new_instance.cdnaChanges = [
                old_instance.reportedVariantCancer.cDnaChange
            ]
        if ne_instance.proteinChange:
            new_instance.proteinChanges = [ne_instance.proteinChange]

        # NOTE: missing fields: genomicChanges
        sample_id = sample_ids.get(old_instance.alleleOrigins[0], None)
        if not sample_id:
            raise MigrationError('Couldn\'t retrieve Sample ID for {}'.format(
                old_instance.alleleOrigins[0]))

        # builds up the VariantCall object
        # NOTE: fields that cannot be filled "phaseSet"
        new_instance.variantCalls = [
            reports_5_0_0.VariantCall(
                depthReference=ne_instance.depthReference,
                depthAlternate=ne_instance.depthAlternate,
                vaf=ne_instance.vaf,
                zygosity=reports_5_0_0.Zygosity.na,
                alleleOrigins=old_instance.alleleOrigins,
                participantId=participant_id,
                sampleId=sample_id)
        ]
        if ne_instance.commonAf is not None:
            new_instance.alleleFrequencies = [
                reports_5_0_0.AlleleFrequency(
                    study='genomics_england',
                    population='ALL',
                    alternateFrequency=self.convert_string_to_float(
                        ne_instance.commonAf) / 100)
            ]
        # NOTE: some fields cannot be filled: "fdp50", "recurrentlyReported", "others"
        new_instance.variantAttributes = reports_5_0_0.VariantAttributes(
            ihp=ne_instance.ihp)
        new_instance.alleleOrigins = old_instance.alleleOrigins
        new_instance.reportEvents = self.convert_collection(
            list(zip(ne_instance.reportEvents, new_instance.reportEvents)),
            self._migrate_report_event_cancer)
        return new_instance
 def _migrate_assembly(self, assembly):
     new_assembly = None
     if assembly is not None:
         if assembly.lower().startswith(reports_5_0_0.Assembly.GRCh37.lower()) \
                 or assembly.lower().startswith('hg19'):
             new_assembly = reports_5_0_0.Assembly.GRCh37
         elif assembly.lower().startswith(
                 reports_5_0_0.Assembly.GRCh38.lower()):
             new_assembly = reports_5_0_0.Assembly.GRCh38
         else:
             raise MigrationError(
                 "Assembly does not match any known value '{}'".format(
                     assembly))
     return new_assembly
 def _extract_variant_details(variant_details):
     """
     The format of variant_details is "chr:pos:ref:alt"
     """
     details = list(
         map(lambda x: x.strip(),
             re.compile(":|>").split(variant_details)))
     if len(details) != 4:
         raise MigrationError(
             "Variant details: {variant_details} should have fields chr, pos, ref and alt"
             .format(variant_details=variant_details))
     try:
         details[1] = int(details[1])
     except ValueError:
         raise MigrationError(
             "Position {position} is not an integer !".format(
                 position=details[1]))
     return {
         "chromosome": details[0],
         "position": details[1],
         "reference": details[2],
         "alternate": details[3],
     }
    def migrate_interpretation_request_rd(self, old_instance, old_ig):
        """
        Migrates a reports_5_0_0.InterpretationRequestRD into a reports_4_0_0.InterpretationRequestRD
        :type old_instance: reports_5_0_0.InterpretationRequestRD
        :type old_ig: reports_5_0_0.InterpretedGenomeRD
        :rtype: reports_4_0_0.InterpretationRequestRD
        """
        new_instance = self.convert_class(
            self.new_model.InterpretationRequestRD, old_instance)
        new_instance.versionControl = self.new_model.ReportVersionControl()
        new_instance.genomeAssemblyVersion = old_instance.genomeAssembly
        # ensure null lists of files are not passing through
        if new_instance.bams is None:
            new_instance.bams = []
        if new_instance.vcfs is None:
            new_instance.vcfs = []
        # grabs the list of variants from the interpreted genome
        new_instance.tieredVariants = self.convert_collection(
            old_ig.variants, self._migrate_reported_variant)
        new_instance.tieringVersion = old_ig.softwareVersions.get(
            "tiering", "")
        new_instance.analysisVersion = ''
        new_instance.analysisReturnUri = ''
        if old_instance.additionalInfo:
            new_instance.analysisVersion = old_instance.additionalInfo.get(
                'analysisVersion') or ''
            new_instance.analysisReturnUri = old_instance.additionalInfo.get(
                'analysisReturnUri', '')
            new_instance.tieringVersion = old_instance.additionalInfo.get(
                'tieringVersion', '')
            new_instance.complexGeneticPhenomena = old_instance.additionalInfo.get(
                'complexGeneticPhenomena')
            new_instance.cellbaseVersion = old_instance.additionalInfo.get(
                'cellbaseVersion', '')
            new_instance.interpretGenome = bool(
                distutils.util.strtobool(
                    old_instance.additionalInfo.get('interpretGenome',
                                                    'false')))

        if not old_instance.pedigree:
            raise MigrationError(
                "Cannot reverse migrate an Interpretation Request for RD with null pedigree"
            )
        new_instance.pedigree = MigrateParticipant110To100().migrate_pedigree(
            old_instance.pedigree)

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.InterpretationRequestRD)
 def _migrate_action(self, actions):
     old_instance = actions[0]
     new_instance = actions[1]
     new_instance.evidenceType = old_instance.actionType
     new_instance.actionType = None
     new_instance.references = old_instance.evidence
     if old_instance.status is not None:
         status = old_instance.status.lower().replace('-', '_')
         if status == reports_5_0_0.ActionStatus.clinical:
             new_instance.status = reports_5_0_0.ActionStatus.clinical
         elif status == reports_5_0_0.ActionStatus.pre_clinical:
             new_instance.status = reports_5_0_0.ActionStatus.pre_clinical
         elif status is not None and status != "":
             raise MigrationError(
                 "Action status does not match any known value '{}'".format(
                     status))
     return new_instance
    def migrate_tumour_sample(self, old_sample, ldp_code):
        ts = self.new_model.TumourSample
        tt = self.new_model.TumourType
        new_sample = self.convert_class(ts, old_sample)  # :type: reports_5_0_0.TumourSample

        tumour_type_enum = [
            tt.PRIMARY, tt.METASTATIC_RECURRENCE, tt.RECURRENCE_OF_PRIMARY_TUMOUR, tt.METASTASES
        ]
        new_sample.tumourType = old_sample.tumourType if old_sample.tumourType in tumour_type_enum else None
        new_sample.tumourId = self.convert_int_to_str(value=old_sample.tumourId)
        if ldp_code is None:
            raise MigrationError("Cannot migrate '{}' to '{}' having an empty value of 'ldp_code'".format(
                type(old_sample), type(new_sample))
            )
        new_sample.LDPCode = ldp_code

        return self.validate_object(object_to_validate=new_sample, object_type=ts)
 def migrate_rd_exit_questionnaire(self, old_instance, assembly):
     """
     :type old_instance: reports_5_0_0.RareDiseaseExitQuestionnaire
     :type assembly: reports_5_0_0.Assembly
     :rtype: reports_6_0_0.RareDiseaseExitQuestionnaire
     """
     if assembly is None:
         raise MigrationError(
             "Parameter <assembly> is required to migrate exit questionnaire to version 6"
         )
     migrated_instance = self.convert_class(
         self.new_model.RareDiseaseExitQuestionnaire, old_instance)
     migrated_instance.variantGroupLevelQuestions = self.convert_collection(
         old_instance.variantGroupLevelQuestions,
         self._migrate_variant_group_level_question,
         assembly=assembly)
     return self.validate_object(
         object_to_validate=migrated_instance,
         object_type=self.new_model.RareDiseaseExitQuestionnaire)
    def migrate_clinical_report_rd(self, old_instance, assembly):
        """
        :type old_instance: reports_4_0_0.ClinicalReportRD
        :type assembly: reports_5_0_0.Assembly
        :rtype: reports_5_0_0.ClinicalReportRD
        """
        if assembly is None:
            raise MigrationError(
                "Parameter <assembly> is required to migrate model versions earlier than 5.0.0"
            )

        new_instance = self.convert_class(
            self.new_model.ClinicalReportRD,
            old_instance)  # :type self.new_model.ClinicalReportRD

        try:
            new_instance.interpretationRequestVersion = self.convert_string_to_integer(
                old_instance.interpretationRequestVersion)
        except MigrationError as ex:
            logging.error(
                "Error converting 'interpretationRequestVersion' to integer from value '{}'"
                .format(old_instance.interpretationRequestVersion))
            raise ex
        new_instance.references = old_instance.supportingEvidence
        new_instance.variants = self.convert_collection(
            old_instance.candidateVariants,
            self._migrate_reported_variant,
            assembly=assembly)
        if old_instance.additionalAnalysisPanels is not None:
            panels = []
            for panel in old_instance.additionalAnalysisPanels:
                new_panel = self.new_model.AdditionalAnalysisPanel(
                )  # :type reports_5_0_0.AdditionalAnalysisPanel
                new_panel.specificDisease = panel.specificDisease
                new_panel.panel = self.new_model.GenePanel(
                    panelName=panel.panelName, panelVersion=panel.panelVersion)
                panels.append(new_panel)
            new_instance.additionalAnalysisPanels = panels

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.ClinicalReportRD)
 def _merge_annotations_and_frequencies(numeric_annotations,
                                        allele_frequencies):
     if numeric_annotations is None:
         numeric_annotations = {}
     if not isinstance(numeric_annotations, dict):
         raise MigrationError(
             "additionalNumericVariantAnnotations should be dict but is: {}"
             .format(numeric_annotations))
     if allele_frequencies is not None:
         for af in allele_frequencies:
             annotation_key = "{}:{}".format(af.study, af.population)
             if annotation_key in numeric_annotations:
                 logging.warning(
                     "{} already exists in numeric_annotations with value {} instead of {}"
                     .format(annotation_key,
                             numeric_annotations.get(annotation_key),
                             af.alternateFrequency))
             else:
                 numeric_annotations["{}:{}".format(
                     af.study, af.population)] = af.alternateFrequency
     return numeric_annotations
    def migrate_interpretation_request_rd(self, old_instance, assembly):
        """
        Migrates an InterpretationRequestRD into an InterpretedGenomeRD, several unexisting fields need to be provided
        :type old_instance: reports_4_0_0.InterpretationRequestRD
        :rtype: reports_5_0_0.InterpretationRequestRD
        """
        if assembly is None:
            raise MigrationError(
                "Parameter <assembly> is required if version is older than 5.0.0"
            )
        new_instance = self.convert_class(
            self.new_model.InterpretationRequestRD,
            old_instance)  # type: reports_5_0_0.InterpretationRequestRD
        new_instance.genomeAssembly = assembly
        new_instance.pedigree = self._migrate_pedigree(old_instance.pedigree)
        # NOTE: store fields in additional fields that are lost otherwise
        if not new_instance.additionalInfo:
            new_instance.additionalInfo = {}
        if old_instance.analysisVersion:
            new_instance.additionalInfo[
                'analysisVersion'] = old_instance.analysisVersion
        if old_instance.analysisReturnUri:
            new_instance.additionalInfo[
                'analysisReturnUri'] = old_instance.analysisReturnUri
        if old_instance.tieringVersion:
            new_instance.additionalInfo[
                'tieringVersion'] = old_instance.tieringVersion
        if old_instance.complexGeneticPhenomena:
            new_instance.additionalInfo['complexGeneticPhenomena'] = str(
                old_instance.complexGeneticPhenomena)
        if old_instance.cellbaseVersion:
            new_instance.additionalInfo[
                'cellbaseVersion'] = old_instance.cellbaseVersion
        if old_instance.interpretGenome:
            new_instance.additionalInfo['interpretGenome'] = str(
                old_instance.interpretGenome)

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.InterpretationRequestRD)
 def migrate(json_dict, types, migrations):
     valid_types = MigrationHelpers.is_valid(json_dict, types)
     if len(valid_types) == 0:
         raise MigrationError("JSON dict not valid according to any model")
     elif len(valid_types) == 1:
         typ = valid_types[0]
     elif len(valid_types) > 1:
         observed_version = MigrationHelpers.get_version_control(json_dict)
         typ = None
         for t in valid_types:
             expected_version = MigrationHelpers.get_version_control(t().toJsonDict())
             if expected_version == observed_version:
                 # chooses the type having the correct expected version
                 typ = t
                 break
         if typ is None:
             # if none matched chooses the most conservative one
             typ = valid_types[-1]
     migrations_to_apply = migrations[0:types.index(typ) + 1]
     migrated = typ.fromJsonDict(json_dict)
     for migration in reversed(migrations_to_apply):
         migrated = migration(migrated)
     return migrated
    def migrate_cancer_clinical_report(self, old_instance, assembly,
                                       participant_id, sample_ids):
        """
        NOTE: we migrate from a model where only one sample and one participant is supported, thus we do not need
        a list of samples or participants
        :type old_instance: reports_4_0_0.ClinicalReportCancer
        :type assembly: reports_5_0_0.Assembly
        :type participant_id: str
        :type sample_ids: map[str (alleleOrigin)]: str - {'germline_variant': 'LP...', 'somatic_variant': 'LP...'}
        :rtype: reports_5_0_0.ClinicalReportCancer
        """
        if not sample_ids or not assembly or not participant_id:
            raise MigrationError(
                "Missing required fields to migrate cancer clinical report from 4.0.0 to 5.0.0"
            )

        new_instance = self.convert_class(
            self.new_model.ClinicalReportCancer,
            old_instance)  # :type: reports_5_0_0.ClinicalReportCancer
        try:
            new_instance.interpretationRequestVersion = self.convert_string_to_integer(
                old_instance.interpretationRequestVersion)
        except MigrationError as ex:
            logging.error(
                "Error converting 'interpretationRequestVersion' to integer from value '{}'"
                .format(old_instance.interpretationRequestVersion))
            raise ex
        new_instance.variants = self.convert_collection(
            old_instance.candidateVariants,
            self._migrate_reported_variant_cancer,
            assembly=assembly,
            participant_id=participant_id,
            sample_ids=sample_ids)

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.ClinicalReportCancer)
    def migrate_cancer_interpretation_request(self, old_instance, assembly):
        """
        :type old_instance: reports_4_0_0.CancerInterpretationRequest
        :rtype: reports_5_0_0.CancerInterpretationRequest
        """
        if assembly is None:
            raise MigrationError(
                "Parameter <assembly> is required to migrate cancer interpretation request to version 5"
            )

        new_instance = self.convert_class(
            self.new_model.CancerInterpretationRequest,
            old_instance)  # :type: reports_5_0_0.CancerInterpretationRequest

        new_instance.interpretationRequestId = old_instance.reportRequestId
        new_instance.interpretationRequestVersion = old_instance.reportVersion
        new_instance.genomeAssembly = assembly
        new_instance.cancerParticipant = self._migrate_cancer_participant(
            old_participant=old_instance.cancerParticipant)
        if not new_instance.additionalInfo:
            new_instance.additionalInfo = {}
        if old_instance.analysisUri:
            new_instance.additionalInfo[
                'analysisUri'] = old_instance.analysisUri
        if old_instance.analysisVersion:
            new_instance.additionalInfo[
                'analysisVersion'] = old_instance.analysisVersion
        if old_instance.tieringVersion:
            new_instance.additionalInfo[
                'tieringVersion'] = old_instance.tieringVersion
        if old_instance.interpretGenome:
            new_instance.additionalInfo['interpretGenome'] = str(
                old_instance.interpretGenome)

        return self.validate_object(
            object_to_validate=new_instance,
            object_type=self.new_model.CancerInterpretationRequest)
 def _raise_migration_error_for_parameter(parameter):
     raise MigrationError(
         "Missing required field {parameter} to migrate a cancer interpreted genome from 4.0.0 to 5.0.0"
         .format(parameter=parameter))