phc-ingestion 0.10.1__py3-none-any.whl → 0.10.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ingestion/nebula/process.py +39 -14
- {phc_ingestion-0.10.1.dist-info → phc_ingestion-0.10.2.dist-info}/METADATA +1 -1
- {phc_ingestion-0.10.1.dist-info → phc_ingestion-0.10.2.dist-info}/RECORD +4 -6
- ingestion/nebula/util/json.py +0 -72
- ingestion/nebula/util/vcf.py +0 -100
- {phc_ingestion-0.10.1.dist-info → phc_ingestion-0.10.2.dist-info}/WHEEL +0 -0
ingestion/nebula/process.py
CHANGED
|
@@ -1,26 +1,51 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
|
-
from ingestion.
|
|
4
|
-
from ingestion.nebula.util.vcf import process_nebula_vcf
|
|
3
|
+
from ingestion.vcf_standardization.standardize import standardize_vcf
|
|
5
4
|
from lifeomic_logging import scoped_logger
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
def process(
|
|
7
|
+
def process(vcf_file, out_path, file_name, source_file_id):
|
|
9
8
|
|
|
10
9
|
with scoped_logger(__name__) as log:
|
|
11
|
-
log.info(
|
|
12
|
-
|
|
13
|
-
result, file_genome_references, json_data = process_nebula_json(
|
|
14
|
-
infile, outpath, file_name, source_file_id, log
|
|
10
|
+
log.info(
|
|
11
|
+
f"Beginning Nebula ingestion for vcf_file: {vcf_file}, file_name: {file_name}, out_path: {out_path}, source_file_id: {source_file_id}"
|
|
15
12
|
)
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
|
|
14
|
+
manifest = {}
|
|
15
|
+
case_id = file_name
|
|
16
|
+
base_vcf_file = os.path.basename(vcf_file)
|
|
17
|
+
vcf_out = base_vcf_file.replace(".vcf", ".modified.vcf")
|
|
18
|
+
vcf_final = base_vcf_file.replace(".vcf", ".modified.nrm.filtered.vcf")
|
|
19
|
+
if not vcf_final.endswith(".gz"):
|
|
20
|
+
vcf_final = vcf_final + ".gz"
|
|
21
|
+
|
|
22
|
+
# All Nebula VCF ingestions are germline, so ensure the
|
|
23
|
+
# sample name is prefixed with "germline_". This matches
|
|
24
|
+
# the downstream logic in genomic-manifest
|
|
25
|
+
sample_name = f"germline_{case_id}"
|
|
26
|
+
vcf_line_count = standardize_vcf(
|
|
27
|
+
vcf_file, vcf_out, out_path, sample_name, log, compression=True
|
|
18
28
|
)
|
|
29
|
+
|
|
30
|
+
# Add to manifest
|
|
31
|
+
manifest["sourceFileId"] = source_file_id
|
|
32
|
+
manifest["resources"] = [{"fileName": f".lifeomic/vcf-ingest/{case_id}/{base_vcf_file}"}]
|
|
33
|
+
manifest["files"] = [
|
|
34
|
+
{
|
|
35
|
+
"fileName": f".lifeomic/vcf-ingest/{case_id}/{vcf_final}",
|
|
36
|
+
"sequenceType": "germline",
|
|
37
|
+
"type": "shortVariant",
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
# Hard-code genome reference for Nebula VCFs
|
|
42
|
+
genome_reference = "GRCh38"
|
|
43
|
+
|
|
19
44
|
case_metadata = {
|
|
20
|
-
"
|
|
45
|
+
"test_type": manifest["testType"],
|
|
46
|
+
"vcf_line_count": vcf_line_count,
|
|
47
|
+
"case_id": manifest["reportID"],
|
|
48
|
+
"germline_genome_reference": genome_reference,
|
|
21
49
|
}
|
|
22
50
|
|
|
23
|
-
|
|
24
|
-
case_metadata.update(file_genome_references)
|
|
25
|
-
|
|
26
|
-
return case_metadata
|
|
51
|
+
return case_metadata, manifest
|
|
@@ -27,9 +27,7 @@ ingestion/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
27
27
|
ingestion/generic/process.py,sha256=ZaVnZ_gx9faDUsuresI1A0oCegTa-dPQT7DBFMeZGyY,1777
|
|
28
28
|
ingestion/generic/utils.py,sha256=1MEIru7uq38IjUdL8lcHqDH0oTki9uWrz1f2e-pmRoU,2814
|
|
29
29
|
ingestion/nebula/__init__.py,sha256=VauK-rup_N8ZXVohx3HYqHX_PE_WoPyMUhdv2R7al4o,45
|
|
30
|
-
ingestion/nebula/process.py,sha256=
|
|
31
|
-
ingestion/nebula/util/json.py,sha256=ChThuJjF7o4xMQ4gkX7s2w9wgZ5_k528XxiSI3-gOCU,2230
|
|
32
|
-
ingestion/nebula/util/vcf.py,sha256=83JWG6ndPxHYZNXVj6-Gon9AY9JnGeR1JMivUQoSHjM,3311
|
|
30
|
+
ingestion/nebula/process.py,sha256=kIFhndcXFUICKMg4PfFhEsBxb_0oPkGPnpVNHhHFJ7k,1853
|
|
33
31
|
ingestion/nextgen/__init__.py,sha256=7LQ-h_Bvc5P1QcHMdzsqi1Qm4fTJn04-ozar2ty9wSc,59
|
|
34
32
|
ingestion/nextgen/process.py,sha256=5Z0RfclwTAYZruGDiLPutjPCYFh1DJpoWY9dnttghT4,3993
|
|
35
33
|
ingestion/nextgen/util/alteration_table.py,sha256=JTWBL1Fqj_pGsH5vwuVEnCUJle2wOBk6VYImHYCF9vg,6129
|
|
@@ -58,6 +56,6 @@ ingestion/vcf_standardization/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
|
|
|
58
56
|
ingestion/vcf_standardization/util/af_helpers.py,sha256=dpTzoeIQVeBRt0ETF3a9rp5ojZqznHg4x_hCZ8OPcOg,1061
|
|
59
57
|
ingestion/vcf_standardization/util/dp_helpers.py,sha256=Nq8oLOLObu4_pv16qwwgpALRlUoJVCULrd9cFOD-eoI,823
|
|
60
58
|
ingestion/vcf_standardization/util/read_write.py,sha256=x3Pf6Dq8tmolblbCS5CrNmrcHS3FGfqBSFpFgvFGC4g,2526
|
|
61
|
-
phc_ingestion-0.10.
|
|
62
|
-
phc_ingestion-0.10.
|
|
63
|
-
phc_ingestion-0.10.
|
|
59
|
+
phc_ingestion-0.10.2.dist-info/WHEEL,sha256=B19PGBCYhWaz2p_UjAoRVh767nYQfk14Sn4TpIZ-nfU,87
|
|
60
|
+
phc_ingestion-0.10.2.dist-info/METADATA,sha256=HuebNLig9ccPPhZrF9It2bxP7p4ZWf0LGiz_rt__1Zk,573
|
|
61
|
+
phc_ingestion-0.10.2.dist-info/RECORD,,
|
ingestion/nebula/util/json.py
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import glob
|
|
2
|
-
import gzip
|
|
3
|
-
import os
|
|
4
|
-
import shutil
|
|
5
|
-
|
|
6
|
-
from ingestion.shared_util.tar import unpack
|
|
7
|
-
from ingestion.nebula.util.vcf import extract_sv
|
|
8
|
-
from ingestion.shared_util.ga4gh import create_yaml
|
|
9
|
-
from logging import Logger
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def handle_tsv(file: str, file_list: list[str]) -> dict[str, str]:
|
|
13
|
-
multiple_tsv = len([file for file in file_list if file.endswith("tsv")]) > 1
|
|
14
|
-
|
|
15
|
-
if not multiple_tsv or "Transformed" in file:
|
|
16
|
-
return {
|
|
17
|
-
"tsv": file,
|
|
18
|
-
}
|
|
19
|
-
return {}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def process_nebula_json(
|
|
23
|
-
infile: str, outpath: str, file_name: str, source_file_id: str, log: Logger
|
|
24
|
-
):
|
|
25
|
-
# Unpack tarball and go into the new directory
|
|
26
|
-
unpack(infile, outpath)
|
|
27
|
-
os.chdir(outpath)
|
|
28
|
-
|
|
29
|
-
file_list = glob.glob("*")
|
|
30
|
-
files: dict[str, str] = {}
|
|
31
|
-
|
|
32
|
-
for file in file_list:
|
|
33
|
-
extension = ".".join(file.split(".")[1:])
|
|
34
|
-
if file.endswith("vcf"):
|
|
35
|
-
files["somatic.vcf"] = file
|
|
36
|
-
else:
|
|
37
|
-
# There should only be the vcf file
|
|
38
|
-
files[extension] = file
|
|
39
|
-
|
|
40
|
-
log.info(f"Files in tarball input: {file_list}")
|
|
41
|
-
|
|
42
|
-
somatic_filename = None
|
|
43
|
-
data = {}
|
|
44
|
-
metadata = {}
|
|
45
|
-
|
|
46
|
-
# Sometimes they don't come in gzipped
|
|
47
|
-
for key in files.keys():
|
|
48
|
-
if "somatic.vcf" in key:
|
|
49
|
-
somatic_filename = files["somatic.vcf"].replace(".vcf", ".somatic.vcf") + ".gz"
|
|
50
|
-
with open(files["somatic.vcf"], "rb") as f_in:
|
|
51
|
-
with gzip.open(somatic_filename, "wb") as f_out:
|
|
52
|
-
shutil.copyfileobj(f_in, f_out)
|
|
53
|
-
|
|
54
|
-
vcf_results = extract_sv(file_name, bool(somatic_filename), False, False)
|
|
55
|
-
|
|
56
|
-
# We might not have any of these files but we need an empty json object here.
|
|
57
|
-
file_genome_references = {}
|
|
58
|
-
if vcf_results:
|
|
59
|
-
metadata["files"] = metadata["files"] + vcf_results
|
|
60
|
-
for vcf in vcf_results:
|
|
61
|
-
seq_type = vcf.get("sequenceType")
|
|
62
|
-
file_genome_references[f"{seq_type}_genome_reference"] = vcf["reference"]
|
|
63
|
-
|
|
64
|
-
create_yaml(metadata, file_name)
|
|
65
|
-
|
|
66
|
-
# Return VCF files for immediate processing, and JSON data for adding vendsig
|
|
67
|
-
result = {}
|
|
68
|
-
|
|
69
|
-
if somatic_filename is not None:
|
|
70
|
-
result["somatic_vcf"] = f"{outpath}/{somatic_filename}"
|
|
71
|
-
|
|
72
|
-
return (result, file_genome_references, data)
|
ingestion/nebula/util/vcf.py
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import gzip
|
|
3
|
-
|
|
4
|
-
from logging import Logger
|
|
5
|
-
|
|
6
|
-
from ingestion.vcf_standardization.standardize import standardize_vcf
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def create_empty_vcf_zip(prefix):
|
|
10
|
-
vcf_gzip_path = f"{prefix}.modified.somatic.vcf.gz"
|
|
11
|
-
content = (
|
|
12
|
-
"""##fileformat=VCFv4.1
|
|
13
|
-
##filedate="""
|
|
14
|
-
+ datetime.datetime.now().isoformat()
|
|
15
|
-
+ """
|
|
16
|
-
##FILTER=<ID=PASS,Description="All filters passed">
|
|
17
|
-
##FILTER=<ID=R8,Description="IndelRepeatLength is greater than 8">
|
|
18
|
-
##FILTER=<ID=R8.1,Description="IndelRepeatLength of a monomer is greater than 8">
|
|
19
|
-
##FILTER=<ID=R8.2,Description="IndelRepeatLength of a dimer is greater than 8">
|
|
20
|
-
##FILTER=<ID=sb,Description="Variant strand bias high">
|
|
21
|
-
##FILTER=<ID=sb.s,Description="Variant strand bias significantly high (only for SNV)">
|
|
22
|
-
##FILTER=<ID=rs,Description="Variant with rs (dbSNP) number in a non-core gene">
|
|
23
|
-
##FILTER=<ID=FP,Description="Possibly false positives due to high similarity to off-target regions">
|
|
24
|
-
##FILTER=<ID=NC,Description="Noncoding INDELs on non-core genes">
|
|
25
|
-
##FILTER=<ID=lowDP,Description="low depth variant">
|
|
26
|
-
##FILTER=<ID=Benign,Description="Benign variant">
|
|
27
|
-
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
|
|
28
|
-
##FORMAT=<ID=AF,Number=1,Type=String,Description="Variant Allele Frequency">
|
|
29
|
-
#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT """
|
|
30
|
-
+ prefix
|
|
31
|
-
+ """
|
|
32
|
-
"""
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
with gzip.open(vcf_gzip_path, "wb") as f:
|
|
36
|
-
f.write(content.encode("utf-8"))
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# This is done in next step, we are just adding to yaml
|
|
40
|
-
def extract_sv(prefix, include_somatic: bool):
|
|
41
|
-
vcfs = []
|
|
42
|
-
|
|
43
|
-
# Hard-code genome reference for Nebula VCFs
|
|
44
|
-
genome_reference = "GRCh38"
|
|
45
|
-
|
|
46
|
-
if include_somatic:
|
|
47
|
-
vcfs.append(
|
|
48
|
-
{
|
|
49
|
-
"fileName": f".lifeomic/nebula/{prefix}/{prefix}.modified.somatic.nrm.filtered.vcf.gz",
|
|
50
|
-
"sequenceType": "somatic",
|
|
51
|
-
"type": "shortVariant", # todo: Is this always going to be shortVariant?
|
|
52
|
-
"reference": genome_reference,
|
|
53
|
-
}
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
return vcfs
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def get_vendsig_dict(json_data, log: Logger):
|
|
60
|
-
# Return a dicitionary of {'chr:star_pos:ref:alt' : 'vendsig'}
|
|
61
|
-
vendsig_dict = {"vendor": "nebula"}
|
|
62
|
-
|
|
63
|
-
return vendsig_dict
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def map_vendsig(ci: str) -> str:
|
|
67
|
-
if ci in ["Pathogenic Variant", "Pathogenic"]:
|
|
68
|
-
return "Pathogenic"
|
|
69
|
-
elif ci in ["Likely Pathogenic Variant", "Likely Pathogenic"]:
|
|
70
|
-
return "Likely pathogenic"
|
|
71
|
-
elif ci in ["Benign Variant", "Benign"]:
|
|
72
|
-
return "Benign"
|
|
73
|
-
elif ci in ["Likely Benign Variant", "Likely Benign"]:
|
|
74
|
-
return "Likely benign"
|
|
75
|
-
elif ci in ["Variant of Uncertain Significance", "VUS"]:
|
|
76
|
-
return "Uncertain significance"
|
|
77
|
-
else:
|
|
78
|
-
return "Unknown"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def process_nebula_vcf(infile, json_data, outpath, file_name, log: Logger):
|
|
82
|
-
line_count = 0
|
|
83
|
-
vendsig_dict = {"vendor": "nebula"}
|
|
84
|
-
|
|
85
|
-
outfile = f"{file_name}.modified.somatic.vcf"
|
|
86
|
-
sample_name = file_name
|
|
87
|
-
# Read in a dictionary of variants with VENDSIG from the JSON file for somatic only
|
|
88
|
-
vendsig_dict = get_vendsig_dict(json_data, log)
|
|
89
|
-
|
|
90
|
-
line_count = standardize_vcf(
|
|
91
|
-
infile=infile,
|
|
92
|
-
outfile=outfile,
|
|
93
|
-
out_path=outpath,
|
|
94
|
-
case_id=sample_name,
|
|
95
|
-
log=log,
|
|
96
|
-
vendsig_dict=vendsig_dict,
|
|
97
|
-
compression=True,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
return line_count
|
|
File without changes
|