seed2lp 2.0.0__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.
Files changed (53) hide show
  1. seed2lp/__init__.py +12 -0
  2. seed2lp/__main__.py +837 -0
  3. seed2lp/_version.py +2 -0
  4. seed2lp/argument.py +717 -0
  5. seed2lp/asp/atom_for_transfers.lp +7 -0
  6. seed2lp/asp/community_heuristic.lp +3 -0
  7. seed2lp/asp/community_search.lp +14 -0
  8. seed2lp/asp/constraints_targets.lp +15 -0
  9. seed2lp/asp/definition_atoms.lp +87 -0
  10. seed2lp/asp/enum-cc.lp +50 -0
  11. seed2lp/asp/flux.lp +70 -0
  12. seed2lp/asp/limit_transfers.lp +9 -0
  13. seed2lp/asp/maximize_flux.lp +2 -0
  14. seed2lp/asp/maximize_produced_target.lp +7 -0
  15. seed2lp/asp/minimize.lp +8 -0
  16. seed2lp/asp/seed-solving.lp +116 -0
  17. seed2lp/asp/seed_external.lp +1 -0
  18. seed2lp/asp/show_seeds.lp +2 -0
  19. seed2lp/asp/show_tranfers.lp +1 -0
  20. seed2lp/asp/test.lp +61 -0
  21. seed2lp/clingo_lpx.py +236 -0
  22. seed2lp/color.py +34 -0
  23. seed2lp/config.yaml +56 -0
  24. seed2lp/description.py +424 -0
  25. seed2lp/file.py +151 -0
  26. seed2lp/flux.py +365 -0
  27. seed2lp/linear.py +431 -0
  28. seed2lp/log_conf.yaml +25 -0
  29. seed2lp/logger.py +112 -0
  30. seed2lp/metabolite.py +46 -0
  31. seed2lp/network.py +1921 -0
  32. seed2lp/reaction.py +207 -0
  33. seed2lp/reasoning.py +459 -0
  34. seed2lp/reasoningcom.py +753 -0
  35. seed2lp/reasoninghybrid.py +791 -0
  36. seed2lp/resmod.py +74 -0
  37. seed2lp/sbml.py +307 -0
  38. seed2lp/scope.py +124 -0
  39. seed2lp/solver.py +333 -0
  40. seed2lp/temp_flux_com.py +74 -0
  41. seed2lp/utils.py +237 -0
  42. seed2lp-2.0.0.dist-info/METADATA +404 -0
  43. seed2lp-2.0.0.dist-info/RECORD +53 -0
  44. seed2lp-2.0.0.dist-info/WHEEL +5 -0
  45. seed2lp-2.0.0.dist-info/entry_points.txt +2 -0
  46. seed2lp-2.0.0.dist-info/licenses/LICENCE.txt +145 -0
  47. seed2lp-2.0.0.dist-info/top_level.txt +2 -0
  48. tests/__init__.py +0 -0
  49. tests/fba.py +147 -0
  50. tests/full_network.py +166 -0
  51. tests/normalization.py +188 -0
  52. tests/target.py +286 -0
  53. tests/utils.py +181 -0
