main   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Test Coverage

Coverage 76.92%

Importance

Changes 0
Metric Value
eloc 80
dl 0
loc 167
ccs 60
cts 78
cp 0.7692
rs 10
c 0
b 0
f 0
wmc 17

7 Functions

Rating   Name   Duplication   Size   Complexity  
A mergeOptionsWithConfigFile() 0 16 3
A printVersion() 0 6 1
A determineProtocol() 0 6 1
A setupLogging() 0 5 2
B parseOptions() 0 27 6
A createBot() 0 7 3
A main() 0 18 1
1
#! /usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
"""
5
An IRC bot that answers random questions, keeps a log from the IRC-chat,
6
easy to integrate in a webpage and montores a phpBB forum for latest topics
7
by loggin in to the forum and checking the RSS-feed.
8
9
You need to install additional modules.
10
11
# Install needed modules in local directory
12
pip3 install --target modules/ feedparser beautifulsoup4 chardet
13
14
Modules in modules/ will be loaded automatically. If you want to use a
15
different directory you can start the program like this instead:
16
17
PYTHONPATH=modules python3 main.py
18
19
# To get help
20
PYTHONPATH=modules python3 main.py --help
21
22
# Example of using options
23
--server=irc.bsnet.se --channel=#db-o-webb
24
--server=irc.bsnet.se --port=6667 --channel=#db-o-webb
25
--nick=marvin --ident=secret
26
27
# Configuration
28
Check out the file 'marvin_config_default.json' on how to configure, instead
29
of using cli-options. The default configfile is 'marvin_config.json' but you
30
can change that using cli-options.
31
32
# Make own actions
33
Check the file 'marvin_strings.json' for the file where most of the strings
34
are defined and check out 'marvin_actions.py' to see how to write your own
35
actions. Its just a small function.
36
37
# Read from incoming
38
Marvin reads messages from the incoming/ directory, if it exists, and writes
39
it out the the irc channel.
40
"""
41
42 1
import argparse
43 1
import json
44 1
import logging
45 1
import logging.config
46 1
import os
47 1
import sys
48
49 1
from discord_bot import DiscordBot
50 1
from irc_bot import IrcBot
51
52 1
import marvin_actions
53 1
import marvin_general_actions
54
55
#
56
# General stuff about this program
57
#
58 1
PROGRAM = "marvin"
59 1
AUTHOR = "Mikael Roos"
60 1
EMAIL = "[email protected]"
61 1
VERSION = "0.3.0"
62 1
MSG_VERSION = f"{PROGRAM} version {VERSION}."
63
64 1
LOG = logging.getLogger("main")
65
66
67 1
def printVersion():
68
    """
69
    Print version information and exit.
70
    """
71 1
    print(MSG_VERSION)
72 1
    sys.exit(0)
73
74
75 1
def mergeOptionsWithConfigFile(options, configFile):
76
    """
77
    Read information from config file.
78
    """
79 1
    if os.path.isfile(configFile):
80 1
        with open(configFile, encoding="UTF-8") as f:
81 1
            data = json.load(f)
82
83 1
        options.update(data)
84 1
        res = json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
85 1
        LOG.info("Read configuration from config file '%s'.", configFile)
86 1
        LOG.info("Current configuration is: %s", res)
87
    else:
88
        LOG.info("Config file '{%s}' is not readable, skipping.", configFile)
89
90 1
    return options
91
92
93 1
def parseOptions(options):
94
    """
95
    Merge default options with incoming options and arguments and return them as a dictionary.
96
    """
97
98 1
    parser = argparse.ArgumentParser()
99 1
    parser.add_argument("protocol", choices=["irc", "discord"], nargs="?", default="irc")
100 1
    parser.add_argument("-v", "--version", action="store_true")
101 1
    parser.add_argument("--config")
102
103 1
    for key, value in options.items():
104 1
        parser.add_argument(f"--{key}", type=type(value))
105
106 1
    args = vars(parser.parse_args())
107 1
    if args["version"]:
108 1
        printVersion()
109 1
    if args["config"]:
110 1
        mergeOptionsWithConfigFile(options, args["config"])
111
112 1
    for parameter in options:
113 1
        if args[parameter]:
114 1
            options[parameter] = args[parameter]
115
116 1
    res = json.dumps(options, sort_keys=True, indent=4, separators=(',', ': '))
117 1
    LOG.info("Configuration updated after cli options: %s", res)
118
119 1
    return options
120
121
122 1
def determineProtocol():
123
    """Parse the argument to determine what protocol to use"""
124 1
    parser = argparse.ArgumentParser()
125 1
    parser.add_argument("protocol", choices=["irc", "discord"], nargs="?", default="irc")
126 1
    arg, _ = parser.parse_known_args()
127 1
    return arg.protocol
128
129
130 1
def createBot(protocol):
131
    """Return an instance of a bot with the requested implementation"""
132 1
    if protocol == "irc":
133 1
        return IrcBot()
134 1
    if protocol == "discord":
135 1
        return DiscordBot()
136 1
    raise ValueError(f"Unsupported protocol: {protocol}")
137
138
139 1
def setupLogging():
140
    """Set up the logging config"""
141
    with open("logging.json", encoding="UTF-8") as f:
142
        config = json.load(f)
143
    logging.config.dictConfig(config)
144
145 1
def main():
146
    """
147
    Main function to carry out the work.
148
    """
149
    setupLogging()
150
    protocol = determineProtocol()
151
    bot = createBot(protocol)
152
    options = bot.getConfig()
153
    options.update(mergeOptionsWithConfigFile(options, "marvin_config.json"))
154
    config = parseOptions(options)
155
    bot.setConfig(config)
156
    actions = marvin_actions.getAllActions()
157
    general_actions = marvin_general_actions.getAllGeneralActions()
158
    bot.registerActions(actions)
159
    bot.registerGeneralActions(general_actions)
160
    bot.begin()
161
162
    sys.exit(0)
163
164
165 1
if __name__ == "__main__":
166
    main()
167