22import click
33import logging
44from civicpy import LOCAL_CACHE_PATH , civic
5- from civicpy .exports .civic_gks_record import CivicGksRecordError , CivicGksPredictiveAssertion , CivicGksDiagnosticAssertion , CivicGksPrognosticAssertion , create_gks_record_from_assertion
5+ from civicpy .exports .civic_gks_record import (
6+ CivicGksRecordError ,
7+ CivicGksPredictiveAssertion ,
8+ CivicGksDiagnosticAssertion ,
9+ CivicGksPrognosticAssertion ,
10+ create_gks_record_from_assertion ,
11+ )
612from civicpy .exports .civic_gks_writer import CivicGksWriter , GksAssertionError
713from civicpy .exports .civic_vcf_writer import CivicVcfWriter
814from civicpy .exports .civic_vcf_record import CivicVcfRecord
915from civicpy .civic import CoordinateQuery
1016import vcfpy
11- import binascii
1217from collections import OrderedDict
1318from civicpy .__version__ import __version__
1419
1520
16- CONTEXT_SETTINGS = dict (help_option_names = ['-h' , ' --help' ])
21+ CONTEXT_SETTINGS = dict (help_option_names = ["-h" , " --help" ])
1722
1823
1924@click .group (context_settings = CONTEXT_SETTINGS )
@@ -23,22 +28,35 @@ def cli():
2328
2429
2530@cli .command (context_settings = CONTEXT_SETTINGS )
26- @click .option ('--soft/--hard' , default = True ,
27- help = 'Hard-update from live API (slow) or \
28- soft-update from daily precache (fast; default)' )
29- @click .option ('--cache-save-path' ,
30- help = 'Filepath to save cache to. Default: {}' .format (LOCAL_CACHE_PATH ),
31- default = LOCAL_CACHE_PATH )
31+ @click .option (
32+ "--soft/--hard" ,
33+ default = True ,
34+ help = "Hard-update from live API (slow) or \
35+ soft-update from daily precache (fast; default)" ,
36+ )
37+ @click .option (
38+ "--cache-save-path" ,
39+ help = "Filepath to save cache to. Default: {}" .format (LOCAL_CACHE_PATH ),
40+ default = LOCAL_CACHE_PATH ,
41+ )
3242def update (soft , cache_save_path ):
3343 """Updates CIViC content from server and stores to local cache file"""
3444 civic .update_cache (from_remote_cache = soft , local_cache_path = cache_save_path )
3545
46+
3647@cli .command (context_settings = CONTEXT_SETTINGS )
37- @click .option ('-v' , '--vcf-file-path' , required = True ,
38- help = "The file path to write the VCF to." )
39- @click .option ('-i' , '--include-status' , required = True , multiple = True , type = click .Choice (['accepted' , 'submitted' , 'rejected' ]),
40- help = "Limits the variants and annotations in the VCF to only the ones that match the given statuses. \
41- May be specified more than once." )
48+ @click .option (
49+ "-v" , "--vcf-file-path" , required = True , help = "The file path to write the VCF to."
50+ )
51+ @click .option (
52+ "-i" ,
53+ "--include-status" ,
54+ required = True ,
55+ multiple = True ,
56+ type = click .Choice (["accepted" , "submitted" , "rejected" ]),
57+ help = "Limits the variants and annotations in the VCF to only the ones that match the given statuses. \
58+ May be specified more than once." ,
59+ )
4260def create_vcf (vcf_file_path , include_status ):
4361 """Create a VCF file of CIViC variants"""
4462 records = []
@@ -47,12 +65,13 @@ def create_vcf(vcf_file_path, include_status):
4765 records .append (CivicVcfRecord (variant , include_status ))
4866 CivicVcfWriter (vcf_file_path , records )
4967
68+
5069@cli .command (context_settings = CONTEXT_SETTINGS )
5170@click .option (
5271 "--organization-id" ,
5372 required = True ,
54- help = "The CIViC organization ID that endorsed the assertion(s) for submission to ClinVar." ,
55- type = int
73+ help = "The CIViC organization ID that approved the assertion(s) for submission to ClinVar." ,
74+ type = int ,
5675)
5776@click .option (
5877 "-o" ,
@@ -64,15 +83,15 @@ def create_vcf(vcf_file_path, include_status):
6483 readable = True ,
6584 dir_okay = False ,
6685 path_type = Path ,
67- )
86+ ),
6887)
6988def create_gks_json (organization_id : int , output_json : Path ) -> None :
70- """Create a JSON file for CIViC assertion records endorsed by a specific organization that are ready for ClinVar submission, represented as GKS objects.
89+ """Create a JSON file for CIViC assertion records approved by a specific organization that are ready for ClinVar submission, represented as GKS objects.
7190
7291 For now, we will only support simple molecular profiles and diagnostic, prognostic,
7392 or predictive assertions.
7493
75- :param organization_id: The CIViC organization ID that endorsed the assertion(s) for submission to ClinVar
94+ :param organization_id: The CIViC organization ID that approved the assertion(s) for submission to ClinVar
7695 :param output_json: The output file path to write the JSON file to
7796 """
7897 try :
@@ -81,41 +100,81 @@ def create_gks_json(organization_id: int, output_json: Path) -> None:
81100 logging .exception ("Error getting organization %i" , organization_id )
82101 return
83102
84- records : list [CivicGksDiagnosticAssertion | CivicGksPredictiveAssertion | CivicGksPrognosticAssertion ] = []
103+ records : list [
104+ CivicGksDiagnosticAssertion
105+ | CivicGksPredictiveAssertion
106+ | CivicGksPrognosticAssertion
107+ ] = []
85108 errors : list [GksAssertionError ] = []
86109
87- for endorsement in civic .get_all_endorsements_ready_for_clinvar_submission_for_org (organization_id ):
88- assertion = endorsement .assertion
110+ for approval in civic .get_all_approvals_ready_for_clinvar_submission_for_org (
111+ organization_id
112+ ):
113+ assertion = approval .assertion
89114 if assertion .is_valid_for_gks_json (emit_warnings = True ):
90115 try :
91- gks_record = create_gks_record_from_assertion (assertion , endorsement = endorsement )
116+ gks_record = create_gks_record_from_assertion (
117+ assertion , approval = approval
118+ )
92119 except (CivicGksRecordError , NotImplementedError ) as e :
93- errors .append (GksAssertionError (assertion_id = assertion .id , message = str (e )))
120+ errors .append (
121+ GksAssertionError (assertion_id = assertion .id , message = str (e ))
122+ )
94123 continue
95124 records .append (gks_record )
96125 else :
97- errors .append (GksAssertionError (assertion_id = assertion .id , message = "Assertion is not valid for GKS JSON. See logs for more details." ))
126+ errors .append (
127+ GksAssertionError (
128+ assertion_id = assertion .id ,
129+ message = "Assertion is not valid for GKS JSON. See logs for more details." ,
130+ )
131+ )
98132 if not records :
99- logging .warning ('No assertions ready for submission to ClinVar found for organization {}' .format (organization_id ))
133+ logging .warning (
134+ "No assertions ready for submission to ClinVar found for organization {}" .format (
135+ organization_id
136+ )
137+ )
100138 else :
101139 CivicGksWriter (output_json , records , errors = errors )
102140
103141
104142@cli .command (context_settings = CONTEXT_SETTINGS )
105- @click .option ('--input-vcf' , required = True ,
106- help = "A VCF to annotate with information from CIViC." )
107- @click .option ('--output-vcf' , required = True ,
108- help = "The file path to write the annotated VCF to." )
109- @click .option ('--reference' , required = True , type = click .Choice (['NCBI36' , 'GRCh37' , 'GRCh38' ]),
110- help = "The reference sequence build used to create the input VCF" )
111- @click .option ('-i' , '--include-status' , required = True , multiple = True , type = click .Choice (['accepted' , 'submitted' , 'rejected' ]),
112- help = "Limits the variants and annotations in the VCF to only the ones that match the given statuses. \
113- May be specified more than once." )
143+ @click .option (
144+ "--input-vcf" , required = True , help = "A VCF to annotate with information from CIViC."
145+ )
146+ @click .option (
147+ "--output-vcf" , required = True , help = "The file path to write the annotated VCF to."
148+ )
149+ @click .option (
150+ "--reference" ,
151+ required = True ,
152+ type = click .Choice (["NCBI36" , "GRCh37" , "GRCh38" ]),
153+ help = "The reference sequence build used to create the input VCF" ,
154+ )
155+ @click .option (
156+ "-i" ,
157+ "--include-status" ,
158+ required = True ,
159+ multiple = True ,
160+ type = click .Choice (["accepted" , "submitted" , "rejected" ]),
161+ help = "Limits the variants and annotations in the VCF to only the ones that match the given statuses. \
162+ May be specified more than once." ,
163+ )
114164def annotate_vcf (input_vcf , output_vcf , reference , include_status ):
115165 """Annotate a VCF with information from CIViC"""
116166 reader = vcfpy .Reader .from_path (input_vcf )
117167 new_header = reader .header .copy ()
118- new_header .add_info_line (OrderedDict ([('ID' , 'CIVIC' ), ('Number' , '.' ), ('Type' , 'String' ), ('Description' , CivicVcfWriter .CSQ_DESCRIPTION )]))
168+ new_header .add_info_line (
169+ OrderedDict (
170+ [
171+ ("ID" , "CIVIC" ),
172+ ("Number" , "." ),
173+ ("Type" , "String" ),
174+ ("Description" , CivicVcfWriter .CSQ_DESCRIPTION ),
175+ ]
176+ )
177+ )
119178 writer = vcfpy .Writer .from_path (output_vcf , new_header )
120179 for entry in reader :
121180 for alt in entry .ALT :
@@ -135,29 +194,37 @@ def annotate_vcf(input_vcf, output_vcf, reference, include_status):
135194 if len (ref ) > len (alt ):
136195 start = position + 1
137196 end = start + len (ref ) - 1
138- if alt == '' :
197+ if alt == "" :
139198 alt = None
140199 else :
141200 start = position
142- if ref == '' :
201+ if ref == "" :
143202 ref = None
144203 end = start + 1
145204 else :
146205 end = start + len (ref ) - 1
147206 query = CoordinateQuery (entry .CHROM , start , end , alt , ref , reference )
148- variants = civic .search_variants_by_coordinates (query , search_mode = ' exact' )
207+ variants = civic .search_variants_by_coordinates (query , search_mode = " exact" )
149208 if variants is not None :
150209 if len (variants ) == 1 :
151210 record = CivicVcfRecord (variants [0 ], include_status )
152- csq = record .INFO [' CSQ' ]
211+ csq = record .INFO [" CSQ" ]
153212 if len (csq ) > 0 :
154- entry .INFO [' CIVIC' ] = csq
213+ entry .INFO [" CIVIC" ] = csq
155214 elif len (variants ) > 1 :
156- print ("More than one variant found for start {} stop {} ref {} alt {}. CIViC Variants IDs: {}" .format (start , end , ref , alt , "," .join (list (map (lambda v : str (v .id ), variants )))))
215+ print (
216+ "More than one variant found for start {} stop {} ref {} alt {}. CIViC Variants IDs: {}" .format (
217+ start ,
218+ end ,
219+ ref ,
220+ alt ,
221+ "," .join (list (map (lambda v : str (v .id ), variants ))),
222+ )
223+ )
157224 writer .write_record (entry )
158225 writer .close ()
159226 reader .close ()
160227
161228
162- if __name__ == ' __main__' :
229+ if __name__ == " __main__" :
163230 cli ()
0 commit comments