Source code for tests.site_generators_tests

#!/usr/bin/env python3
"""Tests for generators of the site module."""
#
# (C) Pywikibot team, 2008-2024
#
# Distributed under the terms of the MIT license.
#
from __future__ import annotations

import unittest
from contextlib import suppress
from unittest.mock import patch

import pywikibot
from pywikibot.data import api
from pywikibot.exceptions import (
    APIError,
    Error,
    HiddenKeyError,
    NoPageError,
    TimeoutError,
)
from pywikibot.tools import suppress_warnings
from tests import WARN_SITE_CODE, unittest_print
from tests.aspects import DefaultSiteTestCase, DeprecationTestCase, TestCase
from tests.utils import skipping


global_expected_params = {
    'action': ['query'],
    'continue': [True],
    'iilimit': ['max'],
    'iiprop': list(pywikibot.site._IIPROP),
    'indexpageids': [True],
    'inprop': ['protection'],
    'prop': ['info', 'imageinfo', 'categoryinfo'],
}


[docs] class TestSiteGenerators(DefaultSiteTestCase): """Test cases for Site methods.""" cached = True
[docs] def setUp(self): """Initialize self.site and self.mainpage.""" super().setUp() self.site = self.get_site() self.mainpage = self.get_mainpage()
[docs] def test_generator_namespace(self): """Test site._generator with namespaces.""" site = self.get_site() gen = site._generator(pywikibot.data.api.PageGenerator, type_arg='backlinks', namespaces=None) self.assertNotIn('gblnamespace', gen.request) gen = site._generator(pywikibot.data.api.PageGenerator, type_arg='backlinks', namespaces=1) self.assertEqual(gen.request['gblnamespace'], [1])
[docs] def test_pagereferences(self): """Test Site.pagereferences.""" # pagereferences includes both backlinks and embeddedin backlinks = set(self.site.pagebacklinks(self.mainpage, namespaces=[0])) with skipping(TimeoutError): embedded = set(self.site.page_embeddedin(self.mainpage, namespaces=[0])) refs = set(self.site.pagereferences(self.mainpage, namespaces=[0])) self.assertLessEqual(backlinks, refs) self.assertLessEqual(embedded, refs) self.assertEqual(refs, backlinks | embedded)
[docs] def test_embeddedin(self): """Test Site.page_embeddedin.""" with skipping(TimeoutError): embedded_ns_0 = set(self.site.page_embeddedin( self.mainpage, namespaces=[0])) embedded_ns_0_2 = set(self.site.page_embeddedin( self.mainpage, namespaces=[0, 2])) redirs = set(self.site.page_embeddedin( self.mainpage, filter_redirects=True, namespaces=[0])) no_redirs = set(self.site.page_embeddedin( self.mainpage, filter_redirects=False, namespaces=[0])) for ei in embedded_ns_0: self.assertIsInstance(ei, pywikibot.Page) self.assertLessEqual(redirs, embedded_ns_0) self.assertLessEqual(no_redirs, embedded_ns_0) self.assertLessEqual(embedded_ns_0, embedded_ns_0_2)
[docs] def test_page_redirects(self): """Test Site.page_redirects.""" redirects_ns_0 = set(self.site.page_redirects( self.mainpage, namespaces=0, )) redirects_ns_0_4 = set(self.site.page_redirects( self.mainpage, namespaces=[0, 4], )) redirects_ns_0_frag = set(self.site.page_redirects( self.mainpage, filter_fragments=True, namespaces=0, )) redirects_ns_0_nofrag = set(self.site.page_redirects( self.mainpage, filter_fragments=False, namespaces=0, )) self.assertLessEqual(redirects_ns_0, redirects_ns_0_4) self.assertLessEqual(redirects_ns_0_frag, redirects_ns_0) self.assertLessEqual(redirects_ns_0_nofrag, redirects_ns_0) for redirect in redirects_ns_0_4: self.assertIsInstance(redirect, pywikibot.Page) self.assertIn(redirect.namespace(), [0, 4]) self.assertTrue(redirect.isRedirectPage()) for redirect in redirects_ns_0: self.assertEqual(redirect.namespace(), 0) for redirect in redirects_ns_0_frag: redirect_target = redirect.getRedirectTarget() self.assertIsNotNone(redirect_target.section()) redirect_target = pywikibot.Page( redirect_target.site, redirect_target.title(with_section=False) ) self.assertEqual(redirect_target, self.mainpage) for redirect in redirects_ns_0_nofrag: redirect_target = redirect.getRedirectTarget() self.assertIsNone(redirect_target.section()) self.assertEqual(redirect_target, self.mainpage)
[docs] def test_pagecategories(self): """Test Site.pagecategories.""" for cat in self.site.pagecategories(self.mainpage): self.assertIsInstance(cat, pywikibot.Category)
[docs] def test_categorymembers(self): """Test Site.categorymembers.""" cats = list(self.site.pagecategories(self.mainpage)) if not cats: self.skipTest('Main page is not in any categories.') for cm in self.site.categorymembers(cats[0]): self.assertIsInstance(cm, pywikibot.Page)
[docs] def test_pageimages(self): """Test Site.pageimages.""" for im in self.site.pageimages(self.mainpage): self.assertIsInstance(im, pywikibot.FilePage)
[docs] def test_pagetemplates(self): """Test Site.pagetemplates.""" tl_gen = self.site.pagetemplates(self.mainpage) expected_params = dict( global_expected_params, generator=['templates'], titles=[self.mainpage.title()], ) self.assertEqual(tl_gen.request._params, expected_params) tl_gen = self.site.pagetemplates(self.mainpage, namespaces=[10]) expected_params['gtlnamespace'] = [10] self.assertEqual(tl_gen.request._params, expected_params) for te in tl_gen: self.assertIsInstance(te, pywikibot.Page) self.assertEqual(te.namespace(), 10)
[docs] def test_allpages(self): """Test the site.allpages() method.""" mysite = self.get_site() fwd = list(mysite.allpages(total=10)) self.assertLessEqual(len(fwd), 10) for page in fwd: self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 0) rev = list(mysite.allpages(reverse=True, start='Aa', total=12)) self.assertLessEqual(len(rev), 12) for page in rev: self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 0) self.assertLessEqual(page.title(), 'Aa') for page in mysite.allpages(start='Py', total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 0) self.assertGreaterEqual(page.title(), 'Py') for page in mysite.allpages(prefix='Pre', total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 0) self.assertTrue(page.title().startswith('Pre')) for page in mysite.allpages(namespace=1, total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 1) for page in mysite.allpages(filterredir=True, total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 0) self.assertTrue(page.isRedirectPage()) for page in mysite.allpages(filterredir=False, total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertEqual(page.namespace(), 0) self.assertFalse(page.isRedirectPage())
[docs] def test_allpages_pagesize(self): """Test allpages with page maxsize parameter.""" mysite = self.get_site() for page in mysite.allpages(minsize=100, total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertGreaterEqual(len(page.text.encode(mysite.encoding())), 100) for page in mysite.allpages(maxsize=200, total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) if len(page.text.encode(mysite.encoding())) > 200 \ and mysite.data_repository() == mysite: # pragma: no cover unittest_print( f'{page}.text is > 200 bytes while raw JSON is <= 200') continue self.assertLessEqual(len(page.text.encode(mysite.encoding())), 200)
[docs] def test_allpages_protection(self): """Test allpages with protect_type parameter.""" mysite = self.get_site() for page in mysite.allpages(protect_type='edit', total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertIn('edit', page._protection) for page in mysite.allpages(protect_type='edit', protect_level='sysop', total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) self.assertIn('edit', page._protection) self.assertIn('sysop', page._protection['edit'])
[docs] def test_all_categories(self): """Test the site.allcategories() method.""" mysite = self.get_site() ac = list(mysite.allcategories(total=10)) self.assertLessEqual(len(ac), 10) for cat in ac: self.assertIsInstance(cat, pywikibot.Category) for cat in mysite.allcategories(total=5, start='Abc'): self.assertIsInstance(cat, pywikibot.Category) self.assertGreaterEqual(cat.title(with_ns=False), 'Abc') for cat in mysite.allcategories(total=5, prefix='Def'): self.assertIsInstance(cat, pywikibot.Category) self.assertTrue(cat.title(with_ns=False).startswith('Def')) # Bug T17985 - reverse and start combined; fixed in v 1.14 for cat in mysite.allcategories(total=5, start='Hij', reverse=True): self.assertIsInstance(cat, pywikibot.Category) self.assertLessEqual(cat.title(with_ns=False), 'Hij')
[docs] def test_all_images(self): """Test the site.allimages() method.""" mysite = self.get_site() ai = list(mysite.allimages(total=10)) self.assertLessEqual(len(ai), 10) for image in ai: self.assertIsInstance(image, pywikibot.FilePage) for impage in mysite.allimages(start='Ba', total=5): self.assertIsInstance(impage, pywikibot.FilePage) self.assertTrue(impage.exists()) self.assertGreaterEqual(impage.title(with_ns=False), 'Ba') # Bug T17985 - reverse and start combined; fixed in v 1.14 for impage in mysite.allimages(start='Da', reverse=True, total=5): self.assertIsInstance(impage, pywikibot.FilePage) self.assertTrue(impage.exists()) self.assertLessEqual(impage.title(with_ns=False), 'Da') for impage in mysite.allimages(prefix='Ch', total=5): self.assertIsInstance(impage, pywikibot.FilePage) self.assertTrue(impage.exists()) self.assertTrue(impage.title(with_ns=False).startswith('Ch')) for impage in mysite.allimages(minsize=100, total=5): self.assertIsInstance(impage, pywikibot.FilePage) self.assertTrue(impage.exists()) self.assertGreaterEqual(impage.latest_file_info['size'], 100) for impage in mysite.allimages(maxsize=2000, total=5): self.assertIsInstance(impage, pywikibot.FilePage) self.assertTrue(impage.exists()) self.assertLessEqual(impage.latest_file_info['size'], 2000)
[docs] def test_querypage(self): """Test the site.querypage() method.""" mysite = self.get_site() pages = mysite.querypage('Longpages', total=10) for p in pages: self.assertIsInstance(p, pywikibot.Page) with self.assertRaises(ValueError): mysite.querypage('LongpageX')
[docs] def test_longpages(self): """Test the site.longpages() method.""" mysite = self.get_site() longpages = mysite.longpages(total=10) # Make sure each object returned by site.longpages() is # a tuple of a Page object and an int for tup in longpages: self.assertIsInstance(tup, tuple) self.assertLength(tup, 2) self.assertIsInstance(tup[0], pywikibot.Page) self.assertIsInstance(tup[1], int)
[docs] def test_shortpages(self): """Test the site.shortpages() method.""" mysite = self.get_site() shortpages = mysite.shortpages(total=10) # Make sure each object returned by site.shortpages() is # a tuple of a Page object and an int for tup in shortpages: self.assertIsInstance(tup, tuple) self.assertLength(tup, 2) self.assertIsInstance(tup[0], pywikibot.Page) self.assertIsInstance(tup[1], int)
[docs] def test_ancientpages(self): """Test the site.ancientpages() method.""" mysite = self.get_site() ancientpages = mysite.ancientpages(total=10) # Make sure each object returned by site.ancientpages() is # a tuple of a Page object and a Timestamp object for tup in ancientpages: self.assertIsInstance(tup, tuple) self.assertLength(tup, 2) self.assertIsInstance(tup[0], pywikibot.Page) self.assertIsInstance(tup[1], pywikibot.Timestamp)
[docs] def test_unwatchedpages(self): """Test the site.unwatchedpages() method.""" mysite = self.get_site() try: unwatchedpages = list(mysite.unwatchedpages(total=10)) except APIError as error: if error.code in ('specialpage-cantexecute', 'gqpspecialpage-cantexecute'): # User must have correct permissions to use # Special:UnwatchedPages self.skipTest(error) raise # Make sure each object returned by site.unwatchedpages() is a # Page object for p in unwatchedpages: self.assertIsInstance(p, pywikibot.Page)
[docs] def test_blocks(self): """Test the site.blocks() method.""" mysite = self.get_site() props = ('id', 'by', 'timestamp', 'expiry', 'reason') with self.subTest(total=10, reverse=False): bl = list(mysite.blocks(total=10)) self.assertLessEqual(len(bl), 10) for block in bl: self.assertIsInstance(block, dict) for prop in props: self.assertIn(prop, block) # timestamps should be in descending order timestamps = [block['timestamp'] for block in bl] for t in range(1, len(timestamps)): self.assertLessEqual(timestamps[t], timestamps[t - 1]) with self.subTest(total=10, reverse=True): b2 = list(mysite.blocks(total=10, reverse=True)) self.assertLessEqual(len(b2), 10) for block in b2: self.assertIsInstance(block, dict) for prop in props: self.assertIn(prop, block) # timestamps should be in ascending order timestamps = [block['timestamp'] for block in b2] for t in range(1, len(timestamps)): self.assertGreaterEqual(timestamps[t], timestamps[t - 1]) ip = '80.100.22.71' with self.subTest(users=ip): for block in mysite.blocks(users=ip, total=5): self.assertIsInstance(block, dict) self.assertEqual(block['user'], ip) low = pywikibot.Timestamp.fromISOformat('2008-08-03T00:00:01Z') high = pywikibot.Timestamp.fromISOformat('2008-08-03T23:59:59Z') with self.subTest(starttime=low): for block in mysite.blocks(starttime=low, total=5): self.assertIsInstance(block, dict) for prop in props: self.assertIn(prop, block) with self.subTest(endtime=high): for block in mysite.blocks(endtime=high, total=5): self.assertIsInstance(block, dict) for prop in props: self.assertIn(prop, block) with self.subTest(starttime=high, endtime=low, reverse=False): for block in mysite.blocks(starttime=high, endtime=low, total=5): self.assertIsInstance(block, dict) for prop in props: self.assertIn(prop, block) with self.subTest(starttime=low, endtime=high, reverse=True): for block in mysite.blocks(starttime=low, endtime=high, reverse=True, total=5): self.assertIsInstance(block, dict) for prop in props: self.assertIn(prop, block) # starttime earlier than endtime with self.subTest(starttime=low, endtime=high, reverse=False), \ self.assertRaises(AssertionError): mysite.blocks(total=5, starttime=low, endtime=high) # reverse: endtime earlier than starttime with self.subTest(starttime=high, endtime=low, reverse=True), \ self.assertRaises(AssertionError): mysite.blocks(total=5, starttime=high, endtime=low, reverse=True)
[docs] def test_exturl_usage(self): """Test the site.exturlusage() method.""" mysite = self.get_site() url = 'www.google.com' eu = list(mysite.exturlusage(url, total=10)) self.assertLessEqual(len(eu), 10) for link in eu: self.assertIsInstance(link, pywikibot.Page) for link in mysite.exturlusage(url, namespaces=[2, 3], total=5): self.assertIsInstance(link, pywikibot.Page) self.assertIn(link.namespace(), (2, 3))
[docs] def test_protectedpages_create(self): """Test that protectedpages returns protected page titles.""" pages = list(self.get_site().protectedpages(protect_type='create', total=10)) # Do not check for the existence of pages as they might exist (T205883) self.assertLessEqual(len(pages), 10)
[docs] def test_protectedpages_edit(self): """Test that protectedpages returns protected pages.""" site = self.get_site() pages = list(site.protectedpages(protect_type='edit', total=10)) for page in pages: self.assertTrue(page.exists()) self.assertIn('edit', page.protection()) self.assertLessEqual(len(pages), 10)
[docs] def test_protectedpages_edit_level(self): """Test protectedpages protection level.""" site = self.get_site() levels = set() all_levels = site.protection_levels().difference(['']) for level in all_levels: if list(site.protectedpages(protect_type='edit', level=level, total=1)): levels.add(level) if not levels: self.skipTest( f'The site "{site}" has no protected pages in main namespace.') # select one level which won't yield all pages from above level = next(iter(levels)) if len(levels) == 1: # if only one level found, then use any other except that level = next(iter(all_levels.difference([level]))) invalid_levels = all_levels.difference([level]) pages = list(site.protectedpages(protect_type='edit', level=level, total=10)) for page in pages: self.assertTrue(page.exists()) self.assertIn('edit', page.protection()) self.assertEqual(page.protection()['edit'][0], level) self.assertNotIn(page.protection()['edit'][0], invalid_levels) self.assertLessEqual(len(pages), 10)
[docs] def test_pages_with_property(self): """Test pages_with_property method.""" mysite = self.get_site() pnames = mysite.get_property_names() for item in ('defaultsort', 'disambiguation', 'displaytitle', 'hiddencat', 'invalid_property'): if item in pnames: for page in mysite.pages_with_property(item, total=5): self.assertIsInstance(page, pywikibot.Page) self.assertTrue(page.exists()) if item == 'disambiguation': self.assertTrue(page.isDisambig) else: with self.assertRaises(NotImplementedError): mysite.pages_with_property(item) self.fail( f'NotImplementedError not raised for {item}')
[docs] def test_unconnected(self): """Test site.unconnected_pages method.""" if not self.site.data_repository(): self.skipTest('Site is not using a Wikibase repository') pages = list(self.site.unconnected_pages(total=3)) self.assertLessEqual(len(pages), 3) site = self.site.data_repository() pattern = (r'Page ' r'\[\[({site.sitename}:|{site.code}:)-1\]\]' r" doesn't exist\.".format(site=site)) for page in pages: with self.assertRaisesRegex(NoPageError, pattern): page.data_item()
[docs] def test_assert_valid_iter_params(self): """Test site.assert_valid_iter_params method.""" func = self.site.assert_valid_iter_params # reverse=False, is_ts=False self.assertIsNone(func('m', 1, 2, False, False)) with self.assertRaises(AssertionError): func('m', 2, 1, False, False) # reverse=False, is_ts=True self.assertIsNone(func('m', 2, 1, False, True)) with self.assertRaises(AssertionError): func('m', 1, 2, False, True) # reverse=True, is_ts=False self.assertIsNone(func('m', 2, 1, True, False)) with self.assertRaises(AssertionError): func('m', 1, 2, True, False) # reverse=True, is_ts=True self.assertIsNone(func('m', 1, 2, True, True)) with self.assertRaises(AssertionError): func('m', 2, 1, True, True)
[docs] class TestSiteGeneratorsUsers(DefaultSiteTestCase): """Test cases for Site methods with users.""" cached = True
[docs] def setUp(self): """Initialize self.site and self.mainpage.""" super().setUp() self.site = self.get_site() self.mainpage = self.get_mainpage()
[docs] def test_botusers(self): """Test the site.botusers() method.""" mysite = self.get_site() bu = list(mysite.botusers(total=10)) self.assertLessEqual(len(bu), 10) for botuser in bu: self.assertIsInstance(botuser, dict) self.assertIn('name', botuser) self.assertIn('userid', botuser) self.assertIn('editcount', botuser) self.assertIn('registration', botuser) self.assertIn('bot', botuser['groups'])
[docs] def test_allusers(self): """Test the site.allusers() method.""" mysite = self.get_site() au = list(mysite.allusers(total=10)) self.assertLessEqual(len(au), 10) for user in au: self.assertIsInstance(user, dict) self.assertIn('name', user) self.assertIn('editcount', user) self.assertIn('registration', user) self.assertIn('*', user['groups'])
[docs] def test_allusers_with_start(self): """Test the site.allusers(start=..) method.""" mysite = self.get_site() for user in mysite.allusers(start='B', total=5): self.assertIsInstance(user, dict) self.assertIn('name', user) self.assertGreaterEqual(user['name'], 'B') self.assertIn('editcount', user) self.assertIn('registration', user)
[docs] def test_allusers_with_prefix(self): """Test the site.allusers(prefix=..) method.""" mysite = self.get_site() for user in mysite.allusers(prefix='C', total=5): self.assertIsInstance(user, dict) self.assertIn('name', user) self.assertTrue(user['name'].startswith('C')) self.assertIn('editcount', user) self.assertIn('registration', user)
[docs] def test_allusers_with_group(self): """Test the site.allusers(group=..) method.""" mysite = self.get_site() for user in mysite.allusers(prefix='D', group='bot', total=5): self.assertIsInstance(user, dict) self.assertIn('name', user) self.assertTrue(user['name'].startswith('D')) self.assertIn('editcount', user) self.assertIn('registration', user) self.assertIn('groups', user) self.assertIn('bot', user['groups'])
[docs] class TestImageUsage(DefaultSiteTestCase): """Test cases for Site.imageusage method.""" cached = True @property def imagepage(self): """Find an image which is used on the main page. If there are no images included in main page it'll skip all tests. .. note:: This is not implemented as setUpClass which would be invoked while initialising all tests, to reduce chance of an error preventing all tests from running. """ if hasattr(self.__class__, '_image_page'): return self.__class__._image_page mysite = self.get_site() page = pywikibot.Page(mysite, mysite.siteinfo['mainpage']) with skipping( StopIteration, msg=f'No images on the main page of site {mysite!r}'): imagepage = next(page.imagelinks()) # 1st image of page unittest_print( f'site_tests.TestImageUsage found {imagepage} on {page}') self.__class__._image_page = imagepage return imagepage
[docs] def test_image_usage(self): """Test the site.imageusage() method.""" mysite = self.get_site() imagepage = self.imagepage iu = list(mysite.imageusage(imagepage, total=10)) self.assertLessEqual(len(iu), 10) for link in iu: self.assertIsInstance(link, pywikibot.Page)
[docs] def test_image_usage_in_namespaces(self): """Test the site.imageusage() method with namespaces.""" mysite = self.get_site() imagepage = self.imagepage for using in mysite.imageusage(imagepage, namespaces=[3, 4], total=5): self.assertIsInstance(using, pywikibot.Page) self.assertIn(imagepage, list(using.imagelinks()))
[docs] def test_image_usage_in_redirects(self): """Test the site.imageusage() method on redirects only.""" mysite = self.get_site() imagepage = self.imagepage for using in mysite.imageusage(imagepage, filterredir=True, total=5): self.assertIsInstance(using, pywikibot.Page) self.assertTrue(using.isRedirectPage())
[docs] def test_image_usage_no_redirect_filter(self): """Test the site.imageusage() method with redirects.""" mysite = self.get_site() imagepage = self.imagepage for using in mysite.imageusage(imagepage, filterredir=False, total=5): self.assertIsInstance(using, pywikibot.Page) if using.isRedirectPage(): # pragma: no cover unittest_print( f'{using} is a redirect, although just non-redirects were' ' searched. See also T75120') self.assertFalse(using.isRedirectPage())
[docs] class TestLogEvents(DefaultSiteTestCase): """Test logevents methods."""
[docs] def test_logevents(self): """Test logevents method.""" mysite = self.get_site() le = list(mysite.logevents(total=10)) self.assertLessEqual(len(le), 10) for entry in le: self.assertIsInstance(entry, pywikibot.logentries.LogEntry) for logtype in mysite.logtypes: with self.subTest(logtype=logtype): gen = iter(mysite.logevents(logtype=logtype, total=3)) while True: try: entry = next(gen) except StopIteration: break except HiddenKeyError as e: # pragma: no cover self.skipTest(e) # T216876 else: self.assertEqual(entry.type(), logtype)
[docs] def test_logevents_mainpage(self): """Test logevents method on the main page.""" mysite = self.get_site() mainpage = self.get_mainpage() for entry in mysite.logevents(page=mainpage, total=3): self.assertEqual(entry.page().title(), mainpage.title()) self.assertEqual(entry.page(), mainpage)
[docs] def test_logevents_timestamp(self): """Test logevents method.""" mysite = self.get_site() for entry in mysite.logevents( start=pywikibot.Timestamp.fromISOformat( '2008-09-01T00:00:01Z'), total=5): self.assertIsInstance(entry, pywikibot.logentries.LogEntry) self.assertLessEqual(str(entry.timestamp()), '2008-09-01T00:00:01Z') for entry in mysite.logevents( end=pywikibot.Timestamp.fromISOformat('2008-09-02T23:59:59Z'), total=5): self.assertIsInstance(entry, pywikibot.logentries.LogEntry) self.assertGreaterEqual(str(entry.timestamp()), '2008-09-02T23:59:59Z') for entry in mysite.logevents( start=pywikibot.Timestamp.fromISOformat( '2008-02-02T00:00:01Z'), end=pywikibot.Timestamp.fromISOformat('2008-02-02T23:59:59Z'), reverse=True, total=5): self.assertIsInstance(entry, pywikibot.logentries.LogEntry) self.assertTrue( '2008-02-02T00:00:01Z' <= str(entry.timestamp()) <= '2008-02-02T23:59:59Z') for entry in mysite.logevents( start=pywikibot.Timestamp.fromISOformat( '2008-02-03T23:59:59Z'), end=pywikibot.Timestamp.fromISOformat('2008-02-03T00:00:01Z'), total=5): self.assertIsInstance(entry, pywikibot.logentries.LogEntry) self.assertTrue( '2008-02-03T00:00:01Z' <= str(entry.timestamp()) <= '2008-02-03T23:59:59Z') # starttime earlier than endtime with self.assertRaises(AssertionError): mysite.logevents(start=pywikibot.Timestamp.fromISOformat( '2008-02-03T00:00:01Z'), end=pywikibot.Timestamp.fromISOformat( '2008-02-03T23:59:59Z'), total=5) # reverse: endtime earlier than starttime with self.assertRaises(AssertionError): mysite.logevents(start=pywikibot.Timestamp.fromISOformat( '2008-02-03T23:59:59Z'), end=pywikibot.Timestamp.fromISOformat( '2008-02-03T00:00:01Z'), reverse=True, total=5)
[docs] class TestRecentChanges(DefaultSiteTestCase): """Test recentchanges method."""
[docs] def test_basic(self): """Test the site.recentchanges() method.""" mysite = self.site rc = list(mysite.recentchanges(total=10)) self.assertLessEqual(len(rc), 10) for change in rc: self.assertIsInstance(change, dict)
[docs] def test_time_range(self): """Test the site.recentchanges() method with start/end.""" mysite = self.site for change in mysite.recentchanges( start=pywikibot.Timestamp.fromISOformat( '2008-10-01T01:02:03Z'), total=5): self.assertIsInstance(change, dict) self.assertLessEqual(change['timestamp'], '2008-10-01T01:02:03Z') for change in mysite.recentchanges( end=pywikibot.Timestamp.fromISOformat('2008-04-01T02:03:04Z'), total=5): self.assertIsInstance(change, dict) self.assertGreaterEqual(change['timestamp'], '2008-10-01T02:03:04Z') for change in mysite.recentchanges( start=pywikibot.Timestamp.fromISOformat( '2008-10-01T03:05:07Z'), total=5, reverse=True): self.assertIsInstance(change, dict) self.assertGreaterEqual(change['timestamp'], '2008-10-01T03:05:07Z') for change in mysite.recentchanges( end=pywikibot.Timestamp.fromISOformat('2008-10-01T04:06:08Z'), total=5, reverse=True): self.assertIsInstance(change, dict) self.assertLessEqual(change['timestamp'], '2008-10-01T04:06:08Z') for change in mysite.recentchanges( start=pywikibot.Timestamp.fromISOformat( '2008-10-03T11:59:59Z'), end=pywikibot.Timestamp.fromISOformat('2008-10-03T00:00:01Z'), total=5): self.assertIsInstance(change, dict) self.assertTrue( '2008-10-03T00:00:01Z' <= change['timestamp'] <= '2008-10-03T11:59:59Z') for change in mysite.recentchanges( start=pywikibot.Timestamp.fromISOformat( '2008-10-05T06:00:01Z'), end=pywikibot.Timestamp.fromISOformat('2008-10-05T23:59:59Z'), reverse=True, total=5): self.assertIsInstance(change, dict) self.assertTrue( '2008-10-05T06:00:01Z' <= change['timestamp'] <= '2008-10-05T23:59:59Z') # start earlier than end with self.assertRaises(AssertionError): mysite.recentchanges(start='2008-02-03T00:00:01Z', end='2008-02-03T23:59:59Z', total=5) # reverse: end earlier than start with self.assertRaises(AssertionError): mysite.recentchanges(start=pywikibot.Timestamp.fromISOformat( '2008-02-03T23:59:59Z'), end=pywikibot.Timestamp.fromISOformat( '2008-02-03T00:00:01Z'), reverse=True, total=5)
[docs] def test_ns_file(self): """Test the site.recentchanges() method with File: and File talk:.""" if self.site.code == 'wikidata': self.skipTest( 'MediaWiki bug frequently occurring on Wikidata. T101502') mysite = self.site for change in mysite.recentchanges(namespaces=[6, 7], total=5): self.assertIsInstance(change, dict) self.assertIn('title', change) self.assertIn('ns', change) title = change['title'] self.assertIn(':', title) prefix = title[:title.index(':')] self.assertIn(self.site.namespaces.lookup_name(prefix).id, [6, 7]) self.assertIn(change['ns'], [6, 7])
[docs] def test_changetype(self): """Test the site.recentchanges() with changetype.""" mysite = self.site for typ in ('edit', 'new', 'log'): for change in mysite.recentchanges(changetype=typ, total=5): self.assertIsInstance(change, dict) self.assertIn('type', change) self.assertEqual(change['type'], typ)
[docs] def test_flags(self): """Test the site.recentchanges() with boolean flags.""" mysite = self.site for change in mysite.recentchanges(minor=True, total=5): self.assertIsInstance(change, dict) self.assertIn('minor', change) for change in mysite.recentchanges(minor=False, total=5): self.assertIsInstance(change, dict) self.assertNotIn('minor', change) for change in mysite.recentchanges(bot=True, total=5): self.assertIsInstance(change, dict) self.assertIn('bot', change) for change in mysite.recentchanges(bot=False, total=5): self.assertIsInstance(change, dict) self.assertNotIn('bot', change) for change in mysite.recentchanges(anon=True, total=5): self.assertIsInstance(change, dict) for change in mysite.recentchanges(anon=False, total=5): self.assertIsInstance(change, dict) for change in mysite.recentchanges(redirect=False, total=5): self.assertIsInstance(change, dict) self.assertNotIn('redirect', change) # Subtest timeouts on Wikidata due to upstream issue, see T245989 if mysite.sitename != 'wikidata:wikidata': for change in mysite.recentchanges(redirect=True, total=5): self.assertIsInstance(change, dict) self.assertIn('redirect', change)
[docs] def test_tag_filter(self): """Test the site.recentchanges() with tag filter.""" mysite = self.site for tag in ('visualeditor', 'mobile edit'): for change in mysite.recentchanges(tag=tag, total=5): self.assertIsInstance(change, dict) self.assertIn('tags', change) self.assertIsInstance(change['tags'], list) self.assertIn(tag, change['tags'])
[docs] class TestUserRecentChanges(DefaultSiteTestCase): """Test recentchanges method requiring a user.""" login = True rights = 'patrol'
[docs] def test_patrolled(self): """Test the site.recentchanges() with patrolled boolean flags.""" mysite = self.site for change in mysite.recentchanges(patrolled=True, total=5): self.assertIsInstance(change, dict) self.assertIn('patrolled', change) for change in mysite.recentchanges(patrolled=False, total=5): self.assertIsInstance(change, dict) self.assertNotIn('patrolled', change)
[docs] class TestUserWatchedPages(DefaultSiteTestCase): """Test user watched pages.""" login = True rights = 'viewmywatchlist'
[docs] def test_watched_pages(self): """Test the site.watched_pages() method.""" gen = self.site.watched_pages(total=5, force=False) self.assertIsInstance(gen.request, api.CachedRequest) for page in gen: self.assertIsInstance(page, pywikibot.Page) gen.restart() # repeat to use the cache self.assertIsInstance(gen.request, api.CachedRequest) for page in gen: self.assertIsInstance(page, pywikibot.Page)
[docs] def test_watched_pages_uncached(self): """Test the site.watched_pages() method uncached.""" gen = self.site.watched_pages(total=5, force=True) self.assertIsInstance(gen.request, api.Request) self.assertFalse(issubclass(gen.request_class, api.CachedRequest)) for page in gen: self.assertIsInstance(page, pywikibot.Page)
[docs] class SearchTestCase(DefaultSiteTestCase): """Test search method."""
[docs] def test_search_where_title(self): """Test site.search() method with 'where' parameter set to title.""" search_gen = self.site.search( 'wiki', namespaces=0, total=10, where='title') expected_params = dict( global_expected_params, generator=['search'], gsrnamespace=[0], gsrsearch=['wiki'], gsrwhat=['title'], ) self.assertEqual(search_gen.request._params, expected_params) for hit in search_gen: self.assertIsInstance(hit, pywikibot.Page) self.assertEqual(hit.namespace(), 0)
[docs] class TestUserContribsAsUser(DefaultSiteTestCase): """Test site method site.usercontribs() with bot user.""" login = True
[docs] def test_basic(self): """Test the site.usercontribs() method.""" mysite = self.get_site() uc = list(mysite.usercontribs(user=mysite.user(), total=10)) self.assertLessEqual(len(uc), 10) for contrib in uc: self.assertIsInstance(contrib, dict) self.assertIn('user', contrib) self.assertEqual(contrib['user'], mysite.user())
[docs] def test_namespaces(self): """Test the site.usercontribs() method using namespaces.""" mysite = self.get_site() for contrib in mysite.usercontribs(user=mysite.user(), namespaces=14, total=5): self.assertIsInstance(contrib, dict) self.assertIn('title', contrib) self.assertTrue(contrib['title'].startswith(mysite.namespace(14))) for contrib in mysite.usercontribs(user=mysite.user(), namespaces=[10, 11], total=5): self.assertIsInstance(contrib, dict) self.assertIn('title', contrib) self.assertIn(contrib['ns'], (10, 11))
[docs] def test_show_minor(self): """Test the site.usercontribs() method using showMinor.""" mysite = self.get_site() for contrib in mysite.usercontribs(user=mysite.user(), minor=True, total=5): self.assertIsInstance(contrib, dict) self.assertIn('minor', contrib) for contrib in mysite.usercontribs(user=mysite.user(), minor=False, total=5): self.assertIsInstance(contrib, dict) self.assertNotIn('minor', contrib)
[docs] class TestUserContribsWithoutUser(DefaultSiteTestCase): """Test site method site.usercontribs() without bot user."""
[docs] def test_user_prefix(self): """Test the site.usercontribs() method with userprefix.""" mysite = self.get_site() if mysite.family.name == 'wowwiki': self.skipTest(f'Too many timeouts on {mysite}') for contrib in mysite.usercontribs(userprefix='John', total=5): self.assertIsInstance(contrib, dict) for key in ('user', 'title', 'ns', 'pageid', 'revid'): self.assertIn(key, contrib) self.assertTrue(contrib['user'].startswith('John'))
[docs] def test_user_prefix_range(self): """Test the site.usercontribs() method.""" mysite = self.get_site() start = '2008-10-06T01:02:03Z' with self.subTest(start=start): for contrib in mysite.usercontribs( userprefix='Jane', start=pywikibot.Timestamp.fromISOformat(start), total=5): self.assertLessEqual(contrib['timestamp'], start) end = '2008-10-07T02:03:04Z' with self.subTest(end=end): for contrib in mysite.usercontribs( userprefix='Jane', end=pywikibot.Timestamp.fromISOformat(end), total=5): self.assertGreaterEqual(contrib['timestamp'], end) start = '2008-10-10T11:59:59Z' end = '2008-10-10T00:00:01Z' with self.subTest(start=start, end=end): for contrib in mysite.usercontribs( userprefix='Timshiel', start=pywikibot.Timestamp.fromISOformat(start), end=pywikibot.Timestamp.fromISOformat(end), total=5): self.assertTrue(end <= contrib['timestamp'] <= start)
[docs] def test_user_prefix_reverse(self): """Test the site.usercontribs() method with range reversed.""" mysite = self.get_site() start = '2008-10-08T03:05:07Z' for contrib in mysite.usercontribs( userprefix='Brion', start=pywikibot.Timestamp.fromISOformat(start), total=5, reverse=True): self.assertGreaterEqual(contrib['timestamp'], start) for contrib in mysite.usercontribs( userprefix='Brion', end=pywikibot.Timestamp.fromISOformat('2008-10-09T04:06:08Z'), total=5, reverse=True): self.assertLessEqual(contrib['timestamp'], '2008-10-09T04:06:08Z') start = '2008-10-11T06:00:01Z' end = '2008-10-11T23:59:59Z' for contrib in mysite.usercontribs( userprefix='Tim symond', start=pywikibot.Timestamp.fromISOformat(start), end=pywikibot.Timestamp.fromISOformat(end), reverse=True, total=5): self.assertTrue(start <= contrib['timestamp'] <= end)
[docs] def test_invalid_range(self): """Test the site.usercontribs() method with invalid parameters.""" mysite = self.get_site() # start earlier than end with self.assertRaises(AssertionError): mysite.usercontribs(userprefix='Jim', start='2008-10-03T00:00:01Z', end='2008-10-03T23:59:59Z', total=5) # reverse: end earlier than start with self.assertRaises(AssertionError): mysite.usercontribs(userprefix='Jim', start='2008-10-03T23:59:59Z', end='2008-10-03T00:00:01Z', reverse=True, total=5)
[docs] class TestAlldeletedrevisionsAsUser(DefaultSiteTestCase): """Test site method site.alldeletedrevisions() with bot user.""" login = True
[docs] def test_basic(self): """Test the site.alldeletedrevisions() method.""" mysite = self.get_site() result = list(mysite.alldeletedrevisions(user=mysite.user(), total=10)) if not result: self.skipTest('No deleted revisions available') for data in result: with self.subTest(data=data): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('user', drev) self.assertEqual(drev['user'], mysite.user())
[docs] def test_namespaces(self): """Test the site.alldeletedrevisions() method using namespaces.""" mysite = self.get_site() for data in mysite.alldeletedrevisions(namespaces=14, total=5): self.assertIsInstance(data, dict) self.assertIn('title', data) self.assertTrue(data['title'].startswith(mysite.namespace(14))) for data in mysite.alldeletedrevisions(user=mysite.user(), namespaces=[10, 11], total=5): self.assertIsInstance(data, dict) self.assertIn('title', data) self.assertIn(data['ns'], (10, 11))
[docs] def test_excludeuser(self): """Test the site.alldeletedrevisions() method using excludeuser.""" mysite = self.get_site() for data in mysite.alldeletedrevisions(excludeuser=mysite.user(), total=5): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('user', drev) self.assertNotEqual(drev['user'], mysite.user())
[docs] def test_user_range(self): """Test the site.alldeletedrevisions() method with range.""" mysite = self.get_site() start = '2008-10-06T01:02:03Z' for data in mysite.alldeletedrevisions( user=mysite.user(), start=pywikibot.Timestamp.fromISOformat(start), total=5): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('timestamp', drev) self.assertLessEqual(drev['timestamp'], start) end = '2008-10-07T02:03:04Z' for data in mysite.alldeletedrevisions( user=mysite.user(), end=pywikibot.Timestamp.fromISOformat(end), total=5): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('timestamp', drev) self.assertGreaterEqual(drev['timestamp'], end) start = '2008-10-10T11:59:59Z' end = '2008-10-10T00:00:01Z' for data in mysite.alldeletedrevisions( user=mysite.user(), start=pywikibot.Timestamp.fromISOformat(start), end=pywikibot.Timestamp.fromISOformat(end), total=5): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('timestamp', drev) self.assertTrue(end <= drev['timestamp'] <= start)
[docs] def test_user_range_reverse(self): """Test the site.alldeletedrevisions() method with range reversed.""" mysite = self.get_site() start = '2008-10-08T03:05:07Z' for data in mysite.alldeletedrevisions( user=mysite.user(), start=pywikibot.Timestamp.fromISOformat(start), total=5, reverse=True): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('timestamp', drev) self.assertGreaterEqual(drev['timestamp'], start) for data in mysite.alldeletedrevisions( user=mysite.user(), end=pywikibot.Timestamp.fromISOformat('2008-10-09T04:06:08Z'), total=5, reverse=True): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('timestamp', drev) self.assertLessEqual(drev['timestamp'], '2008-10-09T04:06:08Z') start = '2008-10-11T06:00:01Z' end = '2008-10-11T23:59:59Z' for data in mysite.alldeletedrevisions( user=mysite.user(), start=pywikibot.Timestamp.fromISOformat(start), end=pywikibot.Timestamp.fromISOformat(end), reverse=True, total=5): self.assertIsInstance(data, dict) self.assertIn('revisions', data) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) self.assertIn('timestamp', drev) self.assertTrue(start <= drev['timestamp'] <= end)
[docs] def test_invalid_range(self): """Test site.alldeletedrevisions() method with invalid range.""" mysite = self.get_site() # start earlier than end with self.assertRaises(AssertionError): adrgen = mysite.alldeletedrevisions(user=mysite.user(), start='2008-10-03T00:00:01Z', end='2008-10-03T23:59:59Z', total=5) next(adrgen) # reverse: end earlier than start with self.assertRaises(AssertionError): adrgen = mysite.alldeletedrevisions(user=mysite.user(), start='2008-10-03T23:59:59Z', end='2008-10-03T00:00:01Z', reverse=True, total=5) next(adrgen)
[docs] class TestAlldeletedrevisionsWithoutUser(DefaultSiteTestCase): """Test site method site.alldeletedrevisions() without bot user."""
[docs] def test_prefix(self): """Test the site.alldeletedrevisions() method with prefix.""" mysite = self.get_site() for data in mysite.alldeletedrevisions(prefix='John', total=5): self.assertIsInstance(data, dict) for key in ('title', 'ns', 'revisions'): self.assertIn(key, data) title = data['title'] if data['ns'] > 0: *_, title = title.partition(':') self.assertTrue(title.startswith('John')) self.assertIsInstance(data['revisions'], list) for drev in data['revisions']: self.assertIsInstance(drev, dict) for key in ('revid', 'timestamp', 'user'): self.assertIn(key, drev)
[docs] class SiteWatchlistRevsTestCase(DefaultSiteTestCase): """Test site method watchlist_revs().""" login = True rights = 'viewmywatchlist'
[docs] def test_watchlist_revs(self): """Test the site.watchlist_revs() method.""" mysite = self.get_site() wl = list(mysite.watchlist_revs(total=10)) self.assertLessEqual(len(wl), 10) for rev in wl: self.assertIsInstance(rev, dict) for rev in mysite.watchlist_revs(start='2008-10-11T01:02:03Z', total=5): self.assertIsInstance(rev, dict) self.assertLessEqual(rev['timestamp'], '2008-10-11T01:02:03Z') for rev in mysite.watchlist_revs(end='2008-04-01T02:03:04Z', total=5): self.assertIsInstance(rev, dict) self.assertGreaterEqual(rev['timestamp'], '2008-10-11T02:03:04Z') for rev in mysite.watchlist_revs(start='2008-10-11T03:05:07Z', total=5, reverse=True): self.assertIsInstance(rev, dict) self.assertGreaterEqual(rev['timestamp'], '2008-10-11T03:05:07Z') for rev in mysite.watchlist_revs(end='2008-10-11T04:06:08Z', total=5, reverse=True): self.assertIsInstance(rev, dict) self.assertLessEqual(rev['timestamp'], '2008-10-11T04:06:08Z') for rev in mysite.watchlist_revs(start='2008-10-13T11:59:59Z', end='2008-10-13T00:00:01Z', total=5): self.assertIsInstance(rev, dict) self.assertTrue( '2008-10-13T00:00:01Z' <= rev['timestamp'] <= '2008-10-13T11:59:59Z') for rev in mysite.watchlist_revs(start='2008-10-15T06:00:01Z', end='2008-10-15T23:59:59Z', reverse=True, total=5): self.assertIsInstance(rev, dict) self.assertTrue( '2008-10-15T06:00:01Z' <= rev['timestamp'] <= '2008-10-15T23:59:59Z') # start earlier than end with self.assertRaises(AssertionError): mysite.watchlist_revs(start='2008-09-03T00:00:01Z', end='2008-09-03T23:59:59Z', total=5) # reverse: end earlier than start with self.assertRaises(AssertionError): mysite.watchlist_revs(start='2008-09-03T23:59:59Z', end='2008-09-03T00:00:01Z', reverse=True, total=5) for rev in mysite.watchlist_revs(namespaces=[6, 7], total=5): self.assertIsInstance(rev, dict) self.assertIn('title', rev) self.assertIn('ns', rev) title = rev['title'] self.assertIn(':', title) prefix = title[:title.index(':')] self.assertIn(self.site.namespaces.lookup_name(prefix).id, [6, 7]) self.assertIn(rev['ns'], [6, 7]) for rev in mysite.watchlist_revs(minor=True, total=5): self.assertIsInstance(rev, dict) self.assertIn('minor', rev) for rev in mysite.watchlist_revs(minor=False, total=5): self.assertIsInstance(rev, dict) self.assertNotIn('minor', rev) for rev in mysite.watchlist_revs(bot=True, total=5): self.assertIsInstance(rev, dict) self.assertIn('bot', rev) for rev in mysite.watchlist_revs(bot=False, total=5): self.assertIsInstance(rev, dict) self.assertNotIn('bot', rev) for rev in mysite.watchlist_revs(anon=True, total=5): self.assertIsInstance(rev, dict) for rev in mysite.watchlist_revs(anon=False, total=5): self.assertIsInstance(rev, dict)
[docs] class TestUserList(DefaultSiteTestCase): """Test usernames Jimbo Wales, Brion VIBBER and Tim Starling.""" cached = True
[docs] def test_users(self): """Test the site.users() method with preset usernames.""" user_list = ['Jimbo Wales', 'Brooke Vibber', 'Tim Starling'] missing = ['A username that should not exist 1A53F6E375B5'] all_users = user_list + missing for cnt, user in enumerate(self.site.users(all_users), start=1): with self.subTest(user=user['name']): self.assertIsInstance(user, dict) self.assertIn(user['name'], all_users) if user['name'] == missing[0]: self.assertIn('missing', user) elif self.site.family.name == 'wikipedia': self.assertNotIn('missing', user) self.assertEqual(cnt, len(all_users), 'Some test usernames not found')
[docs] class SiteRandomTestCase(DefaultSiteTestCase): """Test random methods of a site."""
[docs] @classmethod def setUpClass(cls): """Skip test on beta due to T282602.""" super().setUpClass() site = cls.get_site() if site.family.name in ('wpbeta', 'wsbeta'): cls.skipTest(cls, f'Skipping test on {site} due to T282602')
[docs] def test_unlimited_small_step(self): """Test site.randompages() continuation. Note that uniqueness is not guaranteed if multiple requests are performed, so we also don't test this here. """ mysite = self.get_site() pages = [] rngen = mysite.randompages(total=None) rngen.set_query_increment = 5 for rndpage in rngen: self.assertIsInstance(rndpage, pywikibot.Page) pages.append(rndpage) if len(pages) == 11: break self.assertLength(pages, 11)
[docs] def test_limit_10(self): """Test site.randompages() with limit.""" mysite = self.get_site() rn = list(mysite.randompages(total=10)) self.assertLessEqual(len(rn), 10) for a_page in rn: self.assertIsInstance(a_page, pywikibot.Page) self.assertFalse(a_page.isRedirectPage())
[docs] def test_redirects(self): """Test site.randompages() with redirects.""" mysite = self.get_site() for rndpage in mysite.randompages(total=5, redirects=True): self.assertIsInstance(rndpage, pywikibot.Page) self.assertTrue(rndpage.isRedirectPage())
[docs] def test_all(self): """Test site.randompages() with both types.""" mysite = self.get_site() for rndpage in mysite.randompages(total=5, redirects=None): self.assertIsInstance(rndpage, pywikibot.Page)
[docs] def test_namespaces(self): """Test site.randompages() with namespaces.""" mysite = self.get_site() for rndpage in mysite.randompages(total=5, namespaces=[6, 7]): self.assertIsInstance(rndpage, pywikibot.Page) self.assertIn(rndpage.namespace(), [6, 7])
[docs] class TestSiteAPILimits(TestCase): """Test cases for Site method that use API limits.""" family = 'wikipedia' code = 'en' cached = True
[docs] def test_api_limits_with_site_methods(self): """Test step/total parameters for different sitemethods.""" mysite = self.get_site() mypage = pywikibot.Page(mysite, 'Albert Einstein') mycat = pywikibot.Page(mysite, 'Category:1879 births') gen = mysite.pagecategories(mypage, total=12) gen.set_query_increment = 5 cats = list(gen) self.assertLength(cats, 12) gen = mysite.categorymembers(mycat, total=12) gen.set_query_increment = 5 cat_members = list(gen) self.assertLength(cat_members, 12) gen = mysite.pageimages(mypage, total=5) gen.set_query_increment = 3 images = list(gen) self.assertLength(images, 5) gen = mysite.pagetemplates(mypage, total=5) gen.set_query_increment = 3 templates = list(gen) self.assertLength(templates, 5) mysite.loadrevisions(mypage, step=5, total=12) self.assertLength(mypage._revisions, 12)
[docs] class TestSiteLoadRevisions(TestCase): """Test cases for Site.loadrevision() method.""" family = 'wikipedia' code = 'en' cached = True # Implemented without setUpClass(cls) and global variables as objects # were not completely disposed and recreated but retained 'memory'
[docs] def setUp(self): """Setup tests.""" super().setUp() self.mysite = self.get_site() self.mainpage = pywikibot.Page(pywikibot.Link('Main Page', self.mysite))
[docs] def test_loadrevisions_basic(self): """Test the site.loadrevisions() method.""" # Load revisions without content self.mysite.loadrevisions(self.mainpage, total=15) self.mysite.loadrevisions(self.mainpage) self.assertFalse(hasattr(self.mainpage, '_text')) self.assertLength(self.mainpage._revisions, 15) self.assertIn(self.mainpage._revid, self.mainpage._revisions) self.assertIsNone(self.mainpage._revisions[self.mainpage._revid].text) # The revision content will be loaded by .text self.assertIsNotNone(self.mainpage.text)
[docs] def test_loadrevisions_content(self): """Test the site.loadrevisions() method with content=True.""" self.mysite.loadrevisions(self.mainpage, content=True, total=5) self.assertFalse(hasattr(self.mainpage, '_text')) self.assertIn(self.mainpage._revid, self.mainpage._revisions) self.assertIsNotNone( self.mainpage._revisions[self.mainpage._revid].text) self.assertTrue(self.mainpage._revisions[self.mainpage._revid].text) self.assertIsNotNone(self.mainpage.text)
[docs] def test_loadrevisions_revids(self): """Test the site.loadrevisions() method, listing based on revid.""" # revids as list of int self.mysite.loadrevisions(self.mainpage, revids=[139992, 139993]) for rev in [139992, 139993]: self.assertIn(rev, self.mainpage._revisions) # revids as list of str self.mysite.loadrevisions(self.mainpage, revids=['139994', '139995']) for rev in [139994, 139995]: self.assertIn(rev, self.mainpage._revisions) # revids as int self.mysite.loadrevisions(self.mainpage, revids=140000) self.assertIn(140000, self.mainpage._revisions) # revids as str self.mysite.loadrevisions(self.mainpage, revids='140001') self.assertIn(140001, self.mainpage._revisions) # revids belonging to a different page raises Exception with self.assertRaises(Error): self.mysite.loadrevisions(self.mainpage, revids=130000)
[docs] def test_loadrevisions_continue(self): """Test the site.loadrevisions() method with continue.""" self.mysite.loadrevisions(self.mainpage, step=5, total=12) self.assertLength(self.mainpage._revisions, 12)
[docs] def test_loadrevisions_revdir(self): """Test the site.loadrevisions() method with rvdir=True.""" self.mysite.loadrevisions(self.mainpage, rvdir=True, total=15) self.assertLength(self.mainpage._revisions, 15)
[docs] def test_loadrevisions_timestamp(self): """Test the site.loadrevisions() method, listing based on timestamp.""" self.mysite.loadrevisions(self.mainpage, rvdir=True, total=15) self.assertLength(self.mainpage._revisions, 15) revs = self.mainpage._revisions timestamps = [str(revs[rev].timestamp) for rev in revs] for ts in timestamps: self.assertLess(ts, '2002-01-31T00:00:00Z') # Retrieve oldest revisions; listing based on timestamp. # Raises "loadrevisions: starttime > endtime with rvdir=True" with self.assertRaises(ValueError): self.mysite.loadrevisions(self.mainpage, rvdir=True, starttime='2002-02-01T00:00:00Z', endtime='2002-01-01T00:00:00Z') # Retrieve newest revisions; listing based on timestamp. # Raises "loadrevisions: endtime > starttime with rvdir=False" with self.assertRaises(ValueError): self.mysite.loadrevisions(self.mainpage, rvdir=False, starttime='2002-01-01T00:00:00Z', endtime='2002-02-01T00:00:00Z')
[docs] def test_loadrevisions_rev_id(self): """Test the site.loadrevisions() method, listing based on rev_id.""" self.mysite.loadrevisions(self.mainpage, rvdir=True, total=15) self.assertLength(self.mainpage._revisions, 15) revs = self.mainpage._revisions for rev in revs: self.assertTrue(139900 <= rev <= 140100) # Retrieve oldest revisions; listing based on revid. # Raises "loadrevisions: startid > endid with rvdir=True" with self.assertRaises(ValueError): self.mysite.loadrevisions(self.mainpage, rvdir=True, startid='200000', endid='100000') # Retrieve newest revisions; listing based on revid. # Raises "loadrevisions: endid > startid with rvdir=False with self.assertRaises(ValueError): self.mysite.loadrevisions(self.mainpage, rvdir=False, startid='100000', endid='200000')
[docs] def test_loadrevisions_user(self): """Test the site.loadrevisions() method, filtering by user.""" # Only list revisions made by this user. self.mainpage._revisions = {} self.mysite.loadrevisions(self.mainpage, rvdir=True, user='Magnus Manske') for rev in self.mainpage._revisions.values(): self.assertEqual(rev.user, 'Magnus Manske')
[docs] def test_loadrevisions_excludeuser(self): """Test the site.loadrevisions() method, excluding user.""" excludeuser = 'Magnus Manske' # exclude revisions made by this user self.mainpage._revisions = {} self.mysite.loadrevisions(self.mainpage, rvdir=True, excludeuser=excludeuser) for rev in self.mainpage._revisions.values(): self.assertNotEqual(rev.user, excludeuser)
# TODO test other optional arguments
[docs] class TestFileArchive(DeprecationTestCase): """Test filearchive on Commons.""" family = 'commons' code = 'commons' cached = True
[docs] def test_filearchive(self): """Test filearchive method.""" gen = self.site.filearchive(total=10) self.assertNotIn('fafrom', str(gen.request)) self.assertNotIn('fato', str(gen.request)) fa = list(gen) self.assertLessEqual(len(fa), 10) for item in fa: self.assertIsInstance(item, dict) self.assertIn('id', item) self.assertIn('name', item) self.assertIn('ns', item) self.assertIn('title', item) self.assertIn('timestamp', item) self.assertEqual(item['ns'], 6) self.assertEqual('File:' + item['name'].replace('_', ' '), item['title'])
[docs] def test_filearchive_prefix(self): """Test prefix parameter.""" gen = self.site.filearchive(prefix='py') self.assertIn('faprefix=py', str(gen.request)) for item in gen: self.assertTrue(item['name'].startswith('Py'))
[docs] def test_filearchive_prop(self): """Test properties.""" gen = self.site.filearchive(prop=['sha1', 'size', 'user'], total=1) self.assertIn('faprop=sha1|size|user', str(gen.request)) item = next(gen) self.assertIn('sha1', item) self.assertIn('size', item) self.assertIn('user', item)
[docs] def test_filearchive_reverse(self): """Test reverse parameter.""" gen1 = self.site.filearchive(total=1) gen2 = self.site.filearchive(reverse=True, total=1) self.assertNotIn('fadir=', str(gen1.request)) self.assertIn('fadir=descending', str(gen2.request)) fa1 = next(gen1) fa2 = next(gen2) self.assertLess(fa1['name'], fa2['name'])
[docs] def test_filearchive_start(self): """Test start/end parameters.""" gen = self.site.filearchive(start='py', end='wiki', total=1) self.assertIn('fafrom=py', str(gen.request)) self.assertIn('fato=wiki', str(gen.request)) item = next(gen) self.assertGreaterEqual(item['name'], 'Py')
[docs] def test_filearchive_sha1(self): """Test sha1 parameter.""" sha1 = '0d5a00aa774100408e60da09f5fb21f253b366f1' gen = self.site.filearchive(sha1=sha1, prop='sha1', total=1) self.assertIn('fasha1=' + sha1, str(gen.request)) item = next(gen) self.assertEqual(item['sha1'], sha1)
[docs] class TestLoadPagesFromPageids(DefaultSiteTestCase): """Test site.load_pages_from_pageids().""" cached = True
[docs] def setUp(self): """Setup tests.""" super().setUp() self.site = self.get_site() mainpage = self.get_mainpage() self.links = [ page for page in self.site.pagelinks(mainpage, total=10) if page.exists()]
[docs] def test_load_from_pageids_iterable_of_str(self): """Test basic loading with pageids.""" pageids = [str(page.pageid) for page in self.links] gen = self.site.load_pages_from_pageids(pageids) count = 0 for count, page in enumerate(gen, start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertTrue(page.exists()) self.assertTrue(hasattr(page, '_pageid')) self.assertIn(page, self.links) self.assertEqual(count, len(self.links))
[docs] def test_load_from_pageids_iterable_of_int(self): """Test basic loading with pageids.""" pageids = [page.pageid for page in self.links] gen = self.site.load_pages_from_pageids(pageids) count = 0 for count, page in enumerate(gen, start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertTrue(page.exists()) self.assertTrue(hasattr(page, '_pageid')) self.assertIn(page, self.links) self.assertEqual(count, len(self.links))
[docs] def test_load_from_pageids_iterable_in_order(self): """Test loading with pageids is ordered.""" pageids = [page.pageid for page in self.links] gen = self.site.load_pages_from_pageids(pageids) for page in gen: link = self.links.pop(0) self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertTrue(page.exists()) self.assertTrue(hasattr(page, '_pageid')) self.assertEqual(page, link)
[docs] def test_load_from_pageids_iterable_with_duplicate(self): """Test loading with duplicate pageids.""" pageids = [page.pageid for page in self.links] pageids += pageids gen = self.site.load_pages_from_pageids(pageids) count = 0 for count, page in enumerate(gen, start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertTrue(page.exists()) self.assertTrue(hasattr(page, '_pageid')) self.assertIn(page, self.links) self.assertEqual(count, len(self.links))
[docs] def test_load_from_pageids_comma_separated(self): """Test loading from comma-separated pageids.""" pageids = ', '.join(str(page.pageid) for page in self.links) gen = self.site.load_pages_from_pageids(pageids) count = 0 for count, page in enumerate(gen, start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertTrue(page.exists()) self.assertTrue(hasattr(page, '_pageid')) self.assertIn(page, self.links) self.assertEqual(count, len(self.links))
[docs] def test_load_from_pageids_pipe_separated(self): """Test loading from comma-separated pageids.""" pageids = '|'.join(str(page.pageid) for page in self.links) gen = self.site.load_pages_from_pageids(pageids) count = 0 for count, page in enumerate(gen, start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertTrue(page.exists()) self.assertTrue(hasattr(page, '_pageid')) self.assertIn(page, self.links) self.assertEqual(count, len(self.links))
[docs] class TestPagePreloading(DefaultSiteTestCase): """Test site.preloadpages()."""
[docs] def test_order(self): """Test outcome is following same order of input.""" mainpage = self.get_mainpage() links = [page for page in self.site.pagelinks(mainpage, total=20) if page.exists()] pages = list(self.site.preloadpages(links, groupsize=5)) self.assertEqual(pages, links)
[docs] def test_duplicates(self): """Test outcome is following same order of input.""" mainpage = self.get_mainpage() links = [page for page in self.site.pagelinks(mainpage, total=20) if page.exists()] dupl_links = links + links[::-1] pages = list(self.site.preloadpages(dupl_links, groupsize=40)) self.assertEqual(pages, links)
[docs] def test_pageids(self): """Test basic preloading with pageids.""" mysite = self.get_site() mainpage = self.get_mainpage() links = mysite.pagelinks(mainpage, total=10) # preloadpages will send the page ids, # as they have already been loaded by pagelinks for count, page in enumerate(mysite.preloadpages(links), start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertTrue(hasattr(page, '_revid')) self.assertLength(page._revisions, 1) self.assertIn(page._revid, page._revisions) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) if count >= 5: break
[docs] def test_titles(self): """Test basic preloading with titles.""" mysite = self.get_site() mainpage = self.get_mainpage() links = mysite.pagelinks(mainpage, total=10) # remove the pageids that have already been loaded above by pagelinks # so that preloadpages will use the titles instead for page in links: if hasattr(page, '_pageid'): self.assertEqual(page.pageid, page._pageid) del page._pageid for count, page in enumerate(mysite.preloadpages(links), start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) if count >= 5: break
[docs] def test_preload_continuation(self): """Test preloading continuation works.""" mysite = self.get_site() mainpage = self.get_mainpage() links = mysite.pagelinks(mainpage, total=10) for count, page in enumerate(mysite.preloadpages(links, groupsize=5)): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) if count >= 5: break
[docs] def test_preload_high_groupsize(self): """Test preloading continuation with groupsize greater than total.""" mysite = self.get_site() mainpage = self.get_mainpage() # Determine if there are enough links on the main page, # for the test to be useful. link_count = len(list(mysite.pagelinks(mainpage, total=10))) if link_count < 2: self.skipTest('insufficient links on main page') # get a fresh generator; we now know how many results it will have, # if it is less than 10. links = mysite.pagelinks(mainpage, total=10) count = 0 for count, page in enumerate( mysite.preloadpages(links, groupsize=50), start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) self.assertEqual(count, link_count)
[docs] def test_preload_low_groupsize(self): """Test preloading continuation with groupsize greater than total.""" mysite = self.get_site() mainpage = self.get_mainpage() # Determine if there are enough links on the main page, # for the test to be useful. link_count = len(list(mysite.pagelinks(mainpage, total=10))) if link_count < 2: self.skipTest('insufficient links on main page') # get a fresh generator; we now know how many results it will have, # if it is less than 10. links = mysite.pagelinks(mainpage, total=10) count = 0 for count, page in enumerate( mysite.preloadpages(links, groupsize=5), start=1): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) self.assertEqual(count, link_count)
[docs] def test_preload_unexpected_titles_using_pageids(self): """Test sending pageids with unnormalized titles, causing warnings.""" mysite = self.get_site() mainpage = self.get_mainpage() links = list(mysite.pagelinks(mainpage, total=10)) if len(links) < 2: self.skipTest('insufficient links on main page') # change the title of the page, to test sametitle(). # preloadpages will send the page ids, as they have already been loaded # by pagelinks, and preloadpages should complain the returned titles # do not match any title in the pagelist. # However, APISite.sametitle now correctly links them. for page in links: page._link._text += ' ' gen = mysite.preloadpages(links, groupsize=5) for count, page in enumerate(gen): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) if count >= 5: break
[docs] def test_preload_unexpected_titles_using_titles(self): """Test sending unnormalized titles, causing warnings.""" mysite = self.get_site() mainpage = self.get_mainpage() links = list(mysite.pagelinks(mainpage, total=10)) if len(links) < 2: self.skipTest('insufficient links on main page') # change the title of the page _and_ delete the pageids. # preloadpages can only send the titles, and preloadpages should # complain the returned titles do not match any title in the pagelist. # However, APISite.sametitle now correctly links them. for page in links: page._link._text += ' ' del page._pageid gen = mysite.preloadpages(links, groupsize=5) for count, page in enumerate(gen): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) if count >= 5: break
[docs] def test_preload_invalid_titles_without_pageids(self): """Test sending invalid titles. No warnings issued, but it should.""" mysite = self.get_site() mainpage = self.get_mainpage() links = list(mysite.pagelinks(mainpage, total=10)) if len(links) < 2: self.skipTest('insufficient links on main page') for page in links: page._link._text += ' foobar' del page._pageid gen = mysite.preloadpages(links, groupsize=5) for count, page in enumerate(gen): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) self.assertFalse(page.exists(), f'page {page} exists') if count >= 5: break
[docs] def test_preload_templates(self): """Test preloading templates works.""" mysite = self.get_site() # Use backlinks, as any backlink has at least one link links = mysite.pagelinks(self.get_mainpage(), total=10) gen = mysite.preloadpages(links, templates=True) for count, page in enumerate(gen): with self.subTest(page=page.title()): self.assertIsInstance(page, pywikibot.Page) self.assertIsInstance(page.exists(), bool) if page.exists(): self.assertLength(page._revisions, 1) self.assertIsNotNone(page._revisions[page._revid].text) self.assertFalse(hasattr(page, '_pageprops')) self.assertTrue(hasattr(page, '_templates')) if count >= 5: break
[docs] def test_preload_categories(self): """Test preloading categories works.""" mysite = self.get_site() cats = mysite.randompages(total=10, namespaces=14) gen = mysite.preloadpages(cats, categories=True) for count, page in enumerate(gen): with self.subTest(page=page.title()): self.assertTrue(hasattr(page, '_categories')) # content=True will bypass cache self.assertEqual(page._categories, set(page.categories(content=True))) if count >= 5: break
[docs] def test_preload_content(self): """Test preloading templates and langlinks works.""" mysite = self.get_site() page = next(mysite.preloadpages([self.get_mainpage()], content=False)) self.assertFalse(page.has_content()) page = next(mysite.preloadpages([self.get_mainpage()], content=True)) self.assertTrue(page.has_content())
if __name__ == '__main__': with suppress(SystemExit): unittest.main()