Test Failed
Branch master (c56792)
by John
02:11
created

bbarchivist.scripts.autolookup.autolookup_main()   F

Complexity

Conditions 14

Size

Total Lines 87
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 46
nop 11
dl 0
loc 87
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like bbarchivist.scripts.autolookup.autolookup_main() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
#!/usr/bin/env python3
2
"""Get software release for one/many OS versions."""
3
4
import sys  # load arguments
5
6
import requests  # session
7
from bbarchivist import decorators  # Ctrl+C wrapper
8
from bbarchivist import networkutils  # lookup
9
from bbarchivist import scriptutils  # default parser
10
from bbarchivist import smtputils  # email
11
from bbarchivist import utilities  # incrementer
12
13
__author__ = "Thurask"
14
__license__ = "WTFPL v2"
15
__copyright__ = "2015-2018 Thurask"
16
17
18
def grab_args():
19
    """
20
    Parse arguments from argparse/questionnaire.
21
22
    Invoke :func:`autolookup.autolookup_main` with those arguments.
23
    """
24
    if len(sys.argv) > 1:
25
        parser = scriptutils.default_parser("bb-autolookup", "Get software releases")
26
        parser.add_argument("os", help="OS version, 10.x.y.zzzz")
27
        parser.add_argument(
28
            "-l", "--loop",
29
            dest="recurse",
30
            help="Loop lookup, CTRL-C to quit",
31
            action="store_true",
32
            default=False)
33
        parser.add_argument(
34
            "-o", "--output",
35
            dest="log",
36
            help="Output to file",
37
            action="store_true",
38
            default=False)
39
        parser.add_argument(
40
            "-a", "--autogen",
41
            dest="autogen",
42
            help="Generate links for availables",
43
            action="store_true",
44
            default=False)
45
        parser.add_argument(
46
            "-q", "--quiet",
47
            dest="quiet",
48
            help="Only print if available (implies -p)",
49
            action="store_true",
50
            default=False)
51
        parser.add_argument(
52
            "-i", "--increment",
53
            dest="increment",
54
            help="Loop increment, default = 3",
55
            default=3,
56
            type=utilities.positive_integer,
57
            metavar="INT")
58
        parser = frozen_args(parser)
59
        parser.add_argument(
60
            "-c", "--ceiling",
61
            dest="ceiling",
62
            help="When to stop script, default = 9996",
63
            default=9996,
64
            type=int,
65
            choices=range(1, 9997),
66
            metavar="INT")
67
        parser.add_argument(
68
            "-p", "--prod-only",
69
            dest="production",
70
            help="Only check production server",
71
            action="store_true",
72
            default=False)
73
        parser.add_argument(
74
            "-n2", "--no-2",
75
            dest="no2",
76
            help="Skip checking Alpha/Beta 2 servers",
77
            action="store_true",
78
            default=False)
79
        args = parser.parse_args(sys.argv[1:])
80
        parser.set_defaults()
81
        execute_args(args)
82
    else:
83
        questionnaire()
84
85
86
def frozen_args(parser):
87
    """
88
    Add args to parser if not frozen.
89
90
    :param parser: Parser to modify.
91
    :type parser: argparse.ArgumentParser
92
    """
93
    if not getattr(sys, 'frozen', False):
94
        parser.add_argument(
95
            "-s", "--sql",
96
            dest="sql",
97
            help="Add valid links to database",
98
            action="store_true",
99
            default=False)
100
        parser.add_argument(
101
            "-e", "--email",
102
            dest="email",
103
            help="Email valid links to self",
104
            action="store_true",
105
            default=False)
106
    return parser
107
108
109
def execute_args(args):
110
    """
111
    Get args and decide what to do with them.
112
113
    :param args: Arguments.
114
    :type args: argparse.Namespace
115
    """
116
    if getattr(sys, 'frozen', False):
117
        args.sql = False
118
        args.email = False
119
    if args.quiet:
120
        args.production = True  # impossible otherwise
121
    autolookup_main(args.os, args.recurse, args.log, args.autogen, args.increment, args.sql, args.quiet, args.ceiling, args.email, args.production, args.no2)
122
123
124
def questionnaire():
125
    """
126
    Questions to ask if no arguments given.
127
    """
128
    osversion = input("OS VERSION: ")
129
    recurse = utilities.i2b("LOOP (Y/N)?: ")
130
    if recurse:
131
        print("Press Ctrl+C to stop loop")
132
    print(" ")
133
    autolookup_main(osversion, recurse, True, False, 3, False, False, 9996, False, False)
134
    decorators.enter_to_exit(True)
135
136
137
@decorators.wrap_keyboard_except
138
def autolookup_main(osversion, loop=False, log=False, autogen=False, inc=3, sql=False, quiet=False, ceiling=9996, mailer=False, prod=False, no2=False):
2 ignored issues
show
best-practice introduced by
Too many arguments (11/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (32/15).
Loading history...
139
    """
140
    Lookup a software release from an OS. Can iterate.
141
142
    :param osversion: OS version, 10.x.y.zzzz.
143
    :type osversion: str
144
145
    :param loop: Whether or not to automatically lookup. Default is false.
146
    :type loop: bool
147
148
    :param log: Whether to log. Default is false.
149
    :type log: bool
150
151
    :param autogen: Whether to create text links. Default is false.
152
    :type autogen: bool
153
154
    :param inc: Lookup increment. Default is 3.
155
    :type inc: int
156
157
    :param sql: Whether to add valid lookups to a database. Default is false.
158
    :type sql: bool
159
160
    :param quiet: Whether to only output if release exists. Default is false.
161
    :type quiet: bool
162
163
    :param ceiling: When to stop loop. Default is 9996 (i.e. 10.x.y.9996).
164
    :type ceiling: int
165
166
    :param mailer: Whether to email new valid links. Default is false.
167
    :type mailer: bool
168
169
    :param prod: Whether to check only the production server. Default is false.
170
    :type prod: bool
171
172
    :param no2: Whether to skip Alpha2/Beta2 servers. Default is false.
173
    :type no2: bool
174
    """
175
    if mailer:
176
        sql = True
177
        smtpc = smtputils.smtp_config_loader()
178
        smtpc = smtputils.smtp_config_generator(smtpc)
179
        smtpc['homepath'] = None
180
        pword = smtpc['password']
181
        smtputils.smtp_config_writer(**smtpc)
182
    else:
183
        pword = None
184
    scriptutils.slim_preamble("AUTOLOOKUP")
185
    record = utilities.prep_logfile() if log else None
186
    sess = requests.Session()
187
    while True:
188
        if loop and int(osversion.split(".")[3]) > ceiling:
189
            raise KeyboardInterrupt
190
        print("NOW SCANNING: {0}".format(osversion), end="\r")
191
        if not prod:
192
            results = networkutils.sr_lookup_bootstrap(osversion, sess, no2)
193
        else:
194
            res = networkutils.sr_lookup(osversion, networkutils.SERVERS["p"], sess)
195
            results = {"p": res, "a1": None, "a2": None, "b1": None, "b2": None}
196
        if results is None:
197
            raise KeyboardInterrupt
198
        a1rel, a1av = networkutils.clean_availability(results, 'a1')
199
        if not no2:
200
            a2rel, a2av = networkutils.clean_availability(results, 'a2')
201
        else:
202
            a2rel = "SR not in system"
203
            a2av = "  "
204
        b1rel, b1av = networkutils.clean_availability(results, 'b1')
205
        b2rel, b2av = networkutils.clean_availability(results, 'b2')
206
        prel, pav, avail = scriptutils.prod_avail(results, mailer, osversion, pword)
207
        avpack = (a1av, a2av, b1av, b2av, pav)
208
        swrelease = scriptutils.clean_swrel(set([a1rel, a2rel, b1rel, b2rel, prel]))
209
        if swrelease != "":
210
            out = scriptutils.autolookup_output(osversion, swrelease, avail, avpack, sql)
211
            scriptutils.autolookup_printer(out, avail, log, quiet, record)
212
        if autogen and avail == "Available":
213
            rad = utilities.increment(osversion, 1)
214
            scriptutils.linkgen(osversion, rad, prel)
215
        if not loop:
216
            raise KeyboardInterrupt  # hack, but whatever
217
        else:
218
            if int(osversion.split(".")[3]) > ceiling:
219
                raise KeyboardInterrupt
220
            else:
221
                osversion = utilities.increment(osversion, inc)
222
                swrelease = ""
223
                continue
224
225
226
if __name__ == "__main__":
227
    grab_args()
228