Oncodrive3D 1.0.4__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.
- oncodrive3d-1.0.4.dist-info/METADATA +333 -0
- oncodrive3d-1.0.4.dist-info/RECORD +36 -0
- oncodrive3d-1.0.4.dist-info/WHEEL +4 -0
- oncodrive3d-1.0.4.dist-info/entry_points.txt +5 -0
- oncodrive3d-1.0.4.dist-info/licenses/LICENSE +15 -0
- scripts/__init__.py +2 -0
- scripts/clustering_3d.code-workspace +7 -0
- scripts/datasets/__init__.py +0 -0
- scripts/datasets/af_merge.py +344 -0
- scripts/datasets/build_datasets.py +125 -0
- scripts/datasets/get_pae.py +78 -0
- scripts/datasets/get_structures.py +107 -0
- scripts/datasets/model_confidence.py +97 -0
- scripts/datasets/parse_pae.py +64 -0
- scripts/datasets/prob_contact_maps.py +258 -0
- scripts/datasets/seq_for_mut_prob.py +900 -0
- scripts/datasets/utils.py +394 -0
- scripts/globals.py +169 -0
- scripts/main.py +650 -0
- scripts/plotting/__init__.py +0 -0
- scripts/plotting/build_annotations.py +102 -0
- scripts/plotting/chimerax_plot.py +251 -0
- scripts/plotting/pdb_tool.py +149 -0
- scripts/plotting/pfam.py +94 -0
- scripts/plotting/plot.py +2484 -0
- scripts/plotting/stability_change.py +184 -0
- scripts/plotting/uniprot_feat.py +276 -0
- scripts/plotting/utils.py +594 -0
- scripts/run/__init__.py +0 -0
- scripts/run/clustering.py +749 -0
- scripts/run/communities.py +53 -0
- scripts/run/miss_mut_prob.py +206 -0
- scripts/run/mutability.py +289 -0
- scripts/run/pvalues.py +91 -0
- scripts/run/score_and_simulations.py +155 -0
- scripts/run/utils.py +461 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module including a collection of functions that provide
|
|
3
|
+
general-purpose functionalities that can be used across
|
|
4
|
+
different parts of the dataset building process.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import gzip
|
|
8
|
+
import hashlib
|
|
9
|
+
import io
|
|
10
|
+
import os
|
|
11
|
+
import tarfile
|
|
12
|
+
import time
|
|
13
|
+
from zipfile import ZipFile
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
import daiquiri
|
|
17
|
+
import numpy as np
|
|
18
|
+
import pandas as pd
|
|
19
|
+
import requests
|
|
20
|
+
from Bio import SeqIO
|
|
21
|
+
from pypdl import Pypdl as Downloader
|
|
22
|
+
import aiohttp
|
|
23
|
+
# from unipressed import IdMappingClient
|
|
24
|
+
|
|
25
|
+
from scripts import __logger_name__
|
|
26
|
+
|
|
27
|
+
logger = daiquiri.getLogger(__logger_name__ + ".build.utils")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# General utils
|
|
31
|
+
|
|
32
|
+
def rounded_up_division(num, den):
|
|
33
|
+
"""
|
|
34
|
+
Perform a division and round up the result.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
return -(-num // den)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_pos_fragments(mut_gene_df):
|
|
41
|
+
"""
|
|
42
|
+
Get the corresponding fragment of each position of the protein.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
max_f = rounded_up_division(max(mut_gene_df["Pos"]), 1400)
|
|
46
|
+
bins = [n * 1400 for n in range(0, max_f+1)]
|
|
47
|
+
group_names = list(range(1, max_f+1))
|
|
48
|
+
|
|
49
|
+
return pd.cut(mut_gene_df["Pos"], bins, labels = group_names)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_species(species):
|
|
53
|
+
"""
|
|
54
|
+
Change species name to accepted format.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
if species == "human" or species.capitalize() == "Homo sapiens":
|
|
58
|
+
species = "Homo sapiens"
|
|
59
|
+
elif species == "mouse" or species.capitalize() == "Mus musculus":
|
|
60
|
+
species = "Mus musculus"
|
|
61
|
+
else:
|
|
62
|
+
raise RuntimeError(
|
|
63
|
+
f"Failed to recognize '{species}' as species. Currently accepted ones are 'Homo sapiens' and 'Mus musculus'. Exiting.."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return species
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Download
|
|
70
|
+
|
|
71
|
+
CHECKSUM = {
|
|
72
|
+
"UP000005640_9606_HUMAN_v4": "bf62d5402cb1c4580d219335a9af1ac831416edfbf2892391c8197a8356091f2",
|
|
73
|
+
"UP000000589_10090_MOUSE_v4" : "eb6c529c8757d511b75f4856c1a789378478e6255a442517ad8579708787bbab",
|
|
74
|
+
"mane_overlap_v4" : "c01e9b858c5415cfe2eae7e52a561aa8a872ba0d5d4891ba0cec327b3af49d69"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def assert_proteome_integrity(file_path, proteome):
|
|
79
|
+
|
|
80
|
+
if proteome in CHECKSUM.keys():
|
|
81
|
+
logger.debug('Asserting integrity of file..')
|
|
82
|
+
try:
|
|
83
|
+
if CHECKSUM[proteome] == calculate_hash(file_path):
|
|
84
|
+
logger.debug('File integrity check: PASS')
|
|
85
|
+
return "PASS"
|
|
86
|
+
else:
|
|
87
|
+
logger.debug('File integrity check: FAIL')
|
|
88
|
+
return "FAIL"
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.debug('File integrity check: FAIL')
|
|
91
|
+
logger.debug(f'Error: {e}')
|
|
92
|
+
return "FAIL"
|
|
93
|
+
else:
|
|
94
|
+
logger.warning("Assertion skipped: Proteome checksum not in records.")
|
|
95
|
+
return "PASS"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def calculate_hash(filepath: str, hash_func=hashlib.sha256) -> str:
|
|
99
|
+
"""
|
|
100
|
+
Calculate the hash of a file using the specified hash function.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
filepath (str): The path to the file for which to calculate the hash.
|
|
104
|
+
hash_func (hashlib.Hash): The hash function to use (default is hashlib.sha256).
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
str: The hexadecimal representation of the calculated hash.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
with open(filepath, 'rb') as file:
|
|
111
|
+
hash_obj = hash_func()
|
|
112
|
+
for chunk in iter(lambda: file.read(8192), b''):
|
|
113
|
+
hash_obj.update(chunk)
|
|
114
|
+
return hash_obj.hexdigest()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def download_single_file(url: str, destination: str, threads: int, proteome=None) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Downloads a file from a URL and saves it to the specified destination.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
url (str): The URL of the file to download.
|
|
123
|
+
destination (str): The local path where the file will be saved.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
num_connections = 15 if threads > 40 else threads
|
|
127
|
+
|
|
128
|
+
if os.path.exists(destination):
|
|
129
|
+
logger.debug(f"File {destination} already exists..")
|
|
130
|
+
if proteome is not None:
|
|
131
|
+
status = assert_proteome_integrity(destination, proteome)
|
|
132
|
+
if status == "PASS":
|
|
133
|
+
logger.debug(f"File {destination} already exists: Skipping download..")
|
|
134
|
+
return None
|
|
135
|
+
else:
|
|
136
|
+
logger.debug(f"File {destination} already exists but failed integrity check: Retrying download..")
|
|
137
|
+
|
|
138
|
+
logger.debug(f'Downloading {url}')
|
|
139
|
+
logger.debug(f"Downloading to {destination}")
|
|
140
|
+
dl = Downloader(timeout=aiohttp.ClientTimeout(sock_read=400), ssl=False)
|
|
141
|
+
dl.start(url, destination, segments=num_connections, display=True, retries=10, clear_terminal=False)
|
|
142
|
+
logger.debug('Download complete')
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def extract_tar_file(file_path, path):
|
|
146
|
+
|
|
147
|
+
checkpoint = os.path.join(path, ".tar_checkpoint.txt")
|
|
148
|
+
|
|
149
|
+
if os.path.exists(checkpoint):
|
|
150
|
+
logger.debug('Tar already extracted: Skipping..')
|
|
151
|
+
else:
|
|
152
|
+
with tarfile.open(file_path, "r") as tar:
|
|
153
|
+
tar.extractall(path)
|
|
154
|
+
logger.debug(f'Extracted { int(len(tar.getnames())/2)} structure.')
|
|
155
|
+
with open(checkpoint, "w") as f:
|
|
156
|
+
f.write('')
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def extract_zip_file(file_path, path):
|
|
160
|
+
checkpoint = os.path.join(path, ".zip_checkpoint.txt")
|
|
161
|
+
|
|
162
|
+
if os.path.exists(checkpoint):
|
|
163
|
+
logger.debug('ZIP file already extracted: Skipping..')
|
|
164
|
+
else:
|
|
165
|
+
with ZipFile(file_path, "r") as zip_file:
|
|
166
|
+
zip_file.extractall(path)
|
|
167
|
+
logger.debug(f'Extracted {len(zip_file.namelist())} files.')
|
|
168
|
+
with open(checkpoint, "w") as f:
|
|
169
|
+
f.write('')
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# PDB
|
|
173
|
+
|
|
174
|
+
def get_af_id_from_pdb(path_structure):
|
|
175
|
+
"""
|
|
176
|
+
Get AlphaFold 2 identifier (UniprotID_F) from path
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
return path_structure.split("AF-")[1].split("-model")[0]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def get_seq_from_pdb(path_structure):
|
|
183
|
+
"""
|
|
184
|
+
Get sequense of amino acid residues from PDB structure.
|
|
185
|
+
"""
|
|
186
|
+
if path_structure.endswith("gz"):
|
|
187
|
+
with gzip.open(path_structure, 'rt') as handle:
|
|
188
|
+
return np.array([record.seq for record in SeqIO.parse(handle, 'pdb-seqres')][0])
|
|
189
|
+
else:
|
|
190
|
+
with open(path_structure, 'r') as handle:
|
|
191
|
+
return np.array([record.seq for record in SeqIO.parse(handle, 'pdb-seqres')][0])
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def get_pdb_path_list_from_dir(path_dir):
|
|
195
|
+
"""
|
|
196
|
+
Takes as input a path of a given directory and it
|
|
197
|
+
outputs a list of paths of the contained PDB files.
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
pdb_files = os.listdir(path_dir)
|
|
201
|
+
pdb_path_list = [f"{os.path.join(path_dir, f)}" for f in pdb_files if ".pdb" in f and not os.path.isdir(os.path.join(path_dir, f))]
|
|
202
|
+
return pdb_path_list
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# Uniprot ID to Hugo symbols mapping
|
|
206
|
+
|
|
207
|
+
def split_lst_into_chunks(lst, batch_size = 5000):
|
|
208
|
+
"""
|
|
209
|
+
Simple split a list into list of list of chunk_size elements.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
return [lst[i:i+batch_size] for i in range(0, len(lst), batch_size)]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def convert_dict_hugo_to_uniprot(dict_uniprot_hugo):
|
|
216
|
+
"""
|
|
217
|
+
Convert a Uniprot IDs to Hugo symbol dictionary to a Hugo symbo to
|
|
218
|
+
Uniprot IDs dictionary, if multiple Hugo symbols are mapped to the
|
|
219
|
+
same Uniprot ID, add them as multiple keys.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
dict_hugo_uniprot = {}
|
|
223
|
+
|
|
224
|
+
for uni_id, gene in dict_uniprot_hugo.items():
|
|
225
|
+
if type(gene) == str:
|
|
226
|
+
for g in gene.split(" "):
|
|
227
|
+
dict_hugo_uniprot[g] = uni_id
|
|
228
|
+
|
|
229
|
+
return dict_hugo_uniprot
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def uniprot_to_hudo_df(uniprot_ids):
|
|
233
|
+
"""
|
|
234
|
+
Given a list of Uniprot IDs (from any species), request an Id
|
|
235
|
+
mapping job to UniprotKB to retrieve the corresponding Hugo
|
|
236
|
+
symbols and additional protein info. Return a pandas dataframe.
|
|
237
|
+
It is recommended to provide batches of IDs up to 5000 elements.
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
job_id = get_mapping_jobid(uniprot_ids)
|
|
241
|
+
url = f"https://rest.uniprot.org/idmapping/uniprotkb/results/stream/{job_id}?compressed=true&fields=accession%2Cid%2Cprotein_name%2Cgene_names%2Corganism_name%2Clength&format=tsv"
|
|
242
|
+
df = load_df_from_url(url)
|
|
243
|
+
|
|
244
|
+
i = 60
|
|
245
|
+
while df is None:
|
|
246
|
+
time.sleep(1)
|
|
247
|
+
df = load_df_from_url(url)
|
|
248
|
+
if i % 180 == 0:
|
|
249
|
+
logger.debug("Waiting for UniprotKB mapping job to produce url..")
|
|
250
|
+
i += 1
|
|
251
|
+
|
|
252
|
+
return df
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def load_df_from_url(url):
|
|
256
|
+
"""
|
|
257
|
+
Load a pandas dataframe from url.
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
response = requests.get(url, timeout=(160, 160))
|
|
262
|
+
decompressed_data = gzip.decompress(response.content)
|
|
263
|
+
df = pd.read_csv(io.BytesIO(decompressed_data), sep='\t')
|
|
264
|
+
except:
|
|
265
|
+
df = None
|
|
266
|
+
|
|
267
|
+
return df
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def get_response_jobid(response):
|
|
271
|
+
"""
|
|
272
|
+
Get jobId after submitting ID Mapping job to UniprotKB.
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
try:
|
|
276
|
+
data = response.json()
|
|
277
|
+
job_id = data.get("jobId")
|
|
278
|
+
except:
|
|
279
|
+
job_id = None
|
|
280
|
+
|
|
281
|
+
return job_id
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def get_mapping_jobid(uniprot_ids):
|
|
285
|
+
"""
|
|
286
|
+
Submit an ID Mapping job to UniprotKB.
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
command = f"https://rest.uniprot.org/idmapping/run?from=UniProtKB_AC-ID&to=UniProtKB&ids={','.join(uniprot_ids)}"
|
|
290
|
+
|
|
291
|
+
response = "INIT"
|
|
292
|
+
while str(response) != "<Response [200]>":
|
|
293
|
+
if response != "INIT":
|
|
294
|
+
time.sleep(10)
|
|
295
|
+
try:
|
|
296
|
+
response = requests.post(command)
|
|
297
|
+
except requests.exceptions.RequestException as e:
|
|
298
|
+
response = "ERROR"
|
|
299
|
+
logger.debug(f"Request failed {e}: Retrying")
|
|
300
|
+
|
|
301
|
+
job_id = get_response_jobid(response)
|
|
302
|
+
i = 60
|
|
303
|
+
while job_id is None:
|
|
304
|
+
time.sleep(1)
|
|
305
|
+
job_id = get_response_jobid(response)
|
|
306
|
+
if i % 60 == 0:
|
|
307
|
+
logger.debug("Requesting ID mapping job to UniprotKB for IDs..")
|
|
308
|
+
i += 1
|
|
309
|
+
|
|
310
|
+
return job_id
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def uniprot_to_hugo(uniprot_ids, hugo_as_keys=False, batch_size=5000):
|
|
314
|
+
"""
|
|
315
|
+
Given a list of Uniprot IDs (any species.), request an Id mapping
|
|
316
|
+
job to UniprotKB to retrieve the corresponding Hugo symbols.
|
|
317
|
+
Return a dictionary of Uniprot IDs to Hugo symbols or vice versa.
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
# Split uniprot IDs into chunks
|
|
321
|
+
uniprot_ids_lst = split_lst_into_chunks(uniprot_ids, batch_size)
|
|
322
|
+
|
|
323
|
+
# Get a dataframe including all IDs mapping info
|
|
324
|
+
df_lst = []
|
|
325
|
+
for i, ids in enumerate(uniprot_ids_lst):
|
|
326
|
+
logger.debug(f"Batch {i+1}/{len(uniprot_ids_lst)} ({len(ids)} IDs)..")
|
|
327
|
+
df = uniprot_to_hudo_df(ids)
|
|
328
|
+
df_lst.append(df)
|
|
329
|
+
df = pd.concat(df_lst)
|
|
330
|
+
|
|
331
|
+
# Get a dictionary for Uniprot ID to Hugo symbols
|
|
332
|
+
dictio = {}
|
|
333
|
+
for i, r in df[["Entry", "Gene Names"]].iterrows():
|
|
334
|
+
uni_id, gene = r
|
|
335
|
+
dictio[uni_id] = gene
|
|
336
|
+
|
|
337
|
+
# Convert to a dictionary of Hugo symbols to Uniprot IDs
|
|
338
|
+
if hugo_as_keys:
|
|
339
|
+
dictio = convert_dict_hugo_to_uniprot(dictio)
|
|
340
|
+
|
|
341
|
+
return dictio
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
# def uniprot_to_hugo_pressed(uniprot_ids, hugo_as_keys=False, batch_size=5000, max_attempts=15):
|
|
345
|
+
# """
|
|
346
|
+
# Given a list of Uniprot IDs (any species.), return a
|
|
347
|
+
# dictionary of Uniprot IDs to Hugo symbols or vice versa.
|
|
348
|
+
# """
|
|
349
|
+
|
|
350
|
+
# # Split uniprot IDs into chunks
|
|
351
|
+
# uniprot_ids_lst = split_lst_into_chunks(uniprot_ids, batch_size)
|
|
352
|
+
|
|
353
|
+
# # Get a dataframe including all IDs mapping info
|
|
354
|
+
# result_lst = []
|
|
355
|
+
|
|
356
|
+
# for i, ids in enumerate(uniprot_ids_lst):
|
|
357
|
+
# logger.debug(f"Batch {i+1}/{len(uniprot_ids_lst)} ({len(ids)} IDs)..")
|
|
358
|
+
# status = "INIT"
|
|
359
|
+
|
|
360
|
+
# n = 0
|
|
361
|
+
# while status != "FINISHED":
|
|
362
|
+
# try:
|
|
363
|
+
# request = IdMappingClient.submit(source="UniProtKB_AC-ID",
|
|
364
|
+
# dest="Gene_Name",
|
|
365
|
+
# ids={uni_id for uni_id in ids})
|
|
366
|
+
# j = 0
|
|
367
|
+
# while status != "FINISHED":
|
|
368
|
+
# time.sleep(15)
|
|
369
|
+
# status = request.get_status()
|
|
370
|
+
# if status == "FINISHED":
|
|
371
|
+
# result_lst.append(list(request.each_result()))
|
|
372
|
+
# else:
|
|
373
|
+
# logger.debug(f"Waiting for UniprotKB to process the job..")
|
|
374
|
+
# j += 1
|
|
375
|
+
# if j == max_attempts:
|
|
376
|
+
# logger.debug(f"Failed to obtain Uniprot ID to Hugo Symbol mapping: Retrying..")
|
|
377
|
+
# sys.exit()
|
|
378
|
+
# except Exception as e:
|
|
379
|
+
# n += 1
|
|
380
|
+
# if n == max_attempts:
|
|
381
|
+
# logger.error(f"Failed to obtain Uniprot ID to Hugo Symbol mapping and reached maximum attempts: Exiting..")
|
|
382
|
+
# sys.exit()
|
|
383
|
+
# else:
|
|
384
|
+
# status = "ERROR"
|
|
385
|
+
# logger.debug(f"Error while obtaining Uniprot ID to Hugo Symbol mapping {e}: Retrying..")
|
|
386
|
+
|
|
387
|
+
# result_lst = [entry for batch in result_lst for entry in batch]
|
|
388
|
+
# result_dict = {r["from"] : (r["to"].split()[0] if len(r["to"].split()) > 1 else r["to"]) for r in result_lst}
|
|
389
|
+
|
|
390
|
+
# # Convert to a dictionary of Hugo symbols to Uniprot IDs
|
|
391
|
+
# if hugo_as_keys:
|
|
392
|
+
# result_dict = convert_dict_hugo_to_uniprot(result_dict)
|
|
393
|
+
|
|
394
|
+
# return result_dict
|
scripts/globals.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
import daiquiri
|
|
4
|
+
import click
|
|
5
|
+
import shutil
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
from functools import wraps
|
|
9
|
+
|
|
10
|
+
from scripts import __logger_name__
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
logger = daiquiri.getLogger(__logger_name__)
|
|
14
|
+
|
|
15
|
+
DATE = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
16
|
+
FORMAT = "%(asctime)s - %(color)s%(levelname)-7s%(color_stop)s | %(name)s - %(color)s%(message)s%(color_stop)s"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# =========
|
|
20
|
+
# Logging
|
|
21
|
+
# =========
|
|
22
|
+
|
|
23
|
+
def setup_logging_decorator(func):
|
|
24
|
+
@wraps(func)
|
|
25
|
+
def wrapper(*args, **kwargs):
|
|
26
|
+
log_dir = os.path.join(click.get_current_context().params['output_dir'], 'log')
|
|
27
|
+
command_name = click.get_current_context().command.name
|
|
28
|
+
|
|
29
|
+
if command_name in ['run', 'plot', 'chimerax_plot', 'chimerax-plot']:
|
|
30
|
+
cohort = click.get_current_context().params["cohort"]
|
|
31
|
+
fname = f'{command_name}_{cohort if cohort != "None" else ""}_{DATE}.log'
|
|
32
|
+
else:
|
|
33
|
+
fname = f"{command_name}_{DATE}.log"
|
|
34
|
+
|
|
35
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
36
|
+
|
|
37
|
+
level = logging.DEBUG if click.get_current_context().params['verbose'] else logging.INFO
|
|
38
|
+
|
|
39
|
+
formatter = daiquiri.formatter.ColorFormatter(fmt=FORMAT)
|
|
40
|
+
|
|
41
|
+
daiquiri.setup(level=level, outputs=(
|
|
42
|
+
daiquiri.output.Stream(formatter=formatter),
|
|
43
|
+
daiquiri.output.File(filename=os.path.join(log_dir, fname), formatter=formatter)
|
|
44
|
+
))
|
|
45
|
+
|
|
46
|
+
return func(*args, **kwargs)
|
|
47
|
+
|
|
48
|
+
return wrapper
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def startup_message(version, initializing_text):
|
|
52
|
+
|
|
53
|
+
author = "Biomedical Genomics Lab - IRB Barcelona"
|
|
54
|
+
support_email = "stefano.pellegrini@irbbarcelona.org"
|
|
55
|
+
banner_width = 70
|
|
56
|
+
|
|
57
|
+
logger.info("#" * banner_width)
|
|
58
|
+
logger.info(f"{'#' + ' ' * (banner_width - 2) + '#'}")
|
|
59
|
+
logger.info(f"{'#' + f'Welcome to Oncodrive3D!'.center(banner_width - 2) + '#'}")
|
|
60
|
+
logger.info(f"{'#' + ' ' * (banner_width - 2) + '#'}")
|
|
61
|
+
logger.info(f"{'#' + initializing_text.center(banner_width - 2) + '#'}")
|
|
62
|
+
logger.info(f"{'#' + ' ' * (banner_width - 2) + '#'}")
|
|
63
|
+
logger.info(f"{'#' + f'Version: {version}'.center(banner_width - 2) + '#'}")
|
|
64
|
+
logger.info(f"{'#' + f'Author: {author}'.center(banner_width - 2) + '#'}")
|
|
65
|
+
logger.info(f"{'#' + f'Support: {support_email}'.center(banner_width - 2) + '#'}")
|
|
66
|
+
logger.info(f"{'#' + ' ' * (banner_width - 2) + '#'}")
|
|
67
|
+
logger.info("#" * banner_width)
|
|
68
|
+
logger.info("")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ===================
|
|
72
|
+
# Clean and organize
|
|
73
|
+
# ===================
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def copy_dir(source_dir, destination_dir):
|
|
77
|
+
"""
|
|
78
|
+
Ccopy the entire directory.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
logger.debug("Copying directory..")
|
|
82
|
+
logger.debug(f"From {source_dir}")
|
|
83
|
+
logger.debug(f"To {destination_dir}")
|
|
84
|
+
|
|
85
|
+
if os.path.exists(source_dir):
|
|
86
|
+
if os.path.isdir(source_dir):
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
shutil.copytree(source_dir, destination_dir)
|
|
90
|
+
logger.debug("Directory copied successfully!")
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.warning(f"An error occurred ({e}): Skipping")
|
|
93
|
+
|
|
94
|
+
else:
|
|
95
|
+
logger.warning("Error while copying directory (source path is not a directory): Skipping")
|
|
96
|
+
else:
|
|
97
|
+
logger.warning("Error while copying directory (source path does not exist): Skipping")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def rm_dir(dir_path): # TO DO: Probably, if the directory is not empty, it should ask for confirmation
|
|
101
|
+
"""
|
|
102
|
+
Remove directory.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
if os.path.isdir(dir_path):
|
|
106
|
+
shutil.rmtree(dir_path, ignore_errors=True)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def rm_files(dir_path, ext=[".cif.gz", ".cif"]) -> None:
|
|
110
|
+
"""
|
|
111
|
+
Remove any file with a given extension in a given directory.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
for file in os.listdir(dir_path):
|
|
115
|
+
file_path = os.path.join(dir_path, file)
|
|
116
|
+
if any([file.endswith(ext_i) for ext_i in ext]):
|
|
117
|
+
os.remove(file_path)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def clean_directory(path: str, loc: str) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Clean a directory by removing specific files and subdirectories.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
if loc == "d":
|
|
126
|
+
logger.debug(f"Cleaning {path}")
|
|
127
|
+
rm_files(path, ext=[".tsv", ".csv", ".json", ".txt", ".txt.gz"])
|
|
128
|
+
dirs = "pae", "pdb_structures", "pdb_structures_mane", "prob_cmaps"
|
|
129
|
+
path_dirs = [os.path.join(path, d) for d in dirs]
|
|
130
|
+
for path in path_dirs:
|
|
131
|
+
rm_dir(path)
|
|
132
|
+
|
|
133
|
+
elif loc == "r":
|
|
134
|
+
# TODO: implement cleaning function for output
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def clean_dir(path: str, loc: str = 'd', txt_file=False) -> None:
|
|
139
|
+
"""
|
|
140
|
+
Clean it upon request if it already exists.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
if os.listdir(path) != ['log']:
|
|
144
|
+
logger.warning(f"Directory {path} already exists and is not empty.")
|
|
145
|
+
|
|
146
|
+
overwrite = "y" if click.get_current_context().params['yes'] else input("Clean existing directory? (y/n): ")
|
|
147
|
+
while overwrite.lower() not in ["y", "yes", "n", "no"]:
|
|
148
|
+
print("Please choose yes or no")
|
|
149
|
+
overwrite = input("Clean existing directory? (y/n): ")
|
|
150
|
+
|
|
151
|
+
if overwrite.lower() in ["y", "yes"]:
|
|
152
|
+
clean_directory(path, loc)
|
|
153
|
+
logger.info(f"Dataset files in {path} have been removed.")
|
|
154
|
+
else:
|
|
155
|
+
logger.warning(f"Dataset files in {path} have not been removed.")
|
|
156
|
+
else:
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def clean_temp_files(path: str) -> None:
|
|
161
|
+
"""
|
|
162
|
+
Clean temp files from dir after completing building the datasets.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
pdb_dir = os.path.join(path, "pdb_structures")
|
|
166
|
+
rm_files(pdb_dir, ext=[".cif.gz", ".cif", ".tar"])
|
|
167
|
+
rm_files(os.path.join(path, "pae"), ext=[".json"])
|
|
168
|
+
rm_dir(os.path.join(path, "pdb_structures_mane"))
|
|
169
|
+
rm_dir(os.path.join(pdb_dir, "fragmented_pdbs"))
|