jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/372790 )
Change subject: [IMPR] Improvements for User class ......................................................................
[IMPR] Improvements for User class
new methods: - User.logevents(): return user logged activities - User.last_event: return the last user activity (btw. the first is the creation of the account) - User.first_edit: return the first edit of the given user - User.last_edit: return the last edit of the given user
other changes: - User.contributions(): enable all site.usercontribs options (including reverse which might be missing), extend the doc string - User.uploadedImages(): use User.logevents() here - User.is_thankable: Simplify result - site.logevents(): refer mediawiki api but don't list log types here; some other doc changes
tests added.
Change-Id: I1aa05649b47eff990f63d38663ff647604e7e260 --- M pywikibot/page.py M pywikibot/site.py M tests/user_tests.py 3 files changed, 122 insertions(+), 22 deletions(-)
Approvals: Framawiki: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/page.py b/pywikibot/page.py index 6cff93b..373d339 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -3462,6 +3462,40 @@ """ self.site.unblockuser(self, reason)
+ def logevents(self, **kwargs): + """Yield user activities. + + @keyword logtype: only iterate entries of this type + (see mediawiki api documentation for available types) + @type logtype: basestring + @keyword page: only iterate entries affecting this page + @type page: Page or basestring + @keyword namespace: namespace to retrieve logevents from + @type namespace: int or Namespace + @keyword start: only iterate entries from and after this Timestamp + @type start: Timestamp or ISO date string + @keyword end: only iterate entries up to and through this Timestamp + @type end: Timestamp or ISO date string + @keyword reverse: if True, iterate oldest entries first + (default: newest) + @type reverse: bool + @keyword tag: only iterate entries tagged with this tag + @type tag: basestring + @keyword total: maximum number of events to iterate + @type total: int + @rtype: iterable + """ + return self.site.logevents(user=self.username, **kwargs) + + @property + def last_event(self): + """Return last user activity. + + @return: last user log entry + @rtype: LogEntry + """ + return next(iter(self.logevents(total=1))) + @deprecated("contributions") @deprecate_arg("limit", "total") # To be consistent with rest of framework def editedPages(self, total=500): @@ -3479,7 +3513,7 @@ yield item[0]
@deprecated_args(limit='total', namespace='namespaces') - def contributions(self, total=500, namespaces=[]): + def contributions(self, total=500, **kwargs): """ Yield tuples describing this user edits.
@@ -3490,16 +3524,47 @@
@param total: limit result to this number of pages @type total: int - @param namespaces: only iterate links in these namespaces - @type namespaces: list + @keyword start: Iterate contributions starting at this Timestamp + @keyword end: Iterate contributions ending at this Timestamp + @keyword reverse: Iterate oldest contributions first (default: newest) + @keyword namespaces: only iterate pages in these namespaces + @type namespaces: iterable of basestring or Namespace key, + or a single instance of those types. May be a '|' separated + list of namespace identifiers. + @keyword showMinor: if True, iterate only minor edits; if False and + not None, iterate only non-minor edits (default: iterate both) + @keyword top_only: if True, iterate only edits which are the latest + revision (default: False) + @return tuple of pywikibot.Page, revid, pywikibot.Timestamp, comment + @rtype: tuple """ for contrib in self.site.usercontribs( - user=self.username, namespaces=namespaces, total=total): + user=self.username, total=total, **kwargs): ts = pywikibot.Timestamp.fromISOformat(contrib['timestamp']) yield (Page(self.site, contrib['title'], contrib['ns']), contrib['revid'], ts, contrib.get('comment')) + + @property + def first_edit(self): + """Return first user contribution. + + @return: first user contribution entry + @return tuple of pywikibot.Page, revid, pywikibot.Timestamp, comment + @rtype: tuple + """ + return next(self.contributions(reverse=True, total=1)) + + @property + def last_edit(self): + """Return last user contribution. + + @return: last user contribution entry + @return tuple of pywikibot.Page, revid, pywikibot.Timestamp, comment + @rtype: tuple + """ + return next(self.contributions(total=1))
@deprecate_arg("number", "total") def uploadedImages(self, total=10): @@ -3515,8 +3580,8 @@ """ if not self.isRegistered(): raise StopIteration - for item in self.site.logevents( - logtype='upload', user=self.username, total=total): + for item in self.logevents( + logtype='upload', total=total): yield (item.page(), unicode(item.timestamp()), item.comment(), @@ -3535,14 +3600,8 @@
@rtype: bool """ - if self.isAnonymous(): - return False - if not self.isRegistered(): - return False - if 'bot' in self.groups(): - return False - - return True + return not (self.isAnonymous() or self.isRegistered() + or 'bot' in self.groups())
class WikibasePage(BasePage): diff --git a/pywikibot/site.py b/pywikibot/site.py index 8accf26..cd7ff26 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -4511,10 +4511,8 @@ @note: logevents with logtype='block' only logs user blocks whereas site.blocks iterates all blocks including IP ranges.
- @param logtype: only iterate entries of this type (see wiki - documentation for available types, which will include "block", - "protect", "rights", "delete", "upload", "move", "import", - "patrol", "merge") + @param logtype: only iterate entries of this type + (see mediawiki api documentation for available types) @type logtype: basestring @param user: only iterate entries that match this user name @type user: basestring @@ -4775,8 +4773,11 @@ list of namespace identifiers. @param showMinor: if True, iterate only minor edits; if False and not None, iterate only non-minor edits (default: iterate both) + @param total: limit result to this number of pages + @type total: int @param top_only: if True, iterate only edits which are the latest - revision + revision (default: False) + @raises Error: either user or userprefix must be non-empty @raises KeyError: a namespace identifier was not resolved @raises TypeError: a namespace identifier has an inappropriate type such as NoneType or bool diff --git a/tests/user_tests.py b/tests/user_tests.py index d604a97..f2a8b06 100644 --- a/tests/user_tests.py +++ b/tests/user_tests.py @@ -9,11 +9,11 @@
import pywikibot
+from pywikibot import Page, Timestamp, User from pywikibot.exceptions import AutoblockUser -from pywikibot.tools import suppress_warnings -from pywikibot import User +from pywikibot.tools import StringTypes, suppress_warnings
-from tests.aspects import TestCase, unittest +from tests.aspects import DefaultSiteTestCase, TestCase, unittest
class TestUserClass(TestCase): @@ -164,6 +164,46 @@ user.getUserTalkPage)
+class TestUserMethods(DefaultSiteTestCase): + + """Test User methods with bot user.""" + + user = True + + def test_contribution(self): + """Test the User.usercontribs() method.""" + mysite = self.get_site() + user = User(mysite, mysite.user()) + uc = list(user.contributions(total=10)) + if not uc: + self.skipTest('User {0} has no contributions on site {1}.' + .format(mysite.user(), mysite)) + self.assertLessEqual(len(uc), 10) + last = uc[0] + for contrib in uc: + self.assertIsInstance(contrib, tuple) + self.assertEqual(len(contrib), 4) + p, i, t, c = contrib + self.assertIsInstance(p, Page) + self.assertIsInstance(i, int) + self.assertIsInstance(t, Timestamp) + self.assertIsInstance(c, StringTypes) + self.assertEqual(last, user.last_edit) + + def test_logevents(self): + """Test the User.logevents() method.""" + mysite = self.get_site() + user = User(mysite, mysite.user()) + le = list(user.logevents(total=10)) + if not le: + self.skipTest('User {0} has no logevents on site {1}.' + .format(mysite.user(), mysite)) + self.assertLessEqual(len(le), 10) + last = le[0] + self.assertTrue(all(event.user() == user.username for event in le)) + self.assertEqual(last, user.last_event) + + if __name__ == '__main__': # pragma: no cover try: unittest.main()
pywikibot-commits@lists.wikimedia.org