def test_create_identifier_rules_pipeline(self, variant_type,
                                           exp_pipeline):
     if isinstance(exp_pipeline, KeyError):
         with self.assertRaises(KeyError) as cm:
             TreatmentArmsAccessor._create_identifier_rules_pipeline(
                 variant_type)
         self.assertEqual(str(cm.exception), str(exp_pipeline))
     else:
         pipeline = TreatmentArmsAccessor._create_identifier_rules_pipeline(
             variant_type)
         self.assertEqual(pipeline, exp_pipeline)
Beispiel #2
0
    def get(self):
        """
        Gets the TreatmentArms overview data.
        """
        self.logger.debug("Getting TreatmentArms Overview Data")
        treatment_arms_accessor = TreatmentArmsAccessor()
        counts_by_status = treatment_arms_accessor.aggregate(self.STEPS)

        counts = dict([(cd['_id'], cd['count']) for cd in counts_by_status])
        counts['TOTAL'] = treatment_arms_accessor.count({"dateArchived": None})
        return counts
 def __init__(self):
     self.logger = logging.getLogger(__name__)
     self.pat_accessor = PatientAccessor(
     )  # provides access to the Patient API
     self.ta_accessor = TreatmentArmsAccessor(
     )  # provides access to the TreatmentArms collection in MongoDB
     self.summary_rpts = [
         SummaryReport(ta_data) for ta_data in
         self.ta_accessor.get_arms_for_summary_report_refresh()
     ]
     self.token = create_authentication_token()
    def test_get_ta_non_hotspot_rules(self, mock_documents):
        self.mock_collection.aggregate.return_value = mock_documents

        exp_result = [
            TreatmentArmsAccessor.mongo_to_python(doc)
            for doc in mock_documents
        ]

        result = TreatmentArmsAccessor().get_ta_non_hotspot_rules()
        self.assertEqual(result, exp_result)
        self.mock_collection.aggregate.assert_called_once_with(
            TreatmentArmsAccessor.NON_HOTSPOT_RULES_PIPELINE)
Beispiel #5
0
 def get(self):
     """
     Gets the TreatmentArms with PTEN Assay.
     """
     self.logger.debug("Getting TreatmentArms with PTEN assay results")
     arms = TreatmentArmsAccessor().find(self.QUERY, self.PROJECTION)
     return [arm for arm in arms if 'OUTSIDE_ASSAY' in arm['studyTypes']]
    def __init__(self,
                 non_hotspot_rules=None,
                 cnv_identifier_rules=None,
                 snv_identifier_rules=None,
                 gene_fusion_identifier_rules=None,
                 indel_identifier_rules=None):
        ta_accessor = TreatmentArmsAccessor()
        self.nhs_rules = non_hotspot_rules if non_hotspot_rules is not None \
            else ta_accessor.get_ta_non_hotspot_rules()
        self.cnv_identifier_rules = cnv_identifier_rules if cnv_identifier_rules is not None \
            else ta_accessor.get_ta_identifier_rules('copyNumberVariants')
        self.snv_identifier_rules = snv_identifier_rules if snv_identifier_rules is not None \
            else ta_accessor.get_ta_identifier_rules('singleNucleotideVariants')
        self.gf_identifier_rules = gene_fusion_identifier_rules if gene_fusion_identifier_rules is not None \
            else ta_accessor.get_ta_identifier_rules('geneFusions')
        self.indel_identifier_rules = indel_identifier_rules if indel_identifier_rules is not None \
            else ta_accessor.get_ta_identifier_rules('indels')

        self.cnv_protein_rules = self._extract_protein_rules(
            self.cnv_identifier_rules)
        self.snv_protein_rules = self._extract_protein_rules(
            self.snv_identifier_rules)
        self.gf_protein_rules = self._extract_protein_rules(
            self.gf_identifier_rules)
        self.indel_protein_rules = self._extract_protein_rules(
            self.indel_identifier_rules)
    def test_get_arms_for_summary_report_refresh(self):
        """
        A trivial test:  Only tests that the collection's find function is called with the correct parameters and
        that its return value is what is returned from TreatmentArmsAccessor.get_arms_for_summary_report_refresh.
        """
        mock_documents = [{'doc_num': 4}, {'doc_num': 6}]
        self.mock_collection.find.return_value = mock_documents

        exp_result = [
            TreatmentArmsAccessor.mongo_to_python(doc)
            for doc in mock_documents
        ]

        result = TreatmentArmsAccessor().get_arms_for_summary_report_refresh()
        self.assertEqual(result, exp_result)
        self.mock_collection.find.assert_called_once_with(
            TreatmentArmsAccessor.SUMMARY_REPORT_REFRESH_QUERY,
            TreatmentArmsAccessor.SUMMARY_REPORT_REFRESH_PROJECTION)
