jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
Update archivebot for py3

Bug: T257399
Change-Id: I2bd82f15c6b67cb22a963d2d2a9a942007c0ade7
---
M scripts/archivebot.py
1 file changed, 39 insertions(+), 39 deletions(-)

diff --git a/scripts/archivebot.py b/scripts/archivebot.py
index eddf7cf..9e9adcb 100755
--- a/scripts/archivebot.py
+++ b/scripts/archivebot.py
@@ -93,7 +93,6 @@
#
# Distributed under the terms of the MIT license.
#
-from __future__ import absolute_import, division, unicode_literals

import datetime
import locale
@@ -105,6 +104,7 @@
from collections import OrderedDict
from hashlib import md5
from math import ceil
+from typing import Any, List, Optional, Pattern, Set, Tuple

import pywikibot

@@ -114,6 +114,9 @@
to_local_digits)
from pywikibot.tools import issue_deprecation_warning, FrozenDict

+
+ShouldArchive = Optional[Tuple[str, str]]
+
ZERO = datetime.timedelta(0)

MW_KEYS = FrozenDict({
@@ -160,7 +163,7 @@
"""


-def str2localized_duration(site, string):
+def str2localized_duration(site, string) -> str:
"""
Localise a shorthand duration.

@@ -177,7 +180,7 @@
return to_local_digits(string, site.code)


-def str2time(string, timestamp=None):
+def str2time(string, timestamp=None) -> datetime.timedelta:
"""
Return a timedelta for a shorthand duration.

@@ -192,7 +195,6 @@
used by years
@type timestamp: datetime.datetime
@return: the corresponding timedelta object
- @rtype: datetime.timedelta
"""
key, duration = checkstr(string)

@@ -218,7 +220,7 @@
return datetime.timedelta(days=days)


-def checkstr(string):
+def checkstr(string) -> Tuple[str, str]:
"""
Return the key and duration extracted from the string.

@@ -230,7 +232,6 @@
1y - 1 year
@type string: str
@return: key and duration extracted form the string
- @rtype: (str, str)
"""
key = string[-1]
if string.isdigit():
@@ -244,7 +245,7 @@
return key, duration


-def str2size(string):
+def str2size(string) -> Tuple[int, str]:
"""
Return a size for a shorthand size.

@@ -254,7 +255,6 @@
2M - 2 megabytes
Returns a tuple (size,unit), where size is an integer and unit is
'B' (bytes) or 'T' (threads).
-
"""
r = re.search(r'(\d+) *([BkKMT]?)', string)
if not r:
@@ -270,7 +270,7 @@
return val, unit


-def template_title_regex(tpl_page):
+def template_title_regex(tpl_page) -> Pattern:
"""
Return a regex that matches to variations of the template title.

@@ -293,7 +293,7 @@
return re.compile(r'(?:(?:%s):)%s%s' % ('|'.join(ns), marker, title))


-def calc_md5_hexdigest(txt, salt):
+def calc_md5_hexdigest(txt, salt) -> str:
"""Return md5 hexdigest computed from text and salt."""
s = md5()
s.update(salt.encode('utf-8'))
@@ -307,24 +307,24 @@

"""Class building a UTC tzinfo object."""

- def utcoffset(self, dt):
+ def utcoffset(self, dt) -> datetime.timedelta:
"""Subclass implementation, return timedelta(0)."""
return ZERO

- def tzname(self, dt):
+ def tzname(self, dt) -> str:
"""Subclass implementation."""
return 'UTC'

- def dst(self, dt):
+ def dst(self, dt) -> datetime.timedelta:
"""Subclass implementation, return timedelta(0)."""
return ZERO

- def __repr__(self):
+ def __repr__(self) -> str:
"""Return a string representation."""
return '{}()'.format(self.__class__.__name__)


-class DiscussionThread(object):
+class DiscussionThread:

"""
An object representing a discussion thread on a page.
@@ -337,7 +337,7 @@
:Reply, etc. ~~~~
"""

- def __init__(self, title, now, timestripper):
+ def __init__(self, title, now, timestripper) -> None:
"""Initializer."""
self.title = title
self.now = now
@@ -346,12 +346,12 @@
self.content = ''
self.timestamp = None

- def __repr__(self):
+ def __repr__(self) -> str:
"""Return a string representation."""
return '{}("{}",{} bytes)'.format(self.__class__.__name__, self.title,
len(self.content.encode('utf-8')))

- def feed_line(self, line):
+ def feed_line(self, line) -> None:
"""Add a line to the content and find the newest timestamp."""
if not self.content and not line:
return
@@ -365,21 +365,20 @@
if timestamp:
self.timestamp = max(self.timestamp, timestamp)

- def size(self):
+ def size(self) -> int:
"""Return size of discussion thread."""
return len(self.title.encode('utf-8')) + len(
self.content.encode('utf-8')) + 12

- def to_text(self):
+ def to_text(self) -> str:
"""Return wikitext discussion thread."""
return '== {} ==\n\n{}'.format(self.title, self.content)

- def should_be_archived(self, archiver):
+ def should_be_archived(self, archiver) -> ShouldArchive:
"""
Check whether thread has to be archived.

@return: the archivation reason as a tuple of localization args
- @rtype: tuple
"""
# Archived by timestamp
algo = archiver.get_attr('algo')
@@ -404,7 +403,7 @@
Feed threads to it and run an update() afterwards.
"""

- def __init__(self, source, archiver, params=None):
+ def __init__(self, source, archiver, params=None) -> None:
"""Initializer."""
super(DiscussionPage, self).__init__(source)
self.threads = []
@@ -431,7 +430,7 @@
if self.params:
self.header = self.header % self.params

- def load_page(self):
+ def load_page(self) -> None:
"""Load the page to be archived and break it up into threads."""
self.header = ''
self.threads = []
@@ -466,7 +465,7 @@
pywikibot.output('{} thread(s) found on {}'
.format(len(self.threads), self))

- def feed_thread(self, thread, max_archive_size=(250 * 1024, 'B')):
+ def feed_thread(self, thread, max_archive_size=(250 * 1024, 'B')) -> bool:
"""Check whether archive size exceeded."""
self.threads.append(thread)
self.archived_threads += 1
@@ -478,12 +477,12 @@
self.full = True
return self.full

- def size(self):
+ def size(self) -> int:
"""Return size of talk page threads."""
return len(self.header.encode('utf-8')) + sum(t.size()
for t in self.threads)

- def update(self, summary, sort_threads=False):
+ def update(self, summary, sort_threads=False) -> None:
"""Recombine threads and save page."""
if sort_threads:
pywikibot.output('Sorting threads...')
@@ -498,13 +497,13 @@
self.save(summary)


-class PageArchiver(object):
+class PageArchiver:

"""A class that encapsulates all archiving methods."""

algo = 'none'

- def __init__(self, page, template, salt, force=False):
+ def __init__(self, page, template, salt, force=False) -> None:
"""Initializer.

param page: a page object to be archived
@@ -538,34 +537,34 @@
for n, (_long, _short) in enumerate(self.site.months_names):
self.month_num2orig_names[n + 1] = {'long': _long, 'short': _short}

- def get_attr(self, attr, default=''):
+ def get_attr(self, attr, default='') -> Any:
"""Get an archiver attribute."""
return self.attributes.get(attr, [default])[0]

- def set_attr(self, attr, value, out=True):
+ def set_attr(self, attr, value, out=True) -> None:
"""Set an archiver attribute."""
if attr == 'archive':
value = value.replace('_', ' ')
self.attributes[attr] = [value, out]

- def saveables(self):
+ def saveables(self) -> List[str]:
"""Return a list of saveable attributes."""
return [a for a in self.attributes if self.attributes[a][1]
and a != 'maxage']

- def attr2text(self):
+ def attr2text(self) -> str:
"""Return a template with archiver saveable attributes."""
return '{{%s\n%s\n}}' \
% (self.tpl.title(with_ns=(self.tpl.namespace() != 10)),
'\n'.join('|{} = {}'.format(a, self.get_attr(a))
for a in self.saveables()))

- def key_ok(self):
+ def key_ok(self) -> bool:
"""Return whether key is valid."""
hexdigest = calc_md5_hexdigest(self.page.title(), self.salt)
return self.get_attr('key') == hexdigest

- def load_config(self):
+ def load_config(self) -> None:
"""Load and validate archiver template."""
pywikibot.output('Looking for: {{%s}} in %s' % (self.tpl.title(),
self.page))
@@ -586,7 +585,8 @@
if not self.get_attr('archive', ''):
raise MissingConfigError('Missing argument "archive" in template')

- def feed_archive(self, archive, thread, max_archive_size, params=None):
+ def feed_archive(self, archive, thread, max_archive_size, params=None
+ ) -> bool:
"""
Feed the thread to one of the archives.

@@ -604,7 +604,7 @@
self.archives[title] = DiscussionPage(archive, self, params)
return self.archives[title].feed_thread(thread, max_archive_size)

- def analyze_page(self):
+ def analyze_page(self) -> Set[ShouldArchive]:
"""Analyze DiscussionPage."""
max_arch_size = str2size(self.get_attr('maxarchivesize'))
arch_counter = int(self.get_attr('counter', '1'))
@@ -653,7 +653,7 @@
self.page.threads.append(t)
return whys

- def run(self):
+ def run(self) -> None:
"""Process a single DiscussionPage object."""
if not self.page.botMayEdit():
return
@@ -711,7 +711,7 @@
self.page.update(comment)


-def main(*args):
+def main(*args) -> None:
"""
Process command line arguments and invoke bot.


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

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I2bd82f15c6b67cb22a963d2d2a9a942007c0ade7
Gerrit-Change-Number: 611620
Gerrit-PatchSet: 5
Gerrit-Owner: JJMC89 <JJMC89.Wikimedia@gmail.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged