jenkins-bot submitted this change.

View Change

Approvals: JJMC89: Looks good to me, approved jenkins-bot: Verified
[IMPR] Provide a public counter with BaseBot

BaseBot has 3 private counters but a lot of scripts uses them. Therefore
provide a counter attribute which holds all counters as collections.Counter.

- Add a counter attribute to BaseBot
- deprecate old counters
- update counter's usage in framework and scripts
- update tests

Change-Id: Iebfc770f21cf46538d7dbcff6f34ecc828729ac1
---
M pywikibot/bot.py
M pywikibot/specialbots/_upload.py
M scripts/category.py
M scripts/nowcommons.py
M scripts/parser_function_count.py
M scripts/redirect.py
M scripts/reflinks.py
M tests/bot_tests.py
8 files changed, 69 insertions(+), 36 deletions(-)

diff --git a/pywikibot/bot.py b/pywikibot/bot.py
index d439154..3248a79 100644
--- a/pywikibot/bot.py
+++ b/pywikibot/bot.py
@@ -99,6 +99,7 @@
import warnings
import webbrowser

+from collections import Counter
from collections.abc import Generator
from contextlib import closing
from functools import wraps
@@ -1246,6 +1247,10 @@
treat() or run(), NotImplementedError is raised.

For bot options handling refer OptionHandler class above.
+
+ .. versionchanged:: 7.0
+ A counter attribute is provided which is a collections.Counter;
+ The default counters are 'read', 'write' and 'skip'.
"""

# Handler configuration.
@@ -1279,13 +1284,41 @@
self.available_options.update(self.update_options)
super().__init__(**kwargs)

- self._treat_counter = 0
- self._save_counter = 0
- self._skip_counter = 0
+ self.counter = Counter()
self._generator_completed = False
self.treat_page_type = pywikibot.page.BasePage # default type

@property
+ @deprecated("self.counter['read']", since='7.0.0')
+ def _treat_counter(self):
+ return self.counter['read']
+
+ @_treat_counter.setter
+ @deprecated("self.counter['read']", since='7.0.0')
+ def _treat_counter(self, value):
+ self.counter['read'] = value
+
+ @property
+ @deprecated("self.counter['write']", since='7.0.0')
+ def _save_counter(self):
+ return self.counter['write']
+
+ @_save_counter.setter
+ @deprecated("self.counter['write']", since='7.0.0')
+ def _save_counter(self, value):
+ self.counter['write'] = value
+
+ @property
+ @deprecated("self.counter['skip']", since='7.0.0')
+ def _skip_counter(self):
+ return self.counter['skip']
+
+ @_skip_counter.setter
+ @deprecated("self.counter['skip']", since='7.0.0')
+ def _skip_counter(self, value):
+ self.counter['skip'] = value
+
+ @property
def current_page(self) -> 'pywikibot.page.BasePage':
"""Return the current working page as a property."""
assert self._current_page is not None
@@ -1408,7 +1441,7 @@

try:
func(*args, **kwargs)
- self._save_counter += 1
+ self.counter['save'] += 1
except PageSaveRelatedError as e:
if not ignore_save_related_errors:
raise
@@ -1464,12 +1497,10 @@
# wait until pending threads finished but don't close the queue
pywikibot.stopme()

- pywikibot.output('\n{} pages read'
- '\n{} pages written'
- '\n{} pages skipped'
- .format(self._treat_counter,
- self._save_counter,
- self._skip_counter))
+ pywikibot.output('\n{read} pages read'
+ '\n{write} pages written'
+ '\n{skip} pages skipped'
+ .format_map(self.counter))

if hasattr(self, '_start_ts'):
write_delta = pywikibot.Timestamp.now() - self._start_ts
@@ -1481,12 +1512,14 @@
else:
pywikibot.output('Execution time: {} seconds'
.format(write_delta.seconds))
- if self._treat_counter:
+
+ if self.counter['read']:
pywikibot.output('Read operation time: {:.1f} seconds'
- .format(read_seconds / self._treat_counter))
- if self._save_counter:
- pywikibot.output('Write operation time: {:.1f} seconds'
- .format(write_seconds / self._save_counter))
+ .format(read_seconds / self.counter['read']))
+ if self.counter['write']:
+ pywikibot.output(
+ 'Write operation time: {:.1f} seconds'
+ .format(write_seconds / self.counter['write']))

# exc_info contains exception from self.run() while terminating
exc_info = sys.exc_info()
@@ -1578,12 +1611,12 @@
page.__class__.__name__))

if self.skip_page(page):
- self._skip_counter += 1
+ self.counter['skip'] += 1
continue

# Process the page
self.treat(page)
- self._treat_counter += 1
+ self.counter['read'] += 1

self._generator_completed = True
except QuitKeyboardInterrupt:
diff --git a/pywikibot/specialbots/_upload.py b/pywikibot/specialbots/_upload.py
index 1aff167..8b0aca8 100644
--- a/pywikibot/specialbots/_upload.py
+++ b/pywikibot/specialbots/_upload.py
@@ -438,7 +438,7 @@
# No warning, upload complete.
pywikibot.output('Upload of {} successful.'
.format(filename))
- self._save_counter += 1
+ self.counter['write'] += 1
return filename # data['filename']
pywikibot.output('Upload aborted.')
break
@@ -471,7 +471,7 @@
try:
for file_url in self.url:
self.upload_file(file_url)
- self._treat_counter += 1
+ self.counter['read'] += 1
except QuitKeyboardInterrupt:
pywikibot.output('\nUser quit {} bot run...'
.format(self.__class__.__name__))
diff --git a/scripts/category.py b/scripts/category.py
index d7a6756..e6523d1 100755
--- a/scripts/category.py
+++ b/scripts/category.py
@@ -1219,7 +1219,7 @@

def teardown(self) -> None:
"""Cleanups after run operation."""
- if self._generator_completed and not self._treat_counter:
+ if self._generator_completed and not self.counter['read']:
pywikibot.output('There are no pages or files in category {}.'
.format(self.cat_title))

diff --git a/scripts/nowcommons.py b/scripts/nowcommons.py
index 6bb1c41..ffed174 100755
--- a/scripts/nowcommons.py
+++ b/scripts/nowcommons.py
@@ -364,8 +364,8 @@
pywikibot.output(str(e[0]))
continue
else:
- self._treat_counter += 1
- if not self._treat_counter:
+ self.counter['read'] += 1
+ if not self.counter['read']:
pywikibot.output('No transcluded files found for {}.'
.format(self.nc_templates_list()[0]))
self.exit()
diff --git a/scripts/parser_function_count.py b/scripts/parser_function_count.py
index 84d008e..31f8ecc 100755
--- a/scripts/parser_function_count.py
+++ b/scripts/parser_function_count.py
@@ -133,10 +133,10 @@
def treat(self, page):
"""Process a single template."""
title = page.title()
- if (self._treat_counter + 1) % 50 == 0:
+ if (self.counter['read'] + 1) % 50 == 0:
# Don't let the poor user panic in front of a black screen.
pywikibot.output('{}th template is being processed: {}'
- .format(self._treat_counter + 1, title))
+ .format(self.counter['read'] + 1, title))

text = page.text
functions = self.regex.findall(text)
diff --git a/scripts/redirect.py b/scripts/redirect.py
index 8d5b332..a74bb3d 100755
--- a/scripts/redirect.py
+++ b/scripts/redirect.py
@@ -649,7 +649,7 @@
@param page: Page to be treated.
@type page: pywikibot.page.BasePage
"""
- if self._treat_counter >= self.opt.limit:
+ if self.counter['read'] >= self.opt.limit:
pywikibot.output('\nNumber of pages reached the limit. '
'Script terminated.')
self.generator.close()
diff --git a/scripts/reflinks.py b/scripts/reflinks.py
index da9a975..c37296e 100755
--- a/scripts/reflinks.py
+++ b/scripts/reflinks.py
@@ -732,15 +732,15 @@
ignore_save_related_errors=True,
ignore_server_errors=True)

