jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[lint] Fix lint checks, mainly use f-string instead of .format()

Change-Id: Icf4d99358380194546e1497588cd67cd16790251
---
M pyproject.toml
M tests/__init__.py
M tests/archivebot_tests.py
M tests/aspects.py
M tests/basesite_tests.py
M tests/bot_tests.py
M tests/category_bot_tests.py
M tests/data/fixes.py
M tests/data/set-fixes.py
M tests/date_tests.py
M tests/djvu_tests.py
M tests/edit_tests.py
M tests/eventstreams_tests.py
M tests/family_tests.py
M tests/file_tests.py
M tests/flow_edit_tests.py
M tests/flow_thanks_tests.py
M tests/generate_family_file_tests.py
M tests/i18n_tests.py
M tests/l10n_tests.py
M tests/link_tests.py
M tests/namespace_tests.py
M tests/page_tests.py
M tests/pagegenerators_tests.py
M tests/patrolbot_tests.py
M tests/pwb_tests.py
M tests/replacebot_tests.py
M tests/script_tests.py
M tests/site_generators_tests.py
M tests/site_tests.py
M tests/sparql_tests.py
M tests/textlib_tests.py
M tests/thanks_tests.py
M tests/timestripper_tests.py
M tests/tools_deprecate_tests.py
M tests/ui_options_tests.py
M tests/ui_tests.py
M tests/upload_tests.py
M tests/user_tests.py
M tests/utils.py
M tests/wikistats_tests.py
41 files changed, 191 insertions(+), 209 deletions(-)

diff --git a/pyproject.toml b/pyproject.toml
index 3c8eb7f..f1ac0a4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -125,3 +125,26 @@
Download = "https://www.pywikibot.org"
Changelog = "https://doc.wikimedia.org/pywikibot/master/changelog.html"
Tracker = "https://phabricator.wikimedia.org/tag/pywikibot/"
+
+[tool.ruff]
+line-length = 80
+
+[tool.ruff.format]
+quote-style = "single"
+docstring-code-format = true
+
+[tool.ruff.lint]
+select = [
+ # pycodestyle
+ "E",
+ # Pyflakes
+ "F",
+ # pyupgrade
+ "UP",
+ # flake8-bugbear
+ "B",
+ # flake8-simplify
+ "SIM",
+ # isort
+ "I",
+]
\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
index 0660f96..34944b3 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -6,7 +6,6 @@
#
from __future__ import annotations

-
__all__ = (
'create_path_func', 'join_cache_path', 'join_data_path',
'join_html_data_path', 'join_images_path', 'join_pages_path',
@@ -34,7 +33,6 @@
from pywikibot.data.api import CachedRequest
from pywikibot.data.api import Request as _original_Request

-
_root_dir = os.path.split(os.path.split(__file__)[0])[0]

WARN_SITE_CODE = '^Site .*:.* instantiated using different code *' # T234147
diff --git a/tests/archivebot_tests.py b/tests/archivebot_tests.py
index 20a6052..a5f8db2 100755
--- a/tests/archivebot_tests.py
+++ b/tests/archivebot_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Tests for archivebot scripts."""
#
-# (C) Pywikibot team, 2014-2023
+# (C) Pywikibot team, 2014-2024
#
# Distributed under the terms of the MIT license.
#
@@ -17,7 +17,6 @@
from scripts import archivebot
from tests.aspects import TestCase

-
THREADS = {
'als': 4, 'ar': 1, 'bar': 0, 'bg': 0, 'bjn': 1, 'bs': 0, 'ca': 5, 'ckb': 2,
'cs': 0, 'de': 1, 'en': 25, 'eo': 2, 'es': 13, 'fa': 2, 'fr': 25, 'frr': 2,
@@ -130,8 +129,9 @@
self.assertIsInstance(talk.threads, list)
self.assertGreaterEqual(
len(talk.threads), THREADS[code],
- '{} Threads found on {},\n{} or more expected'
- .format(len(talk.threads), talk, THREADS[code]))
+ f'{len(talk.threads)} Threads found on {talk},\n{THREADS[code]} or'
+ ' more expected'
+ )

for thread in talk.threads:
with self.subTest(thread=thread.title,
@@ -188,9 +188,9 @@
self.assertIsInstance(talk.threads, list)
self.assertGreaterEqual(
len(talk.threads), THREADS_WITH_UPDATED_FORMAT[code],
- '{} Threads found on {},\n{} or more expected'
- .format(len(talk.threads), talk,
- THREADS_WITH_UPDATED_FORMAT[code]))
+ f'{len(talk.threads)} Threads found on {talk},\n'
+ f'{THREADS_WITH_UPDATED_FORMAT[code]} or more expected'
+ )

for thread in talk.threads:
with self.subTest(thread=thread.title,
diff --git a/tests/aspects.py b/tests/aspects.py
index a64d9b9..3ffb41b 100644
--- a/tests/aspects.py
+++ b/tests/aspects.py
@@ -36,8 +36,10 @@
)
from pywikibot.family import WikimediaFamily
from pywikibot.site import BaseSite
-from pywikibot.tools import MediaWikiVersion # noqa: F401 (used by f-string)
-from pywikibot.tools import suppress_warnings
+from pywikibot.tools import ( # noqa: F401 (used by eval())
+ MediaWikiVersion,
+ suppress_warnings,
+)
from tests import (
WARN_SITE_CODE,
patch_request,
@@ -53,7 +55,6 @@
skipping,
)

-
OSWIN32 = (sys.platform == 'win32')
pywikibot.bot.set_interface('buffer')

@@ -456,12 +457,12 @@
if hostname in cls._checked_hostnames:
if isinstance(cls._checked_hostnames[hostname], Exception):
raise unittest.SkipTest(
- '{}: hostname {} failed (cached): {}'
- .format(cls.__name__, hostname,
- cls._checked_hostnames[hostname]))
+ f'{cls.__name__}: hostname {hostname} failed '
+ f'(cached): {cls._checked_hostnames[hostname]}'
+ )
if cls._checked_hostnames[hostname] is False:
- raise unittest.SkipTest('{}: hostname {} failed (cached)'
- .format(cls.__name__, hostname))
+ raise unittest.SkipTest(
+ f'{cls.__name__}: hostname {hostname} failed (cached)')
continue

try:
@@ -476,16 +477,15 @@
HTTPStatus.SEE_OTHER,
HTTPStatus.TEMPORARY_REDIRECT,
HTTPStatus.PERMANENT_REDIRECT}:
- raise ServerError(
- 'HTTP status: {} - {}'.format(
- r.status_code, HTTPStatus(r.status_code).phrase))
+ raise ServerError(f'HTTP status: {r.status_code} - '
+ f'{HTTPStatus(r.status_code).phrase}')
except Exception as e:
- pywikibot.exception('{}: accessing {} caused exception:'
- .format(cls.__name__, hostname))
+ pywikibot.exception(
+ f'{cls.__name__}: accessing {hostname} caused exception:')

cls._checked_hostnames[hostname] = e
- raise unittest.SkipTest(
- f'{cls.__name__}: hostname {hostname} failed: {e}')
+ raise unittest.SkipTest(f'{cls.__name__}: hostname {hostname}'
+ ' failed: {e}') from None

cls._checked_hostnames[hostname] = True

@@ -758,9 +758,9 @@
# check that the script invoked by pwb will not load a site.
if dct.get('pwb') and 'site' not in dct:
raise Exception(
- '{}: Test classes using pwb must set "site"; add '
- 'site=False if the test script will not use a site'
- .format(name))
+ f'{name}: Test classes using pwb must set "site";'
+ ' add site=False if the test script will not use a site'
+ )

# If the 'site' attribute is a false value,
# remove it so it matches 'not site' in pytest.
@@ -822,9 +822,9 @@
# A multi-site test method only accepts 'self' and the site-key
if test_func.__code__.co_argcount != 2:
raise Exception(
- '{}: Test method {} must accept either 1 or 2 arguments; '
- ' {} found'
- .format(name, test, test_func.__code__.co_argcount))
+ f'{name}: Test method {test} must accept either 1 or 2 '
+ f'arguments; {test_func.__code__.co_argcount} found'
+ )

# create test methods processed by unittest
for (key, sitedata) in dct['sites'].items():
@@ -1077,8 +1077,7 @@
:type site: BaseSite
"""
unittest_print(
- '{cls.__name__} using {site} instead of {cls.family}:{cls.code}.'
- .format(cls=cls, site=site))
+ f'{cls.__name__} using {site} instead of {cls.family}:{cls.code}.')
cls.site = site
cls.family = site.family.name
cls.code = site.code
@@ -1180,9 +1179,8 @@

if (hasattr(cls, 'repo')
and cls.repo != site.data_repository()):
- raise Exception(
- '{}: sites do not all have the same data repository'
- .format(cls.__name__))
+ raise Exception(f'{cls.__name__}: sites do not all have'
+ ' the same data repository')

cls.repo = site.data_repository()

@@ -1429,8 +1427,8 @@
or msg is None):
break
else:
- self.fail('No generic deprecation message match found in {}'
- .format(deprecation_messages))
+ self.fail('No generic deprecation message match found in '
+ f'{deprecation_messages}')
else:
head, _, tail = msg.partition('; ')
for message in self.deprecation_messages:
@@ -1438,8 +1436,8 @@
and message.endswith(tail):
break
else:
- self.fail("'{}' not found in {} (ignoring since)"
- .format(msg, self.deprecation_messages))
+ self.fail(f"'{msg}' not found in {self.deprecation_messages}"
+ '(ignoring since)')
if self._do_test_warning_filename:
self.assertDeprecationFile(self.expect_warning_filename)

diff --git a/tests/basesite_tests.py b/tests/basesite_tests.py
index 4b6e138..0e66123 100755
--- a/tests/basesite_tests.py
+++ b/tests/basesite_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Tests for the site module."""
#
-# (C) Pywikibot team, 2008-2022
+# (C) Pywikibot team, 2008-2024
#
# Distributed under the terms of the MIT license.
#
@@ -13,7 +13,6 @@
from pywikibot.exceptions import Error
from tests.aspects import DefaultSiteTestCase, TestCase, unittest

-
WARN_SELF_CALL = (r'Referencing this attribute like a function '
r'is deprecated .+; use it directly instead')

@@ -99,11 +98,11 @@
self.assertIn('No disambiguation category name found', str(e))
except AssertionError:
self.assertIn(
- 'No {repo} qualifier found for disambiguation category '
- 'name in {fam}_family file'.format(
- repo=mysite.data_repository().family.name,
- fam=mysite.family.name),
- str(e))
+ f'No {mysite.data_repository().family.name} qualifier'
+ ' found for disambiguation category name in '
+ f'{mysite.family.name}_family file',
+ str(e)
+ )
else:
self.assertIsInstance(dabcat, pywikibot.Category)

diff --git a/tests/bot_tests.py b/tests/bot_tests.py
index ab8a5cc..44e57d7 100755
--- a/tests/bot_tests.py
+++ b/tests/bot_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Bot tests."""
#
-# (C) Pywikibot team, 2015-2022
+# (C) Pywikibot team, 2015-2024
#
# Distributed under the terms of the MIT license.
#
@@ -29,8 +29,9 @@
def setUpClass(cls):
"""Verify that the translations are available."""
if not i18n.messages_available():
- raise unittest.SkipTest("i18n messages package '{}' not available."
- .format(i18n._messages_package_name))
+ raise unittest.SkipTest(
+ f'i18n messages package {i18n._messages_package_name!r} not'
+ ' available.')
super().setUpClass()


diff --git a/tests/category_bot_tests.py b/tests/category_bot_tests.py
index 0ce04ce..c0fbc89 100755
--- a/tests/category_bot_tests.py
+++ b/tests/category_bot_tests.py
@@ -16,7 +16,6 @@
from scripts.category import CategoryMoveRobot, CategoryPreprocess
from tests.aspects import DefaultSiteTestCase, TestCase

-
MOCKED_USERNAME = Mock(return_value='FakeUsername')


diff --git a/tests/data/fixes.py b/tests/data/fixes.py
index 9708107..8b625c8 100644
--- a/tests/data/fixes.py
+++ b/tests/data/fixes.py
@@ -6,7 +6,6 @@
#
from __future__ import annotations

-
# flake8 cannot detect that fixes is defined via pywikibot.fixes
if 'fixes' not in globals():
fixes = {}
diff --git a/tests/data/set-fixes.py b/tests/data/set-fixes.py
index 0800174..32e4cd0 100644
--- a/tests/data/set-fixes.py
+++ b/tests/data/set-fixes.py
@@ -6,6 +6,5 @@
#
from __future__ import annotations

-
# Just kill the old value suffices
fixes = {}
diff --git a/tests/date_tests.py b/tests/date_tests.py
index b3dfa7e..b1959ea 100755
--- a/tests/date_tests.py
+++ b/tests/date_tests.py
@@ -37,15 +37,16 @@
for value in range(start, stop, step):
self.assertTrue(
predicate(value),
- "date.formats['{}']['{}']:\ninvalid value {}"
- .format(formatname, code, value))
+ f"date.formats['{formatname}']['{code}']:\n"
+ f'invalid value {value}'
+ )

new_value = convert(convert(value))
self.assertEqual(
new_value, value,
- "date.formats['{}']['{}']:\n"
- 'value {} does not match {}'
- .format(formatname, code, new_value, value))
+ f"date.formats['{formatname}']['{code}']:\n"
+ f'value {new_value} does not match {value}'
+ )
return testMapEntry

for formatname in date.formats:
@@ -78,15 +79,16 @@
with self.subTest(code=code, month=value):
self.assertTrue(
predicate(value),
- "date.formats['{}']['{}']:\ninvalid value {}"
- .format(formatname, code, value))
+ f"date.formats['{formatname}']['{code}']:\n"
+ f'invalid value {value}'
+ )

new_value = convert(convert(value))
self.assertEqual(
new_value, value,
- "date.formats['{}']['{}']:\n"
- 'value {} does not match {}'
- .format(formatname, code, new_value, value))
+ f"date.formats['{formatname}']['{code}']:\n"
+ f'value {new_value} does not match {value}'
+ )

def test_month_name(self):
"""Test some MonthName results."""
diff --git a/tests/djvu_tests.py b/tests/djvu_tests.py
index fc0f951..ffc5303 100755
--- a/tests/djvu_tests.py
+++ b/tests/djvu_tests.py
@@ -18,7 +18,6 @@
from tests.aspects import TestCase
from tests.utils import skipping

-
join_djvu_data_path = create_path_func(join_data_path, 'djvu')
file_djvu = join_djvu_data_path('myfilé.djvu') # test non-ASCII name

diff --git a/tests/edit_tests.py b/tests/edit_tests.py
index bc1c108..01d71a1 100755
--- a/tests/edit_tests.py
+++ b/tests/edit_tests.py
@@ -16,7 +16,6 @@
from pywikibot.exceptions import Error
from tests.aspects import TestCase, require_version

-
called_back = False


