jenkins-bot submitted this change.

View Change

Approvals: Zhuyifei1999: Looks good to me, but someone else must approve D3r1ck01: Looks good to me, approved jenkins-bot: Verified
[4.0] Remove UnicodeType from several scripts

Change-Id: I65ecb79798cce36dd542acdad9cec46e448acfd8
---
M pywikibot/data/mysql.py
M pywikibot/flow.py
M pywikibot/login.py
M pywikibot/specialbots/_upload.py
M scripts/create_categories.py
M scripts/misspelling.py
M scripts/replace.py
M tests/file_tests.py
M tests/flow_edit_tests.py
M tests/flow_tests.py
M tests/http_tests.py
M tests/logentries_tests.py
M tests/wikistats_tests.py
13 files changed, 177 insertions(+), 258 deletions(-)

diff --git a/pywikibot/data/mysql.py b/pywikibot/data/mysql.py
index 2b40bf1..620d589 100644
--- a/pywikibot/data/mysql.py
+++ b/pywikibot/data/mysql.py
@@ -5,8 +5,6 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
from contextlib import closing

import pywikibot
@@ -18,11 +16,11 @@


from pywikibot import config2 as config
-from pywikibot.tools import deprecated_args, UnicodeType
+from pywikibot.tools import deprecated_args


@deprecated_args(encoding=None)
-def mysql_query(query, params=None, dbname=None, verbose=None):
+def mysql_query(query: str, params=None, dbname=None, verbose=None):
"""Yield rows from a MySQL query.

An example query that yields all ns0 pages might look like::
@@ -37,7 +35,6 @@
Cursor charset is utf8.

@param query: MySQL query to execute
- @type query: str (unicode in py2)
@param params: input parameters for the query, if needed
if list or tuple, %s shall be used as placeholder in the query string.
if a dict, %(key)s shall be used as placeholder in the query string.
@@ -69,14 +66,12 @@
if verbose:
_query = cursor.mogrify(query, params)

- if not isinstance(_query, UnicodeType):
- _query = UnicodeType(_query, encoding='utf-8')
+ if not isinstance(_query, str):
+ _query = str(_query, encoding='utf-8')
_query = _query.strip()
_query = '\n'.join(' {0}'.format(line)
for line in _query.splitlines())
pywikibot.output('Executing query:\n' + _query)

cursor.execute(query, params)
-
- for row in cursor:
- yield row
+ yield from cursor
diff --git a/pywikibot/flow.py b/pywikibot/flow.py
index 74f9025..239e791 100644
--- a/pywikibot/flow.py
+++ b/pywikibot/flow.py
@@ -5,18 +5,12 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import logging

+from urllib.parse import urlparse, parse_qs
+
from pywikibot.exceptions import NoPage, UnknownExtension, LockedPage
from pywikibot.page import BasePage, User
-from pywikibot.tools import PY2, UnicodeType
-
-if not PY2:
- from urllib.parse import urlparse, parse_qs
-else:
- from urlparse import urlparse, parse_qs


logger = logging.getLogger('pywiki.wiki.flow')
@@ -45,7 +39,7 @@
@raises TypeError: incorrect use of parameters
@raises ValueError: use of non-Flow-enabled Site
"""
- super(FlowPage, self).__init__(source, title)
+ super().__init__(source, title)

if not self.site.has_extension('Flow'):
raise UnknownExtension('site is not Flow-enabled')
@@ -199,7 +193,7 @@
"""
if not isinstance(board, Board):
raise TypeError('board must be a pywikibot.flow.Board object.')
- if not isinstance(root_uuid, UnicodeType):
+ if not isinstance(root_uuid, str):
raise TypeError('Topic/root UUID must be a string.')

topic = cls(board.site, 'Topic:' + root_uuid)
@@ -305,7 +299,7 @@


# Flow non-page-like objects
-class Post(object):
+class Post:

"""A post to a Flow discussion topic."""

@@ -324,7 +318,7 @@
raise TypeError('Page must be a Topic object')
if not page.exists():
raise NoPage(page, 'Topic must exist: %s')
- if not isinstance(uuid, UnicodeType):
+ if not isinstance(uuid, str):
raise TypeError('Post UUID must be a string')

self._page = page
@@ -377,7 +371,7 @@
if 'content' in self._current_revision:
content = self._current_revision.pop('content')
assert isinstance(content, dict)
- assert isinstance(content['content'], UnicodeType)
+ assert isinstance(content['content'], str)
self._content[content['format']] = content['content']

def _load(self, format='wikitext', load_from_topic=False):
diff --git a/pywikibot/login.py b/pywikibot/login.py
index d9d5484..9a283d0 100644
--- a/pywikibot/login.py
+++ b/pywikibot/login.py
@@ -2,37 +2,36 @@
# -*- coding: utf-8 -*-
"""Library to log the bot in to a wiki account."""
#
-# (C) Pywikibot team, 2003-2019
+# (C) Pywikibot team, 2003-2020
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import codecs
import os
import webbrowser

-from pywikibot.tools import file_mode_checker
-
from warnings import warn

+import pywikibot
+
+from pywikibot import config, __url__
+from pywikibot.exceptions import NoUsername
+from pywikibot.tools import (
+ deprecated_args, file_mode_checker, normalize_username, remove_last_args,
+)
+
try:
import mwoauth
except ImportError as e:
mwoauth = e

-import pywikibot
-
-from pywikibot import config, __url__
-from pywikibot.exceptions import NoUsername
-from pywikibot.tools import (deprecated_args, remove_last_args,
- normalize_username, UnicodeType)
-

class OAuthImpossible(ImportError):

"""OAuth authentication is not possible on your system."""

+ pass
+

class _PasswordFileWarning(UserWarning):

@@ -55,7 +54,7 @@
}


-class LoginManager(object):
+class LoginManager:

"""Site login manager."""

@@ -122,16 +121,15 @@
user = next(iter(data))
except pywikibot.data.api.APIError as e:
if e.code == 'readapidenied':
- pywikibot.warning('Could not check user %s exists on %s'
- % (main_username, self.site))
+ pywikibot.warning("Could not check user '{}' exists on {}"
+ .format(main_username, self.site))
return
- else:
- raise
+ raise

if user['name'] != main_username:
# Report the same error as server error code NotExists
- raise NoUsername("Username '%s' does not exist on %s"
- % (main_username, self.site))
+ raise NoUsername("Username '{}' does not exist on {}"
+ .format(main_username, self.site))

def botAllowed(self):
"""
@@ -139,10 +137,9 @@

