jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[IMPR] cosmetic_changes.py type hints

Bug: T286403
Change-Id: I807cab7b358e89704465909e56242635b9347626
---
M pywikibot/backports.py
M pywikibot/cosmetic_changes.py
2 files changed, 62 insertions(+), 43 deletions(-)

diff --git a/pywikibot/backports.py b/pywikibot/backports.py
index 3689416..b565a48 100644
--- a/pywikibot/backports.py
+++ b/pywikibot/backports.py
@@ -68,12 +68,15 @@
Iterable,
List,
Mapping,
+ Match,
+ Pattern,
Sequence,
Set,
Tuple,
)
else:
from collections.abc import Callable, Iterable, Mapping, Sequence
+ from re import Match, Pattern
Dict = dict
FrozenSet = frozenset
List = list
diff --git a/pywikibot/cosmetic_changes.py b/pywikibot/cosmetic_changes.py
index 11a71e9..bb48a3a 100755
--- a/pywikibot/cosmetic_changes.py
+++ b/pywikibot/cosmetic_changes.py
@@ -58,10 +58,11 @@
import re

from enum import IntEnum
-from typing import Optional
+from typing import Any, Optional, Union

import pywikibot
from pywikibot import textlib
+from pywikibot.backports import Callable, Dict, List, Match, Pattern
from pywikibot.exceptions import InvalidTitleError
from pywikibot.textlib import (
FILE_LINK_REGEX,
@@ -184,7 +185,7 @@
If an error occurred and either skips the page or the method
or a single match. ALL raises the exception.

- *New in version 6.3.*
+ .. versionadded:: 6.3
"""

ALL = 0
@@ -193,7 +194,7 @@
MATCH = 3


-def _format_isbn_match(match, strict=True):
+def _format_isbn_match(match: Match[str], strict: bool = True) -> str:
"""Helper function to validate and format a single matched ISBN."""
if not stdnum_isbn:
raise NotImplementedError(
@@ -211,7 +212,7 @@
return stdnum_isbn.format(isbn)


-def _reformat_ISBNs(text, strict=True):
+def _reformat_ISBNs(text: str, strict: bool = True) -> str:
"""Helper function to normalise ISBNs in text.

:raises Exception: Invalid ISBN encountered when strict enabled
@@ -225,15 +226,14 @@
"""Cosmetic changes toolkit."""

@deprecated_args(redirect=True, diff='show_diff', site='page')
- def __init__(self, page, *,
+ def __init__(self, page: 'pywikibot.page.BasePage', *,
show_diff: bool = False,
namespace: Optional[int] = None,
pageTitle: Optional[str] = None,
- ignore: IntEnum = CANCEL.ALL):
+ ignore: IntEnum = CANCEL.ALL) -> None:
"""Initializer.

:param page: the Page object containing the text to be modified
- :type page: pywikibot.Page
:param show_diff: show difference after replacements (default: False)
:param namespace: DEPRECATED namespace parameter
:param pageTitle: DEPRECATED page title parameter
@@ -292,15 +292,15 @@
if stdnum_isbn:
self.common_methods.append(self.fix_ISBN)

- @property
+ @property # type: ignore[misc]
@deprecated('show_diff', since='20200415')
- def diff(self):
+ def diff(self) -> bool:
"""CosmeticChangesToolkit.diff attribute getter."""
return self.show_diff

- @diff.setter
+ @diff.setter # type: ignore[misc]
@deprecated('show_diff', since='20200415')
- def diff(self, value):
+ def diff(self, value: bool) -> None:
"""CosmeticChangesToolkit.diff attribute setter."""
self.show_diff = bool(value)

@@ -308,11 +308,13 @@
@deprecated('CosmeticChangesToolkit with pywikibot.Page object',
since='20200415')
@deprecated_args(diff='show_diff')
- def from_page(cls, page, show_diff=False, ignore=CANCEL.ALL):
+ def from_page(cls, page: 'pywikibot.page.BasePage',
+ show_diff: bool = False,
+ ignore: IntEnum = CANCEL.ALL) -> 'CosmeticChangesToolkit':
"""Create toolkit based on the page."""
return cls(page, show_diff=show_diff, ignore=ignore)

- def safe_execute(self, method, text):
+ def safe_execute(self, method: Callable[[str], str], text: str) -> str:
"""Execute the method and catch exceptions if enabled."""
result = None
try:
@@ -326,13 +328,13 @@
raise
return text if result is None else result

- def _change(self, text):
+ def _change(self, text: str) -> str:
"""Execute all clean up methods."""
for method in self.common_methods:
text = self.safe_execute(method, text)
return text

- def change(self, text):
+ def change(self, text: str) -> Union[bool, str]:
"""Execute all clean up methods and catch errors if activated."""
try:
new_text = self._change(text)
@@ -348,7 +350,7 @@
pywikibot.showDiff(text, new_text)
return new_text

- def fixSelfInterwiki(self, text):
+ def fixSelfInterwiki(self, text: str) -> str:
"""
Interwiki links to the site itself are displayed like local links.

@@ -360,7 +362,7 @@
text = interwikiR.sub(r'[[\1]]', text)
return text

- def standardizePageFooter(self, text):
+ def standardizePageFooter(self, text: str) -> str:
"""
Standardize page footer.

@@ -382,6 +384,9 @@
if not self.template:
categories = textlib.getCategoryLinks(text, site=self.site)

+ if self.title is None:
+ raise ValueError('Page title required to standardize footer')
+
if not self.talkpage:
subpage = False
if self.template:
@@ -422,7 +427,7 @@

return text

- def translateAndCapitalizeNamespaces(self, text):
+ def translateAndCapitalizeNamespaces(self, text: str) -> str:
"""Use localized namespace names."""
# arz uses English stylish codes
if self.site.sitename == 'wikipedia:arz':
@@ -482,7 +487,7 @@
exceptions)
return text

- def translateMagicWords(self, text):
+ def translateMagicWords(self, text: str) -> str:
"""Use localized magic words."""
# not wanted at ru
# arz uses English stylish codes
@@ -490,7 +495,7 @@
if self.site.code in ['arz', 'en', 'ru']:
return text

- def init_cache():
+ def init_cache() -> None:
for magicword in ('img_thumbnail', 'img_left', 'img_center',
'img_right', 'img_none', 'img_framed',
'img_frameless', 'img_border', 'img_upright',
@@ -504,7 +509,7 @@
if not cache:
cache[False] = True # signal there is nothing to replace

- def replace_magicword(match):
+ def replace_magicword(match: Match[str]) -> str:
if cache.get(False):
return match.group()
split = match.group().split('|')
@@ -519,7 +524,7 @@
return '{}|{}]]'.format(
split[0], '|'.join(cache.get(x.strip(), x) for x in split[1:]))

- cache = {}
+ cache = {} # type: Dict[Union[bool, str], Any]
exceptions = ['comment', 'nowiki', 'pre', 'syntaxhighlight']
regex = re.compile(
FILE_LINK_REGEX % '|'.join(self.site.namespaces[6]),
@@ -548,7 +553,7 @@
"""
# helper function which works on one link and either returns it
# unmodified, or returns a replacement.
- def handleOneLink(match):
+ def handleOneLink(match: Match[str]) -> str:
titleWithSection = match.group('titleWithSection')
label = match.group('label')
trailingChars = match.group('linktrail')
@@ -681,7 +686,7 @@
'startspace'])
return text

