Matěj Suchánek has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/347171 )

Change subject: [IMPR] Make a decorator for asynchronous methods
......................................................................

[IMPR] Make a decorator for asynchronous methods

Change-Id: Ib7a696aa45d395009bb096e30fb1900841a278d5
---
M pywikibot/page.py
1 file changed, 65 insertions(+), 43 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core 
refs/changes/71/347171/4

diff --git a/pywikibot/page.py b/pywikibot/page.py
index 00c60c3..1a77813 100644
--- a/pywikibot/page.py
+++ b/pywikibot/page.py
@@ -67,12 +67,12 @@
 from pywikibot.family import Family
 from pywikibot.site import DataSite, Namespace, need_version
 from pywikibot.tools import (
-    compute_file_hash,
     PYTHON_VERSION,
     MediaWikiVersion, UnicodeMixin, ComparableMixin, DotReadableDict,
-    deprecated, deprecate_arg, deprecated_args, issue_deprecation_warning,
+    add_full_name, compute_file_hash, deprecated, deprecate_arg,
+    deprecated_args, first_upper, issue_deprecation_warning,
     ModuleDeprecationWrapper as _ModuleDeprecationWrapper,
-    first_upper, redirect_func, remove_last_args, _NotImplementedWarning,
+    manage_wrapping, redirect_func, remove_last_args, _NotImplementedWarning,
     OrderedDict, Counter,
 )
 from pywikibot.tools.ip import ip_regexp
@@ -100,6 +100,46 @@
 )
 
 logger = logging.getLogger("pywiki.wiki.page")
+
+
+@add_full_name
+def asynchronous(func):
+    """
+    Decorator to make it possible to run a BasePage method asynchronously.
+
+    This is done when the method is called with kwarg asynchronous=True.
+    Optionally, you can also provide kwarg callback, which, if provided, is
+    a callable that gets the page as the first and a possible exception that
+    occurred during saving in the second thread or None as the second argument.
+    """
+    def handle(func, self, do_async=False, callback=None, *args, **kwargs):
+        err = None
+        try:
+            func(self, *args, **kwargs)
+        # TODO: other "expected" error types to catch?
+        except pywikibot.Error as edit_err:
+            err = edit_err  # edit_err will be deleted in the end of the scope
+            link = self.title(asLink=True)
+            pywikibot.log('Error saving page %s (%s)\n' % (link, err),
+                          exc_info=True)
+            if not callback and not do_async:
+                if isinstance(err, pywikibot.PageSaveRelatedError):
+                    raise err
+                raise pywikibot.OtherPageSaveError(self, err)
+        if callback:
+            callback(self, err)
+
+    def wrapper(self, *args, **kwargs):
+        do_async = kwargs.pop('asynchronous', False)
+        if do_async:
+            pywikibot.async_request(handle, func, self, do_async=True,
+                                    *args, **kwargs)
+        else:
+            handle(func, self, *args, **kwargs)
+
+    manage_wrapping(wrapper, func)
+
+    return wrapper
 
 
 # Note: Link objects (defined later on) represent a wiki-page's title, while
@@ -1197,7 +1237,7 @@
         @param quiet: enable/disable successful save operation message;
             defaults to False.
             In asynchronous mode, if True, it is up to the calling bot to
-            manage the ouput e.g. via callback.
+            manage the output e.g. via callback.
         @type quiet: bool
         """
         if not summary:
@@ -1209,47 +1249,26 @@
         if not force and not self.botMayEdit():
             raise pywikibot.OtherPageSaveError(
                 self, "Editing restricted by {{bots}} template")
-        if asynchronous:
-            pywikibot.async_request(self._save, summary=summary, watch=watch,
-                                    minor=minor, botflag=botflag,
-                                    asynchronous=asynchronous,
-                                    callback=callback,
-                                    cc=apply_cosmetic_changes,
-                                    quiet=quiet, **kwargs)
-        else:
-            self._save(summary=summary, watch=watch, minor=minor,
-                       botflag=botflag, asynchronous=asynchronous,
-                       callback=callback, cc=apply_cosmetic_changes,
-                       quiet=quiet, **kwargs)
+        self._save(summary=summary, watch=watch, minor=minor, botflag=botflag,
+                   asynchronous=asynchronous, callback=callback,
+                   cc=apply_cosmetic_changes, quiet=quiet, **kwargs)
 
+    @asynchronous
     def _save(self, summary=None, watch=None, minor=True, botflag=None,
-              asynchronous=False, callback=None, cc=None, quiet=False,
-              **kwargs):
+              cc=None, quiet=False, **kwargs):
         """Helper function for save()."""
-        err = None
         link = self.title(asLink=True)
         if cc or cc is None and config.cosmetic_changes:
             summary = self._cosmetic_changes_hook(summary) or summary
-        try:
-            done = self.site.editpage(self, summary=summary, minor=minor,
-                                      watch=watch, bot=botflag, **kwargs)
-            if not done:
-                if not quiet:
-                    pywikibot.warning(u"Page %s not saved" % link)
-                raise pywikibot.PageNotSaved(self)
+
+        done = self.site.editpage(self, summary=summary, minor=minor,
+                                  watch=watch, bot=botflag, **kwargs)
+        if not done:
             if not quiet:
-                pywikibot.output(u"Page %s saved" % link)
-        # TODO: other "expected" error types to catch?
-        except pywikibot.Error as edit_err:
-            err = edit_err  # edit_err will be deleted in the end of the scope
-            pywikibot.log(u"Error saving page %s (%s)\n" % (link, err),
-                          exc_info=True)
-            if not callback and not asynchronous:
-                if isinstance(err, pywikibot.PageSaveRelatedError):
-                    raise err
-                raise pywikibot.OtherPageSaveError(self, err)
-        if callback:
-            callback(self, err)
+                pywikibot.warning('Page %s not saved' % link)
+            raise pywikibot.PageNotSaved(self)
+        if not quiet:
+            pywikibot.output('Page %s saved' % link)
 
     def _cosmetic_changes_hook(self, comment):
         if self.isTalkPage() or \
@@ -3849,7 +3868,8 @@
             return site.dbName()
         return site
 
-    def editEntity(self, data=None, asynchronous=False, **kwargs):
+    @asynchronous
+    def editEntity(self, data=None, **kwargs):
         """
         Edit an entity using Wikibase wbeditentity API.
 
@@ -3864,11 +3884,13 @@
         @param asynchronous: if True, launch a separate thread to edit
             asynchronously
         @type asynchronous: bool
+        @param callback: a callable object that will be called after the entity
+            has been updated. It must take two arguments: (1) a WikibasePage
+            object, and (2) an exception instance, which will be None if the
+            page was saved successfully. This is intended for use by bots that
+            need to keep track of which saves were successful.
+        @type callback: callable
         """
-        if asynchronous:
-            pywikibot.async_request(self.editEntity, data, **kwargs)
-            return
-
         if hasattr(self, '_revid'):
             baserevid = self.latest_revision_id
         else:

-- 
To view, visit https://gerrit.wikimedia.org/r/347171
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib7a696aa45d395009bb096e30fb1900841a278d5
Gerrit-PatchSet: 4
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Matěj Suchánek <matejsuchane...@gmail.com>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to