jenkins-bot has submitted this change and it was merged.
Change subject: [FEAT] site: Dynamically determine Wikibase repo
......................................................................
[FEAT] site: Dynamically determine Wikibase repo
Instead of statically defining the Wikibase repository in the family, it can
query the API to determine the repository without user input. This also changes
the implementation in `Family` to use the site's implementation.
This does not provide the `DataSite` instance if there is no such family which
supports that URL. And while previous versions would raise a
`SiteDefitionError` if the data returned by the family is invalid, this
implementation does catch the error as it assumes the information is valid and
it instead means that there is no such family created yet.
Bug: T85331
Change-Id: I5568d848a369c8af36a40c193e2409071e23a5fb
---
M pywikibot/families/commons_family.py
M pywikibot/families/wikibooks_family.py
M pywikibot/families/wikidata_family.py
M pywikibot/families/wikinews_family.py
M pywikibot/families/wikipedia_family.py
M pywikibot/families/wikiquote_family.py
M pywikibot/families/wikisource_family.py
M pywikibot/families/wikivoyage_family.py
M pywikibot/family.py
M pywikibot/site.py
M tests/aspects.py
M tests/utils.py
M tests/wikibase_tests.py
13 files changed, 81 insertions(+), 74 deletions(-)
Approvals:
John Vandenberg: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/families/commons_family.py b/pywikibot/families/commons_family.py
index c23ce91..b1776b8 100644
--- a/pywikibot/families/commons_family.py
+++ b/pywikibot/families/commons_family.py
@@ -48,7 +48,3 @@
self.doc_subpages = {
'_default': ((u'/doc', ), ['commons']),
}
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
site."""
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/families/wikibooks_family.py
b/pywikibot/families/wikibooks_family.py
index 91b5a21..e041203 100644
--- a/pywikibot/families/wikibooks_family.py
+++ b/pywikibot/families/wikibooks_family.py
@@ -141,7 +141,3 @@
'pl': self.alphabetic,
'simple': self.alphabetic
}
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
family."""
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/families/wikidata_family.py
b/pywikibot/families/wikidata_family.py
index 2177b90..37d3933 100644
--- a/pywikibot/families/wikidata_family.py
+++ b/pywikibot/families/wikidata_family.py
@@ -41,19 +41,6 @@
"""Return 'DataSite'."""
return 'DataSite'
- def shared_data_repository(self, code, transcluded=False):
- """
- Indicate Wikidata is both a repository and its own client.
-
- Until 20 August 2014, Wikidata was only a data repository,
- and this method only returned a tuple with data if
- transcluded was False.
-
- On that date, the software was enhanced so that Wikidata
- could store sitelinks to itself.
- """
- return (code, self.name)
-
def calendarmodel(self, code):
"""Default calendar model for WbTime datatype."""
return 'http://www.wikidata.org/entity/Q1985727'
diff --git a/pywikibot/families/wikinews_family.py
b/pywikibot/families/wikinews_family.py
index ac83ae7..945fc79 100644
--- a/pywikibot/families/wikinews_family.py
+++ b/pywikibot/families/wikinews_family.py
@@ -53,7 +53,3 @@
'hu': ['en'],
'pl': self.alphabetic,
}
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
site."""
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/families/wikipedia_family.py
b/pywikibot/families/wikipedia_family.py
index 674b046..23de9d6 100644
--- a/pywikibot/families/wikipedia_family.py
+++ b/pywikibot/families/wikipedia_family.py
@@ -414,10 +414,3 @@
'sv': (u'/dok', ),
'uk': (u'/Документація', ),
}
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
site."""
- if code in ['test', 'test2']:
- return ('test', 'wikidata')
- else:
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/families/wikiquote_family.py
b/pywikibot/families/wikiquote_family.py
index 0c9f5d5..5ad714f 100644
--- a/pywikibot/families/wikiquote_family.py
+++ b/pywikibot/families/wikiquote_family.py
@@ -117,7 +117,3 @@
if code == 'ru':
return 'utf-8', 'iso8859-5'
return self.code2encoding(code),
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
family."""
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/families/wikisource_family.py
b/pywikibot/families/wikisource_family.py
index 72a3a07..afbea64 100644
--- a/pywikibot/families/wikisource_family.py
+++ b/pywikibot/families/wikisource_family.py
@@ -124,7 +124,3 @@
'sv': (u'/dok', ),
'uk': (u'/документація', ),
}
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
site."""
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/families/wikivoyage_family.py
b/pywikibot/families/wikivoyage_family.py
index f762c76..5f5a4dd 100644
--- a/pywikibot/families/wikivoyage_family.py
+++ b/pywikibot/families/wikivoyage_family.py
@@ -27,7 +27,3 @@
# Global bot allowed languages on
#
https://meta.wikimedia.org/wiki/Bot_policy/Implementation#Current_implement…
self.cross_allowed = ['es', 'ru', ]
-
- def shared_data_repository(self, code, transcluded=False):
- """Return the shared data repository for this
site."""
- return ('wikidata', 'wikidata')
diff --git a/pywikibot/family.py b/pywikibot/family.py
index 95f7695..ec2fcae 100644
--- a/pywikibot/family.py
+++ b/pywikibot/family.py
@@ -876,6 +876,9 @@
elif name == 'known_families':
issue_deprecation_warning('known_families',
'APISite.interwiki(prefix)', 2)
+ elif name == 'shared_data_repository':
+ issue_deprecation_warning('shared_data_repository',
+ 'APISite.data_repository()', 2)
return super(Family, self).__getattribute__(name)
@staticmethod
@@ -1323,8 +1326,12 @@
"""Return the shared image repository, if any."""
return (None, None)
+ # Deprecated via __getattribute__
def shared_data_repository(self, code, transcluded=False):
"""Return the shared Wikibase repository, if
any."""
+ repo = pywikibot.Site(code, self).data_repository()
+ if repo is not None:
+ return repo.code, repo.family.name
return (None, None)
@deprecated("Site.server_time()")
diff --git a/pywikibot/site.py b/pywikibot/site.py
index 16d3e99..6a411bb 100644
--- a/pywikibot/site.py
+++ b/pywikibot/site.py
@@ -58,6 +58,7 @@
CascadeLockedPage,
LockedNoPage,
NoPage,
+ SiteDefinitionError,
UnknownSite,
UnknownExtension,
FamilyMaintenanceWarning,
@@ -2637,14 +2638,12 @@
@property
def has_data_repository(self):
"""Return True if site has a shared data repository like
Wikidata."""
- code, fam = self.shared_data_repository()
- return bool(code or fam)
+ return self.data_repository() is not None
@property
def has_transcluded_data(self):
"""Return True if site has a shared data repository like
Wikidata."""
- code, fam = self.shared_data_repository(True)
- return bool(code or fam)
+ return self.data_repository() is not None
def image_repository(self):
"""Return Site object for image repository e.g.
commons."""
@@ -2653,18 +2652,40 @@
return pywikibot.Site(code, fam, self.username())
def data_repository(self):
- """Return Site object for data repository e.g.
Wikidata."""
- code, fam = self.shared_data_repository()
- if bool(code or fam):
- return pywikibot.Site(code, fam, self.username(),
- interface="DataSite")
+ """
+ Return the data repository connected to this site.
+
+ @return: The data repository if one is connected or None otherwise.
+ @rtype: DataSite or None
+ """
+ def handle_warning(mod, warning):
+ return (mod == 'query' and
+ warning == "Unrecognized value for parameter 'meta':
"
+ "wikibase")
+
+ req = self._simple_request(action='query', meta='wikibase')
+ req._warning_handler = handle_warning
+ data = req.submit()
+ if 'query' in data and 'wikibase' in data['query']:
+ data =
data['query']['wikibase']['repo']['url']
+ url = data['base'] + data['scriptpath'] +
'/index.php'
+ try:
+ return pywikibot.Site(url=url, user=self.username(),
+ interface='DataSite')
+ except SiteDefinitionError as e:
+ pywikibot.warning('Site "{0}" supports wikibase at
"{1}", but '
+ 'creation failed: {2}.'.format(self, url, e))
+ return None
+ else:
+ assert 'warnings' in data
+ return None
def is_image_repository(self):
"""Return True if Site object is the image
repository."""
return self is self.image_repository()
def is_data_repository(self):
- """Return True if Site object is the data
repository."""
+ """Return True if its data repository is
itself."""
return self is self.data_repository()
def nice_get_address(self, title):
diff --git a/tests/aspects.py b/tests/aspects.py
index bdcc0a0..4b9035c 100644
--- a/tests/aspects.py
+++ b/tests/aspects.py
@@ -906,9 +906,8 @@
cls.sites = {}
# If the test is not cached, create new Site objects for this class
- if not hasattr(cls, 'cached') or not cls.cached:
- orig_sites = pywikibot._sites
- pywikibot._sites = {}
+ cm = cls._uncached()
+ cm.__enter__()
interface = None # defaults to 'APISite'
dry = hasattr(cls, 'dry') and cls.dry
@@ -933,13 +932,22 @@
# without a mapping to a hostname.
pass
- if not hasattr(cls, 'cached') or not cls.cached:
- pywikibot._sites = orig_sites
+ cm.__exit__(None, None, None)
if len(cls.sites) == 1:
key = next(iter(cls.sites.keys()))
if 'site' in cls.sites[key]:
cls.site = cls.sites[key]['site']
+
+ @classmethod
+ @contextmanager
+ def _uncached(cls):
+ if not hasattr(cls, 'cached') or not cls.cached:
+ orig_sites = pywikibot._sites
+ pywikibot._sites = {}
+ yield
+ if not hasattr(cls, 'cached') or not cls.cached:
+ pywikibot._sites = orig_sites
@classmethod
def get_site(cls, name=None):
@@ -1259,23 +1267,24 @@
"""
super(WikibaseTestCase, cls).setUpClass()
- for data in cls.sites.values():
- if 'site' not in data:
- continue
+ with cls._uncached():
+ for data in cls.sites.values():
+ if 'site' not in data:
+ continue
- site = data['site']
- if not site.has_data_repository:
- raise unittest.SkipTest(
- u'%s: %r does not have data repository'
- % (cls.__name__, site))
+ site = data['site']
+ if not site.has_data_repository:
+ raise unittest.SkipTest(
+ u'%s: %r does not have data repository'
+ % (cls.__name__, site))
- if (hasattr(cls, 'repo') and
- cls.repo != site.data_repository()):
- raise Exception(
- '%s: sites do not all have the same data repository'
- % cls.__name__)
+ if (hasattr(cls, 'repo') and
+ cls.repo != site.data_repository()):
+ raise Exception(
+ '%s: sites do not all have the same data repository'
+ % cls.__name__)
- cls.repo = site.data_repository()
+ cls.repo = site.data_repository()
@classmethod
def get_repo(cls):
diff --git a/tests/utils.py b/tests/utils.py
index 6884cb1..408c181 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -449,7 +449,20 @@
def data_repository(self):
"""Return Site object for data repository e.g.
Wikidata."""
- code, fam = self.shared_data_repository()
+ if self.hostname().endswith('.beta.wmflabs.org'):
+ # TODO: Use definition for beta cluster's wikidata
+ code, fam = None, None
+ fam_name = self.hostname().split('.')[-4]
+ else:
+ code, fam = 'wikidata', 'wikidata'
+ fam_name = self.family.name
+
+ # Only let through valid entries
+ if fam_name not in ('commons', 'wikibooks', 'wikidata',
'wikinews',
+ 'wikipedia', 'wikiquote',
'wikisource',
+ 'wikivoyage'):
+ code, fam = None, None
+
if bool(code or fam):
return pywikibot.Site(code, fam, self.username(),
interface=DryDataSite)
diff --git a/tests/wikibase_tests.py b/tests/wikibase_tests.py
index e49945c..ef2d513 100644
--- a/tests/wikibase_tests.py
+++ b/tests/wikibase_tests.py
@@ -889,6 +889,7 @@
"""Test cases to test namespaces of Wikibase
entities."""
+ cached = False
dry = True
@classmethod
--
To view, visit
https://gerrit.wikimedia.org/r/247555
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I5568d848a369c8af36a40c193e2409071e23a5fb
Gerrit-PatchSet: 8
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: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: jenkins-bot <>