- def resolveHtmlEntities(self, text):
+ def resolveHtmlEntities(self, text: str) -> str:
"""Replace HTML entities with string."""
ignore = [
38, # Ampersand (&)
@@ -709,7 +714,7 @@
text, ignore=ignore, exceptions=['comment', 'syntaxhighlight'])
return text

- def removeEmptySections(self, text):
+ def removeEmptySections(self, text: str) -> str:
"""Cleanup empty sections."""
# userspace contains article stubs without nobots/in use templates
if self.namespace == 2:
@@ -753,7 +758,7 @@
new_body.extend(sections[i])
return header + ''.join(new_body) + footer

- def removeUselessSpaces(self, text):
+ def removeUselessSpaces(self, text: str) -> str:
"""Cleanup multiple or trailing spaces."""
exceptions = ['comment', 'math', 'nowiki', 'pre', 'syntaxhighlight',
'startspace', 'table']
@@ -763,7 +768,7 @@
exceptions, site=self.site)
return text

- def removeNonBreakingSpaceBeforePercent(self, text):
+ def removeNonBreakingSpaceBeforePercent(self, text: str) -> str:
"""
Remove a non-breaking space between number and percent sign.

@@ -775,7 +780,7 @@
text, r'(\d)&(?:nbsp|#160|#x[Aa]0);%', r'\1 %', ['timeline'])
return text

- def cleanUpSectionHeaders(self, text):
+ def cleanUpSectionHeaders(self, text: str) -> str:
"""
Add a space between the equal signs and the section title.

