jenkins-bot has submitted this change and it was merged.
Change subject: [IMPROV] site: Deprecate self callable namespaces ......................................................................
[IMPROV] site: Deprecate self callable namespaces
This makes calling site.namespaces deprecated. It also removes all usages of this method and they use now the property directly.
Change-Id: I9c4f73e2d1b6b97eb64797115aeb130f3ecc5c9d --- M pywikibot/botirc.py M pywikibot/cosmetic_changes.py M pywikibot/page.py M pywikibot/site.py M pywikibot/tools/__init__.py M scripts/replicate_wiki.py M scripts/solve_disambiguation.py M tests/site_tests.py M tests/utils.py 9 files changed, 92 insertions(+), 74 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/botirc.py b/pywikibot/botirc.py index c63f4d0..903b89c 100644 --- a/pywikibot/botirc.py +++ b/pywikibot/botirc.py @@ -53,7 +53,7 @@ self.site = site self.other_ns = re.compile( u'\x0314\[\[\x0307(%s)' - % u'|'.join(item.custom_name for item in site.namespaces().values() + % u'|'.join(item.custom_name for item in site.namespaces.values() if item != 0)) self.api_url = self.site.apipath() self.api_url += '?action=query&meta=siteinfo&siprop=statistics&format=xml' diff --git a/pywikibot/cosmetic_changes.py b/pywikibot/cosmetic_changes.py index 9c471fe..bced95d 100755 --- a/pywikibot/cosmetic_changes.py +++ b/pywikibot/cosmetic_changes.py @@ -420,15 +420,15 @@ # wiki links aren't parsed here. exceptions = ['nowiki', 'comment', 'math', 'pre']
- for nsNumber in self.site.namespaces(): - if nsNumber in (0, 2, 3): + for namespace in self.site.namespaces.values(): + if namespace.id in (0, 2, 3): # skip main (article) namespace # skip user namespace, maybe gender is used continue # a clone is needed. Won't change the namespace dict - namespaces = list(self.site.namespace(nsNumber, all=True)) + namespaces = list(namespace) thisNs = namespaces.pop(0) - if nsNumber == 6 and family.name == 'wikipedia': + if namespace.id == 6 and family.name == 'wikipedia': if self.site.code in ('en', 'fr') and \ MediaWikiVersion(self.site.version()) >= MediaWikiVersion('1.14'): # do not change "Image" on en-wiki and fr-wiki diff --git a/pywikibot/page.py b/pywikibot/page.py index db5a1ef..6542a67 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -672,7 +672,7 @@ # Get target (first template argument) try: p = pywikibot.Page(self.site, args[0].strip(), ns=14) - if p.namespace() == 14: + if p.namespace == 14: self._catredirect = p.title() else: pywikibot.warning( @@ -4722,21 +4722,21 @@ """ ns_id = self.namespace ns = self.site.namespaces[ns_id] - ns_names = list(ns)
if onsite is None: namespace = ns.canonical_name else: # look for corresponding ns in onsite by name comparison - for name in ns_names: - onsite_ns = ns.lookup_name(name, namespaces=onsite.namespaces()) - # not found - if onsite_ns is None: + for alias in ns: + namespace = Namespace.lookup_name(alias, onsite.namespaces) + if namespace: + namespace = namespace.custom_name + break + else: + # not found raise pywikibot.Error( u'No corresponding namespace found for namespace %s on %s.' % (self.site.namespaces[ns_id], onsite)) - else: - namespace = onsite_ns.custom_name
if namespace: return u'%s:%s' % (namespace, self.title) diff --git a/pywikibot/site.py b/pywikibot/site.py index eae3500..ebcd71d 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -491,6 +491,14 @@ return result
+# This class can be removed after self-callability has been removed +class _NamespacesDict(SelfCallDict): + + """A wrapper to add a deprecation message when called.""" + + _own_desc = 'the namespaces property' + + class BaseSite(ComparableMixin):
"""Site methods that are independent of the communication interface.""" @@ -694,7 +702,7 @@
def validLanguageLinks(self): """Return list of language codes that can be used in interwiki links.""" - nsnames = [name for name in self.namespaces().values()] + nsnames = [name for name in self.namespaces.values()] return [lang for lang in self.languages() if first_upper(lang) not in nsnames]
@@ -786,13 +794,16 @@ getNamespaceIndex = redirect_func(ns_index, old_name='getNamespaceIndex', class_name='BaseSite')
+ def _build_namespaces(self): + """Create default namespaces.""" + use_image_name = MediaWikiVersion(self.version()) < MediaWikiVersion("1.14") + return Namespace.builtin_namespaces(use_image_name) + @property def namespaces(self): """Return dict of valid namespaces on this wiki.""" if not hasattr(self, '_namespaces'): - use_image_name = MediaWikiVersion(self.version()) < MediaWikiVersion("1.14") - self._namespaces = SelfCallDict( - Namespace.builtin_namespaces(use_image_name)) + self._namespaces = _NamespacesDict(self._build_namespaces()) return self._namespaces
def ns_normalize(self, value): @@ -1820,7 +1831,7 @@ self._useroptions['_name'] = ( None if 'anon' in uidata['query']['userinfo'] else uidata['query']['userinfo']['name']) - return set(ns for ns in self.namespaces().values() if ns.id >= 0 and + return set(ns for ns in self.namespaces.values() if ns.id >= 0 and self._useroptions['searchNs{0}'.format(ns.id)] in ['1', True])
def assert_valid_iter_params(self, msg_prefix, start, end, reverse): @@ -2138,7 +2149,7 @@ return self.getmagicwords("pagenamee")
def _build_namespaces(self): - _namespaces = SelfCallDict() + _namespaces = {}
# In MW 1.14, API siprop 'namespaces' added 'canonical', # and Image became File with Image as an alias. @@ -2174,7 +2185,7 @@ if item['*'] not in _namespaces[ns]: _namespaces[ns].aliases.append(item['*'])
- self._namespaces = _namespaces + return _namespaces
@need_version("1.14") @deprecated("has_extension") @@ -2368,13 +2379,6 @@ if not hasattr(self, '_proofread_levels'): self._cache_proofreadinfo() return self._proofread_levels - - @property - def namespaces(self): - """Return dict of valid namespaces on this wiki.""" - if not hasattr(self, '_namespaces'): - self._build_namespaces() - return self._namespaces
def namespace(self, num, all=False): """Return string containing local name of namespace 'num'. @@ -3161,7 +3165,7 @@
# Covert namespaces to a known type namespaces = set(Namespace.resolve(namespaces or [], - self.namespaces())) + self.namespaces))
if 'page' in member_type: excluded_namespaces = set() @@ -3184,7 +3188,7 @@ # namespaces requested is higher than available, and split # the request into several batches. excluded_namespaces.add([-1, -2]) - namespaces = set(self.namespaces()) - excluded_namespaces + namespaces = set(self.namespaces) - excluded_namespaces else: if 'file' in member_type: namespaces.add(6) @@ -3912,7 +3916,7 @@ if where not in ("text", "titles"): raise Error("search: unrecognized 'where' value: %s" % where) if namespaces == []: - namespaces = [ns for ns in list(self.namespaces().keys()) if ns >= 0] + namespaces = [ns_id for ns_id in self.namespaces if ns_id >= 0] if not namespaces: pywikibot.warning(u"search: namespaces cannot be empty; using [0].") namespaces = [0] @@ -5511,7 +5515,7 @@ self._item_namespace = False self._property_namespace = False
- for namespace in self.namespaces().values(): + for namespace in self.namespaces.values(): if not hasattr(namespace, 'defaultcontentmodel'): continue
diff --git a/pywikibot/tools/__init__.py b/pywikibot/tools/__init__.py index 692fc89..9636c46 100644 --- a/pywikibot/tools/__init__.py +++ b/pywikibot/tools/__init__.py @@ -657,10 +657,18 @@
class SelfCallMixin(object):
- """Return self when called.""" + """ + Return self when called. + + When '_own_desc' is defined it'll also issue a deprecation warning using + issue_deprecation_warning('Calling ' + _own_desc, 'it directly'). + """
def __call__(self): """Do nothing and just return itself.""" + if hasattr(self, '_own_desc'): + issue_deprecation_warning('Calling {0}'.format(self._own_desc), + 'it directly', 2) return self
diff --git a/scripts/replicate_wiki.py b/scripts/replicate_wiki.py index c890910..788f993 100755 --- a/scripts/replicate_wiki.py +++ b/scripts/replicate_wiki.py @@ -49,14 +49,15 @@ import sys
import pywikibot + from pywikibot import config, Page +from pywikibot.tools import deprecated
+@deprecated('BaseSite.namespaces') def namespaces(site): """dict from namespace number to prefix.""" - ns = dict((site.getNamespaceIndex(n), n) for n in site.namespaces()) - ns[0] = '' - return ns + return dict((n.id, n.custom_name) for n in site.namespaces)
def multiple_replace(text, word_dict): @@ -88,9 +89,8 @@ self.original.login()
if options.namespace and 'help' in options.namespace: - nsd = namespaces(self.original) - for k in nsd: - pywikibot.output('%s %s' % (k, nsd[k])) + for namespace in self.original.namespaces.values(): + pywikibot.output('%s %s' % (namespace.id, namespace.custom_name)) sys.exit()
self.sites = [pywikibot.Site(s, family) for s in sites] @@ -191,18 +191,19 @@ page1 = Page(self.original, pagename) txt1 = page1.text
- for site in self.sites: - if self.options.dest_namespace: - prefix = namespaces(site)[int(self.options.dest_namespace)] - if prefix: - prefix += ':' - new_pagename = prefix + page1.titleWithoutNamespace() - pywikibot.output("\nCross namespace, new title: %s" - % new_pagename) - else: - new_pagename = pagename + if self.options.dest_namespace: + dest_ns = int(self.options.dest_namespace) + else: + dest_ns = None
- page2 = Page(site, new_pagename) + for site in self.sites: + if dest_ns is not None: + page2 = Page(site, page1.title(withNamespace=False), dest_ns) + pywikibot.output("\nCross namespace, new title: %s" + % page2.title()) + else: + page2 = Page(site, pagename) + if page2.exists(): txt2 = page2.text else: diff --git a/scripts/solve_disambiguation.py b/scripts/solve_disambiguation.py index 846f1a6..4620a29 100755 --- a/scripts/solve_disambiguation.py +++ b/scripts/solve_disambiguation.py @@ -80,8 +80,9 @@ __version__ = '$Id$' #
-import re import codecs +import itertools +import re
import pywikibot from pywikibot import editor as editarticle @@ -996,10 +997,7 @@ ignore_title[self.mysite.family.name][self.mylang] = []
ignore_title[self.mysite.family.name][self.mylang] += [ - u'%s:' % ns - for namespace in self.mysite.namespaces() - for ns in self.mysite.namespaces[namespace] - ] + '%s:' % ns for ns in itertools.chain(self.mysite.namespaces)]
for disambPage in self.generator: self.primaryIgnoreManager = PrimaryIgnoreManager( diff --git a/tests/site_tests.py b/tests/site_tests.py index b279c02..0810f95 100644 --- a/tests/site_tests.py +++ b/tests/site_tests.py @@ -25,6 +25,7 @@ from tests.aspects import ( unittest, TestCase, DeprecationTestCase, DefaultSiteTestCase, + DefaultDrySiteTestCase, WikimediaDefaultSiteTestCase, WikidataTestCase, DefaultWikidataClientTestCase, @@ -39,7 +40,7 @@
class TestSiteObjectDeprecatedFunctions(DefaultSiteTestCase, DeprecationTestCase):
- """Test cases for Site deprecated methods.""" + """Test cases for Site deprecated methods on a live wiki."""
cached = True user = True @@ -67,6 +68,18 @@ self.assertEqual(token, mysite.token(mainpage, ttype)) self.assertDeprecation("pywikibot.site.APISite.token is deprecated" ", use the 'tokens' property instead.") + + +class TestSiteDryDeprecatedFunctions(DefaultDrySiteTestCase, DeprecationTestCase): + + """Test cases for Site deprecated methods without a user.""" + + def test_namespaces_callable(self): + """Test that namespaces is callable and returns itself.""" + site = self.get_site() + self.assertIs(site.namespaces(), site.namespaces) + self.assertDeprecation('Calling the namespaces property is deprecated, ' + 'use it directly instead.')
class TestBaseSiteProperties(TestCase): @@ -212,7 +225,7 @@ } self.assertTrue(all(mysite.ns_index(b) == builtins[b] for b in builtins)) - ns = mysite.namespaces() + ns = mysite.namespaces self.assertIsInstance(ns, dict) self.assertTrue(all(x in ns for x in range(0, 16))) # built-in namespaces always present @@ -1807,7 +1820,7 @@ def testNamespaceAliases(self): site = self.get_site()
- namespaces = site.namespaces() + namespaces = site.namespaces image_namespace = namespaces[6] self.assertEqual(image_namespace.custom_name, 'Fil') self.assertEqual(image_namespace.canonical_name, 'File') diff --git a/tests/utils.py b/tests/utils.py index 78645ac..d151253 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -20,7 +20,6 @@ import pywikibot
from pywikibot import config -from pywikibot.tools import SelfCallDict from pywikibot.site import Namespace from pywikibot.data.api import CachedRequest from pywikibot.data.api import Request as _original_Request @@ -200,13 +199,13 @@ self._siteinfo._cache['case'] = ( 'case-sensitive' if self.family.name == 'wiktionary' else 'first-letter', True) - self._namespaces = SelfCallDict( - Namespace.builtin_namespaces( - case=self.siteinfo['case'])) extensions = [] if self.family.name == 'wikisource': extensions.append({'name': 'ProofreadPage'}) self._siteinfo._cache['extensions'] = (extensions, True) + + def _build_namespaces(self): + return Namespace.builtin_namespaces(case=self.siteinfo['case'])
def __repr__(self): """Override default so warnings and errors indicate test is dry.""" @@ -244,19 +243,14 @@
"""Dummy class to use instead of L{pywikibot.site.DataSite}."""
- def __init__(self, code, fam, user, sysop): - """Constructor.""" - super(DryDataSite, self).__init__(code, fam, user, sysop) - - self._namespaces[0].defaultcontentmodel = 'wikibase-item' - - self._namespaces.update( - { - 120: Namespace(id=120, - case='first-letter', - canonical_name='Property', - defaultcontentmodel='wikibase-property') - }) + def _build_namespaces(self): + namespaces = super(DryDataSite, self)._build_namespaces() + namespaces[0].defaultcontentmodel = 'wikibase-item' + namespaces[120] = Namespace(id=120, + case='first-letter', + canonical_name='Property', + defaultcontentmodel='wikibase-property') + return namespaces
def execute(command, data_in=None, timeout=0, error=None):