This allows bots to comply with the policy on the respective wiki.
"""
- if self.site.family.name in botList \
- and self.site.code in botList[self.site.family.name]:
- botlist_pagetitle, bot_template_title = botList[
- self.site.family.name][self.site.code]
+ code, fam = self.site.code, self.site.family.name
+ if code in botList.get(fam, []):
+ botlist_pagetitle, bot_template_title = botList[fam][code]
botlist_page = pywikibot.Page(self.site, botlist_pagetitle)
if bot_template_title:
for template, params in botlist_page.templatesWithParams():
@@ -154,9 +151,9 @@
if linked_page.title(with_ns=False) == self.username:
return True
return False
- else:
- # No bot policies on other sites
- return True
+
+ # No bot policies on other sites
+ return True

@remove_last_args(['remember', 'captcha'])
def getCookie(self):
@@ -181,8 +178,7 @@
"""
# THIS IS OVERRIDDEN IN data/api.py
filename = config.datafilepath('pywikibot.lwp')
- pywikibot.debug('Storing cookies to %s' % filename,
- _logger)
+ pywikibot.debug('Storing cookies to {}'.format(filename), _logger)
with open(filename, 'w') as f:
f.write(data)

@@ -228,6 +224,7 @@
line_nr -= 1
if not line.strip() or line.startswith('#'):
continue
+
try:
entry = eval(line)
except SyntaxError:
@@ -248,15 +245,16 @@
if (normalize_username(username) == self.username
and family == self.site.family.name
and code == self.site.code):
- if isinstance(password, UnicodeType):
+ if isinstance(password, str):
self.password = password
break
- elif isinstance(password, BotPassword):
+
+ if isinstance(password, BotPassword):
self.password = password.password
self.login_name = password.login_name(self.username)
break
- else:
- warn('Invalid password format', _PasswordFileWarning)
+
+ warn('Invalid password format', _PasswordFileWarning)

_api_error = {
'NotExists': 'does not exist',
@@ -266,7 +264,7 @@
'FAIL': 'does not have read permissions',
}

- def login(self, retry=False, autocreate=False):
+ def login(self, retry=False, autocreate=False) -> bool:
"""
Attempt to log into the server.

@@ -291,12 +289,12 @@
# As we don't want the password to appear on the screen, we set
# password = True
self.password = pywikibot.input(
- 'Password for user %(name)s on %(site)s (no characters will '
- 'be shown):' % {'name': self.login_name, 'site': self.site},
+ 'Password for user {name} on {site} (no characters will be '
+ 'shown):'.format(name=self.login_name, site=self.site),
password=True)

- pywikibot.output('Logging in to %(site)s as %(name)s'
- % {'name': self.login_name, 'site': self.site})
+ pywikibot.output('Logging in to {site} as {name}'
+ .format(name=self.login_name, site=self.site))
try:
cookiedata = self.getCookie()
except pywikibot.data.api.APIError as e:
@@ -320,11 +318,11 @@
return True


-class BotPassword(object):
+class BotPassword:

"""BotPassword object for storage in password file."""

- def __init__(self, suffix, password):
+ def __init__(self, suffix: str, password: str):
"""
Initializer.

@@ -332,9 +330,7 @@
suffixed username of the form <username>@<suffix>.

@param suffix: Suffix of the login name
- @type suffix: basestring
@param password: bot password
- @type password: basestring

@raises _PasswordFileWarning: suffix improperly specified
"""
@@ -344,13 +340,11 @@
self.suffix = suffix
self.password = password

- def login_name(self, username):
+ def login_name(self, username: str) -> str:
"""
Construct the login name from the username and suffix.

