Source code for scripts.maintenance.addwikis

#!/usr/bin/env python3
#
# (C) Pywikibot team, 2024-2026
#
# Distributed under the terms of the MIT license.
#
"""Script that adds new wikis to the codes set in Wikimedia family files.

Usage:

    python pwb.py addwikis [-family:<fam>] {<wiki>} {-family:<fam> {<wiki>}}


Example:

    :code:`python pwb.py addwikis foo -family:wikisource bar baz`

    adds code ``foo`` to the default (wikipedia) family, and codes ``bar``
    and ``baz`` to wikisource.


.. version-added:: 9.2
.. version-changed:: 10.4
   The options ``-h``, ``-help`` and ``--help`` display the help message.
.. version-deprecated:: 10.4
   The ``help`` option
.. version-changed:: 11.0
   Multiple families can be given with one run. The difference is shown
   instead of the new list.
.. version-changed:: 11.3
   wikinews is no longer supported by this script because all wikinews
   sites are closed. Also update
   :attr:`family.WikimediaFamily.known_codes`.

"""
from __future__ import annotations

import re
import sys
from collections import defaultdict
from pathlib import Path

import pywikibot
from pywikibot.exceptions import ArgumentDeprecationWarning
from pywikibot.family import Family
from pywikibot.tools import issue_deprecation_warning


# supported families by this script
FAMILIES_LIST = [
    'wikibooks',
    'wikipedia',
    'wikiquote',
    'wikisource',
    'wikiversity',
    'wikivoyage',
    'wiktionary',
]


[docs] def combine_codes(codes: set[str], /, *, attr='codes', style='{}') -> str: """Combine codes and return a formatted Python assignment block. .. version-added:: 11.3 """ new = sorted(codes) opening, closing = style text = f' {attr} = {opening}\n' line = ' ' * 7 for code in new: if len(line) + len(code) >= 76: text += line + '\n' line = ' ' * 7 line += f" '{code}'," text += line + '\n' text += f' {closing}' return text
[docs] def update_known_codes(families: list[str]) -> None: """Collect all codes from all families and update Family.known_codes. .. version-added:: 11.3 """ pywikibot.info() family = Family.load(families[0]) if not isinstance(family, pywikibot.family.WikimediaFamily): pywikibot.info(f'{family} is not a WikimediaFamily') return original: set[str] = set(family.known_codes) new_codes: set[str] = set(family.codes) for family_name in families[1:]: new_codes.update(Family.load(family_name).codes) new_codes.discard('mul') if new_codes <= original: pywikibot.info('No codes to add to known_codes list.') return pywikibot.info('Updating known_codes list:\n') text = combine_codes(original | new_codes, attr='known_codes', style='[]') filepath = Path('pywikibot/family.py') old_family_text = filepath.read_text(encoding='utf8') new_family_text = re.sub(r'(?ms)^ {4}known_codes = \[.+?\]', text, old_family_text, count=1) pywikibot.showDiff(old_family_text, new_family_text) filepath.write_text(new_family_text, encoding='utf8')
[docs] def update_family(family_name: str, wikis: set) -> None: """Update codes set in family file.""" joined_wikis = "', '".join(wikis) pywikibot.info(f"Adding '{joined_wikis}' to {family_name} family...\n") family = Family.load(family_name) original = family.codes new_codes = set() for wiki in list(wikis): if wiki in original: pywikibot.warning( f'{wiki!r} is already in Family.codes; ignoring.') else: new_codes.add(wiki) # cleanup cache family._families.clear() module = type(family).__module__ del sys.modules[module] if not new_codes: pywikibot.info('No wikis to add.') return pywikibot.info("The lists don't match, the updated list is:\n") text = combine_codes(original | new_codes) filepath = Path(f'pywikibot/families/{module}.py') old_family_text = filepath.read_text(encoding='utf8') new_family_text = re.sub(r'(?ms)^ {4}codes = \{.+?\}', text, old_family_text, count=1) pywikibot.showDiff(old_family_text, new_family_text) filepath.write_text(new_family_text, encoding='utf8')
[docs] def main(*args: str) -> None: """Script entry point to handle args.""" if not args: args = sys.argv[1:] sys.argv = [sys.argv[0]] current_family = 'wikipedia' wikis = defaultdict(set) for arg in args: if arg.startswith('-family'): current_family = arg.split(':')[1] elif arg in ('help', '-h', '-help', '--help'): if arg == 'help': issue_deprecation_warning( "'help' option", "'-h', '-help' or '--help'", since='10.4.0', warning_class=ArgumentDeprecationWarning ) pywikibot.show_help() return else: wikis[current_family].add(arg) if not wikis: pywikibot.bot.suggest_help( additional_text='No wiki is specified to be added.') for family, codes in wikis.items(): if family not in FAMILIES_LIST: pywikibot.bot.suggest_help( additional_text=f'Script cannot be used for {family} family.') else: update_family(family, codes) update_known_codes(FAMILIES_LIST)
if __name__ == '__main__': main()