Beispiel #8
0
    def get(self):
        """
        Gets the TreatmentArms data.
        """
        self.logger.debug("Getting TreatmentArms")
        args = get_args()
        query = get_query(args)
        projection = get_projection(args)

        treatment_arms = TreatmentArmsAccessor().find(query, projection)
        for ta in treatment_arms:
            reformat_status_log(ta)
        return treatment_arms
    def get(self):
        self.logger.debug('Retrieving TreatmentArms Healthcheck')
        try:
            accessor = TreatmentArmsAccessor()
            self.logger.debug('Connection established.')

            return_info = dict()
            return_info['Total Arm Count'] = accessor.count({})
            return_info['Active Arm Count'] = accessor.count(
                {'dateArchived': None})
            for status in accessor.aggregate(self.status_pipeline):
                return_info['Active Arms in %s Status' %
                            status["_id"]] = status["count"]

            self.logger.debug('Healthcheck returning info: {}'.format(
                str(return_info)))
            return return_info

        except Exception as ex:
            message = str(ex)
            self.logger.exception(message)
            return message, 500
    def test_update_summary_report(self, ta_id, mocked_match_count,
                                   exp_result):
        mocked_update_result = Mock()
        mocked_update_result.matched_count = mocked_match_count
        self.mock_collection.update_one.return_value = mocked_update_result

        summary_report_json = {"sum1": 23, "sum2": 7}

        result = TreatmentArmsAccessor().update_summary_report(
            ta_id, summary_report_json)
        self.assertEqual(result, exp_result)
        self.mock_collection.update_one.assert_called_once_with(
            {'_id': ObjectId(ta_id['$oid'])},
            {'$set': {
                'summaryReport': summary_report_json
            }})
    def test_init(self):
        """
        Simply verify the constructor does what it is supposed to do.
        """

        treatment_arms_accessor = TreatmentArmsAccessor()

        self.assertEqual(treatment_arms_accessor.collection_name, COLL_NAME)
        self.assertEqual(treatment_arms_accessor.db_name, DB)
        self.assertEqual(treatment_arms_accessor.mongo_client,
                         self.mock_mongo_client.return_value)
        self.assertEqual(treatment_arms_accessor.database,
                         self.mock_mongo_client.return_value[DB])
        self.assertEqual(treatment_arms_accessor.collection,
                         self.mock_collection)
        self.assertEqual(treatment_arms_accessor.logger, self.mock_logger)
        self.mock_mongo_client.assert_called_once_with(URI)
Beispiel #12
0
    def get(self, arm_id):
        """
        Gets the TreatmentArms data for the arm_id specified.
        """
        self.logger.debug(
            "Getting TreatmentArms by ID: {ARMID}".format(ARMID=arm_id))
        args = get_args()
        query = {"treatmentArmId": arm_id}
        query.update(get_query(args))
        projection = get_projection(args)

        treatment_arms = TreatmentArmsAccessor().find(query, projection)
        for ta in treatment_arms:
            reformat_status_log(ta)
        return sorted(treatment_arms,
                      key=lambda ta: ta[self.SORT_KEY],
                      reverse=True)
    def test_get_ta_identifier_rules(self, variant_type, exp_pipeline):
        treatment_arms_accessor = TreatmentArmsAccessor()

        if isinstance(exp_pipeline, Exception):
            with self.assertRaises(Exception) as cm:
                treatment_arms_accessor.get_ta_identifier_rules(variant_type)
            self.assertEqual(str(cm.exception), str(exp_pipeline))
        else:
            mock_documents = [{'doc_num': 1}, {'doc_num': 2}]
            self.mock_collection.aggregate.return_value = mock_documents

            exp_result = [
                TreatmentArmsAccessor.mongo_to_python(doc)
                for doc in mock_documents
            ]

            result = treatment_arms_accessor.get_ta_identifier_rules(
                variant_type)
            self.assertEqual(result, exp_result)
            self.mock_collection.aggregate.assert_called_once_with(
                exp_pipeline)