@param user: username (without suffix)
- @type user: basestring
- @rtype: basestring
"""
return '{0}@{1}'.format(username, self.suffix)

@@ -372,9 +366,9 @@
@param site: Site object to log into
@type site: BaseSite
@param user: consumer key
- @type user: basestring
+ @type user: str
@param password: consumer secret
- @type password: basestring
+ @type password: str

@raises pywikibot.exceptions.NoUsername: No username is configured
for the requested site.
@@ -383,12 +377,12 @@
if isinstance(mwoauth, ImportError):
raise OAuthImpossible('mwoauth is not installed: %s.' % mwoauth)
assert password is not None and user is not None
- super(OauthLoginManager, self).__init__(password=None, site=site,
- user=None)
+ super().__init__(password=None, site=site, user=None)
if self.password:
- pywikibot.warn('Password exists in password file for %s:%s.'
- 'Password is unnecessary and should be removed '
- 'when OAuth enabled.' % (self.site, self.username))
+ pywikibot.warn('Password exists in password file for {login.site}:'
+ '{login.username}. Password is unnecessary and '
+ 'should be removed if OAuth enabled.'
+ .format(login=self))
self._consumer_token = (user, password)
self._access_token = None

@@ -406,10 +400,9 @@
"""
if self.access_token is None or force:
pywikibot.output(
- 'Logging in to %(site)s via OAuth consumer %(key)s'
- % {'key': self.consumer_token[0], 'site': self.site})
- consumer_token = mwoauth.ConsumerToken(self.consumer_token[0],
- self.consumer_token[1])
+ 'Logging in to {site} via OAuth consumer {key}'
+ .format(key=self.consumer_token[0], site=self.site))
+ consumer_token = mwoauth.ConsumerToken(*self.consumer_token)
handshaker = mwoauth.Handshaker(
self.site.base_url(self.site.path()), consumer_token)
try:
@@ -417,20 +410,19 @@
pywikibot.stdout('Authenticate via web browser..')
webbrowser.open(redirect)
pywikibot.stdout('If your web browser does not open '
- 'automatically, please point it to: %s'
- % redirect)
+ 'automatically, please point it to: {}'
+ .format(redirect))
request_qs = pywikibot.input('Response query string: ')
- access_token = handshaker.complete(request_token,
- request_qs)
+ access_token = handshaker.complete(request_token, request_qs)
self._access_token = (access_token.key, access_token.secret)
except Exception as e:
pywikibot.error(e)
if retry:
self.login(retry=True, force=force)
else:
- pywikibot.output('Logged in to %(site)s via consumer %(key)s'
- % {'key': self.consumer_token[0],
- 'site': self.site})
+ pywikibot.output('Logged in to {site} via consumer {key}'
+ .format(key=self.consumer_token[0],
+ site=self.site))

@property
def consumer_token(self):
@@ -464,10 +456,9 @@
if self.access_token is None:
pywikibot.error('Access token not set')
return None
- consumer_token = mwoauth.ConsumerToken(self.consumer_token[0],
- self.consumer_token[1])
- access_token = mwoauth.AccessToken(self.access_token[0],
- self.access_token[1])
+
+ consumer_token = mwoauth.ConsumerToken(*self.consumer_token)
+ access_token = mwoauth.AccessToken(*self.access_token)
try:
identity = mwoauth.identify(self.site.base_url(self.site.path()),
consumer_token, access_token)
diff --git a/pywikibot/specialbots/_upload.py b/pywikibot/specialbots/_upload.py
index 56ff407..c30d1cf 100644
--- a/pywikibot/specialbots/_upload.py
+++ b/pywikibot/specialbots/_upload.py
@@ -9,12 +9,12 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import os
import tempfile

from contextlib import closing
+from urllib.parse import urlparse
+from urllib.request import URLopener

import pywikibot
import pywikibot.data.api
@@ -22,16 +22,9 @@
from pywikibot import config

from pywikibot.bot import BaseBot, QuitKeyboardInterrupt
-from pywikibot.tools import PY2, deprecated, deprecated_args, UnicodeType
+from pywikibot.tools import deprecated, deprecated_args
from pywikibot.tools.formatter import color_format

-if not PY2:
- from urllib.parse import urlparse
- from urllib.request import URLopener
-else:
- from urllib import URLopener
- from urlparse import urlparse
-

class UploadRobot(BaseBot):

@@ -41,7 +34,7 @@
useFilename='use_filename', keepFilename='keep_filename',
verifyDescription='verify_description',
ignoreWarning='ignore_warning', targetSite='target_site')
- def __init__(self, url, url_encoding=None, description='',
+ def __init__(self, url: list, url_encoding=None, description='',
use_filename=None, keep_filename=False,
verify_description=True, ignore_warning=False,
target_site=None, aborts=[], chunk_size=0, summary=None,
@@ -51,7 +44,6 @@

@param url: path to url or local file (deprecated), or list of urls or
paths to local files.
- @type url: str (deprecated) or list
@param description: Description of file for its page. If multiple files
are uploading the same description is used for every file.
@type description: str
@@ -88,7 +80,7 @@
overwrites verify_description to False and keep_filename to True.
@type always: bool
"""
- super(UploadRobot, self).__init__(**kwargs)
+ super().__init__(**kwargs)
always = self.getOption('always')
if (always and ignore_warning is not True and aborts is not True):
raise ValueError('When always is set to True, either '
@@ -97,7 +89,7 @@
raise ValueError('When always is set to True, the description '
'must be set.')
self.url = url
- if isinstance(self.url, UnicodeType):
+ if isinstance(self.url, str):
pywikibot.warning('url as string is deprecated. '
'Use an iterable instead.')
self.url_encoding = url_encoding
@@ -122,7 +114,7 @@
file_url = self.url
pywikibot.warning('file_url is not given. '
'Set to self.url by default.')
- pywikibot.output('Reading file %s' % file_url)
+ pywikibot.output('Reading file {}'.format(file_url))
resume = False
rlen = 0
_contents = None
@@ -133,15 +125,12 @@
while not retrieved:
if resume:
pywikibot.output('Resume download...')
- uo.addheader('Range', 'bytes=%s-' % rlen)
+ uo.addheader('Range', 'bytes={}-'.format(rlen))

with closing(uo.open(file_url)) as infile:
info = infile.info()

- if PY2:
- info_get = info.getheader
- else:
- info_get = info.get
+ info_get = info.get
content_type = info_get('Content-Type')
content_len = info_get('Content-Length')
accept_ranges = info_get('Accept-Ranges')
@@ -166,11 +155,11 @@
if rlen < content_len:
retrieved = False
pywikibot.output(
- 'Connection closed at byte %s (%s left)'
- % (rlen, content_len))
+ 'Connection closed at byte {} ({} left)'
+ .format(rlen, content_len))
if valid_ranges and rlen > 0:
resume = True
- pywikibot.output('Sleeping for %d seconds...' % dt)
+ pywikibot.output('Sleeping for {} seconds...'.format(dt))
pywikibot.sleep(dt)
if dt <= 60:
dt += 15
@@ -461,7 +450,7 @@
return

try:
- if isinstance(self.url, UnicodeType):
+ if isinstance(self.url, str):
self._treat_counter = 1
return self.upload_file(self.url)
for file_url in self.url:
diff --git a/scripts/create_categories.py b/scripts/create_categories.py
index ed77cb4..d5bd477 100755
--- a/scripts/create_categories.py
+++ b/scripts/create_categories.py
@@ -29,20 +29,16 @@
The page 'User:Multichill/Wallonia' on commons contains
category links like [[Category:Hensies]], causing this script
to create [[Category:Cultural heritage monuments in Hensies]].
-
"""
#
-# (c) Pywikibot team, 2011-2019
+# (c) Pywikibot team, 2011-2020
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import pywikibot
from pywikibot.bot import AutomaticTWSummaryBot, SingleSiteBot
from pywikibot import pagegenerators
from pywikibot.site import Namespace
-from pywikibot.tools import UnicodeType


class CreateCategoriesBot(SingleSiteBot, AutomaticTWSummaryBot):
@@ -58,11 +54,11 @@
'parent': None,
'overwrite': False,
})
- super(CreateCategoriesBot, self).__init__(**kwargs)
+ super().__init__(**kwargs)