seed2lp/description.py ADDED
@@ -0,0 +1,424 @@
1
+ # Object Description, herit from Network, added properties:
2
+ # - file (str): Path of input network file (sbml)
3
+ # - out_dir (str): Output directory
4
+ # - details (bool): Reaction Details performed if True.
5
+
6
+ import pandas as pd
7
+ import re
8
+ from os import path
9
+ from seed2lp.network import Network
10
+ from . import flux, logger, color
11
+ import warnings
12
+ import difflib
13
+ import seed2lp.sbml as SBML
14
+ import copy
15
+
16
+
17
+ SRC_DIR = path.dirname(path.abspath(__file__))
18
+ ASP_SRC_ENUM_CC = path.join(SRC_DIR, 'asp/enum-cc.lp')
19
+
20
+ BISEAU_VIZ = """
21
+ #defined reactant/4.
22
+ #defined product/4.
23
+ #defined reaction/1.
24
+ link(T,R) :- reactant(T,_,R,_).
25
+ link(R,P) :- product(P,_,R,_).
26
+ shape(R,rectangle) :- reaction(R).
27
+ obj_property(edge,arrowhead,vee).
28
+ """
29
+ BISEAU_VIZ_NOREACTION = """
30
+ link(M,P) :- product(P,_,R,_) ; reactant(M,_,R,_).
31
+ link(P,P) :- product(P,_,R,_) ; not reactant(_,_,R,_).
32
+ link(M,M) :- reactant(M,_,R,_), not product(_,_,R,_).
33
+ obj_property(edge,arrowhead,vee).
34
+ """
35
+
36
+
37
+
38
+ class Description(Network):
39
+ def __init__(self, file:str, keep_import_reactions:bool, out_dir:str,
40
+ details:bool=False, visu:bool=False, visu_no_reaction:bool=False,
41
+ write_file:bool=False):
42
+ """Initialize Object Description, herit from Network
43
+
44
+ Args:
45
+ file (str): Path of input network file (sbml)
46
+ keep_import_reactions (bool): Import reactions are not removed
47
+ out_dir (str): Output directory
48
+ details (bool, optional): Reaction Details performed if True. Defaults to False.
49
+ visu (bool, optional): Graph of Network performed if True. Defaults to False.
50
+ visu_no_reaction (bool, optional): Graph of Network without the reaction performed if True. Defaults to False.
51
+ write_file (bool, optional): Write corrected network into SBML file if True. Defaults to False.
52
+ """
53
+ super().__init__(file, keep_import_reactions=keep_import_reactions, write_sbml=write_file)
54
+ self.out_dir = out_dir
55
+ self.details = details
56
+ self.visu = visu
57
+ self.visu_no_reaction = visu_no_reaction
58
+ self.write_file = write_file
59
+ self.convert_to_facts()
60
+ if self.keep_import_reactions:
61
+ self.short_option="import_rxn"
62
+ else:
63
+ self.short_option="rm_rxn"
64
+ self.cobra_details=""
65
+ self.lp_details=""
66
+
67
+
68
+ ######################## METHODS ########################
69
+ def get_details(self):
70
+ """Reconstruct reaction details from asp facts
71
+ Describe the reaction formula and boundaries
72
+ """
73
+
74
+ print(f"\n\n{color.cyan_dark}############################################")
75
+ print("############################################")
76
+ print(" DETAILS ")
77
+ print("############################################")
78
+ print(f"############################################\n{color.reset}")
79
+
80
+ print(f"\n{color.purple}____________________________________________{color.reset}")
81
+ print("\n LP FACTS ")
82
+ print(f"{color.purple}____________________________________________\n{color.reset}")
83
+ print("Getting details from lp facts ...\n")
84
+ self.details_from_lp()
85
+ print(" ---> done\n")
86
+
87
+ print(f"\n{color.purple}____________________________________________{color.reset}")
88
+ print("\n COBRA ")
89
+ print(f"{color.purple}____________________________________________\n{color.reset}")
90
+ print("Getting details from cobra ...\n")
91
+ self.details_from_cobra()
92
+ print(" ---> done\n")
93
+
94
+ print(f"\n{color.purple}____________________________________________{color.reset}")
95
+ print("\n DIFF ")
96
+ print(f"{color.purple}____________________________________________\n{color.reset}")
97
+ print("Searching diff ...\n")
98
+ self.details_diff()
99
+ print(" ---> done\n")
100
+
101
+
102
+ def details_from_lp(self):
103
+ """Get the network description from lp facts and save it
104
+ """
105
+ logger.log.info("Start Getting Details from LP file")
106
+ reactions_composition_df = pd.DataFrame(columns=['reaction', 'metabolite', 'type_metabolite', 'stoichiometry'])
107
+ reaction_df = pd.DataFrame(columns=['reaction', 'low_bound', 'up_bound','is_forward', 'is_reverse', 'is_low_set'])
108
+ only_forward=list()
109
+ full_details=""
110
+ lis_obj=list()
111
+
112
+ lines=re.split("\n", self.facts)
113
+ # Getting the network and the reaction direction
114
+ for line in lines:
115
+ if re.search("reaction",line):
116
+ reaction = re.split("\"", line)[1]
117
+ if "rev_" in reaction:
118
+ reaction = re.split("rev_R_", reaction)[1]
119
+ df=pd.DataFrame(data=[[reaction, 0.0, 0.0, False, True, False]],columns=['reaction', 'low_bound', 'up_bound','is_forward', 'is_reverse', 'is_low_set'])
120
+ reaction_df=pd.concat([reaction_df,df], ignore_index = True)
121
+ else:
122
+ reaction = re.split("R_", reaction)[1]
123
+ try:
124
+ index=reaction_df[reaction_df["reaction"]==reaction].index[0]
125
+ reaction_df.at[index,'is_forward']=True
126
+ except Exception:
127
+ only_forward.append(f"R_{reaction}")
128
+ df=pd.DataFrame(data=[[reaction, 0.0, 0.0, True, False, False]],columns=['reaction', 'low_bound', 'up_bound','is_forward', 'is_reverse', 'is_low_set'])
129
+ reaction_df=pd.concat([reaction_df,df], ignore_index = True)
130
+ elif re.search("bounds",line):
131
+ split_line = re.split(",", line)
132
+ reaction=re.split("\"", split_line[0])[1]
133
+ lower=re.split("\"", split_line[1])[1]
134
+ lower=float(lower)
135
+ upper=re.split("\"", split_line[2])[1]
136
+ upper=float(upper)
137
+ if "rev_" in reaction:
138
+ reaction = re.split("rev_R_", reaction)[1]
139
+ try:
140
+ index=reaction_df[reaction_df["reaction"]==reaction].index[0]
141
+ reaction_df.at[index,'low_bound'] = -upper
142
+ reaction_df.at[index,'is_low_set'] = True
143
+ except Exception:
144
+ df=pd.DataFrame(data=[[reaction, -upper, 0.0, False, True, True]],columns=['reaction', 'low_bound', 'up_bound','is_forward', 'is_reverse', 'is_low_set'])
145
+ reaction_df=pd.concat([reaction_df,df], ignore_index = True)
146
+ reaction_df.at[index,'is_low_set'] = True
147
+ else:
148
+ reaction = re.split("R_", reaction)[1]
149
+ try:
150
+ index=reaction_df[reaction_df["reaction"]==reaction].index[0]
151
+ reaction_df.at[index,'up_bound'] = upper
152
+ if not reaction_df.at[index,'is_low_set']:
153
+ reaction_df.at[index,'low_bound'] = lower
154
+ reaction_df.at[index,'is_low_set'] = True
155
+ except Exception:
156
+ only_forward.append(f"R_{reaction}")
157
+ df=pd.DataFrame(data=[[reaction, lower, upper, True, False, True]],columns=['reaction', 'low_bound', 'up_bound','is_forward', 'is_reverse', 'is_low_set'])
158
+ reaction_df=pd.concat([reaction_df,df], ignore_index = True)
159
+ elif re.search("reactant",line):
160
+ split_line = re.split(",", line)
161
+ reaction=re.split("\"", split_line[2])[1]
162
+ metabolite = re.split("\"", split_line[0])[1]
163
+ stoichiometry=round(float(re.split("\"", split_line[1])[1]),6)
164
+ if "rev_" in reaction:
165
+ reaction = re.split("rev_R_", reaction)[1]
166
+ df=pd.DataFrame(data=[[reaction, metabolite, "product", stoichiometry]],
167
+ columns=['reaction', 'metabolite', 'type_metabolite', 'stoichiometry'])
168
+ reactions_composition_df=pd.concat([reactions_composition_df,df], ignore_index = True)
169
+ elif reaction in only_forward:
170
+ reaction = re.split("R_", reaction)[1]
171
+ df=pd.DataFrame(data=[[reaction, metabolite, "reactant", stoichiometry]],
172
+ columns=['reaction', 'metabolite', 'type_metabolite', 'stoichiometry'])
173
+ reactions_composition_df=pd.concat([reactions_composition_df,df], ignore_index = True)
174
+ elif re.search("product",line):
175
+ split_line = re.split(",", line)
176
+ reaction=re.split("\"", split_line[2])[1]
177
+ metabolite = re.split("\"", split_line[0])[1]
178
+ stoichiometry=round(float(re.split("\"", split_line[1])[1]),6)
179
+ if "rev_" in reaction:
180
+ reaction = re.split("rev_R_", reaction)[1]
181
+ df=pd.DataFrame(data=[[reaction, metabolite, "reactant", stoichiometry]],
182
+ columns=['reaction', 'metabolite', 'type_metabolite', 'stoichiometry'])
183
+ reactions_composition_df=pd.concat([reactions_composition_df,df], ignore_index = True)
184
+ elif reaction in only_forward:
185
+ reaction = re.split("R_", reaction)[1]
186
+ df=pd.DataFrame(data=[[reaction, metabolite, "product", stoichiometry]],
187
+ columns=['reaction', 'metabolite', 'type_metabolite', 'stoichiometry'])
188
+ reactions_composition_df=pd.concat([reactions_composition_df,df], ignore_index = True)
189
+ reaction_df.sort_values(by=['reaction'])
190
+ reactions_composition_df.sort_values(by=['reaction', 'metabolite'])
191
+ self.objectives = lis_obj
192
+
193
+ #reaction_without_reactant=[]
194
+ #reaction_without_product=[]
195
+ # Writting the network description
196
+ for _,row in reaction_df.iterrows():
197
+ reaction=row[0]
198
+ lower=row[1]
199
+ upper=row[2]
200
+ forward=row[3]
201
+ reverse=row[4]
202
+ symbol=""
203
+ compo_line=f'{reaction}:'
204
+ match ([forward, reverse]):
205
+ case [True, False]:
206
+ symbol=" -->"
207
+ if upper == 0:
208
+ symbol=" <--"
209
+ case [False, True]:
210
+ symbol=" <--"
211
+ if lower == 0:
212
+ symbol=" -->"
213
+ case [True, True]:
214
+ symbol=" <=>"
215
+ sub_reaction=reactions_composition_df[reactions_composition_df["reaction"]==reaction]
216
+ sub_reactant=sub_reaction[sub_reaction["type_metabolite"]=="reactant"]
217
+ sub_product=sub_reaction[sub_reaction["type_metabolite"]=="product"]
218
+ it=0
219
+ if sub_reactant.empty:
220
+ #reaction_without_reactant.append(reaction)
221
+ compo_line += " "
222
+ else:
223
+ for r_metabolite in sub_reactant.iterrows():
224
+ it += 1
225
+ if it!=1:
226
+ compo_line += " +"
227
+ stoic=""
228
+ if r_metabolite[1]["stoichiometry"] != 1.0:
229
+ stoic=f' {r_metabolite[1]["stoichiometry"]}'
230
+ compo_line += f'{stoic} {re.sub("^M_", "", r_metabolite[1]["metabolite"])}'
231
+ compo_line += symbol
232
+ it=0
233
+ if sub_product.empty:
234
+ #reaction_without_product.append(reaction)
235
+ compo_line += " "
236
+ else:
237
+ for p_metabolite in sub_product.iterrows():
238
+ it += 1
239
+ if it!=1:
240
+ compo_line += " +"
241
+ stoic=""
242
+ if p_metabolite[1]["stoichiometry"] != 1.0:
243
+ stoic=f' {p_metabolite[1]["stoichiometry"]}'
244
+ compo_line += f'{stoic} {re.sub("^M_", "", p_metabolite[1]["metabolite"])}'
245
+ compo_line += f'\t[{lower}, {upper}]'
246
+ #print(compo_line)
247
+ full_details += f'{compo_line}\n'
248
+
249
+ self.lp_details = path.join(self.out_dir, f"{self.name}_{self.short_option}_details_from_lp.txt")
250
+ #print("REACTION WITHOUT REACTANT")
251
+ #print(reaction_without_reactant)
252
+ #print("REACTION WITHOUT PRODUCT")
253
+ #print(reaction_without_product)
254
+ save(self.lp_details , full_details)
255
+
256
+
257
+ def details_from_cobra(self):
258
+ """Get the network description from sbml file by using cobra and save it
259
+ """
260
+ logger.log.info("Start Getting Details from Cobra file")
261
+ warnings.filterwarnings("error")
262
+ model = flux.get_model(self.file)
263
+ if not self.keep_import_reactions:
264
+ flux.stop_flux(model)
265
+ full_details=""
266
+ for reaction in model.reactions:
267
+ full_details += f"{reaction}\t[{reaction.lower_bound}, {reaction.upper_bound}]\n"
268
+
269
+ self.cobra_details = path.join(self.out_dir, f"{self.name}_{self.short_option}_details_from_cobra.txt")
270
+ save(self.cobra_details, full_details)
271
+
272
+
273
+ def details_diff(self):
274
+ """Compare the Network description from cobra and lp facts
275
+ save the diff information into file
276
+ """
277
+ logger.log.info("Start checking diff between Cobra and LP Network")
278
+ diff = ""
279
+ with open(self.cobra_details) as cobra_details:
280
+ cobra_details_text = cobra_details.readlines()
281
+
282
+ with open(self.lp_details) as lp_details:
283
+ lp_details_text = lp_details.readlines()
284
+
285
+ # Find the diff:
286
+ for line in difflib.unified_diff(
287
+ cobra_details_text, lp_details_text, fromfile=self.cobra_details,
288
+ tofile=self.lp_details, lineterm=''):
289
+ diff += f'{line}\n'
290
+
291
+ cobra_details.close()
292
+ lp_details.close()
293
+
294
+ diff_path = path.join(self.out_dir, f"{self.name}_{self.short_option}_details_diff.txt")
295
+ save(diff_path, diff)
296
+
297
+ def render_network(self):
298
+ """From lp facts render the network graph with or without reaction
299
+ """
300
+ import biseau
301
+ out_file = path.join(self.out_dir, f"{self.name}_{self.short_option}_visu")
302
+
303
+ print(f"\n\n{color.cyan_dark}############################################")
304
+ print("############################################")
305
+ print(" GRAPH ")
306
+ print("############################################")
307
+ print(f"############################################\n{color.reset}")
308
+ if self.visu:
309
+ print(f"\n{color.purple}____________________________________________{color.reset}")
310
+ print(f"\n GRAPH WITH REACTIONS ")
311
+ print(f"{color.purple}____________________________________________{color.reset}\n")
312
+ print("Generating graph ...\n")
313
+ viz = BISEAU_VIZ
314
+ out_file_visu = f"{out_file}.png"
315
+ try:
316
+ img_visu = biseau.compile_to_single_image(self.facts + viz, outfile=out_file_visu)
317
+ img_visu.close()
318
+ print(f'-> Input graph rendered in {out_file_visu}\n')
319
+ except KeyboardInterrupt:
320
+ print(f'-> Aborted! file :{out_file_visu}\n')
321
+ if self.visu_no_reaction:
322
+ print(f"\n{color.purple}____________________________________________{color.reset}")
323
+ print("\n GRAPH WITHOUT REACTIONS ")
324
+ print(f"{color.purple}____________________________________________\n{color.reset}")
325
+ print("Generating graph ...\n")
326
+ viz = BISEAU_VIZ_NOREACTION
327
+ out_file_visu_no_reaction = f"{out_file}_no_reactions.png"
328
+ try:
329
+ img_visu_no_reaction = biseau.compile_to_single_image(self.facts + viz, outfile=out_file_visu_no_reaction)
330
+ img_visu_no_reaction.close()
331
+ print(f'-> Input graph rendered in {out_file_visu_no_reaction}\n')
332
+ except KeyboardInterrupt:
333
+ print(f'-> Aborted! file :{out_file_visu_no_reaction}\n')
334
+
335
+
336
+ def rewrite_sbml_file(self):
337
+ """SBML file is written from corrected network
338
+ """
339
+ print(f"\n\n{color.cyan_dark}############################################")
340
+ print("############################################")
341
+ print(" WRITING SBML FILE ")
342
+ print("############################################")
343
+ print(f"############################################\n{color.reset}")
344
+
345
+ if self.keep_import_reactions:
346
+ logger.log.warning("IMPORT REACTION KEPT")
347
+ else:
348
+ logger.log.warning("IMPORT REACTION REMOVED BY DEFAULT")
349
+ logger.log.warning("If you want to keep import reaction\nuse option -kir / --keep-import-reactions")
350
+ species=self.name
351
+ original_reactions = SBML.get_listOfReactions(self.model[species])
352
+
353
+ # Need Two loop to remove first then two do modification
354
+ # If removing while looping, then the loop misses some reactions
355
+ # because the index of the reaction changes
356
+ rm_reac_message = "Reaction removed:"
357
+ modif_rev_message = "Reaction with tag reversible modified:"
358
+ switch_meta_message = "Reaction with Reactants and Products exchanged:"
359
+ rm_import_message = "Import reaction removed:"
360
+
361
+ is_modif_rev_log = False
362
+ is_switch_meta_log = False
363
+ is_rm_import_log = False
364
+ for reaction in original_reactions:
365
+ reaction_name = reaction.attrib.get("id")
366
+ if reaction_name in self.deleted_reactions:
367
+ self.sbml_remove_reaction(reaction, species)
368
+ rm_reac_message+=f"\n\t- {reaction_name}"
369
+ logger.log.info(rm_reac_message)
370
+ else:
371
+ # Change the reversibility
372
+ is_modif_rev = self.sbml_review_reversibilty(reaction_name, reaction)
373
+ is_modif_rev_log = is_modif_rev_log or is_modif_rev
374
+ if is_modif_rev:
375
+ modif_rev_message+=f"\n\t- {reaction_name}"
376
+
377
+ # switch reactants and products
378
+ is_switch_meta = self.sbml_switch_meta(reaction_name, reaction, species)
379
+ is_switch_meta_log = is_switch_meta_log or is_switch_meta
380
+ if is_switch_meta:
381
+ switch_meta_message+=f"\n\t- {reaction_name}"
382
+
383
+ # remove import reactions
384
+ if not self.keep_import_reactions:
385
+ is_rm_import = self.sbml_remove_import(reaction_name, reaction, species)
386
+ is_rm_import_log = is_rm_import_log or is_rm_import
387
+ if is_rm_import:
388
+ rm_import_message+=f"\n\t- {reaction_name}"
389
+
390
+ #print and log
391
+ if is_modif_rev_log:
392
+ logger.log.warning(modif_rev_message)
393
+ if is_switch_meta_log:
394
+ logger.log.warning(switch_meta_message)
395
+ if is_rm_import_log:
396
+ logger.log.warning(rm_import_message)
397
+
398
+ # Replace list of parameters because we added new specific parameters for the exchange reactions
399
+ self.sbml_review_parameters(species)
400
+
401
+
402
+ def_ns=self.default_namespace.split("=")
403
+ self.sbml[species].set(def_ns[0], def_ns[1].replace('"',''))
404
+
405
+ file_path = path.join(self.out_dir, self.name+".xml")
406
+ str_model = self.sbml_first_line+SBML.etree_to_string(self.sbml[species])
407
+ print(f"File saved at: {file_path}")
408
+ save(file_path, str_model)
409
+
410
+ ########################################################
411
+
412
+
413
+ ######################## FUNCTIONS ########################
414
+ def save(out_file:str, data):
415
+ """Save file of Network description or graphs
416
+
417
+ Args:
418
+ out_file (str): Output file path
419
+ data: Graph or Network details data
420
+ """
421
+ with open(out_file, 'w') as f:
422
+ f.write(data)
423
+ f.close()
424
+ logger.log.info(f"File saved at: {out_file}")
seed2lp/file.py ADDED
@@ -0,0 +1,151 @@
1
+ from os import path, makedirs, stat, remove
2
+ from json import dump, load
3
+ from csv import writer, reader
4
+ from . import logger
5
+
6
+
7
+ def existant_path(inpath:str) -> str:
8
+ """Argparse type, raising an error if given file does not exists
9
+
10
+ Args:
11
+ inpath (str): Network input path
12
+
13
+ Raises:
14
+ : Error if the file doesn't exist
15
+
16
+ Returns:
17
+ str: Network input path
18
+ """
19
+ if not path.exists(inpath):
20
+ raise FileNotFoundError("File {} doesn't exists".format(inpath))
21
+ return inpath
22
+
23
+ def is_valid_dir(dirpath):
24
+ """Return True if directory exists or can be created (then create it)
25
+
26
+ Args:
27
+ dirpath (str): path of directory
28
+
29
+ Returns:
30
+ bool: True if dir exists, False otherwise
31
+ """
32
+ if not path.isdir(dirpath):
33
+ try:
34
+ makedirs(dirpath)
35
+ return dirpath
36
+ except OSError as e:
37
+ logger.log.error(e)
38
+ return None
39
+ else:
40
+ return dirpath
41
+
42
+ def existing_file(filepath):
43
+ """Return True if file exists
44
+
45
+ Args:
46
+ filepath (str): path of file
47
+
48
+ Returns:
49
+ bool: True if dir exists, False otherwise
50
+ """
51
+ if not path.isfile(filepath):
52
+ return False
53
+ else:
54
+ return True
55
+
56
+
57
+ def save(filename:str, directory:str, results, type:str, is_result_temp=False):
58
+ """Save data into file dependinf on type (json / tsv)
59
+
60
+ Args:
61
+ filename (str): Filename of saved file
62
+ directory (str): Output directory where to save file
63
+ results: Results data in dictionnary (json) or datatrame (tsv)
64
+ type (str): Type of output fils (json or tsv or txt)
65
+ """
66
+
67
+ out_file_path = path.join(directory,filename)
68
+ try:
69
+ match type:
70
+ case 'json':
71
+ out_file_path += '.json'
72
+ with open(out_file_path, 'w') as f:
73
+ dump(results, f, indent="\t")
74
+ f.close()
75
+ case 'tsv':
76
+ if not ".tsv" in out_file_path:
77
+ out_file_path += '.tsv'
78
+ # List is given an we want to append data at the end
79
+ if is_result_temp:
80
+ with open(out_file_path, 'a') as f:
81
+ tsv_output = writer(f, delimiter='\t')
82
+ tsv_output.writerow(results)
83
+ # Dataframe is given, and all results are written at once
84
+ else:
85
+ with open(out_file_path, 'w') as f:
86
+ results.to_csv(out_file_path, sep="\t")
87
+ f.close()
88
+ case 'txt':
89
+ if not ".txt" in out_file_path:
90
+ out_file_path += '.txt'
91
+ with open(out_file_path, "w") as f:
92
+ f.write("\n".join(results))
93
+ except Exception as e:
94
+ logger.log.error(f"while saving file: {e}")
95
+
96
+
97
+
98
+ def file_is_empty(file_path:str):
99
+ """Check if the file is empty
100
+
101
+ Args:
102
+ file_path (str): Path of file to check
103
+
104
+ Returns:
105
+ bool: True if the file is empty
106
+ """
107
+ return stat(file_path).st_size==0
108
+
109
+
110
+ def write_instance_file(instance_file:str, facts:str):
111
+ """Write and Save instance file
112
+ """
113
+ with open(instance_file, 'w') as f:
114
+ f.write(facts)
115
+ f.close()
116
+
117
+ def delete(filepath:str):
118
+ """Delete a file
119
+
120
+ Args:
121
+ filepath (str): Path of File to delete
122
+ """
123
+ if path.exists(filepath):
124
+ remove(filepath)
125
+
126
+ def load_json(filepath:str):
127
+ """Load a json file into a variable
128
+
129
+ Args:
130
+ filepath (str): Path of json file to load
131
+
132
+ Returns:
133
+ result (dict): Data formated into a dictionnary
134
+ """
135
+ file = open(filepath)
136
+ result = load(file)
137
+ file.close()
138
+ return result
139
+
140
+ def load_tsv(filepath:str):
141
+ """Load a tsv file into a variable
142
+
143
+ Args:
144
+ filepath (str): Path of json file to load
145
+
146
+ Returns:
147
+ result (list): Data formated into a list
148
+ """
149
+ file = open(filepath)
150
+ result = reader(file, delimiter='\t')
151
+ return list(result)