jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1081397?usp=email )
Change subject: [tests] update coverage ......................................................................
[tests] update coverage
Change-Id: Icd41894db54a0ed067f5ff2c3370ca2cc69ee2b9 --- M tests/__init__.py M tests/aspects.py 2 files changed, 50 insertions(+), 55 deletions(-)
Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
diff --git a/tests/__init__.py b/tests/__init__.py index 00e5dbf..8eb9a7a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -217,7 +217,7 @@ 'Disabled test modules (to run: python -m unittest ...):\n {}' .format(', '.join(disabled_test_modules)))
- if extra_test_modules: + if extra_test_modules: # pragma: no cover unittest_print( 'Extra test modules (run after library, before scripts):\n {}' .format(', '.join(extra_test_modules))) diff --git a/tests/aspects.py b/tests/aspects.py index 67d5bad..7a6da4e 100644 --- a/tests/aspects.py +++ b/tests/aspects.py @@ -120,14 +120,12 @@ msg, f'len({safe_repr(seq)}): {first_len} != {second_len}') self.fail(msg)
- def assertPageInNamespaces(self, page, namespaces): - """ - Assert that Pages is in namespaces. + def assertPageInNamespaces(self, page, namespaces: int | set[int]) -> None: + """Assert that Pages is in namespaces.
:param page: Page :type page: pywikibot.BasePage :param namespaces: expected namespaces - :type namespaces: int or set of int """ if isinstance(namespaces, int): namespaces = {namespaces} @@ -170,18 +168,13 @@ titles = list(titles) return titles
- def assertPagesInNamespaces(self, gen, namespaces): - """ - Assert that generator returns Pages all in namespaces. + def assertPagesInNamespaces(self, gen, namespaces: int | set[int]) -> None: + """Assert that generator returns Pages all in namespaces.
:param gen: generator to iterate :type gen: generator :param namespaces: expected namespaces - :type namespaces: int or set of int """ - if isinstance(namespaces, int): - namespaces = {namespaces} - for page in gen: self.assertPageInNamespaces(page, namespaces)
@@ -200,8 +193,8 @@ :raises TypeError: Invalid *namespaces* type """ if isinstance(namespaces, int): - namespaces = {namespaces} - elif not isinstance(namespaces, set): + namespaces = {namespaces} # pragma: no cover + elif not isinstance(namespaces, set): # pragma: no cover raise TypeError('namespaces argument must be an int or a set, not ' f'{type(namespaces).__name__}')
@@ -282,12 +275,13 @@ for required_module in required_modules: try: __import__(required_module, globals(), locals(), [], 0) - except ModuleNotFoundError: + except ModuleNotFoundError: # pragma: no cover missing += [required_module] if not missing: return obj - skip_decorator = unittest.skip(f"{', '.join(missing)} not installed") - return skip_decorator(obj) + skip_decorator = unittest.skip( # pragma: no cover + f"{', '.join(missing)} not installed") + return skip_decorator(obj) # pragma: no cover
return test_requirement
@@ -317,17 +311,17 @@ """Validate environment.""" if not isinstance(self.site, BaseSite) \ or isinstance(self.site, DrySite): - raise Exception( + raise Exception( # pragma: no cover f'{type(self).__name__}.site must be a BaseSite not ' f'{type(self.site).__name__}.')
if args or kwargs: - raise Exception( + raise Exception( # pragma: no cover f'Test method {method.__name__!r} has parameters which is ' f'not supported with require_version decorator.')
_, op, version = re.split('([<>]=?)', version_needed) - if not op: + if not op: # pragma: no cover raise Exception(f'There is no valid operator given with ' f'version {version_needed!r}')
@@ -336,7 +330,7 @@ if not skip: return method(self, *args, **kwargs)
- myreason = ' to ' + reason if reason else '' + myreason = ' to ' + reason if reason else '' # pragma: no cover raise unittest.SkipTest( f'MediaWiki {op} v{version} required{myreason}.')
@@ -396,7 +390,7 @@
def __init__(self, code, fam=None, user=None): """Initializer.""" - raise SiteDefinitionError( + raise SiteDefinitionError( # pragma: no cover f'Loading site {fam}:{code} during dry test not permitted')
@@ -452,11 +446,11 @@ super().setUpClass()
if not hasattr(cls, 'sites'): - return + return # pragma: no cover
for key, data in cls.sites.items(): if 'hostname' not in data: - raise Exception( + raise Exception( # pragma: no cover f'{cls.__name__}: hostname not defined for {key}') hostname = data['hostname']
@@ -522,7 +516,7 @@ :raises Exception: test class cannot use *write* attribute together with *cached* and must be run on test sites only. """ - if issubclass(cls, ForceCacheMixin): + if issubclass(cls, ForceCacheMixin): # pragma: no cover raise Exception(f'{cls.__name__} cannot be a subclass of both' ' SiteWriteMixin and ForceCacheMixin')
@@ -535,7 +529,7 @@
if (not hasattr(site.family, 'test_codes') or site.code not in site.family.test_codes): - raise Exception( + raise Exception( # pragma: no cover f'{cls.__name__} should only be run on test sites. To run ' f'this test, add {site.code!r} to the {site.family.name}' " family attribute 'test_codes'." @@ -631,7 +625,7 @@ # For multi-site test classes, or site is specified as a param, # the cached userpage object may not be the desired site. if hasattr(self, '_userpage') and self._userpage.site == site: - return self._userpage + return self._userpage # pragma: no cover
userpage = pywikibot.User(site, site.username()) self._userpage = userpage @@ -761,7 +755,7 @@ if hostnames: dct.setdefault('sites', {}) for hostname in hostnames: - if hostname in dct['sites']: + if hostname in dct['sites']: # pragma: no cover raise AttributeError(f'hostname {hostname!r} already found' f"in dict['sites']:\n{dict['sites']}") dct['sites'][hostname] = {'hostname': hostname} @@ -779,7 +773,7 @@ # test writer explicitly sets 'site=False' so code reviewers # check that the script invoked by pwb will not load a site. if dct.get('pwb') and 'site' not in dct: - raise Exception( + raise Exception( # pragma: no cover f'{name}: Test classes using pwb must set "site";' ' add site=False if the test script will not use a site' ) @@ -790,7 +784,7 @@ del dct['site']
# If there isn't a site, require declaration of net activity. - if 'net' not in dct: + if 'net' not in dct: # pragma: no cover raise Exception(f'{name}: Test classes without a site' ' configured must set "net"')
@@ -814,7 +808,7 @@
if dct.get('net'): bases = cls.add_base(bases, CheckHostnameMixin) - elif hostnames: + elif hostnames: # pragma: no cover raise Exception('"net" must be True with hostnames defined')
if dct.get('write'): @@ -843,7 +837,7 @@
# A multi-site test method only accepts 'self' and the site-key if test_func.__code__.co_argcount != 2: - raise Exception( + raise Exception( # pragma: no cover f'{name}: Test method {test} must accept either 1 or 2 ' f'arguments; {test_func.__code__.co_argcount} found' ) @@ -884,7 +878,7 @@ if doc_suffix: if not doc: doc = method.__doc__ - if doc[-1] != '.': + if doc[-1] != '.': # pragma: no cover raise ValueError('doc string must end with a period.') doc = doc[:-1] + ' ' + doc_suffix + '.'
@@ -911,7 +905,7 @@
# This stores the site under the site name. if not cls.sites: - cls.sites = {} + cls.sites = {} # pragma: no cover
# If the test is not cached, create new Site objects for this class cm = cls._uncached() @@ -964,17 +958,17 @@ *name*. """ if not name and hasattr(cls, 'sites'): - if len(cls.sites) != 1: + if len(cls.sites) != 1: # pragma: no cover raise Exception(f'"{cls.__name__}.get_site(name=None)"' ' called with multiple sites')
name = next(iter(cls.sites.keys()))
- if name and name not in cls.sites: + if name and name not in cls.sites: # pragma: no cover raise Exception(f'"{name}" not declared in {cls.__name__}')
if isinstance(cls.site, BaseSite): - if cls.sites[name]['site'] != cls.site: + if cls.sites[name]['site'] != cls.site: # pragma: no cover raise Exception(f'{cls.__name__}.site is different from ' f"{cls.__name__}.sites[{name!r}]['site']:\n" f"{cls.site} != {cls.sites[name]['site']}") @@ -985,9 +979,9 @@ @classmethod def has_site_user(cls, family, code): """Check the user config has a user for the site.""" - if not family: + if not family: # pragma: no cover raise Exception(f'no family defined for {cls.__name__}') - if not code: + if not code: # pragma: no cover raise Exception(f'no site code defined for {cls.__name__}')
usernames = config.usernames @@ -1027,7 +1021,7 @@ maintitle = removeprefix(maintitle, 'Special:MyLanguage/') # T278702 mainpage = pywikibot.Page(site, maintitle) if not isinstance(site, DrySite) and mainpage.isRedirectPage(): - mainpage = mainpage.getRedirectTarget() + mainpage = mainpage.getRedirectTarget() # pragma: no cover
if force: mainpage = pywikibot.Page(self.site, mainpage.title()) @@ -1189,7 +1183,7 @@ super().setUpClass()
if not (hasattr(cls, 'site') and hasattr(cls, 'sites')) \ - or len(cls.sites) != 1: + or len(cls.sites) != 1: # pragma: no cover raise Exception('"site" or "sites" attribute is missing or "sites"' 'entries count is different from 1')
@@ -1218,7 +1212,7 @@ with cls._uncached(): for data in cls.sites.values(): if 'site' not in data: - continue + continue # pragma: no cover
site = data['site'] if not site.has_data_repository: @@ -1227,8 +1221,9 @@
if (hasattr(cls, 'repo') and cls.repo != site.data_repository()): - raise Exception(f'{cls.__name__}: sites do not all have' - ' the same data repository') + raise Exception( # pragma: no cover + f'{cls.__name__}: sites do not all have the same data' + ' repository')
cls.repo = site.data_repository()
@@ -1327,7 +1322,7 @@ """Prepare the environment for running the pwb.py script.""" super().setUp() self.orig_pywikibot_dir = None - if 'PYWIKIBOT_DIR' in os.environ: + if 'PYWIKIBOT_DIR' in os.environ: # pragma: no cover self.orig_pywikibot_dir = os.environ['PYWIKIBOT_DIR'] base_dir = pywikibot.config.base_dir os.environ['PYWIKIBOT_DIR'] = base_dir @@ -1336,7 +1331,7 @@ """Restore the environment after running the pwb.py script.""" super().tearDown() del os.environ['PYWIKIBOT_DIR'] - if self.orig_pywikibot_dir: + if self.orig_pywikibot_dir: # pragma: no cover os.environ['PYWIKIBOT_DIR'] = self.orig_pywikibot_dir
def execute(self, args: list[str], **kwargs): @@ -1405,7 +1400,7 @@ self.warning_log = []
self.expect_warning_filename = inspect.getfile(self.__class__) - if self.expect_warning_filename.endswith('.pyc'): + if self.expect_warning_filename.endswith('.pyc'): # pragma: no cover self.expect_warning_filename = self.expect_warning_filename[:-1]
self._do_test_warning_filename = True @@ -1439,14 +1434,14 @@ msg = f'{deprecated} is deprecated' if instead: msg += f'; use {instead} instead.' - elif instead is None: + elif instead is None: # pragma: no cover msg = None - elif instead is True: + elif instead is True: # pragma: no cover msg = cls.INSTEAD - elif instead is False: + elif instead is False: # pragma: no cover msg = cls.NO_INSTEAD else: - raise TypeError( + raise TypeError( # pragma: no cover f'instead argument must not be a {type(instead).__name__!r}') return msg
@@ -1485,7 +1480,7 @@ if (match and bool(match[1]) == (msg is self.INSTEAD) or msg is None): break - else: + else: # pragma: no cover self.fail('No generic deprecation message match found in ' f'{deprecation_messages}') else: @@ -1494,7 +1489,7 @@ if message.startswith(head) \ and message.endswith(tail): break - else: + else: # pragma: no cover self.fail(f"'{msg}' not found in {self.deprecation_messages}" '(ignoring since)') if self._do_test_warning_filename: @@ -1522,7 +1517,7 @@
def assertNoDeprecation(self, msg=None): """Assert that no deprecation warning happened.""" - if msg: + if msg: # pragma: no cover self.assertNotIn(msg, self.deprecation_messages) else: self.assertIsEmpty(self.deprecation_messages) @@ -1537,7 +1532,7 @@ for item in self.warning_log: if (self._ignore_unknown_warning_packages and 'pywikibot' not in item.filename): - continue + continue # pragma: no cover
if item.filename != filename: self.fail(f'expected warning filename {filename}; warning '
pywikibot-commits@lists.wikimedia.org