/
cli.py
141 lines (116 loc) · 4.64 KB
/
cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env python3
# -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*-
#
# Copyright (c) 2021 Authors and contributors
#
# Released under the GNU Public Licence, v2 or any higher version
# SPDX-License-Identifier: GPL-2.0-or-later
"""The toplevel command line interface."""
import logging
import sys
import traceback
import warnings
from MDAnalysis.analysis.base import AnalysisBase
from .colors import Emphasise
from .libcli import (
find_cls_members,
init_base_argparse,
run_analsis,
setup_clients,
split_argparse_into_groups,
)
from .logger import setup_logging
from .utils import _exit_if_a_is_b
logger = logging.getLogger(__name__)
def cli(name,
module_list,
base_class=AnalysisBase,
version="",
description="",
skip_modules=None,
ignore_warnings=False):
"""Create the command-line interface.
This function creates a command line interface with a given `name` based
on a module list.
Parameters
----------
name : str
name of the interface
module_list : list
list of module from which the cli is build up.
base_class : cls
Class or list of classes that the Anaylsis modules belong to
description : str
description of the cli
skip_modules : list
list of strings containing modules that should be ommited
ignore_warnings : bool
ignore warnings when importing modules
Examples
--------
This example code creates the command line interface of MDAnalysis::
from MDAnalysis.analysis import __all__
import mdacli
skip_mods = ['AnalysisFromFunction',
'HydrogenBondAnalysis',
'WaterBridgeAnalysis',
'Contacts',
'Dihedral',
'PersistenceLength',
'InterRDF_s']
mdacli.cli(name="MDAnalysis",
module_list=[f'MDAnalysis.analysis.{m}' for m in __all__],
version=mdacli.__version__,
description=__doc__,
skip_modules=skip_mods,
ignore_warnings=True)
"""
modules = find_cls_members(base_class,
module_list,
ignore_warnings=ignore_warnings)
skip_modules = [] if skip_modules is None else skip_modules
modules = [mod for mod in modules if mod.__name__ not in skip_modules]
_exit_if_a_is_b(modules, None, "No analysis modules founds.")
ap = init_base_argparse(name=name,
version=version,
description=description)
if len(sys.argv) < 2:
ap.error("A subcommand is required.")
# There is to much useless code execution done here:
# 1. We do not have to setup all possible clients all the time.
# i.e. for `mda RMSD` only the RMSD client should be build.
# 2. for something like `mdacli -h` We do not have to build every
# sub parser in complete detail.
setup_clients(ap, title=f"{name} Analysis Modules", members=modules)
# Be case insensitive for the subcommand
sys.argv[1] = sys.argv[1].lower()
args = ap.parse_args()
if args.debug:
args.verbose = True
else:
# Ignore all warnings if not in debug mode
warnings.filterwarnings("ignore")
with setup_logging(logger, logfile=args.logfile, debug=args.debug):
# Execute the main client interface.
try:
analysis_callable = args.analysis_callable
# Get the correct ArgumentParser instance from all subparsers
# `[0]` selects the first subparser where our analysises live in.
_key = analysis_callable.__name__.lower()
ap_sup = ap._subparsers._group_actions[0].choices[_key]
arg_grouped_dict = split_argparse_into_groups(ap_sup, args)
# Some parameters may not exist
arg_grouped_dict.setdefault("Optional Parameters", {})
arg_grouped_dict.setdefault("Reference Universe Parameters", None)
arg_grouped_dict.setdefault("Output Parameters", {})
run_analsis(analysis_callable,
arg_grouped_dict["Mandatory Parameters"],
arg_grouped_dict["Optional Parameters"],
arg_grouped_dict["Reference Universe Parameters"],
arg_grouped_dict["Analysis Run Parameters"],
arg_grouped_dict["Output Parameters"])
except Exception as e:
if args.debug:
traceback.print_exc()
else:
sys.exit(Emphasise.error(f"Error: {e}"))