| 
491
 | 
     1 """
 | 
| 
 | 
     2 Convert a tabular (CSV/TSV/Tabular) description of a COBRA model into a COBRA file.
 | 
| 
 | 
     3 
 | 
| 
 | 
     4 Supported output formats: SBML, JSON, MATLAB (.mat), YAML.
 | 
| 
 | 
     5 The script logs to a user-provided file for easier debugging in Galaxy.
 | 
| 
 | 
     6 """
 | 
| 
 | 
     7 
 | 
| 
 | 
     8 import os
 | 
| 
 | 
     9 import cobra
 | 
| 
 | 
    10 import argparse
 | 
| 
 | 
    11 from typing import List
 | 
| 
 | 
    12 import logging
 | 
| 
 | 
    13 import utils.model_utils as modelUtils
 | 
| 
 | 
    14 
 | 
| 
 | 
    15 ARGS : argparse.Namespace
 | 
| 
 | 
    16 def process_args(args: List[str] = None) -> argparse.Namespace:
 | 
| 
 | 
    17     """
 | 
| 
 | 
    18     Parse command-line arguments for the CSV-to-COBRA conversion tool.
 | 
| 
 | 
    19 
 | 
| 
 | 
    20     Returns:
 | 
| 
 | 
    21         argparse.Namespace: Parsed arguments.
 | 
| 
 | 
    22     """
 | 
| 
 | 
    23     parser = argparse.ArgumentParser(
 | 
| 
 | 
    24     usage="%(prog)s [options]",
 | 
| 
 | 
    25     description="Convert a tabular/CSV file to a COBRA model"
 | 
| 
 | 
    26     )
 | 
| 
 | 
    27 
 | 
| 
 | 
    28 
 | 
| 
 | 
    29     parser.add_argument("--out_log", type=str, required=True,
 | 
| 
 | 
    30     help="Output log file")
 | 
| 
 | 
    31 
 | 
| 
 | 
    32 
 | 
| 
 | 
    33     parser.add_argument("--input", type=str, required=True,
 | 
| 
 | 
    34     help="Input tabular file (CSV/TSV)")
 | 
| 
 | 
    35 
 | 
| 
 | 
    36 
 | 
| 
 | 
    37     parser.add_argument("--format", type=str, required=True, choices=["sbml", "json", "mat", "yaml"],
 | 
| 
 | 
    38     help="Model format (SBML, JSON, MATLAB, YAML)")
 | 
| 
 | 
    39 
 | 
| 
 | 
    40 
 | 
| 
 | 
    41     parser.add_argument("--output", type=str, required=True,
 | 
| 
 | 
    42     help="Output model file path")
 | 
| 
 | 
    43 
 | 
| 
 | 
    44     parser.add_argument("--tool_dir", type=str, default=os.path.dirname(__file__),
 | 
| 
 | 
    45     help="Tool directory (passed from Galaxy as $__tool_directory__)")
 | 
| 
 | 
    46 
 | 
| 
 | 
    47 
 | 
| 
 | 
    48     return parser.parse_args(args)
 | 
| 
 | 
    49 
 | 
| 
 | 
    50 
 | 
| 
 | 
    51 ###############################- ENTRY POINT -################################
 | 
| 
 | 
    52 
 | 
| 
 | 
    53 def main(args: List[str] = None) -> None:
 | 
| 
 | 
    54     """
 | 
| 
 | 
    55     Entry point: parse arguments, build the COBRA model from a CSV/TSV file,
 | 
| 
 | 
    56     and save it in the requested format.
 | 
| 
 | 
    57 
 | 
| 
 | 
    58     Returns:
 | 
| 
 | 
    59         None
 | 
| 
 | 
    60     """
 | 
| 
 | 
    61     global ARGS
 | 
| 
 | 
    62     ARGS = process_args(args)
 | 
| 
 | 
    63 
 | 
| 
 | 
    64     # configure logging to the requested log file (overwrite each run)
 | 
