def test_upload_rna_coverage_bigwig_to_scout(
    caplog: Generator[LogCaptureFixture, None, None],
    dna_sample_son_id: str,
    mip_rna_analysis_hk_api: HousekeeperAPI,
    rna_case_id: str,
    rna_sample_son_id: str,
    rna_store: Store,
    upload_scout_api: UploadScoutAPI,
):
    """Test that A RNA case's bigWig file for all samples can be loaded via a cg CLI
    command into an already existing DNA case"""

    # GIVEN an existing RNA case with related sample
    # GIVEN an existing DNA case with related sample
    # GIVEN a sample in the RNA case is connected to a sample in the DNA case via subject_id (i.e. same subject_id)
    upload_scout_api.status_db = rna_store

    # GIVEN the connected RNA sample has a bigWig in Housekeeper

    # WHEN running the method to upload RNA files to Scout
    caplog.set_level(logging.INFO)
    upload_scout_api.upload_rna_coverage_bigwig_to_scout(case_id=rna_case_id,
                                                         dry_run=True)

    # THEN the bigWig file should have been uploaded to the connected sample on the dna case in scout
    assert "Upload RNA coverage bigwig file finished!" in caplog.text

    # THEN the customers dna samples name should have been mentioned in the logging (and used in the upload)
    dna_customer_sample_name: str = rna_store.sample(
        internal_id=dna_sample_son_id).name
    assert dna_customer_sample_name in caplog.text
def test_upload_rna_fusion_report_to_scout_no_subject_id(
    caplog: Generator[LogCaptureFixture, None, None],
    dna_case_id: str,
    mip_rna_analysis_hk_api: HousekeeperAPI,
    rna_case_id: str,
    rna_store: Store,
    upload_scout_api: UploadScoutAPI,
):
    """Test that A RNA case's gene fusion report"""

    # GIVEN a sample in the RNA case is NOT connected to a sample in the DNA case via subject_id (i.e. same subject_id)
    for link in rna_store.family(rna_case_id).links:
        link.sample.subject_id = ""
    for link in rna_store.family(dna_case_id).links:
        link.sample.subject_id = ""
    rna_store.commit()
    upload_scout_api.status_db = rna_store

    # GIVEN the connected RNA case has a research fusion report in Housekeeper

    # WHEN running the method to upload RNA files to Scout
    caplog.set_level(logging.INFO)
    # THEN an exception should be raised on unconnected data
    with pytest.raises(CgDataError):
        upload_scout_api.upload_fusion_report_to_scout(case_id=rna_case_id,
                                                       dry_run=True)
def test_upload_splice_junctions_bed_to_scout_no_subject_id(
    caplog: Generator[LogCaptureFixture, None, None],
    dna_case_id: str,
    mip_rna_analysis_hk_api: HousekeeperAPI,
    rna_case_id: str,
    rna_store: Store,
    upload_scout_api: UploadScoutAPI,
):
    """Test that A RNA case's junction splice files for all samples can be loaded via a cg CLI
    command into an already existing DNA case"""

    # GIVEN a sample in the RNA case is NOT connected to a sample in the DNA case via subject_id (i.e. same subject_id)
    for link in rna_store.family(rna_case_id).links:
        link.sample.subject_id = ""
    for link in rna_store.family(dna_case_id).links:
        link.sample.subject_id = ""
    rna_store.commit()
    upload_scout_api.status_db = rna_store

    # GIVEN the connected RNA sample has a junction bed in Housekeeper

    # WHEN running the method to upload RNA files to Scout
    caplog.set_level(logging.INFO)
    # THEN an exception should be raised on unconnected data
    with pytest.raises(CgDataError):
        upload_scout_api.upload_splice_junctions_bed_to_scout(
            case_id=rna_case_id, dry_run=True)