diff --git a/tests/eventstreams_tests.py b/tests/eventstreams_tests.py
index 1573fbc..0eacee6 100755
--- a/tests/eventstreams_tests.py
+++ b/tests/eventstreams_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Tests for the eventstreams module."""
#
-# (C) Pywikibot team, 2017-2023
+# (C) Pywikibot team, 2017-2024
#
# Distributed under the terms of the MIT license.
#
@@ -245,12 +245,12 @@
self.es.register_filter(lambda x: all_type, ftype='all')
if any_type is not None:
self.es.register_filter(lambda x: any_type, ftype='any')
- self.assertEqual(self.es.streamfilter(self.data), result,
- 'Test EventStreams filter mixed function failed for\n'
- "'none': {}, 'all': {}, 'any': {}\n"
- '(expected {}, given {})'
- .format(none_type, all_type, any_type,
- result, not result))
+ self.assertEqual(
+ self.es.streamfilter(self.data), result,
+ 'Test EventStreams filter mixed function failed for\n'
+ f"'none': {none_type}, 'all': {all_type}, 'any': {any_type}\n"
+ f'(expected {result}, given {not result})'
+ )

def test_filter_mixed_function(self):
"""Test EventStreams filter mixed function."""
@@ -283,9 +283,9 @@
self.source.resp.close() # close SSLSocket
del self.source
raise ValueError(
- '{error}\n\nEvent no {number}: '
- 'Could not load json data from source\n${event}$'
- .format(number=n, event=event, error=e))
+ f'{e}\n\nEvent no {n}: '
+ f'Could not load json data from source\n${event}$'
+ ) from e
yield element
del self.source

diff --git a/tests/family_tests.py b/tests/family_tests.py
index 18ed841..68e52ba 100755
--- a/tests/family_tests.py
+++ b/tests/family_tests.py
@@ -218,9 +218,8 @@
family = Family.load(family)
for code in family.codes:
self.current_code = code
- url = '{}://{}{}/$1'.format(family.protocol(code),
- family.hostname(code),
- family.path(code))
+ url = (f'{family.protocol(code)}://{family.hostname(code)}'
+ f'{family.path(code)}/$1')
with self.subTest(url=url):
self.assertEqual(family.from_url(url), code)

diff --git a/tests/file_tests.py b/tests/file_tests.py
index 6650bcc..dc710ad 100755
--- a/tests/file_tests.py
+++ b/tests/file_tests.py
@@ -74,8 +74,7 @@
self.assertIn('/wikipedia/commons/', itwp_file.get_file_url())
with self.assertRaisesRegex(
NoPageError,
- r'Page \[\[(wikipedia:|)it:{}\]\] doesn\'t exist.'
- .format(title)):
+ rf'Page \[\[(wikipedia:|)it:{title}\]\] doesn\'t exist.'):
itwp_file.get()

def test_local_only(self):
diff --git a/tests/flow_edit_tests.py b/tests/flow_edit_tests.py
index 8e6f303..5f305e1 100755
--- a/tests/flow_edit_tests.py
+++ b/tests/flow_edit_tests.py
@@ -15,7 +15,6 @@
from tests.aspects import TestCase
from tests.utils import skipping

-
MODERATION_REASON = 'Pywikibot test'


diff --git a/tests/flow_thanks_tests.py b/tests/flow_thanks_tests.py
index 258f837..2f875af 100755
--- a/tests/flow_thanks_tests.py
+++ b/tests/flow_thanks_tests.py
@@ -13,7 +13,6 @@
from pywikibot.flow import Topic
from tests.aspects import TestCase

-
NO_THANKABLE_POSTS = 'There is no recent post which can be test thanked.'


diff --git a/tests/generate_family_file_tests.py b/tests/generate_family_file_tests.py
index 844a535..e6f875d 100755
--- a/tests/generate_family_file_tests.py
+++ b/tests/generate_family_file_tests.py
@@ -114,15 +114,11 @@
f'{wiki_parse.netloc}')

site = Site(url=url)
-
+ msg = (f'url has lang "{lang}" but Site {site} has lang '
+ f'"{site.lang}"')
with skipping(AssertionError,
- msg='KNOWN BUG (T194138): url has lang "{lang}" '
- 'but Site {site} has lang "{site.lang}"'
- .format(site=site, lang=lang)):
- self.assertEqual(site.lang, lang,
- 'url has lang "{lang}" '
- 'but Site {site} has lang "{site.lang}"'
- .format(site=site, lang=lang))
+ msg='KNOWN BUG (T194138): ' + msg):
+ self.assertEqual(site.lang, lang, msg)


if __name__ == '__main__':
diff --git a/tests/i18n_tests.py b/tests/i18n_tests.py
index c57a196..528e734 100755
--- a/tests/i18n_tests.py
+++ b/tests/i18n_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Test i18n module."""
#
-# (C) Pywikibot team, 2007-2023
+# (C) Pywikibot team, 2007-2024
#
# Distributed under the terms of the MIT license.
#
@@ -236,8 +236,8 @@
def setUpClass(cls):
"""Verify that the test translations are not empty."""
if not isinstance(cls.message_package, str):
- raise TypeError('{}.message_package must be a package name'
- .format(cls.__name__)) # pragma: no cover
+ raise TypeError( # pragma: no cover
+ f'{cls.__name__}.message_package must be a package name')
# The call to set_messages_package below exists only to confirm
# that the package exists and messages are available, so
# that tests can be skipped if the i18n data doesn't exist.
@@ -246,8 +246,8 @@
has_messages = i18n.messages_available()
i18n._messages_package_name = cls.orig_messages_package_name
if not has_messages:
- raise unittest.SkipTest("i18n messages package '{}' not available."
- .format(cls.message_package))
+ raise unittest.SkipTest('i18n messages package '
+ f"'{cls.message_package}' not available.")
super().setUpClass()


@@ -380,8 +380,8 @@
self.assertFalse(config.cosmetic_changes_mylang_only)

if page.content_model != 'wikitext':
- self.skipTest('Wrong content model {!r} for cosmetic_changes'
- .format(page.content_model))
+ self.skipTest(f'Wrong content model {page.content_model!r}'
+ ' for cosmetic_changes')

summary = f'Working on Test page at site {self.site}'
msg = page._cosmetic_changes_hook(summary)
diff --git a/tests/l10n_tests.py b/tests/l10n_tests.py
index e725493..83c1958 100755
--- a/tests/l10n_tests.py
+++ b/tests/l10n_tests.py
@@ -16,7 +16,6 @@
from pywikibot.textlib import extract_templates_and_params_regex_simple
from tests.aspects import MetaTestCaseClass, TestCase

-
PACKAGES = (
'redirect-broken-redirect-template', # speedy deletion template
'archivebot-archiveheader', # archive header template
@@ -51,20 +50,20 @@
if (package == PACKAGES[0] and site.code in ['simple', 'test2']
or package == PACKAGES[1] and site.code == 'test'):
raise unittest.SkipTest(
- "{site} wiki has '{site.lang}' language code but "
- "missing template for package '{package}'. Must be "
+ f"{site} wiki has '{site.lang}' language code but "
+ f"missing template for package '{package}'. Must be "
'solved by the corresponding script.'
- .format(site=site, package=package))
+ )

# check whether template exists
title = templates[0][0]
page = pywikibot.Page(site, title, ns=10)
self.assertTrue(
page.exists(),
- msg='Invalid L10N in package "{package}"\n'
- 'template "{title}" does not exist for lang '
- '"{site.lang}" on site "{site}"'
- .format(package=package, title=title, site=site))
+ msg=f'Invalid L10N in package "{package}"\n'
+ f'template "{title}" does not exist for lang '
+ f'"{site.lang}" on site "{site}"'
+ )

return test_template

@@ -96,8 +95,9 @@
"""Skip test gracefully if i18n package is missing."""
super().setUpClass()
if not i18n.messages_available():
- raise unittest.SkipTest("i18n messages package '{}' not available."
- .format(i18n._messages_package_name))
+ raise unittest.SkipTest(
+ f'i18n messages package {i18n._messages_package_name!r} not'
+ ' available.')


