jenkins-bot has submitted this change and it was merged.
Change subject: Update DeletionBot for undelete, implement tests ......................................................................
Update DeletionBot for undelete, implement tests
Update DeletionBot to support i18n messages for undelete, pass mark=True to Page.delete() if -always is set (gets rid of prompt)
Add tests for Site.undelete and the deletionbot script.
Fix issues with Page.undelete and Site.undelete_page when an error is raised if None is passed for revisions/timestamps.
Fix unhandled exception with delete.py if undeleting a page that exists,
Bug: T74733 Bug: T57255 Bug: T62572 Change-Id: Ie474bc289951492f7fabc5ea53f63732df7acfdf --- M pywikibot/page.py M pywikibot/site.py M scripts/delete.py M tests/__init__.py A tests/deletionbot_tests.py M tests/site_tests.py 6 files changed, 175 insertions(+), 13 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/page.py b/pywikibot/page.py index cc3012d..2fcb3a5 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -1607,8 +1607,11 @@ @type reason: basestring
""" - undelete_revs = [ts for ts, rev in self._deletedRevs.items() - if 'marked' in rev and rev['marked']] + if hasattr(self, "_deletedRevs"): + undelete_revs = [ts for ts, rev in self._deletedRevs.items() + if 'marked' in rev and rev['marked']] + else: + undelete_revs = [] if reason is None: pywikibot.warning('Not passing a reason for undelete() is deprecated.') pywikibot.output(u'Undeleting %s.' % (self.title(asLink=True))) diff --git a/pywikibot/site.py b/pywikibot/site.py index 6fa32a7..362f7a3 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -4198,9 +4198,14 @@ """ token = self.tokens['undelete'] self.lock_page(page) - req = api.Request(site=self, action="undelete", token=token, - title=page.title(withSection=False), - timestamps=revisions, reason=reason) + + if revisions is None: + req = api.Request(site=self, action='undelete', token=token, + title=page.title(withSection=False), reason=reason) + else: + req = api.Request(site=self, action='undelete', token=token, + title=page.title(withSection=False), + timestamps=revisions, reason=reason) try: req.submit() except api.APIError as err: diff --git a/scripts/delete.py b/scripts/delete.py index fe4f1b6..93f6f8a 100644 --- a/scripts/delete.py +++ b/scripts/delete.py @@ -64,13 +64,17 @@ self.summary = summary
def treat(self, page): - """Delete one page from the generator.""" + """Process one page from the generator.""" self.current_page = page if self.getOption('undelete'): - page.undelete(self.summary) + if page.exists(): + pywikibot.output(u'Skipping: %s already exists.' % page) + else: + page.undelete(self.summary) else: if page.exists(): - page.delete(self.summary, not self.getOption('always')) + page.delete(self.summary, not self.getOption('always'), + self.getOption('always')) else: pywikibot.output(u'Skipping: %s does not exist.' % page)
@@ -95,6 +99,7 @@ mysite = pywikibot.Site()
for arg in local_args: + if arg == '-always': options['always'] = True elif arg.startswith('-summary'): @@ -115,21 +120,23 @@ pageName = arg[found:]
if not summary: + un = 'un' if 'undelete' in options else '' if pageName: if arg.startswith('-cat') or arg.startswith('-subcats'): summary = i18n.twtranslate(mysite, 'delete-from-category', {'page': pageName}) elif arg.startswith('-links'): - summary = i18n.twtranslate(mysite, 'delete-linked-pages', + summary = i18n.twtranslate(mysite, un + 'delete-linked-pages', {'page': pageName}) elif arg.startswith('-ref'): summary = i18n.twtranslate(mysite, 'delete-referring-pages', {'page': pageName}) elif arg.startswith('-imageused'): - summary = i18n.twtranslate(mysite, 'delete-images', + summary = i18n.twtranslate(mysite, un + 'delete-images', {'page': pageName}) elif arg.startswith('-file'): - summary = i18n.twtranslate(mysite, 'delete-from-file') + summary = i18n.twtranslate(mysite, un + 'delete-from-file') + generator = genFactory.getCombinedGenerator() # We are just deleting pages, so we have no need of using a preloading # page generator to actually get the text of those pages. diff --git a/tests/__init__.py b/tests/__init__.py index bd6e9c5..2634a8b 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -92,6 +92,7 @@ 'script', 'archivebot', 'data_ingestion', + 'deletionbot', 'cache', ]
diff --git a/tests/deletionbot_tests.py b/tests/deletionbot_tests.py new file mode 100644 index 0000000..7c0d893 --- /dev/null +++ b/tests/deletionbot_tests.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +"""Tests for scripts/delete.py.""" +# +# (C) Pywikibot team, 2014 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id$' + +import pywikibot +import pywikibot.page + +from scripts import delete + +from tests.aspects import unittest, TestCase + + +class TestDeletionBotWrite(TestCase): + + """Test deletionbot script.""" + + family = 'test' + code = 'test' + + sysop = True + write = True + + def test_delete(self): + """Test deletionbot on the test wiki.""" + site = self.get_site() + cat = pywikibot.Category(site, 'Pywikibot Delete Test') + delete.main('-cat:Pywikibot_Delete_Test', '-always') + self.assertEqual(len(list(cat.members())), 0) + delete.main('-page:User:Unicodesnowman/DeleteTest1', '-always', + '-undelete', '-summary=pywikibot unit tests') + delete.main('-page:User:Unicodesnowman/DeleteTest2', '-always', + '-undelete', '-summary=pywikibot unit tests') + self.assertEqual(len(list(cat.members())), 2) + + def test_undelete_existing(self): + """Test undeleting an existing page.""" + site = self.get_site() + p1 = pywikibot.Page(site, 'User:Unicodesnowman/ExistingPage') + if not p1.exists(): + p1.text = 'pywikibot unit test page' + p1.save('unit test', botflag=True) + delete.main('-page:User:Unicodesnowman/ExistingPage', '-always', + '-undelete', '-summary=pywikibot unit tests') + + +class TestDeletionBotUser(TestCase): + + """Test deletionbot as a user (not sysop).""" + + family = 'test' + code = 'test' + + user = True + write = True + + def test_delete_mark(self): + site = self.get_site() + if site.username(sysop=True): + raise unittest.SkipTest('can't test mark with sysop account') + + p1 = pywikibot.Page(site, 'User:Unicodesnowman/DeleteMark') + if not p1.exists(): + p1.text = 'foo' + p1.save('unit test', botflag=True) + delete.main('-page:User:Unicodesnowman/DeleteMark', '-always', + '-summary=pywikibot unit test. Do NOT actually delete.') + self.assertEqual(p1.get(force=True), '{{delete|1=pywikibot unit test. ' + 'Do NOT actually delete.}}\nfoo') + p1.text = 'foo' + p1.save('unit test', botflag=True) + + +class TestDeletionBot(TestCase): + + """Test deletionbot with patching to make it non-write.""" + + family = 'test' + code = 'test' + + cached = True + + delete_args = [] + undelete_args = [] + + def setUp(self): + self._original_delete = pywikibot.Page.delete + self._original_undelete = pywikibot.Page.undelete + pywikibot.Page.delete = delete_dummy + pywikibot.Page.undelete = undelete_dummy + super(TestDeletionBot, self).setUp() + + def tearDown(self): + pywikibot.Page.delete = self._original_delete + pywikibot.Page.undelete = self._original_undelete + super(TestDeletionBot, self).tearDown() + + def test_dry(self): + delete.main('-page:Main Page', '-always', '-summary:foo') + self.assertEqual(self.delete_args, ['[[Main Page]]', 'foo', False, True]) + delete.main('-page:FoooOoOooO', '-always', '-summary:foo', '-undelete') + self.assertEqual(self.undelete_args, ['[[FoooOoOooO]]', 'foo']) + + +def delete_dummy(self, reason, prompt, mark): + TestDeletionBot.delete_args = [self.title(asLink=True), reason, prompt, mark] + + +def undelete_dummy(self, reason): + TestDeletionBot.undelete_args = [self.title(asLink=True), reason] + + +if __name__ == '__main__': + try: + unittest.main() + except SystemExit: + pass diff --git a/tests/site_tests.py b/tests/site_tests.py index 406e969..df5b2b1 100644 --- a/tests/site_tests.py +++ b/tests/site_tests.py @@ -1150,9 +1150,9 @@ total=5)
-class SiteProtectTestCase(DefaultSiteTestCase): +class TestSiteSysopWrite(TestCase):
- """Test site protect / unprotect using a sysop account.""" + """Test site sysop methods that require writing."""
family = 'test' code = 'test' @@ -1230,6 +1230,31 @@ protections={'edit': 'anInvalidValue'}, page=p1, reason='Pywikibot unit test')
+ def test_delete(self): + """Test the site.deletepage() and site.undelete_page() methods.""" + site = self.get_site() + p = pywikibot.Page(site, u'User:Unicodesnowman/DeleteTestSite') + # Verify state + if not p.exists(): + site.undelete_page(p, 'pywikibot unit tests') + + site.deletepage(p, reason='pywikibot unit tests') + self.assertRaises(pywikibot.NoPage, p.get, force=True) + + site.undelete_page(p, 'pywikibot unit tests', + revisions=[u'2014-12-21T06:07:47Z', + u'2014-12-21T06:07:31Z']) + + revs = list(p.getVersionHistory()) + self.assertEqual(len(revs), 2) + self.assertEqual(revs[0].revid, 219995) + self.assertEqual(revs[1].revid, 219994) + + site.deletepage(p, reason='pywikibot unit tests') + site.undelete_page(p, 'pywikibot unit tests') + revs = list(p.getVersionHistory()) + self.assertTrue(len(revs) > 2) +
class SiteUserTestCase2(DefaultSiteTestCase):
pywikibot-commits@lists.wikimedia.org