jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/736001 )
Change subject: [IMPR] Provide a public counter with BaseBot ......................................................................
[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(-)
Approvals: JJMC89: Looks good to me, approved jenkins-bot: Verified
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:
pywikibot-commits@lists.wikimedia.org