class TestPackages(TestCase):
@@ -126,7 +126,7 @@
bundle = i18n._get_bundle(lang, dirname)
if lang in ('en', 'qqq'):
self.assertIsNotEmpty(bundle)
- for key in bundle.keys():
+ for key in bundle:
if key == '@metadata':
continue
self.assertTrue(
diff --git a/tests/link_tests.py b/tests/link_tests.py
index 5816fef..65a26ee 100755
--- a/tests/link_tests.py
+++ b/tests/link_tests.py
@@ -123,33 +123,29 @@
"""Test that invalid titles raise InvalidTitleError."""
# Bad characters forbidden regardless of wgLegalTitleChars
def generate_contains_illegal_chars_exc_regex(text):
- exc_regex = (
- r'^(u|)\'{}\' contains illegal char\(s\) (u|)\'{}\'$'
- .format(re.escape(text), re.escape(text[2])))
+ exc_regex = (rf'^(u|)\'{re.escape(text)}\' contains illegal char'
+ rf'\(s\) (u|)\'{re.escape(text[2])}\'$')
return exc_regex

# Directory navigation
def generate_contains_dot_combinations_exc_regex(text):
- exc_regex = (r'^\(contains \. / combinations\): (u|)\'{}\'$'
- .format(re.escape(text)))
+ exc_regex = (rf'^\(contains \. / combinations\): (u|)'
+ rf'\'{re.escape(text)}\'$')
return exc_regex

# Tilde
def generate_contains_tilde_exc_regex(text):
- exc_regex = r'^\(contains ~~~\): (u|)\'{}\'$' \
- .format(re.escape(text))
+ exc_regex = rf'^\(contains ~~~\): (u|)\'{re.escape(text)}\'$'
return exc_regex

# Overlength
def generate_overlength_exc_regex(text):
- exc_regex = r'^\(over 255 bytes\): (u|)\'{}\'$' \
- .format(re.escape(text))
+ exc_regex = rf'^\(over 255 bytes\): (u|)\'{re.escape(text)}\'$'
return exc_regex

# Namespace prefix without actual title
def generate_has_no_title_exc_regex(text):
- exc_regex = r'^(u|)\'{}\' has no title\.$'.format(
- re.escape(text.strip()))
+ exc_regex = rf'^(u|)\'{re.escape(text.strip())}\' has no title\.$'
return exc_regex

title_tests = [
diff --git a/tests/namespace_tests.py b/tests/namespace_tests.py
index 28f6cf9..23d11c2 100755
--- a/tests/namespace_tests.py
+++ b/tests/namespace_tests.py
@@ -14,7 +14,6 @@
from pywikibot.site._namespace import BuiltinNamespace
from tests.aspects import TestCase, unittest

-
# Default namespaces which should work in any MW wiki
_base_builtin_ns = {
'Media': -2,
diff --git a/tests/page_tests.py b/tests/page_tests.py
index 6b56914..49070de 100755
--- a/tests/page_tests.py
+++ b/tests/page_tests.py
@@ -37,7 +37,6 @@
)
from tests.utils import skipping

-
EMPTY_TITLE_RE = r'Title must be specified and not empty if source is a Site\.'
INVALID_TITLE_RE = r'The link \[\[.*\]\] does not contain a page title'
NO_PAGE_RE = r"doesn't exist\."
@@ -190,9 +189,8 @@
family_name = (site.family.name + ':'
if pywikibot.config.family != site.family.name
else '')
- self.assertEqual(str(mainpage), '[[{}{}:{}]]'
- .format(family_name, site.code,
- mainpage.title()))
+ self.assertEqual(str(mainpage),
+ f'[[{family_name}{site.code}:{mainpage.title()}]]')
self.assertLess(mainpage, maintalk)

def testHelpTitle(self):
@@ -702,9 +700,8 @@
self.page = pywikibot.Page(self.site,
'not_existent_page_for_pywikibot_tests')
if self.page.exists():
- self.skipTest(
- 'Page {} exists! Change page name in tests/page_tests.py'
- .format(self.page.title()))
+ self.skipTest(f'Page {self.page.title()} exists! Change page name'
+ ' in tests/page_tests.py')

def tearDown(self):
"""Cleanup cache."""
@@ -985,8 +982,8 @@
'testing suite.')
self.assertEqual(p1.get(), text)
with self.assertRaisesRegex(IsRedirectPageError,
- r'{} is a redirect page\.'
- .format(re.escape(str(p2)))):
+ rf'{re.escape(str(p2))} is a redirect '
+ rf'page\.'):
p2.get()

try:
@@ -1019,8 +1016,8 @@

text = p2.get(get_redirect=True)
with self.assertRaisesRegex(IsNotRedirectPageError,
- r'{} is not a redirect page\.'
- .format(re.escape(str(p1)))):
+ rf'{re.escape(str(p1))} is not a redirect '
+ rf'page\.'):
p1.set_redirect_target(p2)
with self.assertRaisesRegex(NoPageError, NO_PAGE_RE):
p3.set_redirect_target(p2)
diff --git a/tests/pagegenerators_tests.py b/tests/pagegenerators_tests.py
index ecb4946..a705b4b 100755
--- a/tests/pagegenerators_tests.py
+++ b/tests/pagegenerators_tests.py
@@ -39,7 +39,6 @@
from tests.tools_tests import GeneratorIntersectTestCase
from tests.utils import skipping

