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/linear.py ADDED
@@ -0,0 +1,431 @@
1
+ # Object Hybrid, herit from Solver, added properties:
2
+ # - temp_dir (str): temporary directory for saving instance file and clingo outputs
3
+ # - instance_file (str): Path of instance file for solving
4
+ # 1 -> Atom output
5
+ # 2 -> Json output
6
+
7
+ # Object FBA, herit from Hybrid, no property added
8
+
9
+ from seed2lp.network import Network
10
+ from seed2lp.solver import Solver
11
+ from . import clingo_lpx, color, logger
12
+
13
+
14
+ ###################################################################
15
+ ################### Class Hybrid : herit Solver ###################
16
+ ###################################################################
17
+ class Hybrid(Solver):
18
+ def __init__(self, run_mode:str, run_solve:str, network:Network,
19
+ time_limit_minute:float=None, number_solution:int=None,
20
+ clingo_configuration:str=None, clingo_strategy:str=None,
21
+ intersection:bool=False, union:bool=False,
22
+ minimize:bool=False, subset_minimal:bool=False,
23
+ maximize_flux:bool=False,
24
+ temp_dir:str=None, short_option:str=None,
25
+ verbose:bool=False):
26
+ """Initialize Object Hybrid, herit from Solver
27
+
28
+ Args:
29
+ run_mode (str): Running command used (full or target or fba)
30
+ run_solve (str): Solving command used (Hybrid)
31
+ network (Network): Network constructed
32
+ time_limit_minute (float, optional): Time limit given by user in minutes . Defaults to None.
33
+ number_solution (int, optional): Limit number of solutions to find. Defaults to None.
34
+ clingo_configuration (str, optional): Configuration for clingo resolution . Defaults to None.
35
+ clingo_strategy (str, optional): Strategy for clingo resolution. Defaults to None.
36
+ enumeration (bool, optional): Enumerate the solutions limited by the number of solutions. Defaults to True.
37
+ intersection (bool, optional): Find the intersection of all solutions without limitation (give one solution). Defaults to False.
38
+ union (bool, optional): Find the union of all solutions without limitation (give one solution). Defaults to False.
39
+ minimize (bool, optional): Search the minimal carinality of solutions. Defaults to False.
40
+ subset_minimal (bool, optional): Search the subset minimal solutions. Defaults to False.
41
+ maximize_flux (bool, optional): Use maximization of flux for calculation. Defaults to False.
42
+ temp_dir (str, optional): Temporary directory for saving instance file and clingo outputs. Defaults to None.
43
+ short_option (str, optional): Short way to write option on filename. Defaults to None.
44
+ verbose (bool, optional): Set debug mode. Defaults to False.
45
+ """
46
+ super().__init__(run_mode, network, time_limit_minute, number_solution, clingo_configuration,
47
+ clingo_strategy, intersection, union, minimize, subset_minimal, temp_dir, short_option, run_solve, verbose)
48
+
49
+ self.is_linear = True
50
+ self.maximize_flux = maximize_flux
51
+ self.temp_dir = temp_dir
52
+ self.short_option = short_option
53
+ self.asp_files.append(self.asp.ASP_SRC_FLUX)
54
+ self.asp_files.append(self.asp.ASP_SRC_SHOW_SEEDS)
55
+ self.get_init_message()
56
+ self._init_clingo_constant()
57
+
58
+
59
+ ######################## METHODS ########################
60
+ def get_init_message(self):
61
+ """Get init message to put on terminal
62
+ """
63
+ title_mess = "\n############################################\n" \
64
+ "############################################\n" \
65
+ f" {color.bold}HYBRID{color.cyan_light}\n"\
66
+ "############################################\n" \
67
+ "############################################\n"
68
+ logger.print_log(title_mess, "info", color.cyan_light)
69
+
70
+
71
+ def _init_clingo_constant(self):
72
+ """Init the list of ASP constant command for resolution
73
+ """
74
+ self.init_const()
75
+
76
+ if self.maximize_flux:
77
+ logger.print_log('Flux: MAXIMIZATION', "info")
78
+ else:
79
+ logger.print_log('Flux: NO MAXIMIZATION', "info")
80
+ logger.print_log(f"Time limit: {self.time_limit_minute} minutes", 'info')
81
+ logger.print_log(f"Solution number limit: {self.number_solution}", 'info')
82
+
83
+
84
+ def search_seed(self):
85
+ """Launch seed searching
86
+ """
87
+ if not self.network.objectives:
88
+ self.get_message('optimum error')
89
+ self.get_message('end')
90
+ return
91
+
92
+ files = self.asp_files.copy()
93
+ if self.maximize_flux:
94
+ files.append(self.asp.ASP_SRC_MAXIMIZE_FLUX)
95
+ if self.subset_minimal:
96
+ self.get_message('subsetmin')
97
+ #logger.print_log("GROUNDING...", "info")
98
+ #self.grounded, timer, err_output, error_code, memory = self.ground(files, self.clingo_constant, self.is_linear, self.verbose)
99
+ self.search_subsetmin(files)
100
+ if self.minimize:
101
+ self.get_message('minimize')
102
+ if self.network.is_subseed:
103
+ files.append(self.asp.ASP_SRC_MAXIMIZE_PRODUCED_TARGET)
104
+ logger.print_log('POSSIBLE SEED: Given', "info")
105
+ logger.print_log(' A subset of possible seed is search \n maximising the number of produced target', "info")
106
+ self.clingo_constant.append('-c')
107
+ self.clingo_constant.append('subseed=1')
108
+ files.append(self.asp.ASP_SRC_MINIMIZE)
109
+ #logger.print_log("GROUNDING...", "info")
110
+ #self.grounded, timer, err_output, error_code, memory = self.ground(files, self.clingo_constant, self.is_linear, self.verbose)
111
+ self.search_minimize(files)
112
+ self.get_message('end')
113
+
114
+
115
+ def search_minimize(self, asp_files):
116
+ """Launch seed searching with minimze options
117
+ """
118
+ logger.print_log("Finding optimum...", "info")
119
+ self.solve(asp_files, "minimize-one-model")
120
+
121
+ if self.one_model_unsat:
122
+ return
123
+
124
+ ok_opti = self.optimum_found and (self.opt_size > 0)
125
+ #ok_opti = (self.optimum is not None) and (self.optimum > 0)
126
+ if self.optimum is None:
127
+ opti_message = "Optimum not found."
128
+ elif self.optimum == 0:
129
+ opti_message = "Optimum is 0."
130
+
131
+ if self.enumeration:
132
+ if ok_opti:
133
+ self.get_message('enumeration')
134
+ self.solve(asp_files, "minimize-enumeration")
135
+ else:
136
+ self.get_message('enumeration')
137
+ logger.print_log(f"\nNot computed: {opti_message}", "info")
138
+
139
+ if self.intersection:
140
+ if ok_opti:
141
+ self.get_message('intersection')
142
+ self.solve(asp_files, "minimize-intersection")
143
+ else:
144
+ self.get_message('intersection')
145
+ logger.print_log(f"\nNot computed: {opti_message}", "info")
146
+
147
+
148
+ def search_subsetmin(self, asp_files):
149
+ """Launch seed searching with subset minimal options
150
+ """
151
+ if self.enumeration:
152
+ self.get_message('enumeration')
153
+ self.solve(asp_files, "submin-enumeration")
154
+ else:
155
+ self.number_solution = 1
156
+ logger.print_log("\n--------------- One solution ---------------", "info")
157
+ self.solve(asp_files, "submin-enumeration")
158
+
159
+
160
+ if self.intersection:
161
+ self.get_message('intersection')
162
+ self.solve(asp_files, "submin-intersection")
163
+
164
+
165
+ def add_result_seeds(self, search_mode:str, model_name:str, len:int, seeds:list, flux_dict:dict):
166
+ """Add a formated resulted set of seeds into the network object
167
+
168
+ Args:
169
+ search_mode (str): search mode type
170
+ model_name (str): model name
171
+ len (int): length of a set of seed
172
+ seeds (list): list of seeds
173
+ flux_dict(dict): Dictionnary of all reaction with their LP flux
174
+ """
175
+ self.network.add_result_seeds('HYBRID', search_mode, model_name, len, seeds, flux_dict)
176
+
177
+
178
+ def get_objectives_flux(self, flux_list):
179
+ """From a list of all reaction and associated LP flux, find objective reactions
180
+ and create a dictionnary to stock the LP flux
181
+
182
+ Args:
183
+ flux_list (list): List of all reaction name and associated LP flux
184
+
185
+ Returns:
186
+ Dict: A dictionnary of Objective reaction with it associated flux
187
+ """
188
+ obj_flux_dict = dict()
189
+ for line in flux_list:
190
+ reaction = line[0]
191
+ if reaction in self.network.objectives:
192
+ obj_flux_dict[reaction] = line[1]
193
+ return obj_flux_dict
194
+
195
+
196
+
197
+ def solve(self, asp_files:list=[], search_mode:str=""):
198
+ """Solve the seed seraching using the launch mode
199
+
200
+ Args:
201
+ asp_files (list, optional): List of ASP files used for sovling. Defaults to [].
202
+ search_mode (str, optional): Describe the launch mode. . Defaults to "".
203
+ """
204
+ logger.print_log("SOLVING...\n", "info")
205
+ results = dict()
206
+ solution_list = dict()
207
+ timer = dict()
208
+
209
+ full_option, _, model_type, output_type = self.get_solutions_infos(search_mode)
210
+ full_option = self.clingo_constant + full_option
211
+
212
+ if self.optimum:
213
+ if self.opt_prod_tgt is not None:
214
+ full_option[-1]=full_option[-1]+f",{self.opt_prod_tgt},{self.opt_size}"
215
+ else:
216
+ full_option[-1]=full_option[-1]+f",{self.opt_size}"
217
+
218
+
219
+ match search_mode:
220
+ case "minimize-one-model":
221
+ cmd = clingo_lpx.command(files=asp_files, options=full_option,
222
+ time_limit=self.time_limit)
223
+ cmd_str = ' '.join(cmd)
224
+ proc_output, err, error_code, \
225
+ memory, is_killed = clingo_lpx.solve(cmd, self.time_limit)
226
+ self.get_message("command")
227
+ logger.print_log(f'{cmd_str}', 'debug')
228
+
229
+ self.get_error(error_code, err)
230
+ output_full_list, unsatisfiable, self.optimum_found, full_timers, opt = clingo_lpx.result_convert(proc_output,
231
+ self.network.objectives,
232
+ "", is_killed, False)
233
+ if unsatisfiable:
234
+ logger.print_log('Unsatisfiable problem', "error")
235
+
236
+ elif self.optimum_found:
237
+ logger.print_log("Optimum Found", "info")
238
+ self.one_model_unsat = False
239
+ one_model_list=output_full_list[list(output_full_list.keys())[-1]]
240
+ self.optimum=opt
241
+ self.get_separate_optimum()
242
+ #TODO Corrects the producible targets count
243
+ #if self.network.is_subseed:
244
+ # logger.print_log((f"Number of producible targets: {- self.opt_prod_tgt}"), 'info')
245
+ #TODO END
246
+ logger.print_log(f"Minimal size of seed set is {self.opt_size}\n", 'info')
247
+ if self.optimum is not None and self.network.keep_import_reactions:
248
+ logger.print_log("Try with the option remove import reactions.", "info")
249
+ solution_list[model_type] = one_model_list
250
+ #Get obejctives fluxes and add results seeds to network object
251
+ obj_flux_dict = self.get_objectives_flux(one_model_list[5])
252
+ self.add_result_seeds(search_mode, model_type, one_model_list[1], one_model_list[3], obj_flux_dict)
253
+ # Satisfiable probleme but optimum not found in given time
254
+ else:
255
+ logger.print_log('Optimum not found', "error")
256
+
257
+ case "minimize-enumeration":
258
+ cmd = clingo_lpx.command(files=asp_files, options=full_option, nb_model= self.number_solution,
259
+ time_limit=self.time_limit)
260
+ cmd_str = ' '.join(cmd)
261
+ proc_output, err, error_code, \
262
+ memory, is_killed = clingo_lpx.solve(cmd, self.time_limit)
263
+ self.get_message("command")
264
+ logger.print_log(f'{cmd_str}', 'debug')
265
+ self.get_error(error_code, err)
266
+ solution_list, unsatisfiable, _, full_timers, _ = clingo_lpx.result_convert(proc_output,
267
+ self.network.objectives, "enumeration", is_killed)
268
+ if unsatisfiable:
269
+ logger.print_log('Unsatisfiable problem', "error")
270
+ else:
271
+ for model_name, solution in solution_list.items():
272
+ #Get obejctives fluxes and add results seeds to network object
273
+ obj_flux_dict = self.get_objectives_flux(solution[5])
274
+ self.add_result_seeds(search_mode, model_name, solution[1], solution[3], obj_flux_dict)
275
+
276
+ case "submin-enumeration":
277
+ cmd = clingo_lpx.command(files=asp_files, options=full_option, nb_model= self.number_solution,
278
+ time_limit=self.time_limit)
279
+ cmd_str = ' '.join(cmd)
280
+ proc_output, err, error_code, \
281
+ memory, is_killed = clingo_lpx.solve(cmd, self.time_limit)
282
+ self.get_message("command")
283
+ logger.print_log(f'{cmd_str}', 'debug')
284
+ self.get_error(error_code, err)
285
+ solution_list, unsatisfiable, _, full_timers,_ = clingo_lpx.result_convert(proc_output,
286
+ self.network.objectives, "enumeration", is_killed)
287
+ if unsatisfiable:
288
+ logger.print_log('Unsatisfiable problem', "error")
289
+ else:
290
+ for model_name, solution in solution_list.items():
291
+ #Get obejctives fluxes and add results seeds to network object
292
+ obj_flux_dict = self.get_objectives_flux(solution[5])
293
+ self.add_result_seeds(search_mode, model_name, solution[1], solution[3], obj_flux_dict)
294
+
295
+ case "minimize-intersection":
296
+ cmd = clingo_lpx.command(files=asp_files, options=full_option,
297
+ time_limit=self.time_limit)
298
+ cmd_str = ' '.join(cmd)
299
+ proc_output, err, error_code, \
300
+ memory, is_killed = clingo_lpx.solve(cmd, self.time_limit)
301
+ self.get_message("command")
302
+ logger.print_log(f'{cmd_str}', 'debug')
303
+ self.get_error(error_code, err)
304
+ output_full_list, unsatisfiable, _, full_timers = clingo_lpx.result_convert(proc_output,
305
+ self.network.objectives, 'cautious', is_killed)
306
+ if unsatisfiable:
307
+ logger.print_log('Unsatisfiable problem', "error")
308
+ elif output_full_list:
309
+ model = output_full_list[list(output_full_list.keys())[-1]]
310
+ solution_list[model_type ] = model
311
+ #Get obejctives fluxes and add results seeds to network object
312
+ obj_flux_dict = self.get_objectives_flux(model[5])
313
+ self.add_result_seeds(search_mode, model_type, model[1], model[3], obj_flux_dict)
314
+
315
+
316
+ case "submin-intersection":
317
+ cmd = clingo_lpx.command(files=asp_files, options=full_option,
318
+ time_limit=self.time_limit)
319
+ cmd_str = ' '.join(cmd)
320
+ proc_output, err, error_code, \
321
+ memory, is_killed = clingo_lpx.solve(files=asp_files, options=full_option,
322
+ time_limit=self.time_limit)
323
+ self.get_message("command")
324
+ logger.print_log(f'{cmd_str}', 'debug')
325
+ self.get_error(error_code, err)
326
+ output_full_list, unsatisfiable, _, full_timers = clingo_lpx.result_convert(proc_output,
327
+ self.network.objectives, 'cautious', is_killed)
328
+ if unsatisfiable:
329
+ logger.print_log('Unsatisfiable problem', "error")
330
+ elif output_full_list:
331
+ model = output_full_list[list(output_full_list.keys())[-1]]
332
+ solution_list[model_type] = model
333
+ #Get obejctives fluxes and add results seeds to network object
334
+ obj_flux_dict = self.get_objectives_flux(model[5])
335
+ self.add_result_seeds(search_mode, model_type, model[1], model[3], obj_flux_dict)
336
+ if 'Total' in full_timers:
337
+ timer["Grounding time"] = round(full_timers['Total'] - full_timers['Solve'], 3)
338
+ timer["Solving time"] = round(full_timers['Solve'], 3)
339
+ else:
340
+ timer["Grounding time"] = "Time out"
341
+ timer["Solving time"] = "Time out"
342
+ results ["Timer"] = timer
343
+ results ["Memory (GB)"] = memory
344
+ results['solutions']= solution_list
345
+ self.output[output_type] = results
346
+
347
+
348
+ def get_error(self,error_code:int, err:bytes):
349
+ """Get and print error
350
+
351
+ Args:
352
+ error_code (int): Code error from Python process
353
+ err (bytes): Error text from python process
354
+
355
+ Raises:
356
+ ValueError: Raise an error and stop the program when value of code < 0
357
+ """
358
+ if error_code and error_code<0:
359
+ print(f'error_code = {error_code}')
360
+ raise ValueError(err.decode())
361
+ elif err:
362
+ logger.print_log(err.decode(), 'debug')
363
+
364
+ ########################################################
365
+
366
+
367
+ ###################################################################
368
+ ##################### Class FBA : herit Hybrid ####################
369
+ ###################################################################
370
+ class FBA(Hybrid):
371
+ def __init__(self, run_mode:str, network:Network,
372
+ time_limit_minute:float=None, number_solution:int=None,
373
+ clingo_configuration:str=None, clingo_strategy:str=None,
374
+ intersection:bool=False, union:bool=False,
375
+ minimize:bool=False, subset_minimal:bool=False,
376
+ maximize_flux:bool=False,
377
+ temp_dir:str=None, short_option:str=None,
378
+ verbose:bool=False):
379
+ """Initialize Object Hybrid, herit from Solver
380
+
381
+ Args:
382
+ run_mode (str): Running command used (full or target or fba)
383
+ network (Network): Network constructed
384
+ time_limit_minute (float, optional): Time limit given by user in minutes . Defaults to None.
385
+ number_solution (int, optional): Limit number of solutions to find. Defaults to None.
386
+ clingo_configuration (str, optional): Configuration for clingo resolution . Defaults to None.
387
+ clingo_strategy (str, optional): Strategy for clingo resolution. Defaults to None.
388
+ enumeration (bool, optional): Enumerate the solutions limited by the number of solutions. Defaults to True.
389
+ intersection (bool, optional): Find the intersection of all solutions without limitation (give one solution). Defaults to False.
390
+ union (bool, optional): Find the union of all solutions without limitation (give one solution). Defaults to False.
391
+ minimize (bool, optional): Search the minimal carinality of solutions. Defaults to False.
392
+ subset_minimal (bool, optional): Search the subset minimal solutions. Defaults to False.
393
+ maximize_flux (bool, optional): Use maximization of flux for calculation. Defaults to False.
394
+ temp_dir (str, optional): Temporary directory for saving instance file and clingo outputs. Defaults to None.
395
+ short_option (str, optional): Short way to write option on filename. Defaults to None.
396
+ verbose (bool, optional): Set debug mode. Defaults to False.
397
+ """
398
+ super().__init__(run_mode, None, network,
399
+ time_limit_minute, number_solution,
400
+ clingo_configuration, clingo_strategy,
401
+ intersection, union, minimize,
402
+ subset_minimal, maximize_flux,
403
+ temp_dir, short_option,
404
+ verbose)
405
+
406
+ ######################## METHODS ########################
407
+
408
+ def get_init_message(self):
409
+ """Get init message to put on terminal
410
+ """
411
+ title_mess = "\n############################################\n" \
412
+ "############################################\n" \
413
+ f" {color.bold}FBA{color.cyan_light}\n"\
414
+ "############################################\n" \
415
+ "############################################\n"
416
+ logger.print_log(title_mess, "info", color.cyan_light)
417
+
418
+ def add_result_seeds(self, search_mode:str, model_name:str, len:int, seeds:list, flux_list:list):
419
+ """Add a formated resulted set of seeds into the network object
420
+
421
+ Args:
422
+ search_mode (str): search mode type
423
+ model_name (str): model name
424
+ len (int): length of a set of seed
425
+ seeds (list): list of seeds
426
+ """
427
+ self.network.add_result_seeds('FBA', search_mode, model_name, len, seeds, flux_list)
428
+ ########################################################
429
+
430
+
431
+
seed2lp/log_conf.yaml ADDED
@@ -0,0 +1,25 @@
1
+ ###############################
2
+ # Logger configuration #
3
+ ###############################
4
+
5
+ version: 1
6
+ disable_existing_loggers: False
7
+ formatters:
8
+ simple:
9
+ format: '%(levelname)s : %(message)s'
10
+ () : seed2lp.logger.ColoredFormatter
11
+ use_color: true
12
+ handlers:
13
+ console:
14
+ class: logging.StreamHandler
15
+ level: WARNING
16
+ formatter: simple
17
+ stream: ext://sys.stdout
18
+ loggers:
19
+ s2lp:
20
+ level: DEBUG
21
+ handlers: [console]
22
+ propagate: no
23
+ root:
24
+ level: DEBUG
25
+ handlers: [console]
seed2lp/logger.py ADDED
@@ -0,0 +1,112 @@
1
+ import logging, logging.config
2
+ from os import path
3
+ from . import color, file
4
+ import yaml
5
+ from ._version import __version__
6
+
7
+ ROJECT_DIR = path.dirname(path.abspath(__file__))
8
+ LOG_DIR:str
9
+ log:logging.Logger
10
+ verbose:bool
11
+
12
+ COLORS = {
13
+ "WARNING": color.yellow,
14
+ "INFO": color.grey,
15
+ "DEBUG": color.reverse_colour,
16
+ "CRITICAL": color.orange_back,
17
+ "ERROR": color.red_bright,
18
+ "RESET": color.reset
19
+ }
20
+
21
+
22
+ class ColoredFormatter(logging.Formatter):
23
+ def __init__(self, *, format:str, use_color:bool):
24
+ logging.Formatter.__init__(self, fmt=format)
25
+ self.use_color = use_color
26
+
27
+ def format(self, record):
28
+ msg = super().format(record)
29
+ if self.use_color:
30
+ levelname = record.levelname
31
+ if hasattr(record, "color"):
32
+ return f"{record.color}{msg}{COLORS['RESET']}"
33
+ if levelname in COLORS:
34
+ return f"{COLORS[levelname]}{msg}{COLORS['RESET']}"
35
+ return msg
36
+
37
+
38
+
39
+ def __init_logger__(log_path:str):
40
+ """Init logger depending on log_path (and therefor run_mode)
41
+
42
+ Args:
43
+ log_path (str): Full path of logger file
44
+ """
45
+ global log
46
+ #logging.config.fileConfig(path.join(ROJECT_DIR,'log_conf.yaml'))
47
+ with open(path.join(ROJECT_DIR,'log_conf.yaml'), "rt") as f:
48
+ config = yaml.safe_load(f.read())
49
+ if verbose:
50
+ config['handlers']['console']['level']='DEBUG'
51
+ logging.config.dictConfig(config)
52
+ formatter = logging.Formatter('%(levelname)s %(asctime)s: %(message)s')
53
+ file_handler = logging.FileHandler(log_path)
54
+
55
+ if verbose:
56
+ file_handler.setLevel(logging.DEBUG)
57
+ else:
58
+ file_handler.setLevel(logging.INFO)
59
+ file_handler.setFormatter(formatter)
60
+
61
+ # create logger
62
+ log = logging.getLogger('s2lp')
63
+ log.addHandler(file_handler)
64
+
65
+
66
+ def print_log(message:str, level:str, col=None):
67
+ """Print and log messages
68
+
69
+ Args:
70
+ message (str): Message
71
+ level (str): level of the message (info, error or debug)
72
+ """
73
+ if not verbose and level != "debug":
74
+ if col:
75
+ print(col + message + color.reset)
76
+ else:
77
+ print(message)
78
+ else:
79
+ pass
80
+
81
+ match level:
82
+ case "info":
83
+ if col:
84
+ log.info(message, extra={"color": col})
85
+ else:
86
+ log.info(message)
87
+ case "debug":
88
+ log.debug(message)
89
+ case "warning":
90
+ log.warning(message)
91
+ case "error":
92
+ log.error(message)
93
+
94
+
95
+
96
+ def get_logger(sbml_file:str, short_option:str, debug:bool=False):
97
+ global log
98
+ global verbose
99
+ verbose=debug
100
+ net_name = f'{path.splitext(path.basename(sbml_file))[0]}'
101
+ filename = f'{net_name}_{short_option}.log'
102
+ log_path = path.join(LOG_DIR, filename)
103
+ if file.existing_file(log_path):
104
+ file.delete(log_path)
105
+ __init_logger__(log_path)
106
+ log.info(f"Seed2LP version: {__version__}")
107
+
108
+
109
+ def set_log_dir(value):
110
+ global LOG_DIR
111
+ LOG_DIR = value
112
+
seed2lp/metabolite.py ADDED
@@ -0,0 +1,46 @@
1
+ # Object Metabolite constitued of:
2
+ # - name (str): Name of the metabolite
3
+ # - stoichiometry (int): Stoiciometry of the metabolite in the reaction eaquation if linked into a reaction
4
+ # (not set for targets or possible seeds or forbidden seeds)
5
+ # - compartment (str): character of the compartment of metabolite
6
+
7
+ class Metabolite:
8
+ def __init__(self, id_meta:str, name:str, stoichiometry:float=None, meta_type:str="",
9
+ species:str=""):
10
+ """Initialize Object Metabolite
11
+
12
+ Args:
13
+ name (str): Name / ID of the Metabolite
14
+ stoichiometry (int, optional): Stoichiometry of the metabolite if into a reactions. Defaults to None.
15
+ """
16
+ self.id_meta = id_meta
17
+ self.name = name
18
+ self.stoichiometry = stoichiometry
19
+ self.type = meta_type
20
+ self.species = species
21
+
22
+
23
+ ######################## METHODS ########################
24
+ def convert_to_facts(self, metabolite_type:str, reaction_name:str=None):
25
+ """Convert metabolite into ASP facts : an atom reactant or product, associated to a reaction
26
+ and having a stoichiometry value
27
+
28
+ Args:
29
+ metabolite_type (str): Type of metabolite (exchange, transport, other)
30
+ reaction_name (str, optional): Name of the reaction associated to the metabolite. Defaults to None.
31
+
32
+ Returns:
33
+ facts (str): The ASP atom created
34
+ """
35
+ facts = ""
36
+ match metabolite_type:
37
+ case "reactant"|"product":
38
+
39
+ facts += f'{metabolite_type}("{self.id_meta}","{"{:.10f}".format(self.stoichiometry)}","{reaction_name}","{self.type}","{self.name}","{self.species}").\n'
40
+ case "seed":
41
+ facts += f'{metabolite_type}("{self.id_meta}","{self.type}","{self.name}").\n'
42
+ case _:
43
+ facts += f'{metabolite_type}("{self.id_meta}","{"{:.10f}".format(self.stoichiometry)}","{reaction_name}","{self.type}","{self.name}","{self.species}").\n'
44
+ return facts
45
+
46
+ ########################################################