bbarchivist.scripts.autolookup.autolookup_main()   F
last analyzed

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