class TreatmentArmAccessorTests(unittest.TestCase):
    # Constants used in the test of the TreatmentArmsAccessor.get_ta_identifier_rules method:
    SNV_IDENTIFIER_RULES_PIPELINE = TreatmentArmsAccessor._create_identifier_rules_pipeline(
        'singleNucleotideVariants')
    CNV_IDENTIFIER_RULES_PIPELINE = TreatmentArmsAccessor._create_identifier_rules_pipeline(
        'copyNumberVariants')
    GENE_FUSION_IDENTIFIER_RULES_PIPELINE = TreatmentArmsAccessor._create_identifier_rules_pipeline(
        'geneFusions')
    INDEL_IDENTIFIER_RULES_PIPELINE = TreatmentArmsAccessor._create_identifier_rules_pipeline(
        'indels')

    def setUp(self):
        mongo_db_patcher = patch('accessors.mongo_db_accessor.MongoClient')
        self.addCleanup(mongo_db_patcher.stop)
        self.mock_mongo_client = mongo_db_patcher.start()
        self.mock_collection = self.mock_mongo_client.return_value[DB][
            COLL_NAME]

        logging_patcher = patch('accessors.treatment_arm_accessor.logging')
        self.addCleanup(logging_patcher.stop)
        self.mock_logger = logging_patcher.start().getLogger()

        env_patcher = patch('accessors.mongo_db_accessor.Environment')
        self.addCleanup(env_patcher.stop)
        self.mock_env = env_patcher.start().return_value
        self.mock_env.mongodb_uri = URI
        self.mock_env.db_name = DB

    # Test the TreatmentArmsAccessor constructor
    def test_init(self):
        """
        Simply verify the constructor does what it is supposed to do.
        """

        treatment_arms_accessor = TreatmentArmsAccessor()

        self.assertEqual(treatment_arms_accessor.collection_name, COLL_NAME)
        self.assertEqual(treatment_arms_accessor.db_name, DB)
        self.assertEqual(treatment_arms_accessor.mongo_client,
                         self.mock_mongo_client.return_value)
        self.assertEqual(treatment_arms_accessor.database,
                         self.mock_mongo_client.return_value[DB])
        self.assertEqual(treatment_arms_accessor.collection,
                         self.mock_collection)
        self.assertEqual(treatment_arms_accessor.logger, self.mock_logger)
        self.mock_mongo_client.assert_called_once_with(URI)

    # Test the TreatmentArmsAccessor.get_ta_non_hotspot_rules method
    @data(
        ([], ),
        ([{
            'currentPatientStatus': 'ON_ARM'
        }, {
            'currentPatientStatus': 'ON_ARM'
        }], ),
    )
    @unpack
    def test_get_ta_non_hotspot_rules(self, mock_documents):
        self.mock_collection.aggregate.return_value = mock_documents

        exp_result = [
            TreatmentArmsAccessor.mongo_to_python(doc)
            for doc in mock_documents
        ]

        result = TreatmentArmsAccessor().get_ta_non_hotspot_rules()
        self.assertEqual(result, exp_result)
        self.mock_collection.aggregate.assert_called_once_with(
            TreatmentArmsAccessor.NON_HOTSPOT_RULES_PIPELINE)

    # Test the TreatmentArmsAccessor.get_ta_identifier_rules method
    @data(
        ('singleNucleotideVariants', SNV_IDENTIFIER_RULES_PIPELINE),
        ('copyNumberVariants', CNV_IDENTIFIER_RULES_PIPELINE),
        ('geneFusions', GENE_FUSION_IDENTIFIER_RULES_PIPELINE),
        ('indels', INDEL_IDENTIFIER_RULES_PIPELINE),
        ('INVALID_VAR_TYPE',
         Exception(
             "Unknown variant_type 'INVALID_VAR_TYPE' passed to TreatmentArmsAccessor"
         )),
    )
    @unpack
    def test_get_ta_identifier_rules(self, variant_type, exp_pipeline):
        treatment_arms_accessor = TreatmentArmsAccessor()

        if isinstance(exp_pipeline, Exception):
            with self.assertRaises(Exception) as cm:
                treatment_arms_accessor.get_ta_identifier_rules(variant_type)
            self.assertEqual(str(cm.exception), str(exp_pipeline))
        else:
            mock_documents = [{'doc_num': 1}, {'doc_num': 2}]
            self.mock_collection.aggregate.return_value = mock_documents

            exp_result = [
                TreatmentArmsAccessor.mongo_to_python(doc)
                for doc in mock_documents
            ]

            result = treatment_arms_accessor.get_ta_identifier_rules(
                variant_type)
            self.assertEqual(result, exp_result)
            self.mock_collection.aggregate.assert_called_once_with(
                exp_pipeline)

    # Test the TreatmentArmsAccessor._create_identifier_rules_pipeline method
    @data(
        ('indels', [{
            "$match": {
                "variantReport.indels": {
                    "$ne": []
                }
            }
        }, {
            "$unwind": "$variantReport.indels"
        }, {
            "$project": {
                "treatmentArmId": 1,
                "version": 1,
                "dateArchived": 1,
                "treatmentArmStatus": 1,
                "identifier": "$variantReport.indels.identifier",
                "protein": "$variantReport.indels.protein",
                "inclusion": "$variantReport.indels.inclusion",
                "type": "Hotspot"
            }
        }]),
        ('INVALID_VAR_TYPE', KeyError("INVALID_VAR_TYPE")),
    )
    @unpack
    def test_create_identifier_rules_pipeline(self, variant_type,
                                              exp_pipeline):
        if isinstance(exp_pipeline, KeyError):
            with self.assertRaises(KeyError) as cm:
                TreatmentArmsAccessor._create_identifier_rules_pipeline(
                    variant_type)
            self.assertEqual(str(cm.exception), str(exp_pipeline))
        else:
            pipeline = TreatmentArmsAccessor._create_identifier_rules_pipeline(
                variant_type)
            self.assertEqual(pipeline, exp_pipeline)

    # Test the TreatmentArmsAccessor.get_arms_for_summary_report_refresh method
    def test_get_arms_for_summary_report_refresh(self):
        """
        A trivial test:  Only tests that the collection's find function is called with the correct parameters and
        that its return value is what is returned from TreatmentArmsAccessor.get_arms_for_summary_report_refresh.
        """
        mock_documents = [{'doc_num': 4}, {'doc_num': 6}]
        self.mock_collection.find.return_value = mock_documents

        exp_result = [
            TreatmentArmsAccessor.mongo_to_python(doc)
            for doc in mock_documents
        ]

        result = TreatmentArmsAccessor().get_arms_for_summary_report_refresh()
        self.assertEqual(result, exp_result)
        self.mock_collection.find.assert_called_once_with(
            TreatmentArmsAccessor.SUMMARY_REPORT_REFRESH_QUERY,
            TreatmentArmsAccessor.SUMMARY_REPORT_REFRESH_PROJECTION)

    # Test the TreatmentArmsAccessor.update_summary_report method
    @data(
        ({
            '$oid': '598386900e04839ba1fabcfa'
        }, 1, True),
        ({
            '$oid': '598386900e04839ba1fabcfa'
        }, 0, False),
    )
    @unpack
    def test_update_summary_report(self, ta_id, mocked_match_count,
                                   exp_result):
        mocked_update_result = Mock()
        mocked_update_result.matched_count = mocked_match_count
        self.mock_collection.update_one.return_value = mocked_update_result

        summary_report_json = {"sum1": 23, "sum2": 7}

        result = TreatmentArmsAccessor().update_summary_report(
            ta_id, summary_report_json)
        self.assertEqual(result, exp_result)
        self.mock_collection.update_one.assert_called_once_with(
            {'_id': ObjectId(ta_id['$oid'])},
            {'$set': {
                'summaryReport': summary_report_json
            }})