def test_upload_rna_junctions_to_scout(
    caplog: Generator[LogCaptureFixture, None, None],
    mip_rna_analysis_hk_api: HousekeeperAPI,
    rna_case_id: str,
    rna_store: Store,
    upload_scout_api: UploadScoutAPI,
):
    """Test that A RNA case's gene fusion report and junction splice files for all samples can be loaded via a cg CLI
    command into an already existing DNA case"""

    # GIVEN an existing RNA case with related sample
    # GIVEN an existing DNA case with related sample
    # GIVEN a sample in the RNA case is connected to a sample in the DNA case via subject_id (i.e. same subject_id)
    upload_scout_api.status_db = rna_store

    # GIVEN the connected RNA sample has a junction bed in Housekeeper
    # GIVEN the connected RNA sample has a bigWig in Housekeeper

    # WHEN running the method to upload RNA files to Scout
    caplog.set_level(logging.INFO)
    upload_scout_api.upload_rna_junctions_to_scout(case_id=rna_case_id,
                                                   dry_run=True)

    # THEN the 2 files should have been uploaded to the connected sample on the dna case in scout
    assert "Upload splice junctions bed file finished!" in caplog.text
    assert "Upload RNA coverage bigwig file finished!" in caplog.text
Exemple #5
0
def test_save_config_creates_file(upload_scout_api: UploadScoutAPI,
                                  mip_load_config: ScoutLoadConfig, tmp_file):
    """ "Tests that save config creates a file"""

    # GIVEN a scout_config object and a path to save it on

    # WHEN calling method to save config
    upload_scout_api.save_config_file(upload_config=mip_load_config,
                                      file_path=tmp_file)

    # THEN the config should exist on disk
    assert _file_exists_on_disk(tmp_file)
Exemple #6
0
def test_save_config_creates_yaml(upload_scout_api: UploadScoutAPI,
                                  mip_load_config: ScoutLoadConfig, tmp_file):
    """Tests that the file created by save_config_file create a yaml"""

    # GIVEN a scout_config dict and a path to save it on

    # WHEN calling method to save config
    upload_scout_api.save_config_file(upload_config=mip_load_config,
                                      file_path=tmp_file)

    # THEN the should be of yaml type
    assert _file_is_yaml(tmp_file)
Exemple #7
0
def test_add_scout_config_to_hk_existing_files(
        upload_scout_api: UploadScoutAPI, tmp_file):
    """Test that scout config is not updated in housekeeper if it already exists"""
    # GIVEN a hk_mock with an scout upload file and a file path to scout load config
    housekeeper_api = upload_scout_api.housekeeper
    # GIVEN that there are files in the hk mock
    housekeeper_api.new_file(tmp_file.name)
    assert housekeeper_api.files
    # WHEN adding the file path to hk_api
    with pytest.raises(FileExistsError):
        # THEN assert File exists exception is raised
        upload_scout_api.add_scout_config_to_hk(config_file_path=tmp_file,
                                                case_id="dummy")
Exemple #8
0
def test_add_scout_config_to_hk(upload_scout_api: UploadScoutAPI, tmp_file):
    """Test that scout load config is added to housekeeper"""
    # GIVEN a hk_mock and a file path to scout load config
    tag_name = UploadScoutAPI.get_load_config_tag()
    housekeeper_api = upload_scout_api.housekeeper
    # GIVEN a hk mock that does not return a config file
    housekeeper_api.add_missing_tag(tag_name)
    # WHEN adding the file path to hk_api

    upload_scout_api.add_scout_config_to_hk(config_file_path=tmp_file,
                                            case_id="dummy")
    # THEN assert that the file path is added to hk
    # file added to hk-db
    assert housekeeper_api.is_file_added() is True
    assert housekeeper_api.is_file_included() is True
Exemple #9
0
def test_generate_config_adds_case_paths(
    sample_id: str,
    mip_dna_analysis_obj: Store.Analysis,
    upload_mip_analysis_scout_api: UploadScoutAPI,
):
    """Test that generate config adds case file paths"""
    # GIVEN a status db and hk with an analysis

    # WHEN generating the scout config for the analysis
    result_data: ScoutLoadConfig = upload_mip_analysis_scout_api.generate_config(
        mip_dna_analysis_obj)

    # THEN the config should contain the multiqc file path
    assert result_data.multiqc
Exemple #10
0
def test_generate_balsamic_load_config(
        balsamic_analysis_obj: models.Analysis,
        upload_balsamic_analysis_scout_api: UploadScoutAPI):
    # GIVEN a analysis object that have been run with balsamic
    assert balsamic_analysis_obj.pipeline == Pipeline.BALSAMIC

    # GIVEN a upload scout api with some balsamic information

    # WHEN generating a load config
    config = upload_balsamic_analysis_scout_api.generate_config(
        analysis_obj=balsamic_analysis_obj)

    # THEN assert that the config is a balsamic config
    assert isinstance(config, BalsamicLoadConfig)
Exemple #11
0
def test_generate_config_adds_meta_result_key(
    result_key: str,
    mip_dna_analysis_obj: models.Analysis,
    upload_mip_analysis_scout_api: UploadScoutAPI,
):
    """Test that generate config adds the expected result keys"""
    # GIVEN a status db and hk with an analysis
    assert mip_dna_analysis_obj

    # WHEN generating the scout config for the analysis
    result_data: ScoutLoadConfig = upload_mip_analysis_scout_api.generate_config(
        analysis_obj=mip_dna_analysis_obj)

    # THEN the config should contain the rank model version used
    assert result_data.dict()[result_key]
Exemple #12
0
def test_generate_config_adds_sample_paths(
    sample_id: str,
    mip_dna_analysis_obj: models.Analysis,
    upload_mip_analysis_scout_api: UploadScoutAPI,
):
    """Test that generate config adds vcf2cytosure file"""
    # GIVEN a status db and hk with an analysis

    # WHEN generating the scout config for the analysis
    result_data: ScoutLoadConfig = upload_mip_analysis_scout_api.generate_config(
        mip_dna_analysis_obj)

    # THEN the config should contain the sample file path for each sample
    sample: ScoutMipIndividual
    for sample in result_data.samples:
        if sample.sample_id == sample_id:
            assert sample.vcf2cytosure
Exemple #13
0
def fixture_scout_hk_bundle_data(case_id: str, scout_load_config: Path,
                                 timestamp: datetime):
    """Get some bundle data for housekeeper"""
    tag_name = UploadScoutAPI.get_load_config_tag()

    return {
        "name":
        case_id,
        "created":
        timestamp,
        "expires":
        timestamp,
        "files": [{
            "path": str(scout_load_config),
            "archive": False,
            "tags": [tag_name],
        }],
    }
Exemple #14
0
def fixture_upload_scout_api(
    scout_api: MockScoutAPI,
    madeline_api: MockMadelineAPI,
    lims_samples: List[dict],
    housekeeper_api: MockHousekeeperAPI,
    store: Store,
) -> UploadScoutAPI:
    """Fixture for upload_scout_api"""
    analysis_mock = MockMipAnalysis()
    lims_api = MockLimsAPI(samples=lims_samples)

    return UploadScoutAPI(
        hk_api=housekeeper_api,
        scout_api=scout_api,
        madeline_api=madeline_api,
        analysis_api=analysis_mock,
        lims_api=lims_api,
        status_db=store,
    )
Exemple #15
0
def upload_context(cg_context: CGConfig) -> CGConfig:
    analysis_api = MipDNAAnalysisAPI(config=cg_context)
    cg_context.meta_apis["analysis_api"] = analysis_api
    cg_context.meta_apis["report_api"] = ReportAPI(
        store=cg_context.status_db,
        lims_api=cg_context.lims_api,
        chanjo_api=cg_context.chanjo_api,
        analysis_api=analysis_api,
        scout_api=cg_context.scout_api,
    )
    cg_context.meta_apis["scout_upload_api"] = UploadScoutAPI(
        hk_api=cg_context.housekeeper_api,
        scout_api=cg_context.scout_api,
        madeline_api=cg_context.madeline_api,
        analysis_api=analysis_api,
        lims_api=cg_context.lims_api,
        status_db=cg_context.status_db,
    )

    return cg_context
