jenkins-bot has submitted this change and it was merged.
Change subject: [FEAT] Add deprecation warnings for textlib/deprecation redirects ......................................................................
[FEAT] Add deprecation warnings for textlib/deprecation redirects
It's adding a function which dynamically can create a redirect to another function and warn because of deprecation when the redirected function is executed. It works similar to the @deprecated decorator but doesn't require the old function.
All functions which from 'textlib' which were simply redirected from 'pywikibot' to the 'textlib' module are created with this function. Also 'deprecated' and 'deprecate_arg' are marked as deprecated too.
Change-Id: I69dbf351c22fd0caacbf047ae38aca067f8cef96 --- M pywikibot/__init__.py M pywikibot/tools.py 2 files changed, 79 insertions(+), 20 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py index 0d13cdf..6804291 100644 --- a/pywikibot/__init__.py +++ b/pywikibot/__init__.py @@ -41,21 +41,24 @@ CaptchaError, SpamfilterError, CircularRedirect, WikiBaseError, CoordinateGlobeUnknownException, ) -from pywikibot.textlib import ( - unescape, replaceExcept, removeDisabledParts, removeHTMLParts, - isDisabled, interwikiFormat, interwikiSort, - getLanguageLinks, replaceLanguageLinks, - removeLanguageLinks, removeLanguageLinksAndSeparator, - getCategoryLinks, categoryFormat, replaceCategoryLinks, - removeCategoryLinks, removeCategoryLinksAndSeparator, - replaceCategoryInPlace, compileLinkR, extract_templates_and_params, -) -from pywikibot.tools import UnicodeMixin, deprecated, deprecate_arg +from pywikibot.tools import UnicodeMixin, redirect_func from pywikibot.i18n import translate from pywikibot.data.api import UploadWarning +import pywikibot.textlib as textlib +import pywikibot.tools + +textlib_methods = ( + 'unescape', 'replaceExcept', 'removeDisabledParts', 'removeHTMLParts', + 'isDisabled', 'interwikiFormat', 'interwikiSort', + 'getLanguageLinks', 'replaceLanguageLinks', + 'removeLanguageLinks', 'removeLanguageLinksAndSeparator', + 'getCategoryLinks', 'categoryFormat', 'replaceCategoryLinks', + 'removeCategoryLinks', 'removeCategoryLinksAndSeparator', + 'replaceCategoryInPlace', 'compileLinkR', 'extract_templates_and_params', +)
__all__ = ( - 'config', 'ui', 'UnicodeMixin', 'translate', 'deprecated', 'deprecate_arg', + 'config', 'ui', 'UnicodeMixin', 'translate', 'Page', 'FilePage', 'ImagePage', 'Category', 'Link', 'User', 'ItemPage', 'PropertyPage', 'Claim', 'TimeStripper', 'html2unicode', 'url2unicode', 'unicode2html', @@ -67,17 +70,24 @@ 'PageRelatedError', 'IsRedirectPage', 'IsNotRedirectPage', 'PageNotSaved', 'UploadWarning', 'LockedPage', 'EditConflict', 'ServerError', 'FatalServerError', 'Server504Error', - 'CaptchaError', 'SpamfilterError', 'CircularRedirect', + 'CaptchaError', 'SpamfilterError', 'CircularRedirect', 'WikiBaseError', 'CoordinateGlobeUnknownException', - 'unescape', 'replaceExcept', 'removeDisabledParts', 'removeHTMLParts', - 'isDisabled', 'interwikiFormat', 'interwikiSort', - 'getLanguageLinks', 'replaceLanguageLinks', - 'removeLanguageLinks', 'removeLanguageLinksAndSeparator', - 'getCategoryLinks', 'categoryFormat', 'replaceCategoryLinks', - 'removeCategoryLinks', 'removeCategoryLinksAndSeparator', - 'replaceCategoryInPlace', 'compileLinkR', 'extract_templates_and_params', 'QuitKeyboardInterrupt', ) +# flake8 is unable to detect concatenation in the same operation +# like: +# ) + textlib_methods +# so instead use this trick +globals()['__all__'] = __all__ + textlib_methods + +for _name in textlib_methods: + target = getattr(textlib, _name) + wrapped_func = redirect_func(target) + globals()[_name] = wrapped_func + + +deprecated = redirect_func(pywikibot.tools.deprecated) +deprecate_arg = redirect_func(pywikibot.tools.deprecate_arg)
class Timestamp(datetime.datetime): @@ -491,7 +501,7 @@ link_regex = re.compile(r'[[(?P<title>[^]|[<>{}]*)(|.*?)?]]')
-@deprecated("comment parameter for page saving method") +@pywikibot.tools.deprecated("comment parameter for page saving method") def setAction(s): """Set a summary to use for changed page submissions""" config.default_edit_summary = s diff --git a/pywikibot/tools.py b/pywikibot/tools.py index 462b5ef..fb8628f 100644 --- a/pywikibot/tools.py +++ b/pywikibot/tools.py @@ -314,6 +314,55 @@ return decorator
+def redirect_func(target, source_module=None, target_module=None): + """ + Return a function which can be used to redirect to 'target'. + + It also acts like marking that function deprecated and copies all + parameters. + + @param target: The targeted function which is to be executed. + @type target: callable + @param source_module: The module of the old function. If '.' defaults + to target_module. If 'None' (default) it tries to guess it from the + executing function. + @type source_module: basestring + @param target_module: The module of the target function. If + 'None' (default) it tries to get it from the target. Might not work + with nested classes. + @type target_module: basestring + @return: A new function which adds a warning prior to each execution. + @rtype: callable + """ + class Wrapper(object): + def __init__(self, function, source, target): + self._function = function + self.parameters = {'new': function.func_name, + 'target': target, + 'source': source} + self.warning = ('{source}{new} is DEPRECATED, use {target}{new} ' + 'instead.').format(**self.parameters) + + def call(self, *a, **kw): + warning(self.warning) + return self._function(*a, **kw) + + if target_module is None: + target_module = target.__module__ + if hasattr(target, 'im_class'): + target_module += '.' + target.im_class.__name__ + if target_module and target_module[-1] != '.': + target_module += '.' + if source_module is '.': + source_module = target_module + elif source_module and source_module[-1] != '.': + source_module += '.' + else: + source_module = (sys._getframe(1).f_code.co_filename.rsplit("/", 1)[0] + .replace("/", ".") + ".") + return Wrapper(target, source_module, target_module).call + + if __name__ == "__main__": def _test(): import doctest