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)