@@ -801,7 +806,7 @@
r'\1 \g<title> \1\n',
['comment', 'math', 'nowiki', 'pre'])

- def putSpacesInLists(self, text):
+ def putSpacesInLists(self, text: str) -> str:
"""
Add a space between the * or # and the text.

@@ -822,7 +827,7 @@
exceptions)
return text

- def replaceDeprecatedTemplates(self, text):
+ def replaceDeprecatedTemplates(self, text: str) -> str:
"""Replace deprecated templates."""
exceptions = ['comment', 'math', 'nowiki', 'pre']
builder = MultiTemplateMatchBuilder(self.site)
@@ -845,9 +850,9 @@
return text

# from fixes.py
- def fixSyntaxSave(self, text):
+ def fixSyntaxSave(self, text: str) -> str:
"""Convert weblinks to wikilink, fix link syntax."""
- def replace_link(match):
+ def replace_link(match: Match[str]) -> str:
"""Create a string to replace a single link."""
replacement = '[['
if re.match(r'(?:' + '|'.join(list(self.site.namespaces[6])
@@ -913,9 +918,9 @@
r'[\g<url> \g<label>]', exceptions)
return text

- def fixHtml(self, text):
+ def fixHtml(self, text: str) -> str:
"""Relace html markups with wikitext markups."""
- def replace_header(match):
+ def replace_header(match: Match[str]) -> str:
"""Create a header string for replacing."""
depth = int(match.group(1))
return r'{0} {1} {0}'.format('=' * depth, match.group(2))
@@ -945,7 +950,7 @@
# TODO: maybe we can make the bot replace <p> tags with \r\n's.
return text

- def fixReferences(self, text):
+ def fixReferences(self, text: str) -> str:
"""Fix references tags."""
# See also
# https://en.wikipedia.org/wiki/User:AnomieBOT/source/tasks/OrphanReferenceFixer.pm
@@ -963,7 +968,7 @@
r'<ref \1/>', exceptions)
return text

- def fixStyle(self, text):
+ def fixStyle(self, text: str) -> str:
"""Convert prettytable to wikitable class."""
exceptions = ['comment', 'math', 'nowiki', 'pre', 'startspace',
'syntaxhighlight']
@@ -973,10 +978,21 @@
r'\1wikitable\2', exceptions)
return text

- def fixTypo(self, text):
+ def fixTypo(self, text: str) -> str:
"""Fix units."""
- exceptions = ['comment', 'gallery', 'hyperlink', 'interwiki', 'link',
- 'nowiki', 'math', 'pre', 'startspace', 'syntaxhighlight']
+ exceptions = [
+ 'comment',
+ 'gallery',
+ 'hyperlink',
+ 'interwiki',
+ 'link',
+ 'nowiki',
+ 'math',
+ 'pre',
+ 'startspace',
+ 'syntaxhighlight',
+ ] # type: List[Union[str, Pattern[str]]]
+
# change <number> ccm -> <number> cm³
text = textlib.replaceExcept(text, r'(\d)\s*(?:&nbsp;)?ccm',
r'\1&nbsp;cm³', exceptions,
@@ -993,7 +1009,7 @@
site=self.site)
return text

- def fixArabicLetters(self, text):
+ def fixArabicLetters(self, text: str) -> str:
"""Fix Arabic and Persian letters."""
if self.site.code not in ['ckb', 'fa']:
return text
@@ -1013,7 +1029,7 @@
'ref',
'startspace',
'syntaxhighlight',
- ]
+ ] # type: List[Union[str, Pattern[str]]]

digits = textlib.NON_LATIN_DIGITS
faChrs = 'ءاآأإئؤبپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیةيك' + digits['fa']
@@ -1039,7 +1055,7 @@

return text

- def commonsfiledesc(self, text):
+ def commonsfiledesc(self, text: str) -> str:
"""
Clean up file descriptions on Wikimedia Commons.

@@ -1105,7 +1121,7 @@
r'\1== {{int:license-header}} ==', exceptions, True)
return text

- def fix_ISBN(self, text):
+ def fix_ISBN(self, text: str) -> str:
"""Hyphenate ISBN numbers."""
return _reformat_ISBNs(text, strict=self.ignore != CANCEL.MATCH)


To view, visit change 705164. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I807cab7b358e89704465909e56242635b9347626
Gerrit-Change-Number: 705164
Gerrit-PatchSet: 6
Gerrit-Owner: Damian <atagar1@gmail.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-CC: JJMC89 <JJMC89.Wikimedia@gmail.com>
Gerrit-MessageType: merged