Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ username = ResourcesBot
password = MySecretPassword

# resourcesbot writes language reports to [Paths:languagereports]
# Post-processing modules to run (abbreviations, space-separated).
# Use "all" to run every module (default). Overridden by -m on the command line.
# Run `python3 resourcesbot.py -h` to see available module abbreviations.
modules = all
# Optionally: log to files (will be relative to path defined in [Paths:logs] )
# Three different verbosity levels (warning, info, debug)
logfile = resourcesbot.log
Expand Down
37 changes: 37 additions & 0 deletions pywikitools/resourcesbot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,43 @@ def load_module(module_name: str) -> Callable:
raise RuntimeError(f"Couldn't load module {module_name}. Giving up")


def build_module_choices() -> Dict[str, str]:
"""Return module abbreviations mapped to full module names."""
modules: Dict[str, str] = {}
for selected_module in AVAILABLE_MODULES:
module = load_module(selected_module)
modules[module.abbreviation()] = selected_module
return modules


def resolve_run_modules(
modules: Dict[str, str],
config: ConfigParser,
cli_modules: Optional[List[str]] = None,
) -> list[str]:
"""
Resolve which post-processing modules to run.

Command-line ``-m`` overrides ``[resourcesbot] modules`` in config.ini.
"""
if cli_modules is not None:
return [modules[abbr] for abbr in cli_modules]

config_value = config.get("resourcesbot", "modules", fallback="all").strip()
if config_value.lower() == "all":
return AVAILABLE_MODULES

selected = config_value.split()
unknown = [abbr for abbr in selected if abbr not in modules]
if unknown:
available = ", ".join(sorted(modules.keys()))
raise ValueError(
"Unknown module(s) in config.ini [resourcesbot] modules: "
f"{', '.join(unknown)}. Available: {available}"
)
return [modules[abbr] for abbr in selected]


class ResourcesBot:
"""Contains all the logic of our bot"""

Expand Down
56 changes: 55 additions & 1 deletion pywikitools/test/test_resourcesbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@

import pywikibot

from pywikitools.resourcesbot.bot import ResourcesBot, load_module
from pywikitools.resourcesbot.bot import (
AVAILABLE_MODULES,
ResourcesBot,
build_module_choices,
load_module,
resolve_run_modules,
)
from pywikitools.resourcesbot.data_structures import TranslationProgress, WorksheetInfo
from pywikitools.test.test_data_structures import TEST_PROGRESS, TEST_TIME, TEST_URL

Expand Down Expand Up @@ -341,5 +347,53 @@ def factory(*args, **kwargs):
# TODO: test_run_with_limit_lang


class TestResolveRunModules(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.modules = build_module_choices()

def _config_with_modules(self, modules_value: str) -> ConfigParser:
config = ConfigParser()
config.read_dict(
{
"resourcesbot": {
"site": "test",
"username": "TestBotName",
"modules": modules_value,
}
}
)
return config

def test_default_is_all_modules(self):
config = ConfigParser()
config.read_dict({"resourcesbot": {"site": "test", "username": "TestBotName"}})
self.assertEqual(resolve_run_modules(self.modules, config), AVAILABLE_MODULES)

def test_config_all(self):
config = self._config_with_modules("all")
self.assertEqual(resolve_run_modules(self.modules, config), AVAILABLE_MODULES)

def test_config_specific_modules(self):
config = self._config_with_modules("list report")
self.assertEqual(
resolve_run_modules(self.modules, config),
["write_lists", "write_report"],
)

def test_cli_overrides_config(self):
config = self._config_with_modules("list")
self.assertEqual(
resolve_run_modules(self.modules, config, cli_modules=["report"]),
["write_report"],
)

def test_config_unknown_module_raises(self):
config = self._config_with_modules("list unknown")
with self.assertRaises(ValueError) as context:
resolve_run_modules(self.modules, config)
self.assertIn("unknown", str(context.exception))


if __name__ == "__main__":
unittest.main()
30 changes: 16 additions & 14 deletions resourcesbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,14 @@
import sys
import traceback
from configparser import ConfigParser
from typing import Dict, List
from typing import List

from pywikitools.resourcesbot.bot import AVAILABLE_MODULES, ResourcesBot, load_module
from pywikitools.resourcesbot.bot import (
ResourcesBot,
build_module_choices,
load_module,
resolve_run_modules,
)


def parse_arguments() -> ResourcesBot:
Expand All @@ -85,16 +90,17 @@ def parse_arguments() -> ResourcesBot:

log_levels: List[str] = ["debug", "info", "warning", "error"]
rewrite_options: List[str] = ["all", "json", "summary"]
modules: Dict[str, str] = {} # abbreviation -> full name
modules = build_module_choices()
modules_help = "Select the modules to be run. Available options are:\n"
# Read module information from the module classes
for selected_module in AVAILABLE_MODULES:
for abbr, selected_module in modules.items():
module = load_module(selected_module)
modules_help += f" - {module.abbreviation()}: {module.help_summary()}\n"
modules[module.abbreviation()] = selected_module
modules_help += f" - {abbr}: {module.help_summary()}\n"
if module.can_be_rewritten():
rewrite_options.append(module.abbreviation())
modules_help += "Default: run all modules"
rewrite_options.append(abbr)
modules_help += (
"Default: all modules, or set [resourcesbot] modules= in config.ini "
"(overridden by -m)"
)

parser.add_argument(
"--read-from-cache",
Expand Down Expand Up @@ -133,11 +139,7 @@ def parse_arguments() -> ResourcesBot:
assert isinstance(numeric_level, int)
set_loglevel(config, numeric_level)

# Map abbreviations to full module names
if args.m is None:
run_modules = AVAILABLE_MODULES
else:
run_modules = [modules[abbr] for abbr in args.m]
run_modules = resolve_run_modules(modules, config, args.m)

return ResourcesBot(
config=config,
Expand Down
Loading