| 
 | 
    65     logging.basicConfig(filename=ARGS.out_log,
 | 
| 
 | 
    66                         level=logging.DEBUG,
 | 
| 
 | 
    67                         format='%(asctime)s %(levelname)s: %(message)s',
 | 
| 
 | 
    68                         filemode='w')
 | 
| 
 | 
    69 
 | 
| 
 | 
    70     logging.info('Starting fromCSVtoCOBRA tool')
 | 
| 
 | 
    71     logging.debug('Args: input=%s format=%s output=%s tool_dir=%s', ARGS.input, ARGS.format, ARGS.output, ARGS.tool_dir)
 | 
| 
 | 
    72 
 | 
| 
 | 
    73     try:
 | 
| 
 | 
    74         # Basic sanity checks
 | 
| 
 | 
    75         if not os.path.exists(ARGS.input):
 | 
| 
 | 
    76             logging.error('Input file not found: %s', ARGS.input)
 | 
| 
 | 
    77 
 | 
| 
 | 
    78         out_dir = os.path.dirname(os.path.abspath(ARGS.output))
 | 
| 
 | 
    79         
 | 
| 
 | 
    80         if out_dir and not os.path.isdir(out_dir):
 | 
| 
 | 
    81             try:
 | 
| 
 | 
    82                 os.makedirs(out_dir, exist_ok=True)
 | 
| 
 | 
    83                 logging.info('Created missing output directory: %s', out_dir)
 | 
| 
 | 
    84             except Exception as e:
 | 
| 
 | 
    85                 logging.exception('Cannot create output directory: %s', out_dir)
 | 
| 
 | 
    86 
 | 
| 
 | 
    87         model = modelUtils.build_cobra_model_from_csv(ARGS.input)
 | 
| 
498
 | 
    88         
 | 
| 
 | 
    89         
 | 
| 
 | 
    90         logging.info('Created model with name: %s (ID: %s)', model.name, model.id)
 | 
| 
491
 | 
    91 
 | 
| 
498
 | 
    92         # Save model in requested format - Galaxy handles the filename
 | 
| 
491
 | 
    93         if ARGS.format == "sbml":
 | 
| 
 | 
    94             cobra.io.write_sbml_model(model, ARGS.output)
 | 
| 
 | 
    95         elif ARGS.format == "json":
 | 
| 
 | 
    96             cobra.io.save_json_model(model, ARGS.output)
 | 
| 
 | 
    97         elif ARGS.format == "mat":
 | 
| 
 | 
    98             cobra.io.save_matlab_model(model, ARGS.output)
 | 
| 
 | 
    99         elif ARGS.format == "yaml":
 | 
| 
 | 
   100             cobra.io.save_yaml_model(model, ARGS.output)
 | 
| 
 | 
   101         else:
 | 
| 
 | 
   102             logging.error('Unknown format requested: %s', ARGS.format)
 | 
| 
498
 | 
   103             raise ValueError(f"Unknown format: {ARGS.format}")
 | 
| 
491
 | 
   104 
 | 
| 
 | 
   105 
 | 
| 
 | 
   106         logging.info('Model successfully written to %s (format=%s)', ARGS.output, ARGS.format)
 | 
| 
498
 | 
   107         print(f"Model created successfully in {ARGS.format.upper()} format")
 | 
| 
491
 | 
   108 
 | 
| 
498
 | 
   109     except Exception as e:
 | 
| 
491
 | 
   110         # Log full traceback to the out_log so Galaxy users/admins can see what happened
 | 
| 
 | 
   111         logging.exception('Unhandled exception in fromCSVtoCOBRA')
 | 
| 
498
 | 
   112         print(f"ERROR: {str(e)}")
 | 
| 
 | 
   113         raise
 | 
| 
491
 | 
   114 
 | 
| 
 | 
   115 
 | 
| 
 | 
   116 if __name__ == '__main__':
 | 
| 
 | 
   117     main()
 |