-
en_wp_page_titles = (
# just a bunch of randomly selected titles for English Wikipedia tests
'Eastern Sayan',
@@ -1394,10 +1393,10 @@

newpages_url = self.site.base_url(
self.site.path() + '?title=Special:NewPages&uselang=en')
- failure_message = 'No new pages returned by -newpages. ' \
- 'If this is the only failure, check whether {url} contains any ' \
+ failure_message = 'No new pages returned by -newpages. If this is ' \
+ f'the only failure, check whether {newpages_url} contains any ' \
'pages. If not, create a new page on the site to make the test ' \
- 'pass again.'.format(url=newpages_url)
+ 'pass again.'

self.assertIsNotEmpty(pages, msg=failure_message)

diff --git a/tests/patrolbot_tests.py b/tests/patrolbot_tests.py
index b957695..28f8a69 100755
--- a/tests/patrolbot_tests.py
+++ b/tests/patrolbot_tests.py
@@ -12,7 +12,6 @@
from scripts.patrol import PatrolBot
from tests.aspects import DefaultDrySiteTestCase, unittest

-
DUMMY_PAGE_TUPLES = """
This is some text above the entries:

diff --git a/tests/pwb_tests.py b/tests/pwb_tests.py
index 6cd561b..b2a39c7 100755
--- a/tests/pwb_tests.py
+++ b/tests/pwb_tests.py
@@ -15,7 +15,6 @@
from tests.aspects import PwbTestCase
from tests.utils import execute, execute_pwb

-
join_pwb_tests_path = create_path_func(join_tests_path, 'pwb')


diff --git a/tests/replacebot_tests.py b/tests/replacebot_tests.py
index a1e7eaf..b9b6bfc 100755
--- a/tests/replacebot_tests.py
+++ b/tests/replacebot_tests.py
@@ -17,7 +17,6 @@
from tests.bot_tests import TWNBotTestCase
from tests.utils import empty_sites

-
# Load only the custom fixes
fixes.fixes.clear()
fixes._load_file(join_data_path('fixes.py'))
diff --git a/tests/script_tests.py b/tests/script_tests.py
index a936e1b..6330641 100755
--- a/tests/script_tests.py
+++ b/tests/script_tests.py
@@ -18,7 +18,6 @@
from tests.aspects import DefaultSiteTestCase, MetaTestCaseClass, PwbTestCase
from tests.utils import execute_pwb

-
ci_test_run = os.environ.get('PYWIKIBOT_TEST_RUNNING', '0') == '1'
scripts_path = join_root_path('scripts')

@@ -147,8 +146,8 @@
to fallback to its own discover() ordering of unit tests.
"""
if unrunnable_script_set: # pragma: no cover
- unittest_print('Skipping execution of unrunnable scripts:\n {!r}'
- .format(unrunnable_script_set))
+ unittest_print('Skipping execution of unrunnable scripts:\n'
+ f'{unrunnable_script_set!r}')

test_pattern = 'tests.script_tests.TestScript{}.test_{}'

@@ -258,14 +257,14 @@
exit_codes = [0, 1, -9]
if not out_result and not err_result:
unittest_print(' auto-run script unresponsive after '
- '{} seconds'.format(timeout), end=' ')
+ f'{timeout} seconds', end=' ')
elif 'SIMULATION: edit action blocked' in err_result:
unittest_print(' auto-run script simulated edit '
'blocked', end=' ')
else:
- unittest_print(
- ' auto-run script stderr within {} seconds: {!r}'
- .format(timeout, err_result), end=' ')
+ unittest_print(' auto-run script stderr within '
+ f'{timeout} seconds: {err_result!r}',
+ end=' ')
unittest_print(f" exit code: {result['exit_code']}",
end=' ')

diff --git a/tests/site_generators_tests.py b/tests/site_generators_tests.py
index 189943c..91ea577 100755
--- a/tests/site_generators_tests.py
+++ b/tests/site_generators_tests.py
@@ -25,7 +25,6 @@
from tests.aspects import DefaultSiteTestCase, DeprecationTestCase, TestCase
from tests.utils import skipping

-
global_expected_params = {
'action': ['query'],
'continue': [True],
@@ -660,8 +659,8 @@

site = self.site.data_repository()
pattern = (r'Page '
- r'\[\[({site.sitename}:|{site.code}:)-1\]\]'
- r" doesn't exist\.".format(site=site))
+ rf'\[\[({site.sitename}:|{site.code}:)-1\]\]'
+ r" doesn't exist\.")
for page in pages:
with self.assertRaisesRegex(NoPageError, pattern):
page.data_item()
diff --git a/tests/site_tests.py b/tests/site_tests.py
index 415dcd4..b0b86ac 100755
--- a/tests/site_tests.py
+++ b/tests/site_tests.py
@@ -391,7 +391,7 @@
if not mysite.has_right('deletedhistory'):
self.skipTest(
"You don't have permission to view the deleted revisions "
- 'on {}.'.format(mysite))
+ f'on {mysite}.')
mainpage = self.get_mainpage()
gen = mysite.deletedrevs(total=10, titles=mainpage)

@@ -491,7 +491,7 @@
if not mysite.has_right('deletedhistory'):
self.skipTest(
"You don't have permission to view the deleted revisions "
- 'on {}.'.format(mysite))
+ f'on {mysite}.')
prop = ['ids', 'timestamp', 'flags', 'user', 'comment']
gen = mysite.alldeletedrevisions(total=10, prop=prop)

diff --git a/tests/sparql_tests.py b/tests/sparql_tests.py
index 2b65988..2037ada 100755
--- a/tests/sparql_tests.py
+++ b/tests/sparql_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Test cases for the SPARQL API."""
#
-# (C) Pywikibot team, 2016-2022
+# (C) Pywikibot team, 2016-2024
#
# Distributed under the terms of the MIT license.
#
@@ -18,7 +18,6 @@
from tests.aspects import TestCase, WikidataTestCase
from tests.utils import skipping

-
# See: https://www.w3.org/TR/2013/REC-sparql11-results-json-20130321/

SQL_RESPONSE_CONTAINER = """
@@ -157,8 +156,9 @@
def testGetItems(self, mock_method):
"""Test item list retrieval via SPARQL."""
mock_method.return_value = Container(
- SQL_RESPONSE_CONTAINER % '{0}, {1}, {1}'.format(ITEM_Q498787,
- ITEM_Q677525))
+ SQL_RESPONSE_CONTAINER % (f'{ITEM_Q498787}, {ITEM_Q677525}, '
+ f'{ITEM_Q677525}')
+ )
with skipping(pywikibot.exceptions.TimeoutError):
q = sparql.SparqlQuery()
res = q.get_items('SELECT * WHERE { ?x ?y ?z }', 'cat')
diff --git a/tests/textlib_tests.py b/tests/textlib_tests.py
index 5acd756..742a317 100755
--- a/tests/textlib_tests.py
+++ b/tests/textlib_tests.py
@@ -29,7 +29,6 @@
require_modules,
)