def init_page(self, item):
"""Create a category to be processed with the given page title."""
- page = super(CreateCategoriesBot, self).init_page(item)
+ page = super().init_page(item)
title = page.title(with_ns=False)
if page.namespace() != Namespace.CATEGORY:
# return the page title to be skipped later within skip_page
@@ -71,11 +67,11 @@
category = pywikibot.Category(
page.site, '{} {}'.format(self.getOption('basename'), title))

- text = ('[[{namespace}:{parent}|{title}]]\n{category}\n'
- .format(namespace=page.site.namespace(Namespace.CATEGORY),
- parent=self.getOption('parent'),
- title=title,
- category=page.title(as_link=True)))
+ text = '[[{namespace}:{parent}|{title}]]\n{category}\n'.format(
+ namespace=page.site.namespace(Namespace.CATEGORY),
+ parent=self.getOption('parent'),
+ title=title,
+ category=page)
category.text = text
return category

@@ -87,13 +83,13 @@

def skip_page(self, page):
"""Skip page if it is not overwritten."""
- if isinstance(page, UnicodeType):
+ if isinstance(page, str):
pywikibot.warning(page + ' is not a category, skipping')
return True
if page.exists() and not self.getOption('overwrite'):
pywikibot.warning('{} already exists, skipping'.format(page))
return True
- return super(CreateCategoriesBot, self).skip_page(page)
+ return super().skip_page(page)


def main(*args):
diff --git a/scripts/misspelling.py b/scripts/misspelling.py
index 897cf4c..85cba8e 100755
--- a/scripts/misspelling.py
+++ b/scripts/misspelling.py
@@ -31,7 +31,6 @@
import pywikibot

from pywikibot import i18n, pagegenerators
-from pywikibot.tools import UnicodeType

from scripts.solve_disambiguation import DisambiguationRobot