- if not self._save_counter:
+ if not self.counter['write']:
return

- if self.opt.limit and self._save_counter >= self.opt.limit:
+ if self.opt.limit and self.counter['write'] >= self.opt.limit:
pywikibot.output('Edited {} pages, stopping.'
.format(self.opt.limit))
self.generator.close()

- if self.site_stop_page and self._save_counter % 20 == 0:
+ if self.site_stop_page and self.counter['write'] % 20 == 0:
self.stop_page = pywikibot.Page(self.site, self.site_stop_page)
if self.stop_page.exists():
pywikibot.output(color_format(
diff --git a/tests/bot_tests.py b/tests/bot_tests.py
index d387c37..06ad46f 100644
--- a/tests/bot_tests.py
+++ b/tests/bot_tests.py
@@ -75,7 +75,7 @@
self._bot.opt.always = True
self._original = self._bot._save_page
self._bot._save_page = self.bot_save
- self._old_counter = self._bot._save_counter
+ self._old_counter = self._bot.counter['write']

def setUp(self):
"""Set up test by resetting the counters."""
@@ -85,20 +85,20 @@

def tearDown(self):
"""Tear down by asserting the counters."""
- self.assertEqual(self._bot._save_counter,
+ self.assertEqual(self._bot.counter['write'],
self._old_counter + self.assert_saves)
self.assertEqual(self.save_called, self.assert_saves)
super().tearDown()

def bot_save(self, page, func, *args, **kwargs):
"""Handle when bot's userPut was called."""
- self.assertGreaterEqual(self._bot._save_counter, 0)
- old_counter = self._bot._save_counter
+ self.assertGreaterEqual(self._bot.counter['write'], 0)
+ old_counter = self._bot.counter['write']
old_local_cnt = self.save_called
result = self._original(page, self.page_save, *args, **kwargs)
- self.assertEqual(self._bot._save_counter, old_counter + 1)
+ self.assertEqual(self._bot.counter['write'], old_counter + 1)
self.assertEqual(self.save_called, old_local_cnt + 1)
- self.assertGreater(self._bot._save_counter, self._old_counter)
+ self.assertGreater(self._bot.counter['write'], self._old_counter)
return result

def page_save(self, *args, **kwargs):
@@ -168,8 +168,8 @@
# assertions as they are invalid anyway and hide the actual
# failed assertion
return
- self.assertEqual(self.bot._treat_counter, treated)
- self.assertEqual(self.bot._save_counter, written)
+ self.assertEqual(self.bot.counter['read'], treated)
+ self.assertEqual(self.bot.counter['write'], written)
if exception:
self.assertIs(exc, exception)
else:

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

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Iebfc770f21cf46538d7dbcff6f34ecc828729ac1
Gerrit-Change-Number: 736001
Gerrit-PatchSet: 3
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: D3r1ck01 <xsavitar.wiki@aol.com>
Gerrit-Reviewer: JJMC89 <JJMC89.Wikimedia@gmail.com>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged