Example #1
0
    def get(self, request):
        """
        Returns information about a specific patient,
        including a list of samples and aliquots derived from this patient.
        Takes a patient barcode (of length 12, *eg* TCGA-B9-7268) as a required parameter.
        User does not need to be authenticated.
        """

        cursor = None
        db = None

        patient_barcode = request.get_assigned_value('patient_barcode')
        query_tuple = (str(patient_barcode),)
        clinical_query_str, sample_query_str, aliquot_query_str = PatientsGetQueryBuilder().build_queries()

        try:
            db = sql_connection()
            cursor = db.cursor(MySQLdb.cursors.DictCursor)

            # build clinical data message
            cursor.execute(clinical_query_str, query_tuple)
            row = cursor.fetchone()
            if row is None:
                cursor.close()
                db.close()
                logger.warn("Patient barcode {} not found in metadata_clinical table.".format(patient_barcode))
                raise endpoints.NotFoundException("Patient barcode {} not found".format(patient_barcode))
            constructor_dict = build_constructor_dict_for_message(MetadataItem(), row)
            clinical_data_item = MetadataItem(**constructor_dict)

            # get list of samples
            cursor.execute(sample_query_str, query_tuple)
            sample_list = [row['sample_barcode'] for row in cursor.fetchall()]

            # get list of aliquots
            cursor.execute(aliquot_query_str, query_tuple)
            aliquot_list = [row['AliquotBarcode'] for row in cursor.fetchall()]

            return PatientDetails(clinical_data=clinical_data_item, samples=sample_list, aliquots=aliquot_list)

        except (IndexError, TypeError), e:
            logger.info("Patient {} not found. Error: {}".format(patient_barcode, e))
            raise endpoints.NotFoundException("Patient {} not found.".format(patient_barcode))
    def annotations(self, request):
        """
        Returns TCGA annotations about a specific aliquot,
        Takes a aliquot barcode (of length 28 *eg* TCGA-01-0628-11A-01D-0358-06) as a required parameter.
        User does not need to be authenticated.
        """

        cursor = None
        db = None

        aliquot_barcode = request.get_assigned_value('aliquot_barcode')
        query_tuple = (str(aliquot_barcode),)
        # check to make sure aliquot_barcode is in correct form
        try:
            parts = aliquot_barcode.split('-')
            assert len(parts) == 7
            assert len(parts[0]) == 4
            assert len(parts[1]) == 2
            assert len(parts[2]) == 4
            assert len(parts[3]) == 3
            assert len(parts[4]) in [2, 3]
            assert len(parts[5]) == 4
            assert len(parts[6]) == 2
        except AssertionError:
            raise endpoints.BadRequestException('{} is not the correct format for a aliquot barcode. '
                                                'Aliquot barcodes must be of the form XXXX-XX-XXXX-XXX-XXX-XXXX-XX '
                                                'or XXXX-XX-XXXX-XXX-XX-XXXX-XX.'.format(aliquot_barcode))

        item_type_name = request.get_assigned_value('item_type_name')

        # check to make sure each item_type_name is valid
        if len(item_type_name) > 0:
            for itm in item_type_name:
                itm = itm.strip()
                if itm.lower() not in ['patient', 'aliquot', 'analyte', 'shipped portion', 'portion', 'slide', 'sample']:
                    raise endpoints.BadRequestException("'{}' is not a valid entry for item_type_name. "
                                                        "Valid entries include 'Patient', 'Aliquot', 'Analyte', 'Shipped Portion', "
                                                        "'Portion', 'Slide', and 'Sample'".format(itm))
                query_tuple += (itm,)

        query_str = AliquotsAnnotationsQueryBuilder().build_query(item_type_name=item_type_name)
        metadata_samples_query_str = AliquotsAnnotationsQueryBuilder().build_metadata_samples_query()

        try:
            db = sql_connection()
            cursor = db.cursor(MySQLdb.cursors.DictCursor)

            # build annotation message
            cursor.execute(query_str, query_tuple)
            rows = cursor.fetchall()
            cursor.execute(metadata_samples_query_str, (str(aliquot_barcode),))
            metadata_sample_rows = cursor.fetchall()
            if len(rows) == 0:
                cursor.close()
                db.close()
                if len(metadata_sample_rows) == 0:
                    msg = "Aliquot barcode {} not found in the database.".format(aliquot_barcode)
                    logger.info(msg)
                else:
                    msg = "No annotations found for aliquot barcode {}".format(aliquot_barcode)
                    if item_type_name is not None:
                        msg += " and item type name {}. Item type name must be one of the following: " \
                               "'Patient', 'Aliquot', 'Analyte', 'Shipped Portion', 'Portion', 'Slide', 'Sample'.".format(item_type_name)
                    logger.info(msg)
                raise endpoints.NotFoundException(msg)

            items = []
            for row in rows:
                constructor_dict = build_constructor_dict_for_message(MetadataAnnotationItem(), row)
                items.append(MetadataAnnotationItem(**constructor_dict))

            return MetadataAnnotationList(items=items, count=len(items))

        except (IndexError, TypeError), e:
            logger.info("Aliquot {} not found. Error: {}".format(aliquot_barcode, e))
            raise endpoints.NotFoundException("Aliquot {} not found.".format(aliquot_barcode))