-
files = {}
dirname = os.path.join(os.path.dirname(__file__), 'pages')

diff --git a/tests/thanks_tests.py b/tests/thanks_tests.py
index f0300a0..2f8910b 100755
--- a/tests/thanks_tests.py
+++ b/tests/thanks_tests.py
@@ -13,7 +13,6 @@
from pywikibot.page import Page, User
from tests.aspects import TestCase

-
NO_THANKABLE_REVS = 'There is no recent change which can be test thanked.'


diff --git a/tests/timestripper_tests.py b/tests/timestripper_tests.py
index 2b768f1..39d1b47 100755
--- a/tests/timestripper_tests.py
+++ b/tests/timestripper_tests.py
@@ -15,7 +15,6 @@
from pywikibot.time import TZoneFixedOffset
from tests.aspects import TestCase, unittest

-
MatchObject = type(re.search('', ''))


diff --git a/tests/tools_deprecate_tests.py b/tests/tools_deprecate_tests.py
index c54dc84..335f3b8 100755
--- a/tests/tools_deprecate_tests.py
+++ b/tests/tools_deprecate_tests.py
@@ -497,43 +497,38 @@

def test_function_remove_last_args(self):
"""Test @remove_last_args on functions."""
+ msg_foo = ("The trailing arguments ('foo', 'bar') of "
+ f'{__name__}.deprecated_all are deprecated. The value(s)'
+ " provided for 'foo' have been dropped.")
+ msg_f_b = ("The trailing arguments ('foo', 'bar') of "
+ f'{__name__}.deprecated_all are deprecated. The value(s)'
+ " provided for 'foo', 'bar' have been dropped.")
+
rv = deprecated_all()
self.assertIsNone(rv)
self.assertNoDeprecation()

rv = deprecated_all(foo=42)
self.assertIsNone(rv)
- self.assertDeprecation(
- "The trailing arguments ('foo', 'bar') of {}.deprecated_all are "
- "deprecated. The value(s) provided for 'foo' have been "
- 'dropped.'.format(__name__))
+ self.assertDeprecation(msg_foo)

self._reset_messages()

rv = deprecated_all(42)
self.assertIsNone(rv)
- self.assertDeprecation(
- "The trailing arguments ('foo', 'bar') of {}.deprecated_all are "
- "deprecated. The value(s) provided for 'foo' have been "
- 'dropped.'.format(__name__))
+ self.assertDeprecation(msg_foo)

self._reset_messages()

rv = deprecated_all(foo=42, bar=47)
self.assertIsNone(rv)
- self.assertDeprecation(
- "The trailing arguments ('foo', 'bar') of {}.deprecated_all are "
- "deprecated. The value(s) provided for 'foo', 'bar' have been "
- 'dropped.'.format(__name__))
+ self.assertDeprecation(msg_f_b)

self._reset_messages()

rv = deprecated_all(42, 47)
self.assertIsNone(rv)
- self.assertDeprecation(
- "The trailing arguments ('foo', 'bar') of {}.deprecated_all are "
- "deprecated. The value(s) provided for 'foo', 'bar' have been "
- 'dropped.'.format(__name__))
+ self.assertDeprecation(msg_f_b)

self._reset_messages()

@@ -548,9 +543,8 @@
rv = deprecated_all2(42, bar=47)
self.assertEqual(rv, 42)
self.assertDeprecation(
- "The trailing arguments ('bar') of {}.deprecated_all2 are "
- "deprecated. The value(s) provided for 'bar' have been "
- 'dropped.'.format(__name__))
+ f"The trailing arguments ('bar') of {__name__}.deprecated_all2 are"
+ " deprecated. The value(s) provided for 'bar' have been dropped.")

self._reset_messages()

@@ -566,9 +560,9 @@
self.assertIsNone(rv)
self.assertDeprecation(
"The trailing arguments ('foo', 'bar') of "
- '{}.DeprecatedMethodClass.deprecated_all are deprecated. '
+ f'{__name__}.DeprecatedMethodClass.deprecated_all are deprecated. '
"The value(s) provided for 'foo' have been dropped."
- .format(__name__))
+ )

self._reset_messages()

@@ -576,9 +570,9 @@
self.assertIsNone(rv)
self.assertDeprecation(
"The trailing arguments ('foo', 'bar') of "
- '{}.DeprecatedMethodClass.deprecated_all are deprecated. '
+ f'{__name__}.DeprecatedMethodClass.deprecated_all are deprecated. '
"The value(s) provided for 'foo' have been dropped."
- .format(__name__))
+ )

self._reset_messages()

@@ -586,9 +580,9 @@
self.assertIsNone(rv)
self.assertDeprecation(
"The trailing arguments ('foo', 'bar') of "
- '{}.DeprecatedMethodClass.deprecated_all are deprecated. The '
- "value(s) provided for 'foo', 'bar' have been dropped."
- .format(__name__))
+ f'{__name__}.DeprecatedMethodClass.deprecated_all are deprecated.'
+ " The value(s) provided for 'foo', 'bar' have been dropped."
+ )

self._reset_messages()

@@ -596,9 +590,9 @@
self.assertIsNone(rv)
self.assertDeprecation(
"The trailing arguments ('foo', 'bar') of "
- '{}.DeprecatedMethodClass.deprecated_all are deprecated. The '
- "value(s) provided for 'foo', 'bar' have been dropped."
- .format(__name__))
+ f'{__name__}.DeprecatedMethodClass.deprecated_all are deprecated.'
+ " The value(s) provided for 'foo', 'bar' have been dropped."
+ )

self._reset_messages()

@@ -611,12 +605,13 @@
self.assertNoDeprecation()

rv = f.deprecated_all2(42, bar=47)
- self.assertEqual(rv, 42)
+ self.assertEqual(rv, 42
+ )
self.assertDeprecation(
"The trailing arguments ('bar') of "
- '{}.DeprecatedMethodClass.deprecated_all2 are deprecated. '
- "The value(s) provided for 'bar' have been dropped."
- .format(__name__))
+ f'{__name__}.DeprecatedMethodClass.deprecated_all2 are deprecated.'
+ " The value(s) provided for 'bar' have been dropped."
+ )

def test_deprecate_positionals(self):
"""Test deprecation of positional parameters."""
diff --git a/tests/ui_options_tests.py b/tests/ui_options_tests.py
index d9f2f07..bb6793b 100755
--- a/tests/ui_options_tests.py
+++ b/tests/ui_options_tests.py
@@ -14,7 +14,6 @@
from pywikibot.bot_choice import ChoiceException, QuitKeyboardInterrupt
from tests.aspects import TestCase

-
message = bot.Option.formatted


diff --git a/tests/ui_tests.py b/tests/ui_tests.py
index d688b0c..d8706ef 100755
--- a/tests/ui_tests.py
+++ b/tests/ui_tests.py
@@ -33,7 +33,6 @@
from pywikibot.userinterfaces.transliteration import NON_LATIN_DIGITS, _trans
from tests.aspects import TestCase, TestCaseBase

-
logger = logging.getLogger('pywiki')
loggingcontext = {'caller_name': 'ui_tests',
'caller_file': 'ui_tests',
diff --git a/tests/upload_tests.py b/tests/upload_tests.py
index 3a41724..66cd0e8 100755
--- a/tests/upload_tests.py
+++ b/tests/upload_tests.py
@@ -61,10 +61,7 @@
self._file_key = warnings[0].file_key
self._offset = warnings[0].offset

- if chunk_size:
- expected_warns = ['exists']
- else:
- expected_warns = ['duplicate', 'exists']
+ expected_warns = ['exists'] if chunk_size else ['duplicate', 'exists']

# First upload the warning with warnings enabled
page = pywikibot.FilePage(self.site, 'MP_sounds-pwb.png')
@@ -105,8 +102,8 @@
with self.assertAPIError('siiinvalidsessiondata') as cm:
self.site.stash_info(self._file_key)
self.assertTrue(cm.exception.info.startswith('File not found'),
- 'info ({}) did not start with '
- '"File not found"'.format(cm.exception.info))
+ f'info ({cm.exception.info}) did not start with '
+ '"File not found"')

@unittest.expectedFailure # T367314
def test_continue_filekey_once(self):
@@ -126,9 +123,9 @@
self._finish_upload(1024, self.arrow_png)
self.assertEqual(
str(cm.exception),
- 'The SHA1 of 1024 bytes of the stashed "{}" is '
+ f'The SHA1 of 1024 bytes of the stashed "{self._file_key}" is '
'3503db342c8dfb0a38db0682b7370ddd271fa163 while the local file is '
- '3dd334f11aa1e780d636416dc0649b96b67588b6'.format(self._file_key))
+ '3dd334f11aa1e780d636416dc0649b96b67588b6')
self._verify_stash()

@unittest.expectedFailure # T367316
@@ -140,8 +137,9 @@
self._finish_upload(1024, self.sounds_png)
self.assertEqual(
str(cm.exception),
- 'For the file key "{}" the server reported a size 1024 while the '
- 'offset was 0'.format(self._file_key))
+ f'For the file key "{self._file_key}" the server reported a size'
+ ' 1024 while the offset was 0'
+ )
self._verify_stash()

@unittest.expectedFailure # T367317
@@ -153,8 +151,9 @@
self._finish_upload(1024, self.sounds_png)
self.assertEqual(
str(cm.exception),
- 'For the file key "{}" the offset was set to 2000 while the file '
- 'is only 1276 bytes large.'.format(self._file_key))
+ f'For the file key "{self._file_key}" the offset was set to 2000'
+ ' while the file is only 1276 bytes large.'
+ )
self._verify_stash()


diff --git a/tests/user_tests.py b/tests/user_tests.py
index 9242e8b..3dc36ab 100755
--- a/tests/user_tests.py
+++ b/tests/user_tests.py
@@ -181,8 +181,8 @@
user = User(mysite, mysite.user())
uc = list(user.contributions(total=total))
if not uc:
- self.skipTest('User {} has no contributions on site {}.'
- .format(mysite.user(), mysite))
+ self.skipTest(
+ f'User {mysite.user()} has no contributions on site {mysite}.')
self.assertLessEqual(len(uc), total)
self.assertEqual(uc[0], user.last_edit)
first_edit = uc[-1] if len(uc) < total else list(
diff --git a/tests/utils.py b/tests/utils.py
index 209ac34..31aea38 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -26,7 +26,6 @@
from pywikibot.tools.collections import EMPTY_DEFAULT
from tests import _pwb_py

-
OSWIN32 = (sys.platform == 'win32')


diff --git a/tests/wikistats_tests.py b/tests/wikistats_tests.py
index 762de32..d94e6e9 100755
--- a/tests/wikistats_tests.py
+++ b/tests/wikistats_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Test cases for the WikiStats dataset."""
#
-# (C) Pywikibot team, 2014-2022
+# (C) Pywikibot team, 2014-2024
#
# Distributed under the terms of the MIT license.
#
@@ -87,7 +87,7 @@
self.assertGreater(int(data['en']['total']), int(data['en']['good']))
data = data['en']
self.assertTrue(all(isinstance(key, str)
- for key in data.keys() if key is not None))
+ for key in data if key is not None))
self.assertIsInstance(data['total'], str)
self.assertIn('prefix', data)
self.assertIn('total', data)
@@ -102,7 +102,7 @@
self.assertGreater(int(data['fr']['total']), int(data['fr']['good']))
data = data['fr']
self.assertTrue(all(isinstance(key, str)
- for key in data.keys() if key is not None))
+ for key in data if key is not None))
self.assertIsInstance(data['total'], str)
self.assertIn('prefix', data)
self.assertIn('total', data)

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

Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Icf4d99358380194546e1497588cd67cd16790251
Gerrit-Change-Number: 1051686
Gerrit-PatchSet: 5
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot