jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/708872 )
Change subject: [IMPR] date.py type hints
......................................................................
[IMPR] date.py type hints
Bug: T286403
Change-Id: Ie6d26c20b9a5f83c37c5c8fbc01a36a569e7266b
---
M pywikibot/backports.py
M pywikibot/date.py
2 files changed, 141 insertions(+), 93 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/backports.py b/pywikibot/backports.py
index 00f880a..9569b2a 100644
--- a/pywikibot/backports.py
+++ b/pywikibot/backports.py
@@ -67,6 +67,7 @@
Dict,
FrozenSet,
Iterable,
+ Iterator,
List,
Mapping,
Match,
@@ -76,7 +77,7 @@
Tuple,
)
else:
- from collections.abc import Callable, Iterable, Mapping, Sequence
+ from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
from re import Match, Pattern
Dict = dict # type: ignore[misc]
FrozenSet = frozenset # type: ignore[misc]
diff --git a/pywikibot/date.py b/pywikibot/date.py
index 5abb2d4..bd82a7d 100644
--- a/pywikibot/date.py
+++ b/pywikibot/date.py
@@ -8,16 +8,28 @@
import datetime
import re
from collections import defaultdict
-from collections.abc import Mapping, MutableMapping
+from collections.abc import MutableMapping
from contextlib import suppress
from functools import singledispatch
from string import digits as _decimalDigits # noqa: N812
+from typing import Optional, Union
+import pywikibot.site
from pywikibot import Site
-from pywikibot.backports import Tuple
from pywikibot.textlib import NON_LATIN_DIGITS
from pywikibot.tools import deprecated, first_lower, first_upper
+from pywikibot.backports import (
+ Any,
+ Callable,
+ Dict,
+ Iterator,
+ List,
+ Mapping,
+ Pattern,
+ Sequence,
+ Tuple,
+)
#
# Different collections of well known formats
@@ -42,10 +54,22 @@
yearFormats = ['YearAD', 'YearBC']
millFormats = ['MillenniumAD', 'MillenniumBC']
snglValsFormats = ['CurrEvents']
+tuplst_type = List[Tuple[Callable[[Union[int, str]], Any],
+ Callable[[Union[int, str]], bool]]]
+encf_type = Callable[[int], Union[int, Sequence[int]]]
+decf_type = Callable[[Sequence[int]], int]
+
+# decoders are three value tuples, with an optional fourth to represent a
+# required number of digits
+
+decoder_type = Union[
+ Tuple[str, Callable[[int], str], Callable[[str], int]],
+ Tuple[str, Callable[[int], str], Callable[[str], int], int]
+]
@singledispatch
-def multi(value: int, tuplst):
+def multi(value: int, tuplst: tuplst_type) -> Any:
"""
Run multiple pattern checks for the same entry.
@@ -65,7 +89,7 @@
@multi.register(str)
-def _(value: str, tuplst):
+def _(value: str, tuplst: tuplst_type) -> Any:
# Try all functions, and test result against predicates
for func, pred in tuplst:
try:
@@ -81,12 +105,12 @@
# Helper functions that aid with single value no corrections encoding/decoding.
# Various filters are item dependent.
#
-def dh_noConv(value, pattern, limit):
+def dh_noConv(value: int, pattern: str, limit: Callable[[int], bool]) -> str:
"""Helper for decoding an integer value, no conversion, no rounding."""
return dh(value, pattern, lambda i: i, decSinglVal, limit)
-def dh_dayOfMnth(value, pattern):
+def dh_dayOfMnth(value: int, pattern: str) -> str:
"""
Helper for decoding a single integer value.
@@ -97,7 +121,7 @@
return dh_noConv(value, pattern, formatLimits[dayMnthFmts[0]][0])
-def dh_mnthOfYear(value, pattern):
+def dh_mnthOfYear(value: int, pattern: str) -> str:
"""
Helper for decoding a single integer value.
@@ -107,7 +131,7 @@
return dh_noConv(value, pattern, _formatLimit_MonthOfYear[0])
-def dh_decAD(value, pattern):
+def dh_decAD(value: int, pattern: str) -> str:
"""
Helper for decoding a single integer value.
@@ -117,7 +141,7 @@
formatLimits['DecadeAD'][0])
-def dh_decBC(value, pattern):
+def dh_decBC(value: int, pattern: str) -> str:
"""
Helper for decoding a single integer value.
@@ -127,7 +151,7 @@
formatLimits['DecadeBC'][0])
-def dh_yearBC(value, pattern):
+def dh_yearBC(value: int, pattern: str) -> str:
"""Helper for decoding a year value.
The value should have no conversion, no rounding, limits to 3000.
@@ -135,7 +159,7 @@
return dh_noConv(value, pattern, formatLimits['YearBC'][0])
-def dh_yearAD(value, pattern):
+def dh_yearAD(value: int, pattern: str) -> str:
"""Helper for decoding a year value.
The value should have no conversion, no rounding, limits to 3000.
@@ -143,7 +167,7 @@
return dh_noConv(value, pattern, formatLimits['YearAD'][0])
-def dh_simpleYearAD(value):
+def dh_simpleYearAD(value: int) -> str:
"""Helper for decoding a single integer value.
This value should be representing a year with no extra symbols.
@@ -151,47 +175,48 @@
return dh_yearAD(value, '%d')
-def dh_number(value, pattern):
+def dh_number(value: int, pattern: str) -> str:
"""Helper for decoding a number."""
return dh_noConv(value, pattern, formatLimits['Number'][0])
-def dh_centuryAD(value, pattern):
+def dh_centuryAD(value: int, pattern: str) -> str:
"""Helper for decoding an AD century."""
return dh_noConv(value, pattern, formatLimits['CenturyAD'][0])
-def dh_centuryBC(value, pattern):
+def dh_centuryBC(value: int, pattern: str) -> str:
"""Helper for decoding an BC century."""
return dh_noConv(value, pattern, formatLimits['CenturyBC'][0])
-def dh_millenniumAD(value, pattern):
+def dh_millenniumAD(value: int, pattern: str) -> str:
"""Helper for decoding an AD millennium."""
return dh_noConv(value, pattern, formatLimits['MillenniumAD'][0])
-def dh_millenniumBC(value, pattern):
+def dh_millenniumBC(value: int, pattern: str) -> str:
"""Helper for decoding an BC millennium."""
return dh_noConv(value, pattern, formatLimits['MillenniumBC'][0])
-def decSinglVal(v):
+def decSinglVal(v: Sequence[Any]) -> Any:
"""Return first item in list v."""
return v[0]
-def encDec0(i):
+def encDec0(i: int) -> int:
"""Round to the nearest decade, decade starts with a '0'-ending year."""
return (i // 10) * 10
-def encDec1(i):
+def encDec1(i: int) -> int:
"""Round to the nearest decade, decade starts with a '1'-ending year."""
return encDec0(i) + 1
-def slh(value, lst):
+@singledispatch
+def slh(value: int, lst: Sequence[str]) -> str:
"""Helper function for simple list value matching.
!!!!! The index starts at 1, so 1st element has index 1, not 0 !!!!!
@@ -207,29 +232,45 @@
formats['MonthName']['en']('anything else') => raise ValueError
"""
- return lst.index(value) + 1 if isinstance(value, str) else lst[value - 1]
+ return lst[value - 1]
-def dh_singVal(value, match):
+(a)slh.register(str) # type: ignore
+def _(value: str, lst: Sequence[str]) -> int:
+ return lst.index(value) + 1
+
+
+@singledispatch
+def dh_singVal(value: int, match: str) -> str:
"""Helper function to match a single value to a constant."""
return dh_constVal(value, 0, match)
-def dh_constVal(value, ind, match):
+(a)dh_singVal.register(str) # type: ignore
+def _(value: str, match: str) -> int:
+ return dh_constVal(value, 0, match) # type: ignore[return-value]
+
+
+@singledispatch
+def dh_constVal(value: int, ind: int, match: str) -> str:
"""Helper function to match a single value to a constant.
formats['CurrEvents']['en'](ind) => 'Current Events'
formats['CurrEvents']['en']('Current Events') => ind
"""
- if isinstance(value, str):
- if value == match:
- return ind
- elif value == ind:
+ if value == ind:
return match
raise ValueError('unknown value {}'.format(value))
-def alwaysTrue(x):
+(a)dh_constVal.register(str) # type: ignore
+def _(value: str, ind: int, match: str) -> int:
+ if value == match:
+ return ind
+ raise ValueError('unknown value {}'.format(value))
+
+
+def alwaysTrue(x: Any) -> bool:
"""
Return True, always.
@@ -237,12 +278,11 @@
:param x: not used
:return: True
- :rtype: bool
"""
return True
-def monthName(lang, ind):
+def monthName(lang: str, ind: int) -> str:
"""Return the month name for a language."""
return formats['MonthName'][lang](ind)
@@ -273,12 +313,14 @@
_guLocalToDigits = {ord(_guDigits[i]): str(i) for i in range(10)}
-def intToLocalDigitsStr(value, digitsToLocalDict):
+def intToLocalDigitsStr(value: int, digitsToLocalDict: Mapping[int, str]
+ ) -> str:
"""Encode an integer value into a textual form."""
return str(value).translate(digitsToLocalDict)
-def localDigitsStrToInt(value, digitsToLocalDict, localToDigitsDict):
+def localDigitsStrToInt(value: str, digitsToLocalDict: Mapping[int, str],
+ localToDigitsDict: Mapping[int, str]) -> int:
"""Convert digits to integer."""
# First make sure there are no real digits in the string
tmp = value.translate(digitsToLocalDict) # Test
@@ -294,14 +336,14 @@
'XXVII', 'XXVIII', 'XXIX', 'XXX']
-def intToRomanNum(i):
+def intToRomanNum(i: int) -> str:
"""Convert integer to roman numeral."""
if i >= len(_romanNumbers):
raise IndexError('Roman value {} is not defined'.format(i))
return _romanNumbers[i]
-def romanNumToInt(v):
+def romanNumToInt(v: str) -> int:
"""Convert roman numeral to integer."""
return _romanNumbers.index(v)
@@ -310,7 +352,7 @@
# (from int to a str) and decoder (from str to an int)
_digitDecoders = {
# %% is a %
- '%': '%',
+ '%': '%', # type: ignore
# %d is a decimal
'd': (_decimalDigits, str, int),
# %R is a roman numeral. This allows for only the simplest linear
@@ -339,7 +381,7 @@
# %T is a year in TH: -- all years are shifted: 2005 => 'พ.ศ. 2548'
'T': (_decimalDigits, lambda v: str(v + 543),
lambda v: int(v) - 543),
-}
+} # type: Dict[str, decoder_type]
# Allows to search for '(%%)|(%d)|(%R)|...", and allows one digit 1-9 to set
# the size of zero-padding for numbers
@@ -350,7 +392,9 @@
_escPtrnCache2 = {}
-def escapePattern2(pattern):
+def escapePattern2(pattern: str
+ ) -> Tuple[Pattern[str], str,
+ List[Union[decoder_type, decoder_type]]]:
"""
Convert a string pattern into a regex expression and cache.
@@ -358,7 +402,7 @@
Returns a compiled regex object and a list of digit decoders.
"""
@singledispatch
- def decode(dec: tuple, subpattern: str, newpattern: str,
+ def decode(dec: decoder_type, subpattern: str, newpattern: str,
strpattern: str) -> Tuple[str, str]:
if len(subpattern) == 3:
@@ -366,7 +410,7 @@
newpattern += '([%s]{%s})' % (dec[0], subpattern[1])
# add the number of required digits as the last (4th)
# part of the tuple
- decoders.append(dec + (int(s[1]),))
+ decoders.append(dec + (int(s[1]),)) # type: ignore
else:
newpattern += '([{}]+)'.format(dec[0])
decoders.append(dec)
@@ -390,7 +434,7 @@
if pattern not in _escPtrnCache2:
newPattern = '' # match starts at the beginning of the string
strPattern = ''
- decoders = []
+ decoders = [] # type: List[decoder_type]
for s in _reParameters.split(pattern):
if s is None:
continue
@@ -412,7 +456,8 @@
@singledispatch
-def dh(value: int, pattern, encf, decf, filter=None):
+def dh(value: int, pattern: str, encf: encf_type, decf: decf_type,
+ filter: Optional[Callable[[int], bool]] = None) -> str:
"""Function to help with year parsing.
Usually it will be used as a lambda call in a map::
@@ -452,18 +497,20 @@
'parameter count ({}) does not match decoder count ({})'
.format(len(params), len(decoders)))
# convert integer parameters into their textual representation
- params = tuple(_make_parameter(decoders[i], param)
- for i, param in enumerate(params))
- return strPattern % params
+ str_params = tuple(_make_parameter(decoders[i], param)
+ for i, param in enumerate(params))
+ return strPattern % str_params
assert len(decoders) == 1, (
'A single parameter does not match {} decoders.'
.format(len(decoders)))
# convert integer parameter into its textual representation
+ assert isinstance(params, int)
return strPattern % _make_parameter(decoders[0], params)
-(a)dh.register(str)
-def _(value: str, pattern, encf, decf, filter=None):
+(a)dh.register(str) # type: ignore
+def _(value: str, pattern: str, encf: encf_type, decf: decf_type,
+ filter: Optional[Callable[[int], bool]] = None) -> int:
compPattern, strPattern, decoders = escapePattern2(pattern)
m = compPattern.match(value)
if m:
@@ -483,13 +530,14 @@
raise ValueError("reverse encoding didn't match")
-def _make_parameter(decoder, param):
+def _make_parameter(decoder: decoder_type, param: int) -> str:
newValue = decoder[1](param)
- if len(decoder) == 4 and len(newValue) < decoder[3]:
+ required_digits = decoder[3] if len(decoder) == 4 else None # type: ignore
+ if required_digits is not None and len(newValue) < required_digits:
# force parameter length by taking the first digit in the list and
# repeating it required number of times
# This converts "205" into "0205" for "%4d"
- newValue = decoder[0][0] * (decoder[3] - len(newValue)) + newValue
+ newValue = decoder[0][0] * (required_digits - len(newValue)) + newValue
return newValue
@@ -505,7 +553,7 @@
# This is useful when trying to decide if a certain article is a localized date
# or not, or generating dates.
# See dh() for additional information.
-class MonthNames(Mapping):
+class MonthNames(Mapping[str, Callable[[int], str]]):
"""A Mapping which reads month names from MediaWiki messages."""
@@ -521,7 +569,8 @@
'zh': lambda v: slh(v, makeMonthList('%d月')),
}
- def __getitem__(self, lang):
+ def __getitem__(self, lang: str
+ ) -> Callable[[int], str]:
if lang not in self.months:
site = Site()
# may_long differs
@@ -533,15 +582,15 @@
return self.months[lang]
- def __iter__(self):
+ def __iter__(self) -> Iterator[str]:
return iter(self.months)
- def __len__(self):
+ def __len__(self) -> int:
"""Length of preloaded languages with all month names."""
return len(self.months)
-class MonthFormat(MutableMapping):
+class MonthFormat(MutableMapping): # type: ignore[type-arg]
"""A Mapping which creates months formats."""
@@ -607,19 +656,17 @@
'tl': ('{} %d', None),
}
- def __init__(self, index, format_key):
+ def __init__(self, index: int, format_key: str) -> None:
"""Initializer of MonthFormat mapping.
:param index: month number
- :type index: int
:param format_key: formats key like Day_January or Year_December
- :type format_key: str
"""
self.index = index
self.variant, _, self.month = format_key.partition('_')
- self.data = {}
+ self.data = {} # type: Dict[str, Callable[[int], str]]
- def __getitem__(self, key):
+ def __getitem__(self, key: str) -> Callable[[int], str]:
if key not in self.data:
if self.variant == 'Day':
pattern, ucase = self.day_formats.get(key, ('%d. {}', False))
@@ -635,24 +682,24 @@
elif ucase is False:
f = first_lower
else:
- f = str
+ f = str # type: ignore
month_pattern = pattern.format(f(monthName(key, self.index)))
expression = "lambda v: {}(v, '{}')".format(func, month_pattern)
self.data[key] = eval(expression)
return self.data[key]
- def __setitem__(self, key, value):
+ def __setitem__(self, key: str, value: Callable[[int], str]) -> None:
self.data[key] = value
- def __delitem__(self, key):
+ def __delitem__(self, key: str) -> None:
raise NotImplementedError("Deleting of key '{}' is not implemented"
.format(key))
- def __iter__(self):
+ def __iter__(self) -> Iterator[str]:
return iter(self.data)
- def __len__(self):
+ def __len__(self) -> int:
return len(self.data)
@@ -1617,19 +1664,22 @@
'yo': lambda v: dh_singVal(v, 'Current events'),
'zh': lambda v: dh_singVal(v, '新闻动态'),
},
-}
+} # type: Dict[str, Dict[str, Callable[[int], str]]]
-formats['MonthName'] = MonthNames()
+formats['MonthName'] = MonthNames() # type: ignore[assignment]
#
# Add auto-generated empty dictionaries for DayOfMonth and MonthOfYear articles
#
for index, day_of_month in enumerate(dayMnthFmts, 1):
- formats[day_of_month] = MonthFormat(index, day_of_month)
+ val = MonthFormat(index, day_of_month)
+ formats[day_of_month] = val # type: ignore[assignment]
for index, month_of_year in enumerate(yrMnthFmts, 1):
- formats[month_of_year] = MonthFormat(index, month_of_year)
+ val = MonthFormat(index, month_of_year)
+ formats[month_of_year] = val # type: ignore[assignment]
-def addFmt1(lang: str, isMnthOfYear, patterns):
+def addFmt1(lang: str, isMnthOfYear: bool,
+ patterns: Sequence[Optional[str]]) -> None:
"""Add 12 month formats for a specific type ('January', 'Feb.').
The function must accept one parameter for the ->int or ->string
@@ -1650,12 +1700,13 @@
'lambda v: dh_dayOfMnth(v, "{}")'.format(patterns[i]))
-def makeMonthList(pattern):
+def makeMonthList(pattern: str) -> List[str]:
"""Return a list of 12 elements based on the number of the month."""
return [pattern % m for m in range(1, 13)]
-def makeMonthNamedList(lang, pattern, makeUpperCase=None):
+def makeMonthNamedList(lang: str, pattern: str,
+ makeUpperCase: Optional[bool] = None) -> List[str]:
"""Create a list of 12 elements based on the name of the month.
The language-dependent month name is used as a formatting argument to the
@@ -1891,7 +1942,7 @@
formatLimits[month] = _formatLimit_MonthOfYear
-def _format_limit_dom(days):
+def _format_limit_dom(days: int) -> Tuple[Callable[[int], bool], int, int]:
"""Return day of month format limit."""
assert 29 <= days <= 31
return lambda v: 1 <= v <= days, 1, days + 1
@@ -1909,18 +1960,18 @@
formatLimits[dayMnthFmts[monthId]] = _format_limit_dom(30)
-def getAutoFormat(lang, title, ignoreFirstLetterCase=True):
+def getAutoFormat(lang: str, title: str, ignoreFirstLetterCase: bool = True
+ ) -> Tuple[Optional[str], Optional[str]]:
"""
Return first matching formatted date value.
:param lang: language code
:param title: value to format
:return: dictName ('YearBC', 'December', ...) and value (a year, date, ...)
- :rtype: tuple
"""
for dict_name, dictionary in formats.items():
with suppress(Exception):
- year = dictionary[lang](title)
+ year = dictionary[lang](title) # type: ignore
return dict_name, year
# sometimes the title may begin with an upper case while its listed as
# lower case, or the other way around
@@ -1940,51 +1991,51 @@
"""DEPRECATED. Format a date."""
- def __init__(self, site):
+ def __init__(self, site: Union[str, 'pywikibot.site.BaseSite']) -> None:
"""Initializer."""
self.site = site
- def __call__(self, m, d):
+ def __call__(self, m: int, d: int) -> str:
"""Return a formatted month and day."""
return format_date(m, d, self.site)
-def format_date(month, day, lang=None, year=2000):
+def format_date(month: int, day: int,
+ lang: Union[None, str, 'pywikibot.site.BaseSite'] = None,
+ year: int = 2000) -> str:
"""Format a date localized to given lang.
:param month: month in range of 1..12
:param day: day of month in range of 1..31
- :type day: int
:param lang: a site object or language key. Defaults to current site.
- :type lang: BaseSite or string
:param year: year for which the date is to be formatted. always 29 will be
given For February except the year is given. Default is leap year 2000.
- :type year: int
:return: localized date like "January 11"
- :rtype: str
:raises ValueError: Wrong day value; must be 1-28/29/30/31
:raises IllegalMonthError: bad month number; must be 1-12
"""
if not lang:
lang = Site().lang
elif hasattr(lang, 'lang'):
- lang = lang.lang
+ lang = lang.lang # type: ignore[union-attr]
max_day = calendar.monthrange(year, month)[1]
if not 1 <= day <= max_day:
raise ValueError(
'Wrong day value {day}; must be 1-{max_day}'
.format(day=day, max_day=max_day))
+ assert isinstance(lang, str)
return formats[dayMnthFmts[month - 1]][lang](day)
-def formatYear(lang, year):
+def formatYear(lang: str, year: int) -> str:
"""Return year name in a language."""
if year < 0:
return formats['YearBC'][lang](-year)
return formats['YearAD'][lang](year)
-def apply_month_delta(date, month_delta=1, add_overlap=False):
+def apply_month_delta(date: datetime.date, month_delta: int = 1,
+ add_overlap: bool = False) -> datetime.date:
"""
Add or subtract months from the date.
@@ -1999,14 +2050,10 @@
months are numbered consecutively beginning by 1.
:param date: The starting date
- :type date: date
:param month_delta: The amount of months added or subtracted.
- :type month_delta: int
:param add_overlap: Add any missing days to the date, increasing the month
once more.
- :type add_overlap: bool
:return: The end date
- :rtype: type of date
"""
if not isinstance(month_delta, int):
raise ValueError('Month delta must be an integer')
@@ -2021,9 +2068,9 @@
return new_date
-def get_month_delta(date1, date2):
+def get_month_delta(date1: datetime.date, date2: datetime.date) -> int:
"""
- Return the difference between to dates in months.
+ Return the difference between two dates in months.
It does only work on calendars with 12 months per year, and where the
months are consecutive and non-negative numbers.
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/708872
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ie6d26c20b9a5f83c37c5c8fbc01a36a569e7266b
Gerrit-Change-Number: 708872
Gerrit-PatchSet: 1
Gerrit-Owner: Damian <atagar1(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/707869 )
Change subject: [bugfix] site_tests.TestAlldeletedrevisionsAsUser fails
......................................................................
[bugfix] site_tests.TestAlldeletedrevisionsAsUser fails
This test only passed when the test user lacked any deleted revisions. This
both corrects that and provides more helpful output in the case of failures.
Bug: T287393
Change-Id: I5c04d8bc928472ceb15fc0f58130c2c20cabcff0
---
M tests/site_tests.py
1 file changed, 16 insertions(+), 13 deletions(-)
Approvals:
Xqt: Looks good to me, but someone else must approve
JJMC89: Looks good to me, approved
jenkins-bot: Verified
diff --git a/tests/site_tests.py b/tests/site_tests.py
index 56a9789..1ea2c8d 100644
--- a/tests/site_tests.py
+++ b/tests/site_tests.py
@@ -1604,22 +1604,25 @@
def setUpClass(cls):
"""Skip test if necessary."""
super().setUpClass()
- if cls.site.mw_version < '1.34':
- cls.skipTest(cls, 'site.alldeletedrevisions() needs mw 1.34')
+ if cls.site.mw_version < '1.25':
+ cls.skipTest(cls, 'site.alldeletedrevisions() needs mw 1.25')
def test_basic(self):
"""Test the site.alldeletedrevisions() method."""
mysite = self.get_site()
drev = list(mysite.alldeletedrevisions(user=mysite.user(), total=10))
- self.assertTrue(all(isinstance(data, dict)
- for data in drev))
- self.assertTrue(all('revisions' in data
- and isinstance(data['revisions'], dict)
- for data in drev))
- self.assertTrue(all('user' in rev
- and rev['user'] == mysite.user()
- for data in drev
- for rev in data))
+
+ if not drev:
+ self.skipTest('No deleted revisions available')
+
+ for data in drev:
+ with self.subTest(data=data):
+ self.assertIsInstance(data, dict)
+ self.assertIn('revisions', data)
+ self.assertIsInstance(data['revisions'], list)
+
+ for rev in data['revisions']:
+ self.assertEqual(mysite.user(), rev.get('user'))
def test_namespaces(self):
"""Test the site.alldeletedrevisions() method using namespaces."""
@@ -1763,8 +1766,8 @@
def test_prefix(self):
"""Test the site.alldeletedrevisions() method with prefix."""
mysite = self.get_site()
- if mysite.mw_version < '1.34':
- self.skipTest('site.alldeletedrevisions() needs mw 1.34')
+ if mysite.mw_version < '1.25':
+ self.skipTest('site.alldeletedrevisions() needs mw 1.25')
for data in mysite.alldeletedrevisions(prefix='John', total=5):
self.assertIsInstance(data, dict)
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/707869
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I5c04d8bc928472ceb15fc0f58130c2c20cabcff0
Gerrit-Change-Number: 707869
Gerrit-PatchSet: 3
Gerrit-Owner: Damian <atagar1(a)gmail.com>
Gerrit-Reviewer: JJMC89 <JJMC89.Wikimedia(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/708190 )
Change subject: [bugfix] Minor flake8 warning
......................................................................
[bugfix] Minor flake8 warning
For the last month or so I've gotten the following warning whenever I run
tox...
./tests/category_tests.py: line 163:9: H214: Use assertIn/NotIn(A, B) rather
than assertTrue/False(A in/not in B) when checking collection contents.
Honestly I don't know why or why Gerrit's checks don't have it.
Bug: T287434
Change-Id: Ibf66b5b605334855637ca49ffb305a070df98cac
---
M tests/category_tests.py
1 file changed, 1 insertion(+), 1 deletion(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/tests/category_tests.py b/tests/category_tests.py
index 1dd3dfa..a39a684 100644
--- a/tests/category_tests.py
+++ b/tests/category_tests.py
@@ -160,7 +160,7 @@
# Invalid title case
cat3 = pywikibot.Category(site, '2021 establishments in Orissa')
cat4 = pywikibot.Category(site, '2021 establishments in Odisha')
- self.assertTrue('{{title year}}' in cat3.text)
+ self.assertIn('{{title year}}', cat3.text)
self.assertTrue(cat3.isCategoryRedirect())
self.assertFalse(cat4.isCategoryRedirect())
tgt = cat3.getCategoryRedirectTarget()
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/708190
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ibf66b5b605334855637ca49ffb305a070df98cac
Gerrit-Change-Number: 708190
Gerrit-PatchSet: 2
Gerrit-Owner: Damian <atagar1(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/707865 )
Change subject: [bugfix] Tests fail if family is named 'test'
......................................................................
[bugfix] Tests fail if family is named 'test'
This file had a vestigial conditional for the 'test' family that was removed in
commit 66d88aa. This causes a test failure for me because I coincidently chose
the same name.
======================================================================
FAIL: test_each_family (tests.family_tests.TestFamilyUrlRegex) (family='test')
Test each family builds a working regex.
----------------------------------------------------------------------
Traceback (most recent call last):
File "pywikibot/tests/family_tests.py", line 235, in test_each_family
self.assertEqual(family.from_url(url), code)
File "pywikibot/pywikibot/family.py", line 864, in from_url
site = pywikibot.Site(code, self.name)
File "pywikibot/tests/family_tests.py", line 161, in Site
self.assertEqual(fam, 'wikipedia')
AssertionError: 'test' != 'wikipedia'
- test
+ wikipedia
Bug: T287332
Change-Id: I4cdba4acfda166375a8edcabe74d735f86fec235
---
M tests/family_tests.py
1 file changed, 1 insertion(+), 4 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/tests/family_tests.py b/tests/family_tests.py
index d82d723..94ed871 100644
--- a/tests/family_tests.py
+++ b/tests/family_tests.py
@@ -157,10 +157,7 @@
self.assertEqual(args, ())
self.assertEqual(kwargs, {})
self.assertEqual(code, self.current_code)
- if self.current_family == 'test':
- self.assertEqual(fam, 'wikipedia')
- else:
- self.assertEqual(fam, self.current_family)
+ self.assertEqual(fam, self.current_family)
site = DrySite(code, fam, None)
site._siteinfo._cache['general'] = ({'articlepath': self.article_path},
True)
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/707865
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I4cdba4acfda166375a8edcabe74d735f86fec235
Gerrit-Change-Number: 707865
Gerrit-PatchSet: 1
Gerrit-Owner: Damian <atagar1(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged