Module: cli¶
The CLI is basically documented everywhere else. It takes the following subcommands:
* fetch: Connect to a bunch of servers and fetch toots
* analyse: Read the files we stored from fetch and analyse them. Store results in JSON files for later use
* post: Read the analysis files, post the results on Mastodon
* graph: Draw a histogram diagram of activity during the event
* wordcloud: Draw a word cloud diagram of words used during the event
* init: Interactively ask you for answers to some questions so you can get an INI file started
* graphs: Just a convenience command that will call graph and then wordcloud in a single run.
Debugging¶
The main thing that the CLI module does is handle command line arguments and set the debug level. I intended debug to be a config option in the config module. That way you could turn up or turn down the verbosity on different phases. I didn't implement it that way. That's on the TODO list. Instead you have to give the --debug (or -d) option on the command line and it will apply everywhere.
Code Reference¶
cli.py: Command line module for calling mastoscore to do its work
main()
¶
Parse command line arguments, figure out what we're doing. Do it.
Source code in mastoscore/cli.py
def main():
"""
Parse command line arguments, figure out what we're doing. Do it.
"""
args = None
logger = None
valid_actions = ['init', 'fetch', 'analyse', 'post', 'graph', 'wordcloud', 'postgraphs']
parser = argparse.ArgumentParser(
description='Fetch recent toots on a hashtag, score them. Optionally post the analysis')
parser.add_argument('-d', '--debug', type=str, required=False,
default='WARN', help='Enable debugging messages. Logger levels like DEBUG, INFO, WARN, ERROR. Default: WARN')
parser.add_argument('config', type=str, nargs='?',
help='INI config file with config plus credentials. Not required for init action.')
parser.add_argument('action', type=str, nargs='?', default=None,
help='Action to take: init (create new config), fetch, analyse, post, graph, wordcloud, postgraphs.')
args = parser.parse_args()
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(levelname)s\t%(message)s')
args.debug = args.debug.upper()
log_level = logging.getLevelName(args.debug)
# If level_name is a string recognized by logging, you get an int
# else, you get a string
if type(log_level).__name__ == "int":
logger.setLevel(log_level)
logger.debug("Logging activated")
else:
logger.setLevel(logging.ERROR)
logger.error(f"'{args.debug}' is not a valid log level. Logging set to ERROR")
# Handle init action separately
if args.config == 'init':
from .init import init
if init():
exit(0)
else:
exit(1)
# For all other actions, require and validate config file
if args.config is None:
logger.error("Config file is required for all actions except 'init'")
exit(2)
try:
config = read_config(args.config)
if config is None:
exit(2)
except FileNotFoundError:
logger.error(f"Config file not found: {args.config}")
exit(2)
except PermissionError:
logger.error(f"Permission denied reading config file: {args.config}")
exit(2)
except Exception as e:
logger.error(f"Error reading config file: {e}")
exit(2)
config.set(config.default_section, 'debug', str(logger.level))
match args.action:
case "blog":
blog(config)
case "fetch":
fetch(config)
case "analyse":
analyse(config)
case "post":
post(config)
case "graph":
graph(config)
case "graphs":
graph(config)
write_wordcloud(config)
case "wordcloud":
write_wordcloud(config)
case "postgraphs":
post_graphs(config)
case _:
parser.print_help()
logger.error(
f"'{args.action}' is not a valid action. Must be one of: {valid_actions}")
exit(1)
exit(0)