From c04705e7ad0bc1cf38cdd117626c65fb1ff66b3c Mon Sep 17 00:00:00 2001 From: xqt Date: Tue, 2 Jan 2024 15:11:00 +0100 Subject: [PATCH] [bugfix] Check for 'from' option first - import pydot first, use exception for dependency warning - make args method a staticmethod and renamit it to setup_args - remove ap parametr from CategoryGraphBot which isn't used - use vars() function to access to args.__dict__ - fix usage of args attribute within CategoryGraphBot - add main() function - pass local_args to ap.parse_known_args - pass rest of ap.parse_known_args to suggest_help as unknown_parameters - call suggest_help() first - use contextlib.suppress to ignore FileNotFoundError Bug: T354162 Change-Id: Ic8694814ed54825ae9999cdb4610387e6a2e94c4 --- scripts/category_graph.py | 63 ++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/scripts/category_graph.py b/scripts/category_graph.py index c50a1dca62..9be4863552 100755 --- a/scripts/category_graph.py +++ b/scripts/category_graph.py @@ -6,7 +6,7 @@ Usage: - pwb.py graph [-style STYLE] [-depth DEPTH] [-from FROM] [-to TO] + pwb.py category_graph [-style STYLE] [-depth DEPTH] [-from FROM] [-to TO] actions: @@ -37,7 +37,7 @@ .. versionadded:: 8.0 """ # -# (C) Pywikibot team, 2022-2023 +# (C) Pywikibot team, 2022-2024 # # Distributed under the terms of the MIT license. # @@ -45,8 +45,8 @@ import argparse import glob -import sys from collections import defaultdict +from contextlib import suppress from pathlib import Path import pywikibot @@ -54,10 +54,17 @@ from pywikibot.bot import SingleSiteBot, suggest_help +try: + import pydot +except ImportError as e: + pydot = e + + class CategoryGraphBot(SingleSiteBot): """Bot to create graph of the category structure.""" - def args(self, ap): + @staticmethod + def setup_args(ap): """Declares arguments.""" ap.add_argument('-from', nargs='?', default=argparse.SUPPRESS) ap.add_argument('-to', nargs='?', default='') @@ -65,11 +72,11 @@ def args(self, ap): ap.add_argument('-depth', nargs='?', default=2) ap.add_argument('-downsize', nargs='?', default=4) - def __init__(self, ap, args: argparse.Namespace) -> None: + def __init__(self, args: argparse.Namespace) -> None: """Initializer.""" super().__init__() self.args = args - cat_title = args.__dict__.get('from') + cat_title = vars(args)['from'] if not cat_title: cat_title = 'Main topic classifications' if cat_title == '?': @@ -106,7 +113,7 @@ def scan_level(self, cat, level, hue=None) -> str: the tree (for recursion), opposite of depth. """ title = cat.title(with_ns=False) - size = float(args.downsize) ** level + size = float(self.args.downsize) ** level subcats = sorted(cat.subcategories()) def node(): @@ -202,11 +209,26 @@ def run(self) -> None: o.write(self.dot.create('dot', 'svg', encoding='utf-8')) -if __name__ == '__main__': +def main(*args: str) -> None: + """ + Process command line arguments and invoke bot. + + If args is an empty list, sys.argv is used. + + :param args: command line arguments + """ ap = argparse.ArgumentParser(add_help=False) - CategoryGraphBot.args(None, ap) + CategoryGraphBot.setup_args(ap) local_args = pywikibot.handle_args() - args, rest = ap.parse_known_args() + args, rest = ap.parse_known_args(local_args) + + if suggest_help( + missing_action='from' not in args, + unknown_parameters=rest, + missing_dependencies=(['pydot'] if isinstance(pydot, ImportError) + else []) + ): + return file_path = args.to # If file exists, ask user if ok to overwrite. Otherwise, make @@ -216,16 +238,15 @@ def run(self) -> None: 'n', automatic_quit=False) if not choice: pywikibot.info('Exiting...') - sys.exit(1) + return else: - try: - dir_path = Path(file_path) + dir_path = Path(file_path) + with suppress(FileNotFoundError): dir_path.parent.mkdir(parents=True, exist_ok=True) - # Except ValueError in the event that the directory is top level - # and does not contain any slashes. - except FileNotFoundError: - pass - if not suggest_help(missing_action='from' not in args): - import pydot - bot = CategoryGraphBot(ap, args) - bot.run() + + bot = CategoryGraphBot(args) + bot.run() + + +if __name__ == '__main__': + main()