Xqt has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1081972?usp=email )
Change subject: [doc] Adjust scripts options ......................................................................
[doc] Adjust scripts options
script options where idented by 1 space to show it as literal block. Now use the option list and not appropriate e.g. having a ':' inside the option use a definition list and mark the option with 'kbd: role.
Change-Id: I0cfc01994264c17815f4e838759af3118a8decfb --- M docs/conf.py M scripts/archivebot.py M scripts/basic.py M scripts/blockpageschecker.py M scripts/category.py M scripts/category_graph.py M scripts/commonscat.py M scripts/create_isbn_edition.py M scripts/delete.py M scripts/djvutext.py M scripts/listpages.py M scripts/reflinks.py M scripts/revertbot.py M scripts/unusedfiles.py M scripts/upload.py 15 files changed, 570 insertions(+), 494 deletions(-)
Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
diff --git a/docs/conf.py b/docs/conf.py index f18f61c..e36ab8f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,7 +44,6 @@
os.environ['PYWIKIBOT_NO_USER_CONFIG'] = '1' import pywikibot # noqa: E402 -from pywikibot.backports import removeprefix # noqa: E402
# -- General configuration ------------------------------------------------ @@ -533,17 +532,11 @@ """Pywikibot specific conversions.""" from scripts.cosmetic_changes import warning
- # these scripts are skipped for fixing options lists - skipscripts = {'add_text', 'clean_sandbox'} - - if what != 'module': - return - - if not name.startswith('scripts.'): + if what != 'module' or 'scripts.' not in name: return
length = 0 - shortname = removeprefix(name, 'scripts.') + desc = '' for index, line in enumerate(lines): # highlight the first line if index == 0: # highlight the first line @@ -563,46 +556,30 @@ elif name == 'scripts.cosmetic_changes' and line == '&warning;': lines[index] = warning
- # Initiate code block except pagegenerator arguments follows - elif (shortname not in skipscripts - and line.endswith(':') - and not line.lstrip().startswith(':') - and 'Traceback (most recent call last)' not in line): - for afterline in lines[index + 1:]: - if not afterline: - continue - if afterline != '¶ms;': - lines[index] = line + ':' - break - - # adjust options - if shortname not in skipscripts and line.startswith('-'): - # Indent options - match = re.match(r'-[^ ]+? +', line) + # adjust options: if the option contains a colon, convert it to a + # definition list and mark the option with a :kbd: role. Also convert + # option types enclosed in square brackets to italic style. + if line.startswith('-'): + # extract term and wrap it with :kbd: role + match = re.fullmatch(r'(-\w.+?[^ ])( {2,})(.+)', line) if match: - length = len(match[0]) - lines[index] = ' ' + line - elif length and line.startswith(' ' * length): - # Indent descriptions of options (as options are indented) - lines[index] = ' ' + line + opt, sp, desc = match.groups() + desc = re.sub(r'[(float|int|str)]', r'*(\1)*', desc) + if ':' in opt or ' ' in opt: + length = len(opt + sp) + lines[index] = f':kbd:`{opt}`' + else: + lines[index] = f'{opt}{sp}{desc}' + + elif length and (not line or line.startswith(' ' * length)): + # Add descriptions to the next line + lines[index] = ' ' * length + f'{desc} {line.strip()}' + length = 0 elif line: # Reset length length = 0
-TYPE_PATTERN = re.compile(r'( +)[(float|int|str)]') - - -def pywikibot_option_types_fixups(app, what, name, obj, options, lines): - """Convert option types enclosed in square brackets to italic style.""" - if what != 'module' or 'scripts.' not in name: - return - - for index, line in enumerate(lines): - if line.startswith('-'): - lines[index] = TYPE_PATTERN.sub(r'\1*(\2)*', line) - - def pywikibot_family_classproperty_getattr(obj, name, *defargs): """Custom getattr() to get classproperty instances.""" from sphinx.util.inspect import safe_getattr @@ -631,7 +608,6 @@ """Implicit Sphinx extension hook.""" app.connect('autodoc-process-docstring', pywikibot_docstring_fixups) app.connect('autodoc-process-docstring', pywikibot_script_docstring_fixups) - app.connect('autodoc-process-docstring', pywikibot_option_types_fixups) app.add_autodoc_attrgetter(type, pywikibot_family_classproperty_getattr)
diff --git a/scripts/archivebot.py b/scripts/archivebot.py index 8694d64..3a2b220 100755 --- a/scripts/archivebot.py +++ b/scripts/archivebot.py @@ -17,76 +17,100 @@
Transcluded template may contain the following parameters:
- {{TEMPLATE_PAGE - |archive = - |algo = - |counter = - |maxarchivesize = - |minthreadsleft = - |minthreadstoarchive = - |archiveheader = - |key = - }} +.. code:: wikitext + + {{TEMPLATE_PAGE + |archive = + |algo = + |counter = + |maxarchivesize = + |minthreadsleft = + |minthreadstoarchive = + |archiveheader = + |key = + }}
Meanings of parameters are:
- archive Name of the page to which archived threads will be put. - Must be a subpage of the current page. Variables are - supported. - algo Specifies the maximum age of a thread. Must be - in the form old(<delay>) where <delay> specifies - the age in seconds (s), hours (h), days (d), - weeks (w), or years (y) like 24h or 5d. Default is - old(24h). - counter The current value of a counter which could be assigned as - variable. Will be updated by bot. Initial value is 1. - maxarchivesize The maximum archive size before incrementing the counter. - Value can be given with appending letter like K or M - which indicates KByte or MByte. Default value is 200K. - minthreadsleft Minimum number of threads that should be left on a page. - Default value is 5. - minthreadstoarchive The minimum number of threads to archive at once. Default - value is 2. - archiveheader Content that will be put on new archive pages as the - header. This parameter supports the use of variables. - Default value is {{talkarchive}} - key A secret key that (if valid) allows archives not to be - subpages of the page being archived. +archive + Name of the page to which archived threads will be put. Must be a + subpage of the current page. Variables are supported. +algo + Specifies the maximum age of a thread. Must be in the form + :code:`old(<delay>)` where ``<delay>`` specifies the age in + seconds (s), hours (h), days (d), weeks (w), or years (y) like ``24h`` + or ``5d``. Default is :code:`old(24h)`. +counter + The current value of a counter which could be assigned as variable. + Will be updated by bot. Initial value is 1. +maxarchivesize + The maximum archive size before incrementing the counter. Value can + be given with appending letter like ``K`` or ``M`` which indicates + KByte or MByte. Default value is ``200K``. +minthreadsleft + Minimum number of threads that should be left on a page. Default + value is 5. +minthreadstoarchive + The minimum number of threads to archive at once. Default value is 2. +archiveheader + Content that will be put on new archive pages as the header. This + parameter supports the use of variables. Default value is + ``{{talkarchive}}``. +key + A secret key that (if valid) allows archives not to be subpages of + the page being archived.
Variables below can be used in the value for "archive" in the template -above; numbers are latin digits: +above; numbers are **latin** digits. Alternatively you may use +**localized** digits. This is only available for a few site languages. +Refer :attr:`NON_LATIN_DIGITS +<userinterfaces.transliteration.NON_LATIN_DIGITS>` whether there is a +localized one.
-%(counter)d the current value of the counter -%(year)d year of the thread being archived -%(isoyear)d ISO year of the thread being archived -%(isoweek)d ISO week number of the thread being archived -%(semester)d semester term of the year of the thread being archived -%(quarter)d quarter of the year of the thread being archived -%(month)d month (as a number 1-12) of the thread being archived -%(monthname)s localized name of the month above -%(monthnameshort)s first three letters of the name above -%(week)d week number of the thread being archived +.. list-table:: + :header-rows: 1
-Alternatively you may use localized digits. This is only available for a -few site languages. Refer :attr:`NON_LATIN_DIGITS -<userinterfaces.transliteration.NON_LATIN_DIGITS>` whether -there is a localized one: + * - latin + - localized + - Description + * - %(counter)d + - %(localcounter)s + - the current value of the counter + * - %(year)d + - %(localyear)s + - year of the thread being archived + * - %(isoyear)d + - %(localisoyear)s + - ISO year of the thread being archived + * - %(isoweek)d + - %(localisoweek)s + - ISO week number of the thread being archived + * - %(semester)d + - %(localsemester)s + - semester term of the year of the thread being archived + * - %(quarter)d + - %(localquarter)s + - quarter of the year of the thread being archived + * - %(month)d + - %(localmonth)s + - month (as a number 1-12) of the thread being archived + * - %(monthname)s + - + - localized name of the month above + * - %(monthnameshort)s + - + - first three letters of the name above + * - %(week)d + - %(localweek)s + - week number of the thread being archived
-%(localcounter)s the current value of the counter -%(localyear)s year of the thread being archived -%(localisoyear)s ISO year of the thread being archived -%(localisoweek)s ISO week number of the thread being archived -%(localsemester)s semester term of the year of the thread being archived -%(localquarter)s quarter of the year of the thread being archived -%(localmonth)s month (as a number 1-12) of the thread being archived -%(localweek)s week number of the thread being archived - -The ISO calendar starts with the Monday of the week which has at least four -days in the new Gregorian calendar. If January 1st is between Monday and -Thursday (including), the first week of that year started the Monday of that -week, which is in the year before if January 1st is not a Monday. If it's -between Friday or Sunday (including) the following week is then the first week -of the year. So up to three days are still counted as the year before. +The ISO calendar starts with the Monday of the week which has at least +four days in the new Gregorian calendar. If January 1st is between +Monday and Thursday (including), the first week of that year started the +Monday of that week, which is in the year before if January 1st is not a +Monday. If it's between Friday or Sunday (including) the following week +is then the first week of the year. So up to three days are still +counted as the year before.
.. seealso:: Python :python:`datetime.date.isocalendar <library/datetime.html#datetime.date.isocalendar>`, @@ -94,18 +118,27 @@
Options (may be omitted):
- -help show this help message and exit - -calc:PAGE calculate key for PAGE and exit - -file:FILE load list of pages from FILE - -force override security options - -locale:LOCALE switch to locale LOCALE - -namespace:NS only archive pages from a given namespace - -page:PAGE archive a single PAGE, default ns is a user talk page - -salt:SALT specify salt - -keep Preserve thread order in archive even if threads are - archived later - -sort Sort archive by timestamp; should not be used with -keep - -async Run the bot in parallel tasks. +-help show this help message and exit + +-calc:PAGE calculate key for PAGE and exit + +-file:FILE load list of pages from FILE + +-force override security options + +-locale:LOCALE switch to locale LOCALE + +-namespace:NS only archive pages from a given namespace + +-page:PAGE archive a single PAGE, default ns is a user talk page + +-salt:SALT specify salt + +-keep Preserve thread order in archive even if threads are + archived later +-sort Sort archive by timestamp; should not be used with `keep` + +-async Run the bot in parallel tasks.
.. versionchanged:: 7.6 Localized variables for "archive" template parameter are supported. diff --git a/scripts/basic.py b/scripts/basic.py index 5775b2b..4465544 100755 --- a/scripts/basic.py +++ b/scripts/basic.py @@ -1,33 +1,33 @@ #!/usr/bin/env python3 -""" -An incomplete sample script. +"""An incomplete sample script.
This is not a complete bot; rather, it is a template from which simple bots can be made. You can rename it to mybot.py, then edit it in whatever way you want.
-Use global -simulate option for test purposes. No changes to live wiki -will be done. +Use :ref:`global<Global Options>` ``-simulate`` option for test purposes. +No changes to live wiki will be done.
The following parameters are supported:
--always The bot won't ask for confirmation when putting a page +-always The bot won't ask for confirmation when putting a page
--text: Use this text to be added; otherwise 'Test' is used +-text: Use this text to be added; otherwise 'Test' is used
--replace: Don't add text but replace it +-replace: Don't add text but replace it
--top Place additional text on top of the page +-top Place additional text on top of the page
--summary: Set the action summary message for the edit. +-summary: Set the action summary message for the edit.
-This sample script is a -:py:obj:`ConfigParserBot <bot.ConfigParserBot>`. All settings can be -made either by giving option with the command line or with a settings file -which is scripts.ini by default. If you don't want the default values you can -add any option you want to change to that settings file below the [basic] -section like: +This sample script is a :class:`ConfigParserBot <bot.ConfigParserBot>`. +All settings can be made either by giving option with the command line +or with a settings file which is scripts.ini by default. If you don't +want the default values you can add any option you want to change to +that settings file below the [basic] section like: + +.. code:: ini
[basic] ; inline comments starts with colon # This is a commend line. Assignments may be done with '=' or ':' @@ -44,7 +44,7 @@ ¶ms; """ # -# (C) Pywikibot team, 2006-2022 +# (C) Pywikibot team, 2006-2024 # # Distributed under the terms of the MIT license. # diff --git a/scripts/blockpageschecker.py b/scripts/blockpageschecker.py index afb9eb1..02f5562 100755 --- a/scripts/blockpageschecker.py +++ b/scripts/blockpageschecker.py @@ -3,33 +3,35 @@ A bot to remove stale protection templates from pages that are not protected.
Very often sysops block the pages for a set time but then they forget to -remove the warning! This script is useful if you want to remove those useless -warning left in these pages. +remove the warning! This script is useful if you want to remove those +useless warning left in these pages.
-These command line parameters can be used to specify which pages to work on: +These command line parameters can be used to specify which pages to work +on:
¶ms;
Furthermore, the following command line parameters are supported:
-protectedpages Check all the blocked pages; useful when you have not - categories or when you have problems with them. (add the - namespace after ":" where you want to check - default checks - all protected pages.) + categories or when you have problems with them. (add + the namespace after ":" where you want to check - + default checks all protected pages.)
-moveprotected Same as -protectedpages, for moveprotected pages
-This script is a :py:obj:`ConfigParserBot <bot.ConfigParserBot>`. -The following options can be set within a settings file which is scripts.ini -by default:: +This script is a :class:`ConfigParserBot <bot.ConfigParserBot>`. The +following options can be set within a settings file which is scripts.ini +by default:
--always Doesn't ask every time whether the bot should make the change. - Do it always. +-always Doesn't ask every time whether the bot should make the + change. Do it always.
--show When the bot can't delete the template from the page (wrong - regex or something like that) it will ask you if it should - show the page on your browser. - (attention: pages included may give false positives!) +-show When the bot can't delete the template from the page + (wrong regex or something like that) it will ask you if + it should show the page on your browser. + + .. attention:: Pages included may give false positives!
-move The bot will check if the page is blocked also for the move option, not only for edit diff --git a/scripts/category.py b/scripts/category.py index a430341..83ff20b 100755 --- a/scripts/category.py +++ b/scripts/category.py @@ -10,11 +10,13 @@ *add* mass-add a category to a list of pages. *remove* - remove category tag from all pages in a category. If a pagegenerators - option is given, the intersection with category pages is processed. + remove category tag from all pages in a category. If a + pagegenerators option is given, the intersection with category pages + is processed. *move* - move all pages in a category to another category. If a pagegenerators - option is given, the intersection with category pages is processed. + move all pages in a category to another category. If a + pagegenerators option is given, the intersection with category pages + is processed. *tidy* tidy up a category by moving its pages into subcategories. *tree* @@ -28,97 +30,105 @@
and option can be one of these
-Options for "add" action: +Options for *add* action:
- -person - Sort persons by their last name. - -create - If a page doesn't exist, do not skip it, create it instead. - -redirect - Follow redirects. +-person Sort persons by their last name. +-create If a page doesn't exist, do not skip it, create it instead. +-redirect Follow redirects.
-Options for "listify" action: +Options for *listify* action:
- -append - This appends the list to the current page that is already - existing (appending to the bottom by default). - -overwrite - This overwrites the current page with the list even if - something is already there. - -showimages - This displays images rather than linking them in the list. - -talkpages - This outputs the links to talk pages of the pages to be - listified in addition to the pages themselves. - -prefix:# - You may specify a list prefix like "#" for a numbered list or - any other prefix. Default is a bullet list with prefix "*". +-append This appends the list to the current page that is already + existing (appending to the bottom by default). +-overwrite This overwrites the current page with the list even if + something is already there. +-showimages This displays images rather than linking them in the list. +-talkpages This outputs the links to talk pages of the pages to be + listified in addition to the pages themselves. +-prefix:# You may specify a list prefix like "#" for a numbered list + or any other prefix. Default is a bullet list with prefix + "*".
-Options for "remove" action: +Options for *remove* action:
- -nodelsum - This specifies not to use the custom edit summary as the - deletion reason. Instead, it uses the default deletion reason - for the language, which is "Category was disbanded" in - English. +-nodelsum This specifies not to use the custom edit summary as the + deletion reason. Instead, it uses the default deletion + reason for the language, which is "Category was disbanded" + in English.
-Options for "move" action: +Options for *move* action:
- -hist - Creates a nice wikitable on the talk page of target category - that contains detailed page history of the source category. - -nodelete - Don't delete the old category after move. - -nowb - Don't update the Wikibase repository. - -allowsplit - If that option is not set, it only moves the talk and main - page together. - -mvtogether - Only move the pages/subcategories of a category, if the - target page (and talk page, if -allowsplit is not set) - doesn't exist. - -keepsortkey - Use sortKey of the old category also for the new category. - If not specified, sortKey is removed. - An alternative method to keep sortKey is to use -inplace - option. +-hist Creates a nice wikitable on the talk page of target + category that contains detailed page history of the source + category. +-nodelete Don't delete the old category after move. +-nowb Don't update the Wikibase repository. +-allowsplit If that option is not set, it only moves the talk and main + page together. +-mvtogether Only move the pages/subcategories of a category, if the + target page (and talk page, if ``-allowsplit`` is not set) + doesn't exist. +-keepsortkey Use sortKey of the old category also for the new category. + If not specified, sortKey is removed. An alternative + method to keep sortKey is to use ``-inplace`` option.
-Options for "listify" and "tidy" actions: +Options for *listify* and *tidy* actions:
- -namespaces Filter the arcitles in the specified namespaces. Separate - -namespace multiple namespace numbers or names with commas. Examples: - -ns -ns:0,2,4 - -ns:Help,MediaWiki +-namespaces, -namespace, -ns + Filter the arcitles in the specified namespaces. Separate + multiple namespace numbers or names with commas. Examples: + :samp:`-ns:0,2,4`, :samp:`-ns:Help,MediaWiki`
-Options for "clean" action: +Options for *clean* action:
- -always +-always The bot won't ask for confirmation when putting a page.
Options for several actions:
- -rebuild - Reset the database. - -from: - The category to move from (for the move option) - Also, the category to remove from in the remove option - Also, the category to make a list of in the listify option. - -to: - The category to move to (for the move option). - - Also, the name of the list to make in the listify option. +-rebuild Reset the database.
- -batch - Don't prompt to delete emptied categories (do it - automatically). - -summary: - Pick a custom edit summary for the bot. - -inplace - Use this flag to change categories in place rather than - rearranging them. - -recurse[:<depth>] - - Recurse through subcategories of the category to - optional depth. - -pagesonly - While removing pages from a category, keep the subpage links - and do not remove them. - -match - Only work on pages whose titles match the given regex (for - move and remove actions). - -depth: - The max depth limit beyond which no subcategories will be - listed. +-from: The category to move from (for the move option). Also, the + category to remove from in the remove option. Also, the + category to make a list of in the listify option. + +-to: The category to move to (for the move option). Also, the + name of the list to make in the listify option. + +-batch Don't prompt to delete emptied categories (do it + automatically). + +-summary: Pick a custom edit summary for the bot. + +-inplace Use this flag to change categories in place rather than + rearranging them. + +-recurse[:<depth>] Recurse through subcategories of the category to + optional depth. + +-pagesonly While removing pages from a category, keep the subpage + links and do not remove them. + +-match Only work on pages whose titles match the given regex (for + move and remove actions). + +-depth: The max depth limit beyond which no subcategories will be + isted.
.. note:: If the category names have spaces in them you may need to use a special syntax in your shell so that the names aren't treated as separate parameters. For instance, in BASH, use single quotes, e.g. ``-from:'Polar bears'``.
-If action is "add", "move" or "remove, the following additional options are -supported: +If action is "add", "move" or "remove, the following additional options +are supported:
¶ms;
For the actions tidy and tree, the bot will store the category structure -locally in category.dump. This saves time and server load, but if it uses -these data later, they may be outdated; use the -rebuild parameter in this -case. +locally in category.dump. This saves time and server load, but if it +uses these data later, they may be outdated; use the -rebuild parameter +in this case.
For example, to create a new category from a list of persons, type:
@@ -132,7 +142,7 @@
This will move all pages in the category US to the category United States.
-A pagegenerators option can be given with ``move`` and ``remove`` action: +A pagegenerators option can be given with *move* and *remove* action:
pwb category -site:wikipedia:en remove -from:Hydraulics -cat:Pneumatics
diff --git a/scripts/category_graph.py b/scripts/category_graph.py index 829abb7..fd46d30 100755 --- a/scripts/category_graph.py +++ b/scripts/category_graph.py @@ -10,15 +10,18 @@
actions:
--from [FROM] Category name to scan, default is main category, "?" to ask. +-from [FROM] Category name to scan, default is main category, "?" to ask.
optional arguments:
--to TO base file name to save, "?" to ask --style STYLE graphviz style definitions in dot format (see below) --depth DEPTH maximal hierarchy depth. 2 by default --downsize K font size divider for subcategories. 4 by default - Use 1 for the same font size +-to TO base file name to save, "?" to ask + +-style STYLE graphviz style definitions in dot format (see below) + +-depth DEPTH maximal hierarchy depth. 2 by default + +-downsize K font size divider for subcategories. 4 by default Use 1 + for the same font size
.. seealso:: https://graphviz.org/doc/info/attrs.html for graphviz style definitions. diff --git a/scripts/commonscat.py b/scripts/commonscat.py index 9536a96..b71a559 100755 --- a/scripts/commonscat.py +++ b/scripts/commonscat.py @@ -1,29 +1,31 @@ #!/usr/bin/env python3 -""" -With this tool you can add the template {{commonscat}} to categories. +"""With this tool you can add the template {{commonscat}} to categories.
-The tool works by following the interwiki links. If the template is present on -another language page, the bot will use it. +The tool works by following the interwiki links. If the template is +present on another language page, the bot will use it.
-You could probably use it at articles as well, but this isn't tested. +.. warning:: + You could probably use it at articles as well, but this isn't tested.
The following parameters are supported:
--checkcurrent Work on all category pages that use the primary commonscat - template. +-checkcurrent Work on all category pages that use the primary commonscat + template.
-This script is a :py:obj:`ConfigParserBot <bot.ConfigParserBot>`. -The following options can be set within a settings file which is scripts.ini -by default:: +This script is a :class:`ConfigParserBot <bot.ConfigParserBot>`. The +following options can be set within a settings file which is scripts.ini +by default:
--always Don't prompt you for each replacement. Warning message - has not to be confirmed. ATTENTION: Use this with care! +-always Don't prompt you for each replacement. Warning message + has not to be confirmed.
--summary:XYZ Set the action summary message for the edit to XYZ, - otherwise it uses messages from add_text.py as default. + .. attention:: Use this with care!
-This bot uses pagegenerators to get a list of pages. The following options are -supported: +-summary:XYZ Set the action summary message for the edit to XYZ, + otherwise it uses messages from add_text.py as default. + +This bot uses pagegenerators to get a list of pages. The following +options are supported:
¶ms;
diff --git a/scripts/create_isbn_edition.py b/scripts/create_isbn_edition.py index 53a4b36..427b7e1 100755 --- a/scripts/create_isbn_edition.py +++ b/scripts/create_isbn_edition.py @@ -1,46 +1,47 @@ #!/usr/bin/env python3 r"""Pywikibot script to load ISBN related data into Wikidata.
-Pywikibot script to get ISBN data from a digital library, -and create or amend the related Wikidata item for edition -(with the P212=ISBN number as unique external ID). +Pywikibot script to get ISBN data from a digital library, and create or +amend the related Wikidata item for edition (with the +:samp:`P212={ISBN number}` as unique external ID).
Use digital libraries to get ISBN data in JSON format, and integrate the results into Wikidata.
Then the resulting item number can be used e.g. to generate Wikipedia -references using template Cite_Q. +references using template ``Cite_Q``.
-Parameters: - +**Parameters**: All parameters are optional:
- P1: digital library (default goob "-") + .. code:: text
- bnf Catalogue General (France) - bol Bol.com - dnb Deutsche National Library - goob Google Books - kb National Library of the Netherlands - loc Library of Congress US - mcues Ministerio de Cultura (Spain) - openl OpenLibrary.org - porbase urn.porbase.org Portugal - sbn Servizio Bibliotecario Nazionale - wiki wikipedia.org - worldcat WorldCat + *P1:* digital library (default goob "-")
- P2: ISO 639-1 language code - Default LANG; e.g. en, nl, fr, de, es, it, etc. + bnf Catalogue General (France) + bol Bol.com + dnb Deutsche National Library + goob Google Books + kb National Library of the Netherlands + loc Library of Congress US + mcues Ministerio de Cultura (Spain) + openl OpenLibrary.org + porbase urn.porbase.org Portugal + sbn Servizio Bibliotecario Nazionale + wiki wikipedia.org + worldcat WorldCat
- P3 P4...: P/Q pairs to add additional claims (repeated) - e.g. P921 Q107643461 (main subject: database - management linked to P2163 Fast ID) + *P2:* ISO 639-1 language code. Default LANG; e.g. en, nl, + fr, de, es, it, etc.
- stdin: ISBN numbers (International standard book number) + *P3 P4...:* P/Q pairs to add additional claims (repeated) e.g. + P921 Q107643461 (main subject: database management + linked to P2163 Fast ID)
- Free text (e.g. Wikipedia references list, or publication list) - is accepted. Identification is done via an ISBN regex expression. + *stdin:* ISBN numbers (International standard book number) + + Free text (e.g. Wikipedia references list, or publication list) + is accepted. Identification is done via an ISBN regex expression.
**Functionality:** * The ISBN number is used as a primary key (P212 where no duplicates @@ -52,21 +53,20 @@ (ambiguous items are skipped) * Book title and subtitle are separated with '.', ':', or '-' * This script can be run incrementally with the same parameters - Caveat: Take into account the Wikidata Query database - replication delay. Wait for minimum 5 minutes to avoid creating - duplicate objects. + Caveat: Take into account the Wikidata Query database replication + delay. Wait for minimum 5 minutes to avoid creating duplicate + objects.
**Data quality:** * Use https://query.wikidata.org/querybuilder/ to identify P212 - duplicates. Merge duplicate items before running the script - again. + duplicates. Merge duplicate items before running the script again. * The following properties should only be used for written works - P5331: OCLC work ID (editions should only have P243) - P8383: Goodreads-identificatiecode for work (editions should - only have P2969)
-Examples: + * P5331: OCLC work ID (editions should only have P243) + * P8383: Goodreads-identificatiecode for work (editions should + only have P2969)
+**Examples:** Default library (Google Books), language (LANG), no additional statements:
@@ -76,47 +76,54 @@
pwb create_isbn_edition.py wiki en P921 Q107643461 978-0-596-10089-6
-Standard ISBN properties: +**Standard ISBN properties:** + ::
- P31:Q3331189: instance of edition - P50: author - P123: publisher - P212: canonical ISBN number (lookup via Wikidata Query) - P407: language of work (Qnumber linked to ISO 639-1 language code) - P577: date of publication (year) - P1476: book title - P1680: subtitle + P31:Q3331189: instance of edition + P50: author + P123: publisher + P212: canonical ISBN number (lookup via Wikidata Query) + P407: language of work + (Qnumber linked to ISO 639-1 language code) + P577: date of publication (year) + P1476: book title + P1680: subtitle
-Other ISBN properties: +**Other ISBN properties:** + ::
- P291: place of publication - P921: main subject (inverse lookup from external Fast ID P2163) - P629: work for edition - P747: edition of work - P1104: number of pages + P291: place of publication + P921: main subject (inverse lookup from external Fast ID P2163) + P629: work for edition + P747: edition of work + P1104: number of pages
-Qualifiers: +**Qualifiers:** + ::
- P1545: (author) sequence number + P1545: (author) sequence number
-External identifiers: +**External identifiers:** + ::
- P213: ISNI ID - P243: OCLC ID - P496: ORCID iD - P675: Google Books-identificatiecode - P1036: Dewey Decimal Classification - P2163: Fast ID (inverse lookup via Wikidata Query) -> P921: main subject - P2969: Goodreads-identificatiecode + P213: ISNI ID + P243: OCLC ID + P496: ORCID iD + P675: Google Books-identificatiecode + P1036: Dewey Decimal Classification + P2163: Fast ID (inverse lookup via Wikidata Query) + -> P921: main subject + P2969: Goodreads-identificatiecode
- (only for written works) - P5331: OCLC work ID (editions should only have P243) - P8383: Goodreads-identificatiecode for work (editions should only - have P2969) + (only for written works) + P5331: OCLC work ID (editions should only have P243) + P8383: Goodreads-identificatiecode for work + (editions should only have P2969)
**Author:** - Geert Van Pamel, 2022-08-04, - GNU General Public License v3.0, User:Geertivp + Geert Van Pamel (User:Geertivp), 2022-08-04, + + Licensed under MIT amd GNU General Public License v3.0
**Documentation:** * :wiki:`ISBN` @@ -146,61 +153,68 @@ * https://www.wikidata.org/wiki/Wikidata:Pywikibot%5C_-_Python_3_Tutorial/Sett...
**Prerequisites:** - pywikibot + In addition to Pywikibot the following ISBN lib package is mandatory; + install it with:
- Install the following ISBN lib packages: - https://pypi.org/search/?q=isbnlib_ + .. code:: shell
- pip install isbnlib (mandatory) + pip install isbnlib
- (optional) + The following ISBN lib package are optional; install them with: + + .. code:: shell + pip install isbnlib-bol pip install isbnlib-bnf pip install isbnlib-dnb pip install isbnlib-kb pip install isbnlib-loc pip install isbnlib-worldcat2 - etc.
**Restrictions:** - * Better use the ISO 639-1 language code parameter as a default - The language code is not always available from the digital library. - * SPARQL queries run on a replicated database - Possible important replication delay; wait 5 minutes before retry - -- otherwise risk for creating duplicates. + * Better use the ISO 639-1 language code parameter as a default. The + language code is not always available from the digital library. + * SPARQL queries run on a replicated database. + + .. important:: + Replication delay: wait 5 minutes before retry, otherwise there + is a risk for creating duplicates.
**Algorithm:** - # Get parameters - # Validate parameters - # Get ISBN data - # Convert ISBN data - # Get additional data - # Register ISBN data into Wikidata (create or amend items or claims) + #. Get parameters + #. Validate parameters + #. Get ISBN data + #. Convert ISBN data + #. Get additional data + #. Register ISBN data into Wikidata (create or amend items or claims)
-Environment: - +**Environment:** The python script can run on the following platforms:
- Linux client - Google Chromebook (Linux container) - Toolforge Portal - PAWS + * Linux client + * Google Chromebook (Linux container) + * Toolforge Portal + * PAWS
LANG: ISO 639-1 language code
-Applications: +**Applications:** + Generate a book reference. Example for (wp.en):
- Generate a book reference - Example: {{Cite Q|Q63413107}} (wp.en) - See also: - https://meta.wikimedia.org/wiki/WikiCite - https://www.wikidata.org/wiki/Q21831105 (WikiCite) - https://www.wikidata.org/wiki/Q22321052 (Cite_Q) - https://www.mediawiki.org/wiki/Global_templates - https://www.wikidata.org/wiki/Wikidata:WikiProject_Source_MetaData - https://phabricator.wikimedia.org/tag/wikicite/ - https://meta.wikimedia.org/wiki/WikiCite/Shared_Citations + .. code:: wikitext + + {{Cite Q|Q63413107}} + + .. seealso:: + + - https://meta.wikimedia.org/wiki/WikiCite + - https://www.wikidata.org/wiki/Q21831105 (WikiCite) + - https://www.wikidata.org/wiki/Q22321052 (Cite_Q) + - https://www.mediawiki.org/wiki/Global_templates + - https://www.wikidata.org/wiki/Wikidata:WikiProject_Source_MetaData + - https://phabricator.wikimedia.org/tag/wikicite/ + - https://meta.wikimedia.org/wiki/WikiCite/Shared_Citations
**Wikidata Query:** * List of editions about musicians: https://w.wiki/5aaz @@ -218,7 +232,7 @@ * https://zenodo.org/record/55004#.YvwO4hTP1D8
**Other systems:** - * `wiki:`bibliographic_database` + * wiki:`bibliographic_database` * https://www.titelbank.nl/pls/ttb/f?p=103:4012:::NO::P4012_TTEL_ID:3496019&am...
.. versionadded:: 7.7 diff --git a/scripts/delete.py b/scripts/delete.py index d9b334e..977e3e5 100755 --- a/scripts/delete.py +++ b/scripts/delete.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" -This script can be used to delete and undelete pages en masse. +"""This script can be used to delete and undelete pages en masse.
Of course, you will need an admin account on the relevant wiki.
@@ -10,31 +9,33 @@
Furthermore, the following command line parameters are supported:
--always Don't prompt to delete pages, just do it. +-always Don't prompt to delete pages, just do it.
--summary:XYZ Set the summary message text for the edit to XYZ. +-summary:XYZ Set the summary message text for the edit to XYZ.
--undelete Actually undelete pages instead of deleting. - Obviously makes sense only with -page and -file. +-undelete Actually undelete pages instead of deleting. Obviously + makes sense only with -page and -file.
--isorphan Alert if there are pages that link to page to be - deleted (check 'What links here'). - By default it is active and only the summary per namespace - is be given. - If given as -isorphan:n, n pages per namespace will be shown, - If given as -isorphan:0, only the summary per namespace will - be shown, - If given as -isorphan:n, with n < 0, the option is disabled. - This option is disregarded if -always is set. +-isorphan Alert if there are pages that link to page to be deleted + (check 'What links here'). By default it is active and + only the summary per namespace is be given. If given as + ``-isorphan:n``, n pages per namespace will be shown. If + given as ``-isorphan:0``, only the summary per namespace + will be shown. If given as ``-isorphan:n``, with n < 0, + the option is disabled. This option is disregarded if + ``-always`` is set.
--orphansonly: Specified namespaces. Separate multiple namespace - numbers or names with commas. - Examples: +-orphansonly: Specified namespaces. Separate multiple namespace numbers + or names with commas. Examples: + + .. code:: shell
-orphansonly:0,2,4 -orphansonly:Help,MediaWiki
- Note that Main ns can be indicated either with a 0 or a ',': + Note that Main ns can be indicated either with a 0 or a ',': + + .. code:: shell
-orphansonly:0,1 -orphansonly:,Talk diff --git a/scripts/djvutext.py b/scripts/djvutext.py index eda0d92..6e8d305 100755 --- a/scripts/djvutext.py +++ b/scripts/djvutext.py @@ -1,38 +1,44 @@ #!/usr/bin/env python3 -""" -This bot uploads text from djvu files onto pages in the "Page" namespace. +"""This bot uploads text from djvu files onto pages in the "Page" namespace.
-It is intended to be used for Wikisource. +.. note:: It is intended to be used for Wikisource.
The following parameters are supported:
- -index:... name of the index page (without the Index: prefix) - -djvu:... path to the djvu file, it shall be: - - path to a file name - - dir where a djvu file name as index is located - optional, by default is current dir '.' - -pages:<start>-<end>,...<start>-<end>,<start>-<end> - Page range to upload; - optional, start=1, end=djvu file number of images. - Page ranges can be specified as: - A-B -> pages A until B - A- -> pages A until number of images - A -> just page A - -B -> pages 1 until B +-index: name of the index page (without the Index: prefix)
-This script is a :py:obj:`ConfigParserBot <bot.ConfigParserBot>`. -The following options can be set within a settings file which is scripts.ini +-djvu: path to the djvu file, it shall be: + + .. hlist:: + + * path to a file name + * dir where a djvu file name as index is located optional, + by default is current dir '.' + +-pages:<start>-<end>,...<start>-<end>,<start>-<end> Page range to + upload; optional, :samp:`start=1`, + :samp:`end={djvu file number of images}`. Page ranges can be + specified as:: + + A-B -> pages A until B + A- -> pages A until number of images + A -> just page A + -B -> pages 1 until B + +This script is a :class:`ConfigParserBot <bot.ConfigParserBot>`. The +following options can be set within a settings file which is scripts.ini by default:
- -summary: custom edit summary. - Use quotes if edit summary contains spaces. - -force overwrites existing text - optional, default False - -always do not bother asking to confirm any of the changes. +-summary: [str] Custom edit summary. Use quotes if edit summary + contains spaces. + +-force Overwrites existing text optional, default False. + +-always Do not bother asking to confirm any of the changes.
""" # -# (C) Pywikibot team, 2008-2022 +# (C) Pywikibot team, 2008-2024 # # Distributed under the terms of the MIT license. # diff --git a/scripts/listpages.py b/scripts/listpages.py index fcb1735..0ae87e6 100755 --- a/scripts/listpages.py +++ b/scripts/listpages.py @@ -9,9 +9,10 @@
-format Defines the output format.
- Can be a custom string according to python string.format() notation - or can be selected by a number from following list + Can be a custom string according to python string.format() + notation or can be selected by a number from following list (1 is default format): + 1 - '{num:4d} {page.title}' --> 10 PageTitle
@@ -38,10 +39,11 @@
num is the sequential number of the listed page.
- An empty format is equal to -notitle and just shows the total - amount of pages. + An empty format is equal to ``-notitle`` and just shows the + total amount of pages.
--outputlang Language for translation of namespaces. +-outputlang + Language for translation of namespaces.
-notitle Page title is not printed.
@@ -50,47 +52,55 @@ -tofile Save Page titles to a single file. File name can be set with -tofile:filename or -tofile:dir_name/filename.
--save Save Page content to a file named as page.title(as_filename=True). - Directory can be set with -save:dir_name - If no dir is specified, current directory will be used. +-save Save Page content to a file named as + :code:`page.title(as_filename=True)`. Directory can be set + with ``-save:dir_name``. If no dir is specified, current + directory will be used.
--encode File encoding can be specified with '-encode:name' (name must be - a valid python encoding: utf-8, etc.). - If not specified, it defaults to config.textfile_encoding. +-encode File encoding can be specified with '-encode:name' (name + must be a valid python encoding: utf-8, etc.). If not + specified, it defaults to :code:`config.textfile_encoding`.
--put: Save the list to the defined page of the wiki. By default it does - not overwrite an existing page. +-put: [str] Save the list to the defined page of the wiki. By + default it does not overwrite an existing page.
--overwrite Overwrite the page if it exists. Can only by applied with -put. +-overwrite Overwrite the page if it exists. Can only by applied with + -put.
--summary: The summary text when the page is written. If it's one word just - containing letters, dashes and underscores it uses that as a - translation key. +-summary: [str] The summary text when the page is written. If it's one + word just containing letters, dashes and underscores it uses + that as a translation key.
Custom format can be applied to the following items extrapolated from a page object:
- site: obtained from page._link._site. +*site* + Obtained from :code:`page._link._site`.
- title: obtained from page._link._title. +*title* + Obtained from :code:`page._link._title`.
- loc_title: obtained from page._link.canonical_title(). +*loc_title* + Obtained from :code:`page._link.canonical_title()`.
- can_title: obtained from page._link.ns_title(). - based either the canonical namespace name or on the namespace name - in the language specified by the -trans param; - a default value '******' will be used if no ns is found. +*can_title* + Obtained from :code:`page._link.ns_title()`. Based either the + canonical namespace name or on the namespace name in the language + specified by the ``-trans`` param; a default value ``******`` will + be used if no *ns* is found.
- onsite: obtained from pywikibot.Site(outputlang, self.site.family). +*onsite* + Obtained from :code:`pywikibot.Site(outputlang, self.site.family)`.
- trs_title: obtained from page._link.ns_title(onsite=onsite). - If selected format requires trs_title, outputlang must be set. +*trs_title* + Obtained from :code:`page._link.ns_title(onsite=onsite)`. If + selected, format requires *trs_title*, ``-outputlang`` must be set.
¶ms; """ # -# (C) Pywikibot team, 2008-2022 +# (C) Pywikibot team, 2008-2024 # # Distributed under the terms of the MIT license. # diff --git a/scripts/reflinks.py b/scripts/reflinks.py index 50c2397..95b719e 100755 --- a/scripts/reflinks.py +++ b/scripts/reflinks.py @@ -1,42 +1,45 @@ #!/usr/bin/env python3 -""" -Fetch and add titles for bare links in references. +"""Fetch and add titles for bare links in references.
This bot will search for references which are only made of a link -without title (i.e. <ref>[https://www.google.fr/]</ref> or -<ref>https://www.google.fr/</ref>) and will fetch the html title from -the link to use it as the title of the wiki link in the reference, i.e. -<ref>[https://www.google.fr/search?q=test test - Google Search]</ref> +without title (i.e. ``<ref>[https://www.google.fr/]</ref>`` or +``<ref>https://www.google.fr/</ref>``) and will fetch the html title +from the link to use it as the title of the wiki link in the reference, +i.e. + +.. code:: wikitext + + <ref>[https://www.google.fr/search?q=test test - Google Search]</ref>
The bot checks every 20 edits a special stop page. If the page has been edited, it stops.
-As it uses it, you need to configure noreferences.py for your wiki, or it +As it uses it, you need to configure reflinks.py for your wiki, or it will not work.
pdfinfo is needed for parsing pdf titles.
The following parameters are supported:
--xml:dump.xml Should be used instead of a simple page fetching method - from pagegenerators.py for performance and load issues +-xml:dump.xml Should be used instead of a simple page fetching method + from pagegenerators.py for performance and load issues
--xmlstart Page to start with when using an XML dump +-xmlstart Page to start with when using an XML dump
-This script is a :py:obj:`ConfigParserBot <bot.ConfigParserBot>`. -The following options can be set within a settings file which is scripts.ini -by default:: +This script is a :class:`ConfigParserBot <bot.ConfigParserBot>`. The +following options can be set within a settings file which is scripts.ini +by default:
--always Doesn't ask every time whether the bot should make the change. - Do it always. +-always Doesn't ask every time whether the bot should make the + change. Do it always.
--limit:n Stops after n edits +-limit:n [int] Stops after n edits
--ignorepdf Do not handle PDF files (handy if you use Windows and - can't get pdfinfo) +-ignorepdf Do not handle PDF files (handy if you use Windows and + can't get pdfinfo)
--summary Use a custom edit summary. Otherwise it uses the - default one from translatewiki +-summary [str] Use a custom edit summary. Otherwise it uses the + default one from translatewiki
The following generators and filters are supported:
diff --git a/scripts/revertbot.py b/scripts/revertbot.py index 6a86c45..94b1136 100755 --- a/scripts/revertbot.py +++ b/scripts/revertbot.py @@ -1,21 +1,23 @@ #!/usr/bin/env python3 -r""" -This script can be used for reverting certain edits. +r"""This script can be used for reverting certain edits.
The following command line parameters are supported:
--username Edits of which user need to be reverted. - Default is bot's username (site.username()) +-username Edits of which user need to be reverted. Default is bot's + username (:code:`site.username()`).
--rollback Rollback edits instead of reverting them. - Note that in rollback, no diff would be shown. +-rollback Rollback edits instead of reverting them.
--limit:num Use the last num contributions to be checked for revert. - Default is 500. + .. note:: No diff would be shown in this mode. + +-limit:num [int] Use the last num contributions to be checked for + revert. Default is 500.
Users who want to customize the behaviour should subclass the `BaseRevertBot` and override its `callback` method. Here is a sample:
+.. code:: python + class myRevertBot(BaseRevertBot):
'''Example revert bot.''' @@ -35,7 +37,7 @@
""" # -# (C) Pywikibot team, 2008-2023 +# (C) Pywikibot team, 2008-2024 # # Distributed under the terms of the MIT license. # diff --git a/scripts/unusedfiles.py b/scripts/unusedfiles.py index aa885e1..a1bff9e 100755 --- a/scripts/unusedfiles.py +++ b/scripts/unusedfiles.py @@ -1,21 +1,22 @@ #!/usr/bin/env python3 -""" -This bot appends some text to all unused images and notifies uploaders. +"""This bot appends some text to all unused images and notifies uploaders.
Parameters:
--limit Specify number of pages to work on with "-limit:n" where - n is the maximum number of articles to work on. - If not used, all pages are used. +-limit:n [int] Specify number of pages to work on where *n* is + the maximum number of articles to work on. If not used, + all pages are processe. -always Don't be asked every time.
-This script is a :py:obj:`ConfigParserBot <bot.ConfigParserBot>`. -The following options can be set within a settings file which is scripts.ini -by default:: +This script is a :class:`ConfigParserBot <bot.ConfigParserBot>`. The +following options can be set within a settings file which is scripts.ini +by default:
-nouserwarning Do not warn uploader about orphaned file. --filetemplate: Use a custom template on unused file pages. --usertemplate: Use a custom template to warn the uploader. + +-filetemplate: [str] Use a custom template on unused file pages. + +-usertemplate: [str] Use a custom template to warn the uploader. """ # # (C) Pywikibot team, 2007-2024 diff --git a/scripts/upload.py b/scripts/upload.py index 1fc092a..10152bd 100755 --- a/scripts/upload.py +++ b/scripts/upload.py @@ -1,58 +1,71 @@ #!/usr/bin/env python3 -""" -Script to upload images to Wikipedia. +"""Script to upload images to Wikipedia.
The following parameters are supported:
- -keep Keep the filename as is - -filename: Target filename without the namespace prefix - -prefix: Add specified prefix to every filename. - -noverify Do not ask for verification of the upload description if one - is given - -abortonwarn: Abort upload on the specified warning type. If no warning type - is specified, aborts on any warning. - -ignorewarn: Ignores specified upload warnings. If no warning type is - specified, ignores all warnings. Use with caution - -chunked: Upload the file in chunks (more overhead, but restartable). If - no value is specified the chunk size is 1 MiB. The value must - be a number which can be preceded by a suffix. The units are: +-keep Keep the filename as is
- No suffix: Bytes - 'k': Kilobytes (1000 B) - 'M': Megabytes (1000000 B) - 'Ki': Kibibytes (1024 B) - 'Mi': Mebibytes (1024x1024 B) +-filename: Target filename without the namespace prefix
- The suffixes are case insensitive. - -async Make potentially large file operations asynchronous on the - server side when possible. - -always Don't ask the user anything. This will imply -keep and - -noverify and require that either -abortonwarn or -ignorewarn - is defined for all. It will also require a valid file name and - description. It'll only overwrite files if -ignorewarn includes - the 'exists' warning. - -recursive When the filename is a directory it also uploads the files from - the subdirectories. - -summary: Pick a custom edit summary for the bot. - -descfile: Specify a filename where the description is stored +-prefix: Add specified prefix to every filename.
-It is possible to combine -abortonwarn and -ignorewarn so that if the specific -warning is given it won't apply the general one but more specific one. So if it -should ignore specific warnings and abort on the rest it's possible by defining -no warning for -abortonwarn and the specific warnings for -ignorewarn. The -order does not matter. If both are unspecific or a warning is specified by -both, it'll prefer aborting. +-noverify Do not ask for verification of the upload description if + one is given + +-abortonwarn: Abort upload on the specified warning type. If no warning + type is specified, aborts on any warning. + +-ignorewarn: Ignores specified upload warnings. If no warning type is + specified, ignores all warnings. Use with caution + +-chunked: Upload the file in chunks (more overhead, but restartable). + If no value is specified the chunk size is 1 MiB. The + value must be a number which can be preceded by a suffix. + The units are:: + + No suffix: Bytes + 'k': Kilobytes (1000 B) + 'M': Megabytes (1000000 B) + 'Ki': Kibibytes (1024 B) + 'Mi': Mebibytes (1024x1024 B) + + The suffixes are case insensitive. + +-async Make potentially large file operations asynchronous on + the server side when possible. + +-always Don't ask the user anything. This will imply -keep and + ``-noverify`` and require that either ``-abortonwarn`` or + ``-ignorewarn`` is defined for all. It will also require + a valid file name and description. It'll only overwrite + files if ``-ignorewarn`` includes the 'exists' warning. + +-recursive When the filename is a directory it also uploads the + files from the subdirectories. + +-summary: Pick a custom edit summary for the bot. + +-descfile: Specify a filename where the description is stored + +It is possible to combine ``-abortonwarn`` and ``-ignorewarn`` so that +if the specific warning is given it won't apply the general one but more +specific one. So if it should ignore specific warnings and abort on the +rest it's possible by defining no warning for -abortonwarn and the +specific warnings for ``-ignorewarn``. The order does not matter. If +both are unspecific or a warning is specified by both, it'll prefer +aborting.
If any other arguments are given, the first is either URL, filename or -directory to upload, and the rest is a proposed description to go with the -upload. If none of these are given, the user is asked for the directory, file -or URL to upload. The bot will then upload the image to the wiki. +directory to upload, and the rest is a proposed description to go with +the upload. If none of these are given, the user is asked for the +directory, file or URL to upload. The bot will then upload the image to +the wiki.
The script will ask for the location of an image(s), if not given as a parameter, and for a description. """ # -# (C) Pywikibot team, 2003-2022 +# (C) Pywikibot team, 2003-2024 # # Distributed under the terms of the MIT license. #
pywikibot-commits@lists.wikimedia.org