jenkins-bot has submitted this change and it was merged.
Change subject: [FEAT] Deprecrate module classes and variables
......................................................................
[FEAT] Deprecrate module classes and variables
This adds a way to deprecrate classes or variables in modules. The
difference to '@deprecated' is that the access alone is important and
not calling the function. So this warns also if someone is just
importing a class (e.g. 'from pywikibot.excptions import
UploadWarning').
Unfortunately __getattr__ is not available on module level, so the
module must be wrapped in a class which redirects all accesses.
Change-Id: I3e83472ba780d9d99745c8dff864926432e9f254
---
M pywikibot/__init__.py
M pywikibot/exceptions.py
M pywikibot/page.py
M pywikibot/tools.py
4 files changed, 86 insertions(+), 5 deletions(-)
Approvals:
John Vandenberg: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index 0c9ac51..394043c 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -61,7 +61,7 @@
# pep257 doesn't understand when the first entry is on the next line
__all__ = ('config', 'ui', 'UnicodeMixin', 'translate',
- 'Page', 'FilePage', 'ImagePage', 'Category',
'Link', 'User',
+ 'Page', 'FilePage', 'Category', 'Link',
'User',
'ItemPage', 'PropertyPage', 'Claim',
'TimeStripper',
'html2unicode', 'url2unicode', 'unicode2html',
'stdout', 'output', 'warning', 'error',
'critical', 'debug',
@@ -542,7 +542,6 @@
from .page import (
Page,
FilePage,
- ImagePage,
Category,
Link,
User,
@@ -714,3 +713,6 @@
# identification for debugging purposes
_putthread.setName('Put-Thread')
_putthread.setDaemon(True)
+
+wrapper = pywikibot.tools.ModuleDeprecationWrapper(__name__)
+wrapper._add_deprecated_attr('ImagePage', FilePage)
diff --git a/pywikibot/exceptions.py b/pywikibot/exceptions.py
index ed620e1..7022935 100644
--- a/pywikibot/exceptions.py
+++ b/pywikibot/exceptions.py
@@ -374,6 +374,7 @@
pass
-# TODO: Warn about the deprecated usage
import pywikibot.data.api
-UploadWarning = pywikibot.data.api.UploadWarning
+import pywikibot.tools
+wrapper = pywikibot.tools.ModuleDeprecationWrapper(__name__)
+wrapper._add_deprecated_attr('UploadWarning', pywikibot.data.api.UploadWarning)
diff --git a/pywikibot/page.py b/pywikibot/page.py
index 70f8dd1..c17dd9b 100644
--- a/pywikibot/page.py
+++ b/pywikibot/page.py
@@ -1930,7 +1930,9 @@
self, step=step, total=total, content=content)
-ImagePage = FilePage
+import pywikibot.tools
+wrapper = pywikibot.tools.ModuleDeprecationWrapper(__name__)
+wrapper._add_deprecated_attr('ImagePage', FilePage)
class Category(Page):
diff --git a/pywikibot/tools.py b/pywikibot/tools.py
index 3ef95c4..c11d0d7 100644
--- a/pywikibot/tools.py
+++ b/pywikibot/tools.py
@@ -425,6 +425,82 @@
return Wrapper().call
+class ModuleDeprecationWrapper(object):
+
+ """A wrapper for a module to deprecate classes or variables of
it."""
+
+ def __init__(self, module):
+ """
+ Initialise the wrapper.
+
+ It will automatically overwrite the module with this instance in
+ C{sys.modules}.
+
+ @param module: The module name or instance
+ @type module: str or module
+ """
+ if isinstance(module, basestring):
+ module = sys.modules[module]
+ super(ModuleDeprecationWrapper, self).__setattr__('_deprecated', {})
+ super(ModuleDeprecationWrapper, self).__setattr__('_module', module)
+ sys.modules[module.__name__] = self
+
+ def _add_deprecated_attr(self, name, replacement=None,
+ replacement_name=None):
+ """
+ Add the name to the local deprecated names dict.
+
+ @param name: The name of the deprecated class or variable. It may not
+ be already deprecated.
+ @type name: str
+ @param replacement: The replacement value which should be returned
+ instead. If the name is already an attribute of that module this
+ must be None. If None it'll return the attribute of the module.
+ @type replacement: any
+ @param replacement_name: The name of the new replaced value. Required
+ if C{replacement} is not None and it has no __name__ attribute.
+ @type replacement_name: str
+ """
+ if '.' in name:
+ raise ValueError('Deprecated name "{0}" may not contain '
+ '".".'.format(name))
+ if name in self._deprecated:
+ raise ValueError('Name "{0}" is already
deprecated.'.format(name))
+ if replacement is not None and hasattr(self._module, name):
+ raise ValueError('Module has already an attribute named '
+ '"{0}".'.format(name))
+ if replacement_name is None:
+ if hasattr(replacement, '__name__'):
+ replacement_name = replacement.__module__
+ if hasattr(replacement, '__self__'):
+ replacement_name += '.'
+ replacement_name += replacement.__self__.__class__.__name__
+ replacement_name += '.' + replacement.__name__
+ else:
+ raise TypeError('Replacement must have a __name__ attribute '
+ 'or a replacement name must be set '
+ 'specifically.')
+ self._deprecated[name] = (replacement_name, replacement)
+
+ def __setattr__(self, attr, value):
+ """Set a the value of the wrapped module."""
+ setattr(self._module, attr, value)
+
+ def __getattr__(self, attr):
+ """Return the attribute with a deprecation warning if
required."""
+ if attr in self._deprecated:
+ if self._deprecated[attr][0]:
+ warning(u"{0}.{1} is DEPRECATED, use {2} instead.".format(
+ self._module.__name__, attr,
+ self._deprecated[attr][0]))
+ if self._deprecated[attr][1]:
+ return self._deprecated[attr][1]
+ else:
+ warning(u"{0}.{1} is DEPRECATED.".format(
+ self._module.__name__, attr))
+ return getattr(self._module, attr)
+
+
if __name__ == "__main__":
def _test():
import doctest
--
To view, visit
https://gerrit.wikimedia.org/r/162572
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I3e83472ba780d9d99745c8dff864926432e9f254
Gerrit-PatchSet: 4
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: jenkins-bot <>