@@ -77,7 +76,7 @@
mycode = self.site.code
if mycode in self.misspellingCategory:
categories = self.misspellingCategory[mycode]
- if isinstance(categories, UnicodeType):
+ if isinstance(categories, str):
categories = (categories, )
generators = (
pagegenerators.CategorizedPageGenerator(
@@ -86,7 +85,7 @@
for misspellingCategoryTitle in categories)
elif mycode in self.misspellingTemplate:
templates = self.misspellingTemplate[mycode]
- if isinstance(templates, UnicodeType):
+ if isinstance(templates, str):
templates = (templates, )
generators = (
pagegenerators.ReferringPageGenerator(
@@ -119,7 +118,7 @@
return True
if self.misspellingTemplate.get(disambPage.site.code) is not None:
templates = self.misspellingTemplate[disambPage.site.code]
- if isinstance(templates, UnicodeType):
+ if isinstance(templates, str):
templates = (templates, )
for template, params in disambPage.templatesWithParams():
if template.title(with_ns=False) in templates:
diff --git a/scripts/replace.py b/scripts/replace.py
index e9f1d68..c7d3609 100755
--- a/scripts/replace.py
+++ b/scripts/replace.py
@@ -140,16 +140,14 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import codecs
-try:
- from collections.abc import Sequence
-except ImportError: # Python 2.7
- from collections import Sequence
import re
import warnings

+from collections.abc import Sequence
+from contextlib import suppress
+from queue import Queue
+
import pywikibot
from pywikibot import editor
from pywikibot.exceptions import ArgumentDeprecationWarning
@@ -162,15 +160,8 @@
deprecated,
deprecated_args,
issue_deprecation_warning,
- PY2,
- UnicodeType
)

-if not PY2:
- from queue import Queue
-else:
- from Queue import Queue
-

# This is required for the text that is shown when you run this script
# with the parameter -help.
@@ -199,7 +190,7 @@
return exceptions.get('inside-tags', []) + exceptions.get('inside', [])


-class ReplacementBase(object):
+class ReplacementBase:

"""The replacement instructions."""

@@ -212,12 +203,12 @@
self.default_summary = default_summary

@property
- def edit_summary(self):
+ def edit_summary(self) -> str:
"""Return the edit summary for this fix."""
return self._edit_summary

@property
- def description(self):
+ def description(self) -> str:
"""Description of the changes that this replacement applies.

This description is used as the default summary of the replacement. If
@@ -253,8 +244,6 @@
def compile(self, use_regex, flags):
"""Compile the search text."""
# Set the regular expression flags
- flags |= re.UNICODE
-
if self.case_insensitive is False:
flags &= ~re.IGNORECASE
elif self.case_insensitive:
@@ -273,8 +262,7 @@
case_insensitive=None, edit_summary=None,
default_summary=True):
"""Create a single replacement entry unrelated to a fix."""
- super(Replacement, self).__init__(old, new, edit_summary,
- default_summary)
+ super().__init__(old, new, edit_summary, default_summary)
self._use_regex = use_regex
self.exceptions = exceptions
self._case_insensitive = case_insensitive
@@ -300,7 +288,7 @@

def _compile(self, use_regex, flags):
"""Compile the search regex and exceptions."""
- super(Replacement, self)._compile(use_regex, flags)
+ super()._compile(use_regex, flags)
precompile_exceptions(self.exceptions, use_regex, flags)

def get_inside_exceptions(self):
@@ -325,7 +313,7 @@
def __init__(self, use_regex, exceptions, case_insensitive, edit_summary,
name):
"""Create a fix list which can contain multiple replacements."""
- super(ReplacementList, self).__init__()
+ super().__init__()
self.use_regex = use_regex
self._exceptions = exceptions
self.exceptions = None
@@ -347,8 +335,7 @@
def __init__(self, old, new, fix_set, edit_summary=None,
default_summary=True):
"""Create a replacement entry inside a fix set."""
- super(ReplacementListEntry, self).__init__(old, new, edit_summary,
- default_summary)
+ super().__init__(old, new, edit_summary, default_summary)
self.fix_set = fix_set

@property
@@ -389,7 +376,7 @@

def _compile(self, use_regex, flags):
"""Compile the search regex and the fix's exceptions."""
- super(ReplacementListEntry, self)._compile(use_regex, flags)
+ super()._compile(use_regex, flags)
self.fix_set._compile_exceptions(use_regex, flags)

def get_inside_exceptions(self):
@@ -460,13 +447,11 @@
yield pywikibot.Page(self.site, entry.title)

except KeyboardInterrupt:
- try:
+ with suppress(NameError):
if not self.skipping:
pywikibot.output(
'To resume, use "-xmlstart:{0}" on the command line.'
.format(entry.title))
- except NameError:
- pass

def isTitleExcepted(self, title):
"""
@@ -557,7 +542,7 @@
'sleep': 0.0,
'summary': None,
})
- super(ReplaceRobot, self).__init__(generator=generator, **kwargs)
+ super().__init__(generator=generator, **kwargs)

for i, replacement in enumerate(replacements):
if isinstance(replacement, Sequence):
@@ -575,17 +560,13 @@
self.summary = self.getOption('summary')

self.addcat = self.getOption('addcat')
- if self.addcat and isinstance(self.addcat, UnicodeType):
+ if self.addcat and isinstance(self.addcat, str):
self.addcat = pywikibot.Category(self.site, self.addcat)

self._pending_processed_titles = Queue()

- def isTitleExcepted(self, title, exceptions=None):
- """
- Return True iff one of the exceptions applies for the given title.
-
- @rtype: bool
- """
+ def isTitleExcepted(self, title, exceptions=None) -> bool:
+ """Return True if one of the exceptions applies for the given title."""
if exceptions is None:
exceptions = self.exceptions
if 'title' in exceptions:
@@ -598,12 +579,8 @@
return True
return False

- def isTextExcepted(self, original_text):
- """
- Return True iff one of the exceptions applies for the given text.
-
- @rtype: bool
- """
+ def isTextExcepted(self, original_text) -> bool:
+ """Return True iff one of the exceptions applies for the given text."""
if 'text-contains' in self.exceptions:
for exc in self.exceptions['text-contains']:
if exc.search(original_text):
@@ -725,7 +702,7 @@
pywikibot.warning("You can't edit page {}".format(page))
return True

- return super(ReplaceRobot, self).skip_page(page)
+ return super().skip_page(page)

def treat(self, page):
"""Work on each page retrieved from generator."""
@@ -888,7 +865,7 @@
useSql = False
sql_query = None
# Set the default regular expression flags
- flags = re.UNICODE
+ flags = 0
# Request manual replacements even if replacements are already defined
manual_input = False
# Replacements loaded from a file
@@ -1041,7 +1018,7 @@
'"{0}"'.format(fix_name))
continue
if 'msg' in fix:
- if isinstance(fix['msg'], UnicodeType):
+ if isinstance(fix['msg'], str):
set_summary = i18n.twtranslate(site, str(fix['msg']))
else:
set_summary = i18n.translate(site, fix['msg'], fallback=True)
@@ -1049,7 +1026,7 @@
set_summary = None
if not generators_given and 'generator' in fix:
gen_args = fix['generator']
- if isinstance(gen_args, UnicodeType):
+ if isinstance(gen_args, str):
gen_args = [gen_args]
for gen_arg in gen_args:
genFactory.handleArg(gen_arg)
diff --git a/tests/file_tests.py b/tests/file_tests.py
index c96cae1..6100e6f 100644
--- a/tests/file_tests.py
+++ b/tests/file_tests.py
@@ -5,14 +5,12 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import os
import re

-import pywikibot
+from contextlib import suppress

-from pywikibot.tools import UnicodeType as unicode
+import pywikibot

from tests import join_images_path

@@ -210,7 +208,7 @@

def setUp(self):
"""Create File page."""
- super(TestCase, self).setUp()
+ super().setUp()
self.image = pywikibot.FilePage(self.site, self.file_name)

def test_get_file_url(self):
@@ -272,8 +270,6 @@
first = page.getFirstUploader()
self.assertOneDeprecation()
self.assertEqual(first, ['Herbizid', '2011-03-18T10:04:48Z'])
- self.assertIsInstance(first[0], unicode)
- self.assertIsInstance(first[1], unicode)

def test_getLatestUploader(self):
"""Test getLatestUploader."""
@@ -281,8 +277,8 @@
latest = page.getLatestUploader()
self.assertOneDeprecation()
self.assertLength(latest, 2)
- self.assertIsInstance(latest[0], unicode)
- self.assertIsInstance(latest[1], unicode)
+ for item in latest:
+ self.assertIsInstance(item, str)


class TestFilePageDownload(TestCase):
@@ -316,7 +312,5 @@


if __name__ == '__main__': # pragma: no cover
- try:
+ with suppress(SystemExit):
unittest.main()
- except SystemExit:
- pass
diff --git a/tests/flow_edit_tests.py b/tests/flow_edit_tests.py
index 330499a..bdf2797 100644
--- a/tests/flow_edit_tests.py
+++ b/tests/flow_edit_tests.py
@@ -1,15 +1,14 @@
# -*- coding: utf-8 -*-
"""Edit tests for the flow module."""
#
-# (C) Pywikibot team, 2015-2019
+# (C) Pywikibot team, 2015-2020
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
+from contextlib import suppress

from pywikibot.exceptions import LockedPage
from pywikibot.flow import Board, Topic, Post
-from pywikibot.tools import UnicodeType as unicode

from tests.aspects import TestCase
from tests import unittest
@@ -34,7 +33,7 @@
wikitext = first_post.get(format='wikitext')
self.assertIn('wikitext', first_post._content)
self.assertNotIn('html', first_post._content)
- self.assertIsInstance(wikitext, unicode)
+ self.assertIsInstance(wikitext, str)
self.assertEqual(wikitext, content)


@@ -51,7 +50,7 @@
@classmethod
def setUpClass(cls):
"""Set up class."""
- super(TestFlowReply, cls).setUpClass()
+ super().setUpClass()
cls._topic_title = 'Topic:Stf56oxx0sd4dkj1'

def test_reply_to_topic(self):
@@ -66,7 +65,7 @@
wikitext = reply_post.get(format='wikitext')
self.assertIn('wikitext', reply_post._content)
self.assertNotIn('html', reply_post._content)
- self.assertIsInstance(wikitext, unicode)
+ self.assertIsInstance(wikitext, str)
self.assertEqual(wikitext, content)
# Test reply list in topic
new_replies = topic.replies(force=True)
@@ -86,7 +85,7 @@
wikitext = reply_post.get(format='wikitext')
self.assertIn('wikitext', reply_post._content)
self.assertNotIn('html', reply_post._content)
- self.assertIsInstance(wikitext, unicode)
+ self.assertIsInstance(wikitext, str)
self.assertEqual(wikitext, content)
# Test reply list in topic
new_replies = topic_root.replies(force=True)
@@ -105,7 +104,7 @@
wikitext = reply_post.get(format='wikitext')
self.assertIn('wikitext', reply_post._content)
self.assertNotIn('html', reply_post._content)
- self.assertIsInstance(wikitext, unicode)
+ self.assertIsInstance(wikitext, str)
self.assertEqual(wikitext, content)
# Test reply list in topic
new_replies = root_post.replies(force=True)
@@ -126,7 +125,7 @@
first_wikitext = first_reply_post.get(format='wikitext')
self.assertIn('wikitext', first_reply_post._content)
self.assertNotIn('html', first_reply_post._content)
- self.assertIsInstance(first_wikitext, unicode)
+ self.assertIsInstance(first_wikitext, str)
self.assertEqual(first_wikitext, first_content)
# Test reply list in topic
new_root_replies = topic_root.replies(force=True)
@@ -141,7 +140,7 @@
second_wikitext = second_reply_post.get(format='wikitext')
self.assertIn('wikitext', second_reply_post._content)
self.assertNotIn('html', second_reply_post._content)
- self.assertIsInstance(second_wikitext, unicode)
+ self.assertIsInstance(second_wikitext, str)
self.assertEqual(second_wikitext, second_content)

# Test reply list in first reply
@@ -326,7 +325,5 @@


if __name__ == '__main__': # pragma: no cover
- try:
+ with suppress(SystemExit):
unittest.main()
- except SystemExit:
- pass
diff --git a/tests/flow_tests.py b/tests/flow_tests.py
index 62b3d96..60f644f 100644
--- a/tests/flow_tests.py
+++ b/tests/flow_tests.py
@@ -1,15 +1,14 @@
# -*- coding: utf-8 -*-
"""Tests for the flow module."""
#
-# (C) Pywikibot team, 2015-2019
+# (C) Pywikibot team, 2015-2020
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
+from contextlib import suppress

from pywikibot.exceptions import NoPage
from pywikibot.flow import Board, Topic, Post
-from pywikibot.tools import UnicodeType as unicode

from tests import unittest
from tests.aspects import (
@@ -32,7 +31,7 @@
"""Set up unit test."""
self._page = Board(self.site,
'Project talk:Sandbox/Structured_Discussions_test')
- super(TestMediaWikiFlowSandbox, self).setUp()
+ super().setUp()


class TestBoardBasePageMethods(BasePageMethodsTestBase,
@@ -61,7 +60,7 @@
def setUp(self):
"""Set up unit test."""
self._page = Topic(self.site, 'Topic:Sh6wgo5tu3qui1w2')
- super(TestTopicBasePageMethods, self).setUp()
+ super().setUp()

def test_basepage_methods(self):
"""Test basic Page methods on a Flow topic page."""
@@ -122,24 +121,24 @@
wikitext = post.get(format='wikitext')
self.assertIn('wikitext', post._content)
self.assertNotIn('html', post._content)
- self.assertIsInstance(wikitext, unicode)
+ self.assertIsInstance(wikitext, str)
self.assertNotEqual(wikitext, '')
# HTML
html = post.get(format='html')
self.assertIn('html', post._content)
self.assertIn('wikitext', post._content)
- self.assertIsInstance(html, unicode)
+ self.assertIsInstance(html, str)
self.assertNotEqual(html, '')
# Caching (hit)
post._content['html'] = 'something'
html = post.get(format='html')
- self.assertIsInstance(html, unicode)
+ self.assertIsInstance(html, str)
self.assertEqual(html, 'something')
self.assertIn('html', post._content)
# Caching (reload)
post._content['html'] = 'something'
html = post.get(format='html', force=True)
- self.assertIsInstance(html, unicode)
+ self.assertIsInstance(html, str)
self.assertNotEqual(html, 'something')
self.assertIn('html', post._content)

@@ -247,7 +246,5 @@


if __name__ == '__main__': # pragma: no cover
- try:
+ with suppress(SystemExit):
unittest.main()
- except SystemExit:
- pass
diff --git a/tests/http_tests.py b/tests/http_tests.py
index 8bf693a..9a8b0b7 100644
--- a/tests/http_tests.py
+++ b/tests/http_tests.py
@@ -1,27 +1,23 @@
# -*- coding: utf-8 -*-
"""Tests for http module."""
#
-# (C) Pywikibot team, 2014-2018
+# (C) Pywikibot team, 2014-2020
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import json
import re
import warnings

+from contextlib import suppress
+
import requests

import pywikibot

from pywikibot import config2 as config
from pywikibot.comms import http, threadedhttp
-from pywikibot.tools import (
- PYTHON_VERSION,
- suppress_warnings,
- UnicodeType as unicode,
-)
+from pywikibot.tools import PYTHON_VERSION, suppress_warnings

from tests import join_images_path, patch
from tests.aspects import (
@@ -49,7 +45,7 @@
self.assertIsInstance(r, threadedhttp.HttpRequest)
self.assertEqual(r.status, 200)
self.assertIn('<html lang="mul"', r.text)
- self.assertIsInstance(r.text, unicode)
+ self.assertIsInstance(r.text, str)
self.assertIsInstance(r.raw, bytes)

def test_fetch(self):
@@ -58,7 +54,7 @@
self.assertIsInstance(r, threadedhttp.HttpRequest)
self.assertEqual(r.status, 200)
self.assertIn('<html lang="mul"', r.text)
- self.assertIsInstance(r.text, unicode)
+ self.assertIsInstance(r.text, str)
with suppress_warnings(r'.*HttpRequest\.content is deprecated'):
self.assertEqual(r.content, r.text)
self.assertIsInstance(r.raw, bytes)
@@ -80,7 +76,7 @@
def test_http(self):
"""Test http.request using http://www.wikipedia.org/."""
r = http.request(site=None, uri='http://www.wikipedia.org/')
- self.assertIsInstance(r, unicode)
+ self.assertIsInstance(r, str)
self.assertIn('<html lang="mul"', r)
self.assertOneDeprecationParts(
'Invoking http.request without argument site', 'http.fetch()')
@@ -88,7 +84,7 @@
def test_https(self):
"""Test http.request using https://www.wikiquote.org/."""
r = http.request(site=None, uri='https://www.wikiquote.org/')
- self.assertIsInstance(r, unicode)
+ self.assertIsInstance(r, str)
self.assertIn('<html lang="mul"', r)
self.assertOneDeprecationParts(
'Invoking http.request without argument site', 'http.fetch()')
@@ -102,7 +98,7 @@

def setUp(self):
"""Set up test by configuring config.authenticate."""
- super(TestGetAuthenticationConfig, self).setUp()
+ super().setUp()
self._authenticate = config.authenticate
config.authenticate = {
'zh.wikipedia.beta.wmflabs.org': ('1', '2'),
@@ -113,7 +109,7 @@

def tearDown(self):
"""Tear down test by resetting config.authenticate."""
- super(TestGetAuthenticationConfig, self).tearDown()
+ super().tearDown()
config.authenticate = self._authenticate

def test_url_based_authentication(self):
@@ -153,7 +149,7 @@
uri='https://testssl-expire-r2i2.disig.sk/index.en.html',
disable_ssl_certificate_validation=True)
r = response.text
- self.assertIsInstance(r, unicode)
+ self.assertIsInstance(r, str)
self.assertTrue(re.search(r'<title>.*</title>', r))
http.session.close() # clear the connection

@@ -282,7 +278,7 @@

def setUp(self):
"""Set up unit test."""
- super(DefaultUserAgentTestCase, self).setUp()
+ super().setUp()
self.orig_format = config.user_agent_format
config.user_agent_format = ('{script_product} ({script_comments}) '
'{pwb} ({revision}) {http_backend} '
@@ -290,7 +286,7 @@

def tearDown(self):
"""Tear down unit test."""
- super(DefaultUserAgentTestCase, self).tearDown()
+ super().tearDown()
config.user_agent_format = self.orig_format

def test_default_user_agent(self):
@@ -314,13 +310,13 @@
"""Set up the unit test."""
self.orig_fake_user_agent_exceptions = (
config.fake_user_agent_exceptions)
- super(LiveFakeUserAgentTestCase, self).setUp()
+ super().setUp()

def tearDown(self):
"""Tear down unit test."""
config.fake_user_agent_exceptions = (
self.orig_fake_user_agent_exceptions)
- super(LiveFakeUserAgentTestCase, self).tearDown()
+ super().tearDown()

def _test_fetch_use_fake_user_agent(self):
"""Test `use_fake_user_agent` argument of http.fetch."""
@@ -364,12 +360,12 @@
def setUp(self):
"""Set up unit test."""
self.orig_fake_user_agent = config.fake_user_agent
- super(GetFakeUserAgentTestCase, self).setUp()
+ super().setUp()

def tearDown(self):
"""Tear down unit test."""
config.fake_user_agent = self.orig_fake_user_agent
- super(GetFakeUserAgentTestCase, self).tearDown()
+ super().tearDown()

def _test_config_settings(self):
"""Test if method honours configuration toggle."""
@@ -562,7 +558,7 @@
@classmethod
def setUpClass(cls):
"""Set up test class."""
- super(BinaryTestCase, cls).setUpClass()
+ super().setUpClass()

with open(join_images_path('MP_sounds.png'), 'rb') as f:
cls.png = f.read()
@@ -612,7 +608,7 @@

def setUp(self):
"""Set up tests."""
- super(QueryStringParamsTestCase, self).setUp()
+ super().setUp()
self.url = self.get_httpbin_url('/get')

def test_no_params(self):
@@ -689,7 +685,5 @@


if __name__ == '__main__': # pragma: no cover
- try:
+ with suppress(SystemExit):
unittest.main()
- except SystemExit:
- pass
diff --git a/tests/logentries_tests.py b/tests/logentries_tests.py
index 81fc48a..39f31d6 100644
--- a/tests/logentries_tests.py
+++ b/tests/logentries_tests.py
@@ -14,7 +14,6 @@
from pywikibot.exceptions import HiddenKeyError
from pywikibot.logentries import (
LogEntryFactory, OtherLogEntry, UserTargetLogEntry)
-from pywikibot.tools import UnicodeType

from tests import unittest_print
from tests.aspects import (
@@ -75,10 +74,10 @@
else:
self.assertNotIn(logentry.type(), logentry.data)

- self.assertIsInstance(logentry.action(), UnicodeType)
+ self.assertIsInstance(logentry.action(), str)

try:
- self.assertIsInstance(logentry.comment(), UnicodeType)
+ self.assertIsInstance(logentry.comment(), str)
except HiddenKeyError as e:
self.assertRegex(
str(e),
@@ -115,7 +114,7 @@
self.assertRaises(KeyError, logentry.page)

self.assertEqual(logentry.type(), logtype)
- self.assertIsInstance(logentry.user(), UnicodeType)
+ self.assertIsInstance(logentry.user(), str)
self.assertGreaterEqual(logentry.logid(), 0)

# test new UserDict style
@@ -144,7 +143,7 @@
cls.add_method(dct, 'test_{}Entry'.format(logtype.title()),
test_method(logtype))

- return super(TestLogentriesMeta, cls).__new__(cls, name, bases, dct)
+ return super().__new__(cls, name, bases, dct)


class TestLogentries(TestLogentriesBase, metaclass=TestLogentriesMeta):
@@ -212,7 +211,7 @@
self.assertIsInstance(logentry.target_ns, pywikibot.site.Namespace)
self.assertEqual(logentry.target_page.namespace(),
logentry.target_ns.id)
- self.assertIsInstance(logentry.target_title, UnicodeType)
+ self.assertIsInstance(logentry.target_title, str)
self.assertIsInstance(logentry.target_page, pywikibot.Page)
self.assertIsInstance(logentry.suppressedredirect(), bool)

diff --git a/tests/wikistats_tests.py b/tests/wikistats_tests.py
index 2af381e..a68926e 100644
--- a/tests/wikistats_tests.py
+++ b/tests/wikistats_tests.py
@@ -5,12 +5,9 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals
-
import sys

from pywikibot.data.wikistats import WikiStats, csv
-from pywikibot.tools import UnicodeType

from tests.aspects import unittest, TestCase

@@ -35,13 +32,13 @@
self.assertIn(key, top)
self.assertIn(key, bottom)

- self.assertTrue(all(isinstance(key, UnicodeType)
+ self.assertTrue(all(isinstance(key, str)
for key in top.keys()
if key is not None))
- self.assertIsInstance(top['good'], UnicodeType)
- self.assertIsInstance(top['total'], UnicodeType)
- self.assertIsInstance(bottom['good'], UnicodeType)
- self.assertIsInstance(bottom['total'], UnicodeType)
+ self.assertIsInstance(top['good'], str)
+ self.assertIsInstance(top['total'], str)
+ self.assertIsInstance(bottom['good'], str)
+ self.assertIsInstance(bottom['total'], str)

self.assertGreater(int(top['total']), int(bottom['good']))
self.assertGreater(int(top['good']), int(bottom['good']))
@@ -74,10 +71,10 @@
self.assertIn('ht', data)
self.assertGreater(int(data['en']['total']), int(data['en']['good']))
data = data['en']
- self.assertTrue(all(isinstance(key, UnicodeType)
+ self.assertTrue(all(isinstance(key, str)
for key in data.keys()
if key is not None))
- self.assertIsInstance(data['total'], UnicodeType)
+ self.assertIsInstance(data['total'], str)
self.assertIn('prefix', data)
self.assertIn('total', data)

@@ -90,10 +87,10 @@
self.assertIn('id', data)
self.assertGreater(int(data['fr']['total']), int(data['fr']['good']))
data = data['fr']
- self.assertTrue(all(isinstance(key, UnicodeType)
+ self.assertTrue(all(isinstance(key, str)
for key in data.keys()
if key is not None))
- self.assertIsInstance(data['total'], UnicodeType)
+ self.assertIsInstance(data['total'], str)
self.assertIn('prefix', data)
self.assertIn('total', data)


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

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I65ecb79798cce36dd542acdad9cec46e448acfd8
Gerrit-Change-Number: 616170
Gerrit-PatchSet: 9
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: D3r1ck01 <xsavitar.wiki@aol.com>
Gerrit-Reviewer: Matěj Suchánek <matejsuchanek97@gmail.com>
Gerrit-Reviewer: Zhuyifei1999 <zhuyifei1999@gmail.com>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged