commands.py 14.4 KB
Newer Older
1
# coding=utf-8
fabrice's avatar
fabrice committed
2
3
4
"""
                            Input/Output aria_ec
"""
5
from __future__ import absolute_import, division, print_function
fabrice's avatar
fabrice committed
6
7
8
9
10

import os
import logging
import argparse as argp

11
from .base import format_dict, CustomLogging
fabrice's avatar
fabrice committed
12
13
from .ecsettings import AriaEcSettings
from .maplot import AriaEcContactMap
14
from .econverter import AriaEcBbConverter, AriaEcXMLConverter
fabrice's avatar
fabrice committed
15
from .setup import AriaEcSetup
Fabrice Allain's avatar
Fabrice Allain committed
16
from .pdbqual import AriaEcPdbqual
Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
17
from .pdbdist import PDBDist
fabrice's avatar
fabrice committed
18

19
20

LOG = logging.getLogger(__name__)
fabrice's avatar
fabrice committed
21
22
23


def check_file(prospective_file):
24
    """
fabrice's avatar
fabrice committed
25

26
27
    :param prospective_file:
    """
28
    LOG.debug("Checking if %s is a readable file", prospective_file)
fabrice's avatar
fabrice committed
29
30
31
32
33
34
35
36
37
    if not os.path.exists(prospective_file):
        raise argp.ArgumentTypeError("readable_file:'{0}' is not a valid "
                                     "path".format(prospective_file))
    if not os.access(prospective_file, os.R_OK):
        raise argp.ArgumentTypeError("readable_file:'{0}' is not a readable "
                                     "file".format(prospective_file))


class ReadableFile(argp.Action):
38
39
40
    """
    Class used with argparse action to check if a file is readable
    """
fabrice's avatar
fabrice committed
41

Fabrice Allain's avatar
Fabrice Allain committed
42
43
44
    def __init__(self, *args, **kwargs):
        super(ReadableFile, self).__init__(*args, **kwargs)

fabrice's avatar
fabrice committed
45
    def __call__(self, parser, namespace, values, option_string=None):
46
        if isinstance(values, list):
fabrice's avatar
fabrice committed
47
48
            for prospective_file in values:
                check_file(prospective_file)
Fabrice Allain's avatar
Fabrice Allain committed
49
50
            setattr(namespace, self.dest,
                    [os.path.abspath(os.path.expanduser(val)) for val in values])
51
        elif isinstance(values, str):
fabrice's avatar
fabrice committed
52
            check_file(values)
Fabrice Allain's avatar
Fabrice Allain committed
53
            setattr(namespace, self.dest, os.path.abspath(os.path.expanduser(values)))
fabrice's avatar
fabrice committed
54
55
56
57


# TODO: Make parent Command class with _create_argparser, self.args,
# update_logger and run
58
class AriaEcCommand(object):
fabrice's avatar
fabrice committed
59
60
61
62
    """
    Argparse interface for aria_ec
    """

Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
63
64
    command_list = ("setup", "bbconv", "contactmap", "pdbqual", "tbl2xml",
                    "pdbdist")
fabrice's avatar
fabrice committed
65
66
67
    desc_list = (u"Setup ARIA infrastructure with given contacts translated "
                 u"into ARIA restraints",
                 u"Convert contacts in bbcontact format",
Fabrice Allain's avatar
Fabrice Allain committed
68
                 u"Contactmap tool",
69
                 u"Quality tool for pdb file(s)",
Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
70
71
72
73
74
75
                 u"XML converter for tbl distance restraint",
                 u"Extract distance distribution from culled list of pdb files")
    contact_types = ("evfold", "plmev", "plm", "plmdca", "plmc", "bbcontacts",
                     "pconsc", "pconsc1", "pconsc2", "psicov", "metapsicovhb",
                     "metapsicov_stg1", "metapsicov_stg2", "gremlin", "pdb",
                     "native", "native_full", "contactlist")
fabrice's avatar
fabrice committed
76
77
78
79
80
81
82
    default_confile = "conf/aria_ec.ini"

    def __init__(self, custom_logging=None):
        # Def Argument parser
        parser = self._create_argparser()
        # parse args
        self.args = parser.parse_args()
83
        # Update LOG with outdir
fabrice's avatar
fabrice committed
84
85
86
87
        self._update_logger(custom_logging)

    def _update_logger(self, log):
        if log and hasattr(self.args, "output_directory"):
fabrice's avatar
fabrice committed
88
89
90
            if not self.args.nolog:
                # Don't generate log files
                # TODO: get handler list from json file or customlogging object
91
92
93
                LOG.removeHandler("info_file_handler")
                LOG.removeHandler("error_file_handler")
                LOG.removeHandler("debug_file_handler")
fabrice's avatar
fabrice committed
94
                log.set_outdir(self.args.output_directory)
fabrice's avatar
fabrice committed
95
96
97
98
99
100
101
102
            log.update_msg(self.args.command)
            log.welcome()

    def _create_argparser(self):
        parser = argp.ArgumentParser(description=u"ARIA Evolutionary "
                                                 u"restraints toolbox",
                                     formatter_class=argp.ArgumentDefaultsHelpFormatter)
        parser.add_argument("-o", "--output", dest="output_directory",
103
                            type=str, help="Output directory", required=True)
104
105
        parser.add_argument("-c", "--conf", action=ReadableFile,
                            dest="conf_file",
fabrice's avatar
fabrice committed
106
                            default=None, help="configuration file")
fabrice's avatar
fabrice committed
107
108
        parser.add_argument("--nolog", action="store_true",
                            default=False, help="Don't generate log files")
Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
109
110
111
        parser.add_argument("-v", "--verbose", dest="verbose", default=False,
                            action='store_true',
                            help="Increase output verbosity")
fabrice's avatar
fabrice committed
112
113
114
115
116
117
118
119
120
121
122
123
        # Create subcommands
        self._create_subparsers(parser.add_subparsers(dest="command"))
        return parser

    def _create_subparsers(self, parser):
        """
        Generate subcommands
        :param parser: argparser object
        :return:
        """
        for index, command in enumerate(self.command_list):
            # Create subparser defined in command list
124
            subcommand = getattr(self, "_" + command + "_argparser")(
125
126
                desc=self.desc_list[
                    index])
fabrice's avatar
fabrice committed
127
128
            parser.add_parser(command, parents=[subcommand])

129
    def _setup_argparser(self, desc=None):
fabrice's avatar
fabrice committed
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        """
        setup opt & args
        :param desc: command descriptor
        :return: argparser object
        """
        parser = argp.ArgumentParser(description=desc,
                                     add_help=False)
        # Options
        # Args
        group = parser.add_argument_group('required arguments')
        group.add_argument("seq", action=ReadableFile,
                           help="sequence file [FASTA]")
        group.add_argument("sspred", action=ReadableFile,
                           help="secondary structure prediction file")
        group.add_argument("infiles", nargs="+", metavar="infile",
                           action=ReadableFile,
                           help="contact or pdb file(s) used to build aria "
                                "distance restraints")
        group.add_argument("-d", "--distfile", dest="distfile",
                           help="Pdb or distance matrix iif distance_type "
                                "set  to   distfile in conf  file,  "
                                "use distances in the  given file as "
                                "target  distance to build  distance "
                                "restraints")
        group.add_argument("-t", "--type", required=True,
                           nargs="+", dest="contact_types",
                           choices=self.contact_types, help="Infile(s) contact "
                                                            "type(s)")
        group.add_argument("-r", "--ref", dest="ref",
                           help="Native pdb. Allow TP/FP detection.")
        group.add_argument("--hb", dest="hb",
                           help="H-bonds contact file (eg: metapsicov.hb)")
        group.add_argument("--ssidx", dest="ssidx", action="store_true",
                           default=False, help="Use secondary structure index")
164
165
        group.add_argument("--no-filter", dest="no_filter", action="store_true",
                           default=False, help="Do not filter contact map.")
fabrice's avatar
fabrice committed
166
167
        return parser

168
    def _bbconv_argparser(self, desc=None):
fabrice's avatar
fabrice committed
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
        """
        bbconv opt & args
        :param desc: command descriptor
        :return: argparser object
        """
        parser = argp.ArgumentParser(description=desc,
                                     add_help=False)
        # args
        parser.add_argument("contactfile", help="contacts file (pconsc, plm)",
                            action=ReadableFile)
        parser.add_argument("sspred", help="psipred file",
                            action=ReadableFile)
        parser.add_argument("seq", help="sequence file [FASTA]",
                            action=ReadableFile)
        parser.add_argument("msa", nargs='?',
                            help="MSA [FASTA] for diversityvalue"
                                 "used with bbcontacts")
        parser.add_argument("-t", "--type", required=True, dest="contact_type",
                            choices=self.contact_types, help="Infile contact "
                                                             "type")
        return parser

191
    def _contactmap_argparser(self, desc=None):
fabrice's avatar
fabrice committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        """
        contactmap opt & args
        :param desc: command descriptor
        :return: argparser object
        """
        parser = argp.ArgumentParser(description=desc,
                                     add_help=False)
        parser.add_argument("seq", action=ReadableFile,
                            help="sequence file [FASTA]")
        parser.add_argument("sspred", action=ReadableFile,
                            help="secondary structure prediction file")
        parser.add_argument("infiles", nargs="+", metavar="infile",
                            action=ReadableFile,
                            help="contact or pdb file(s) used to build aria "
                                 "distance restraints")
        parser.add_argument("-t", "--type", required=True,
                            nargs="+", dest="contact_types",
                            choices=self.contact_types, help="Infile(s) "
                                                             "contact "
                                                             "type(s)")
fabrice's avatar
fabrice committed
212
213
214
        parser.add_argument("--merge", nargs="+", dest="merge",
                            choices=self.contact_types,
                            help="Merge given contact types with other maps")
215
        parser.add_argument("--filter", dest="filter", action="store_true",
216
217
                            default=False, help="Use contact list filter "
                                                "and top n contacts selection")
fabrice's avatar
fabrice committed
218
219
220
        parser.add_argument("--onlyreport", dest="onlyreport",
                            action="store_true",
                            default=False, help="Generate only report file")
fabrice's avatar
fabrice committed
221
222
223
        parser.add_argument("--ssidx", dest="ssidx", action="store_true",
                            default=False,
                            help="Use secondary structure index")
fabrice's avatar
fabrice committed
224
        parser.add_argument("--prefix", dest="prefix", default="",
225
                            help="Contact map name", nargs="+")
fabrice's avatar
fabrice committed
226
227
        return parser

Fabrice Allain's avatar
Fabrice Allain committed
228
    @staticmethod
229
    def _pdbqual_argparser(desc=None):
Fabrice Allain's avatar
Fabrice Allain committed
230
231
232
233
234
235
236
237
        parser = argp.ArgumentParser(description=desc,
                                     add_help=False)
        parser.add_argument("infiles", nargs="+", metavar="infile",
                            action=ReadableFile,
                            help="PDB file(s) used to run quality tools with "
                                 "aria API")
        return parser

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
    @staticmethod
    def _tbl2xml_argparser(desc=None):
        parser = argp.ArgumentParser(description=desc,
                                     add_help=False)
        parser.add_argument(
            "outfile", metavar="outfile.xml", action=ReadableFile,
            help="Output distance restraint file in ARIA XML format")
        parser.add_argument(
            "molecule", metavar="molecule.xml", action=ReadableFile,
            help="ARIA XML molecule file")
        parser.add_argument("listname", metavar="list_name",
                            help="Restraint list name in the tbl file")
        parser.add_argument("infiles", nargs="+", metavar="infile.tbl",
                            action=ReadableFile,
                            help="TBL distance restraint file(s)")
        return parser

Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    @staticmethod
    def _pdbdist_argparser(desc=None):
        parser = argp.ArgumentParser(description=desc,
                                     add_help=False)
        parser.add_argument(
            "--cullist", dest="cullpdbs", default=None,
            metavar="CULLED_PDB_LIST", action=ReadableFile,
            help="Culled list of pdb files")
        parser.add_argument(
            "--pdbdir", dest="pdbdir", default=None,
            metavar="PDB_FOLDER",
            help="Folder containing pdb file entries")
        return parser

fabrice's avatar
fabrice committed
269
    def create_settings(self):
270
271
        """Create settings relative to args.command"""

Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
272
        if self.args.verbose:
Fabrice Allain's avatar
Fabrice Allain committed
273
274
            LOG.info("Toggle on debug mode")
            logging.getLogger().setLevel(logging.DEBUG)
275
        LOG.debug("Create AriaEcSettings")
276
        settings = AriaEcSettings(self.args.command)
277
        LOG.info("Loading default config file")
fabrice's avatar
fabrice committed
278
279
        settings.load_config(self.default_confile, pkg=True)
        if self.args.conf_file:
280
            LOG.info("Updating settings with conf file")
fabrice's avatar
fabrice committed
281
282
            settings.load_config(self.args.conf_file)
        # Update settings associated to command section
283
        LOG.info("Updating %s args settings", self.args.command)
284
        LOG.debug(self.args.__dict__)
285
286
        getattr(settings, self.args.command).args.update(format_dict(self.args.__dict__))
        LOG.debug(getattr(settings, self.args.command).args)
fabrice's avatar
fabrice committed
287
        if self.args.output_directory:
288
            LOG.info("Updating output directory %s", self.args.output_directory)
fabrice's avatar
fabrice committed
289
290
291
292
            settings.infra = self.args.output_directory
        return settings

    def run(self):
293
294
295
        """
        call method relative to args.command
        """
296
        LOG.info("Run %s command", self.args.command)
fabrice's avatar
fabrice committed
297
298
299
        getattr(self, self.args.command)()

    def setup(self):
300
301
302
        """
        Setup call
        """
fabrice's avatar
fabrice committed
303
304
305
306
        setup_inst = AriaEcSetup(self.create_settings())
        setup_inst.run()

    def bbconv(self):
307
308
309
        """
        bbcontacts converter call
        """
fabrice's avatar
fabrice committed
310
311
312
313
        bbconverter = AriaEcBbConverter(self.create_settings())
        bbconverter.run()

    def contactmap(self):
314
315
316
        """
        instantiate AriaEcContactmap with AriaSettings
        """
fabrice's avatar
fabrice committed
317
318
319
        econtactmap = AriaEcContactMap(self.create_settings())
        econtactmap.run()

Fabrice Allain's avatar
Fabrice Allain committed
320
321
322
323
324
325
326
    def pdbqual(self):
        """
        Quality run subcommand
        """
        qualprot = AriaEcPdbqual(self.create_settings())
        qualprot.run()

327
328
329
330
331
332
    def tbl2xml(self):
        """
        tbl2xml command
        """
        tblconverter = AriaEcXMLConverter(self.create_settings())
        tblconverter.run_tbl2xml()
fabrice's avatar
fabrice committed
333

Fabrice  ALLAIN's avatar
Fabrice ALLAIN committed
334
335
336
337
338
339
340
    def pdbdist(self):
        """
        Extract pdb distance distributions
        """
        inst = PDBDist(self.create_settings())
        inst.run()

341
342
343
344
345
346
347
348
349
350
351
352
353

def ec2aria():
    """
    Launch ariaec command interface
    """

    mylog = CustomLogging(desc="ARIA Evolutionary Constraints Tools")

    command = AriaEcCommand(custom_logging=mylog)

    command.run()


fabrice's avatar
fabrice committed
354
355
356
if __name__ == "__main__":
    # Test AriaEcCommand object
    logging.basicConfig(level=logging.DEBUG)
357
    LOG = logging.getLogger("IO")
358
    AriaEcCommand()