Exemple #16
0
def upload_case_to_scout(context: CGConfig, re_upload: bool, dry_run: bool, case_id: str):
    """Upload variants and case from analysis to Scout."""

    LOG.info("----------------- UPLOAD -----------------------")

    housekeeper_api: HousekeeperAPI = context.housekeeper_api
    scout_api: ScoutAPI = context.scout_api

    tag_name = UploadScoutAPI.get_load_config_tag()
    version_obj = housekeeper_api.last_version(case_id)
    scout_config_file: Optional[hk_models.File] = housekeeper_api.fetch_file_from_version(
        version_obj=version_obj, tags={tag_name}
    )

    if scout_config_file is None:
        raise FileNotFoundError(f"No scout load config was found in housekeeper for {case_id}")

    LOG.info("uploading case %s to scout", case_id)

    if not dry_run:
        scout_api.upload(scout_load_config=scout_config_file.full_path, force=re_upload)

    LOG.info("uploaded to scout using load config %s", scout_config_file.full_path)
    LOG.info("Case loaded successfully to Scout")
Exemple #17
0
def upload(context: click.Context, family_id: Optional[str],
           force_restart: bool):
    """Upload results from analyses."""
    config_object: CGConfig = context.obj
    if not config_object.meta_apis.get("analysis_api"):
        config_object.meta_apis["analysis_api"] = MipDNAAnalysisAPI(
            context.obj)
    analysis_api: AnalysisAPI = config_object.meta_apis["analysis_api"]
    status_db: Store = config_object.status_db

    click.echo(click.style("----------------- UPLOAD ----------------------"))

    if family_id:
        try:
            analysis_api.verify_case_id_in_statusdb(case_id=family_id)
        except CgError:
            raise click.Abort

        case_obj: models.Family = status_db.family(family_id)
        if not case_obj.analyses:
            message = f"no analysis exists for family: {family_id}"
            click.echo(click.style(message, fg="red"))
            raise click.Abort

        analysis_obj: models.Analysis = case_obj.analyses[0]

        if analysis_obj.uploaded_at is not None:
            message = f"analysis already uploaded: {analysis_obj.uploaded_at.date()}"
            click.echo(click.style(message, fg="red"))
            raise click.Abort

        if not force_restart and analysis_obj.upload_started_at is not None:
            if dt.datetime.now(
            ) - analysis_obj.upload_started_at > dt.timedelta(hours=24):
                raise AnalysisUploadError(
                    f"The upload started at {analysis_obj.upload_started_at} "
                    f"something went wrong, restart it with the --restart flag"
                )

            message = f"analysis upload already started: {analysis_obj.upload_started_at.date()}"
            click.echo(click.style(message, fg="yellow"))
            return

    context.obj.meta_apis["report_api"] = ReportAPI(
        store=status_db,
        lims_api=config_object.lims_api,
        chanjo_api=config_object.chanjo_api,
        analysis_api=analysis_api,
        scout_api=config_object.scout_api,
    )

    context.obj.meta_apis["scout_upload_api"] = UploadScoutAPI(
        hk_api=config_object.housekeeper_api,
        scout_api=config_object.scout_api,
        madeline_api=config_object.madeline_api,
        analysis_api=analysis_api,
        lims_api=config_object.lims_api,
        status_db=status_db,
    )

    if context.invoked_subcommand is not None:
        return

    if not family_id:
        suggest_cases_to_upload(status_db=status_db)
        raise click.Abort

    case_obj: models.Family = status_db.family(family_id)
    analysis_obj: models.Analysis = case_obj.analyses[0]
    if analysis_obj.uploaded_at is not None:
        message = f"analysis already uploaded: {analysis_obj.uploaded_at.date()}"
        click.echo(click.style(message, fg="yellow"))
    else:
        analysis_obj.upload_started_at = dt.datetime.now()
        status_db.commit()
        context.invoke(coverage, re_upload=True, family_id=family_id)
        context.invoke(validate, family_id=family_id)
        context.invoke(genotypes, re_upload=False, family_id=family_id)
        context.invoke(observations, case_id=family_id)
        context.invoke(scout, case_id=family_id)
        analysis_obj.uploaded_at = dt.datetime.now()
        status_db.commit()
        click.echo(click.style(f"{family_id}: analysis uploaded!", fg="green"))