class Refresher(object):

    FORMATTED_STATUS_CONVERTER = {
        'PROGRESSION': 'FORMERLY_ON_ARM_PROGRESSED',
        'PROGRESSION_REBIOPSY': 'FORMERLY_ON_ARM_PROGRESSED',
        'OFF_TRIAL': 'FORMERLY_ON_ARM_OFF_TRIAL',
        'OFF_TRIAL_DECEASED': 'FORMERLY_ON_ARM_DECEASED',
    }

    def __init__(self):
        self.logger = logging.getLogger(__name__)
        self.pat_accessor = PatientAccessor(
        )  # provides access to the Patient API
        self.ta_accessor = TreatmentArmsAccessor(
        )  # provides access to the TreatmentArms collection in MongoDB
        self.summary_rpts = [
            SummaryReport(ta_data) for ta_data in
            self.ta_accessor.get_arms_for_summary_report_refresh()
        ]
        self.token = create_authentication_token()

    def run(self):
        sum_rpt_cnt = len(self.summary_rpts)
        self.logger.info("{cnt} summary reports selected for update".format(
            cnt=sum_rpt_cnt))

        upd_cnt = 0
        for sr in self.summary_rpts:
            if self._update_summary_report(sr):
                upd_cnt += 1
            else:
                self.logger.error(
                    "Failed to update Summary Report for {trtmtId}:{version}".
                    format(trtmtId=sr.treatmentArmId, version=sr.version))

        if upd_cnt != sum_rpt_cnt:
            self.logger.error(
                "Only {cnt}/{total} summary reports updated".format(
                    cnt=upd_cnt, total=sum_rpt_cnt))
        else:
            self.logger.info("All {cnt} summary reports were updated.".format(
                cnt=sum_rpt_cnt))

    def _update_summary_report(self, sum_rpt):
        """
        Update the given summary report with counts and assignment records.
        :param sum_rpt: The summary report of a treatment arm that requires updating.
        """
        # Get all patients associated with the Treatment Arm of the given Summary Report.
        # Patients are sorted by patientSequenceNumber (ascending) and patientAssignments.dateConfirmed (descending).
        # patients = [Patient(p) for p in self.pat_accessor.get_patients_by_treatment_arm_id(sum_rpt.treatmentArmId)]
        patients = [
            Patient(p)
            for p in self.pat_accessor.get_patients_by_treatment_arm_id(
                sum_rpt.treatmentArmId, self.token)
        ]
        self.logger.info("{cnt} patients returned for '{trtmt_id}".format(
            cnt=len(patients), trtmt_id=sum_rpt.treatmentArmId))

        # Update the summary report object for any patients that meet the criteria.
        pat_id = []
        for pat in patients:
            # Only match the patient the first time he/she is encountered.  (A patient can be assigned to an arm more
            # than once [different versions], but only the most recent occurrence should be counted.)
            if pat.patientSequenceNumber not in pat_id:
                Refresher._match(pat, sum_rpt)
                pat_id.append(pat.patientSequenceNumber)

        # Update the summary report in the treatmentArms collection on the database
        return self.ta_accessor.update_summary_report(sum_rpt._id,
                                                      sum_rpt.get_json())

    @staticmethod
    def _match(patient, sum_rpt):
        assignment_rec = Refresher._create_assignment_record(
            patient, sum_rpt.treatmentArmId)
        patient_type = Refresher._determine_patient_classification_by_dates(
            assignment_rec)

        if patient_type is not None:
            sum_rpt.add_patient_by_type(patient_type, assignment_rec)

    @staticmethod
    def _determine_patient_classification_by_dates(assignment_rec):
        """
        Determines if patient is a patient currently on the the Treatment Arm, pending for the Treatment Arm,
        formerly on the Treatment Arm, or once considered but not enrolled on the Treatment Arm.
        :param assignment_rec: an AssignmentRecord for a patient
        :return: SummaryReport.CURRENT, SummaryReport.PENDING, SummaryReport.FORMER, SummaryReport.NOT_ENROLLED, or None
        """
        match_type = None

        if assignment_rec.date_selected:
            if assignment_rec.date_on_arm:
                if assignment_rec.date_off_arm:
                    match_type = SummaryReport.FORMER
                else:
                    match_type = SummaryReport.CURRENT
            elif assignment_rec.assignment_status_outcome in PENDING_STATUSES:
                match_type = SummaryReport.PENDING
            else:
                match_type = SummaryReport.NOT_ENROLLED

        return match_type

    @staticmethod
    def _create_assignment_record(patient, ta_id):
        """
        Creates an assignment record for the given patient based on the given Treatment Arm ID.
        :param patient: the Patient object for the patient
        :param ta_id: the treatment arm ID
        :return: the created AssignmentRecord for patient and ta_id
        """
        ta_version = patient.treatment_arm_version()
        (date_assigned, date_on_arm, date_off_arm,
         status) = patient.get_dates_status_from_arm()

        analysis_id, biopsy_seq_num = patient.get_analysis_id_and_bsn()

        # The step number from the assignment is the step number that the patient was on at the time of the
        # assignment.  If the patient has been put on the treatment arm, then the step number needs to reflect
        # the step number the patient is at while on the arm.
        step_number = patient.get_patient_assignment_step_number()
        if int(step_number) % 2 == 0 and date_on_arm is not None:
            step_number = str(int(step_number) + 1)

        if date_on_arm is not None and status in Refresher.FORMATTED_STATUS_CONVERTER:
            status = Refresher.FORMATTED_STATUS_CONVERTER[status]

        return AssignmentRecord(
            patient.patientSequenceNumber,
            patient.patientType,
            ta_version,
            status,
            patient.get_assignment_reason(ta_id, ta_version),
            step_number,
            patient.diseases,
            analysis_id,
            patient.patientAssignmentIdx,
            biopsy_seq_num,
            date_assigned,
            date_on_arm,
            date_off_arm,
        )