Example #3
0
    def get(self, request):
        """
        Given a sample barcode (of length 16, *eg* TCGA-B9-7268-01A), this endpoint returns
        all available "biospecimen" information about this sample,
        the associated patient barcode, a list of associated aliquots,
        and a list of "data_details" blocks describing each of the data files associated with this sample
        """

        cursor = None
        db = None

        sample_barcode = request.get_assigned_value('sample_barcode')
        pipeline = request.get_assigned_value('pipeline')
        platform = request.get_assigned_value('platform')

        aliquot_query_str = SamplesGetQueryBuilder().build_aliquot_query(platform=platform, pipeline=pipeline)
        biospecimen_query_str = SamplesGetQueryBuilder().build_biospecimen_query()
        data_query_str = SamplesGetQueryBuilder().build_data_query(platform=platform, pipeline=pipeline)
        patient_query_str = SamplesGetQueryBuilder().build_patient_query()

        query_tuple = (str(sample_barcode),)
        extra_query_tuple = query_tuple
        if pipeline is not None: extra_query_tuple += (pipeline,)
        if platform is not None: extra_query_tuple += (platform,)

        try:
            db = sql_connection()
            cursor = db.cursor(MySQLdb.cursors.DictCursor)

            # build biospecimen data message
            cursor.execute(biospecimen_query_str, query_tuple)
            row = cursor.fetchone()
            if row is None:
                cursor.close()
                db.close()
                error_message = "Sample barcode {} not found in metadata_biospecimen table.".format(sample_barcode)
                raise endpoints.NotFoundException(error_message)
            constructor_dict = build_constructor_dict_for_message(MetadataItem(), row)
            biospecimen_data_item = MetadataItem(**constructor_dict)

            # get list of aliquots
            cursor.execute(aliquot_query_str, extra_query_tuple)
            aliquot_list = [row['AliquotBarcode'] for row in cursor.fetchall()]

            # get patient barcode (superfluous?)
            cursor.execute(patient_query_str, query_tuple)
            row = cursor.fetchone()
            patient_barcode = str(row["case_barcode"])

            # prepare to build list of data details messages
            cursor.execute(data_query_str, extra_query_tuple)
            cursor_rows = cursor.fetchall()
            # update every dictionary in cursor_rows to contain the full cloud_storage_path for each sample
            bad_repo_count, bad_repo_set = \
                CohortsSamplesFilesMessageBuilder().get_GCS_file_paths_and_bad_repos(cursor_rows)
            if bad_repo_count > 0:
                logger.warn("not returning {count} row(s) in sample_details due to repositories: {bad_repo_list}"
                            .format(count=bad_repo_count, bad_repo_list=list(bad_repo_set)))

            # build a data details message for each row returned from metadata_data table
            data_details_list = []
            for row in cursor_rows:
                constructor_dict = build_constructor_dict_for_message(DataDetails(), row)
                data_details_item = DataDetails(**constructor_dict)
                data_details_list.append(data_details_item)

            if bad_repo_count > 0:
                logger.warn("not returning {count} row(s) in sample_details due to repositories: {bad_repo_list}"
                            .format(count=bad_repo_count, bad_repo_list=list(bad_repo_set)))

            return SampleDetails(aliquots=aliquot_list,
                                 biospecimen_data=biospecimen_data_item,
                                 data_details=data_details_list,
                                 data_details_count=len(data_details_list),
                                 patient=patient_barcode)

        except (IndexError, TypeError) as e:
            logger.info("Sample details for barcode {} not found. Error: {}".format(sample_barcode, e))
            raise endpoints.NotFoundException(
                "Sample details for barcode {} not found.".format(sample_barcode))
        except MySQLdb.ProgrammingError as e:
            logger.warn(e)
            raise endpoints.BadRequestException("Error retrieving biospecimen, patient, or other data. {}".format(e))
        finally:
            if cursor: cursor.close()
            if db and db.open: db.close()