jenkins-bot merged this change.

View Change

Approvals: Dalba: Looks good to me, approved jenkins-bot: Verified
Make family classes singletons

Families are realistically singletons because multiple instances
for the same family simply make no sense. See my complaints on:
https://gerrit.wikimedia.org/r/#/c/429875/3

Family is made a basic singleton class (not using metaclass). It
will refuse to create more than one instances of the same class
without hacks such as programmatically overwriting or deleting
class attributes / methods.

The exception to this rule is AutoFamily, which needs many
instances in order to represent sites with different uris. This
AutoFamily isreplaced with a dynamic class generator via 3-argument
type() constructor call, generating singleton classes.

Many instance initialization logic is now flattened to the class
code, with few exceptions that depend on parent class, in which case
they are converted to classproperties. The majority of instance
properties are also converted to class properties.

Change-Id: I2a3cb83c5fb6fb3648c9ef2e08313cf77dbb9c29
---
M generate_family_file.py
M pywikibot/families/commons_family.py
M pywikibot/families/meta_family.py
M pywikibot/families/omegawiki_family.py
M pywikibot/families/outreach_family.py
M pywikibot/families/species_family.py
M pywikibot/families/strategy_family.py
M pywikibot/families/wikibooks_family.py
M pywikibot/families/wikidata_family.py
M pywikibot/families/wikimania_family.py
M pywikibot/families/wikimediachapter_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/wikiversity_family.py
M pywikibot/families/wikivoyage_family.py
M pywikibot/families/wiktionary_family.py
M pywikibot/families/wowwiki_family.py
M pywikibot/family.py
M scripts/maintenance/wikimedia_sites.py
M tests/family_tests.py
M tox.ini
23 files changed, 1,539 insertions(+), 1,559 deletions(-)

diff --git a/generate_family_file.py b/generate_family_file.py
index 2abb768..a93ff05 100755
--- a/generate_family_file.py
+++ b/generate_family_file.py
@@ -154,17 +154,15 @@


class Family(family.Family):
- def __init__(self):
- family.Family.__init__(self)
- self.name = '%(name)s'
- self.langs = {
+ name = '%(name)s'
+ langs = {
""".lstrip() % {'url': self.base_url, 'name': self.name})

for k, w in self.wikis.items():
- f.write(" '%(lang)s': '%(hostname)s',\n"
+ f.write(" '%(lang)s': '%(hostname)s',\n"
% {'lang': k, 'hostname': urlparse(w.server).netloc})

- f.write(" }\n\n")
+ f.write(' }\n\n')
f.write(" def scriptpath(self, code):\n")
f.write(" return {\n")

diff --git a/pywikibot/families/commons_family.py b/pywikibot/families/commons_family.py
index 99c96d1..130c761 100644
--- a/pywikibot/families/commons_family.py
+++ b/pywikibot/families/commons_family.py
@@ -17,30 +17,26 @@

name = 'commons'

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
+ langs = {
+ 'commons': 'commons.wikimedia.org',
+ 'beta': 'commons.wikimedia.beta.wmflabs.org'
+ }

- self.langs = {
- 'commons': 'commons.wikimedia.org',
- 'beta': 'commons.wikimedia.beta.wmflabs.org'
- }
+ interwiki_forward = 'wikipedia'

- self.interwiki_forward = 'wikipedia'
+ # Templates that indicate a category redirect
+ # Redirects to these templates are automatically included
+ category_redirect_templates = {
+ '_default': (
+ 'Category redirect',
+ 'Synonym taxon category redirect',
+ 'Invalid taxon category redirect',
+ 'Monotypic taxon category redirect',
+ 'Endashcatredirect',
+ ),
+ }

- # Templates that indicate a category redirect
- # Redirects to these templates are automatically included
- self.category_redirect_templates = {
- '_default': (
- u'Category redirect',
- u'Synonym taxon category redirect',
- u'Invalid taxon category redirect',
- u'Monotypic taxon category redirect',
- 'Endashcatredirect',
- ),
- }
-
- # Subpages for documentation.
- self.doc_subpages = {
- '_default': ((u'/doc', ), ['commons']),
- }
+ # Subpages for documentation.
+ doc_subpages = {
+ '_default': (('/doc', ), ['commons']),
+ }
diff --git a/pywikibot/families/meta_family.py b/pywikibot/families/meta_family.py
index d97bae6..3bb6146 100644
--- a/pywikibot/families/meta_family.py
+++ b/pywikibot/families/meta_family.py
@@ -17,20 +17,16 @@

name = 'meta'

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
+ interwiki_forward = 'wikipedia'
+ cross_allowed = ['meta', ]

- self.interwiki_forward = 'wikipedia'
- self.cross_allowed = ['meta', ]
+ category_redirect_templates = {
+ 'meta': (
+ 'Category redirect',
+ ),
+ }

- self.category_redirect_templates = {
- 'meta': (
- 'Category redirect',
- ),
- }
-
- # Subpages for documentation.
- self.doc_subpages = {
- '_default': (('/doc',), ['meta']),
- }
+ # Subpages for documentation.
+ doc_subpages = {
+ '_default': (('/doc',), ['meta']),
+ }
diff --git a/pywikibot/families/omegawiki_family.py b/pywikibot/families/omegawiki_family.py
index cf9f6f4..7db781e 100644
--- a/pywikibot/families/omegawiki_family.py
+++ b/pywikibot/families/omegawiki_family.py
@@ -18,14 +18,9 @@
name = 'omegawiki'
domain = 'www.omegawiki.org'

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
-
- # On most Wikipedias page names must start with a capital letter,
- # but some languages don't use this.
-
- self.nocapitalize = list(self.langs.keys())
+ # On most Wikipedias page names must start with a capital letter, but some
+ # languages don't use this.
+ nocapitalize = ['omegawiki']

def scriptpath(self, code):
"""Return the script path for this family."""
diff --git a/pywikibot/families/outreach_family.py b/pywikibot/families/outreach_family.py
index 4500287..d1fe3f9 100644
--- a/pywikibot/families/outreach_family.py
+++ b/pywikibot/families/outreach_family.py
@@ -17,8 +17,4 @@

name = 'outreach'

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
-
- self.interwiki_forward = 'wikipedia'
+ interwiki_forward = 'wikipedia'
diff --git a/pywikibot/families/species_family.py b/pywikibot/families/species_family.py
index 00089ff..26851ce 100644
--- a/pywikibot/families/species_family.py
+++ b/pywikibot/families/species_family.py
@@ -17,8 +17,4 @@

name = 'species'

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
-
- self.interwiki_forward = 'wikipedia'
+ interwiki_forward = 'wikipedia'
diff --git a/pywikibot/families/strategy_family.py b/pywikibot/families/strategy_family.py
index e67dce2..87d799c 100644
--- a/pywikibot/families/strategy_family.py
+++ b/pywikibot/families/strategy_family.py
@@ -17,11 +17,7 @@

name = 'strategy'

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
-
- self.interwiki_forward = 'wikipedia'
+ interwiki_forward = 'wikipedia'

def dbName(self, code):
"""Return the database name for this family."""
diff --git a/pywikibot/families/wikibooks_family.py b/pywikibot/families/wikibooks_family.py
index f63a16d..ef078ce 100644
--- a/pywikibot/families/wikibooks_family.py
+++ b/pywikibot/families/wikibooks_family.py
@@ -32,39 +32,35 @@
'dk', 'tokipona',
]

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'en', 'hu', 'de', 'fr', 'pt', 'ja', 'it', 'nl', 'es', 'pl', 'th',
- 'he', 'id', 'sq', 'fi', 'fa', 'zh', 'ca', 'ru', 'az', 'vi', 'da',
- 'ko', 'sv', 'gl', 'sr', 'cs', 'hr', 'ba', 'no', 'tr', 'ar', 'ta',
- 'sa', 'sk', 'uk', 'is', 'hi', 'ro', 'eo', 'si', 'mk', 'bn', 'bg',
- 'ka', 'ms', 'lt', 'tt', 'li', 'el', 'ur', 'sl', 'km', 'tl', 'kk',
- 'et', 'ml', 'oc', 'be', 'ia', 'eu', 'ne', 'pa', 'hy', 'la', 'cv',
- 'tg', 'fy', 'ku', 'bs', 'cy', 'te', 'af', 'mr', 'mg', 'ky',
- ]
+ languages_by_size = [
+ 'en', 'hu', 'de', 'fr', 'pt', 'ja', 'it', 'nl', 'es', 'pl', 'th', 'he',
+ 'id', 'sq', 'fi', 'fa', 'zh', 'ca', 'ru', 'az', 'vi', 'da', 'ko', 'sv',
+ 'gl', 'sr', 'cs', 'hr', 'ba', 'no', 'tr', 'ar', 'ta', 'sa', 'sk', 'uk',
+ 'is', 'hi', 'ro', 'eo', 'si', 'mk', 'bn', 'bg', 'ka', 'ms', 'lt', 'tt',
+ 'li', 'el', 'ur', 'sl', 'km', 'tl', 'kk', 'et', 'ml', 'oc', 'be', 'ia',
+ 'eu', 'ne', 'pa', 'hy', 'la', 'cv', 'tg', 'fy', 'ku', 'bs', 'cy', 'te',
+ 'af', 'mr', 'mg', 'ky',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'en': ('Category redirect',),
+ 'es': ('Categoría redirigida',),
+ 'ro': ('Redirect categorie',),
+ 'vi': ('Đổi hướng thể loại',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'en': ('Category redirect',),
- 'es': ('Categoría redirigida',),
- 'ro': ('Redirect categorie',),
- 'vi': ('Đổi hướng thể loại',),
- }
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ cross_allowed = [
+ 'af', 'ca', 'fa', 'fy', 'gl', 'it', 'nl', 'ru', 'th', 'zh',
+ ]

- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- self.cross_allowed = [
- 'af', 'ca', 'fa', 'fy', 'gl', 'it', 'nl', 'ru', 'th', 'zh',
- ]
-
- # Subpages for documentation.
- # TODO: List is incomplete, to be completed for missing languages.
- self.doc_subpages = {
- '_default': ((u'/doc', ),
- ['en']
- ),
- 'es': ('/uso', '/doc'),
- }
+ # Subpages for documentation.
+ # TODO: List is incomplete, to be completed for missing languages.
+ doc_subpages = {
+ '_default': (('/doc', ),
+ ['en']
+ ),
+ 'es': ('/uso', '/doc'),
+ }
diff --git a/pywikibot/families/wikidata_family.py b/pywikibot/families/wikidata_family.py
index 29d5825..742f489 100644
--- a/pywikibot/families/wikidata_family.py
+++ b/pywikibot/families/wikidata_family.py
@@ -19,31 +19,28 @@
name = 'wikidata'
test_codes = ('test', )

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
- self.langs = {
- 'wikidata': 'www.wikidata.org',
- 'test': 'test.wikidata.org',
- }
+ langs = {
+ 'wikidata': 'www.wikidata.org',
+ 'test': 'test.wikidata.org',
+ }

- self.interwiki_forward = 'wikipedia'
+ interwiki_forward = 'wikipedia'

- self.category_redirect_templates = {
- 'wikidata': (
- 'Category redirect',
- ),
- }
+ category_redirect_templates = {
+ 'wikidata': (
+ 'Category redirect',
+ ),
+ }

- # Subpages for documentation.
- self.doc_subpages = {
- '_default': ((u'/doc', ), ['wikidata']),
- }
+ # Subpages for documentation.
+ doc_subpages = {
+ '_default': (('/doc', ), ['wikidata']),
+ }

- # Disable cosmetic changes
- config.cosmetic_changes_disable.update({
- 'wikidata': ('wikidata', 'test')
- })
+ # Disable cosmetic changes
+ config.cosmetic_changes_disable.update({
+ 'wikidata': ('wikidata', 'test')
+ })

def interface(self, code):
"""Return 'DataSite'."""
diff --git a/pywikibot/families/wikimania_family.py b/pywikibot/families/wikimania_family.py
index d525940..51afca4 100644
--- a/pywikibot/families/wikimania_family.py
+++ b/pywikibot/families/wikimania_family.py
@@ -22,12 +22,8 @@
'2014', '2015', '2016', '2017'
]

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
+ langs = {
+ '2018': 'wikimania2018.wikimedia.org'
+ }

- self.langs = {
- '2018': 'wikimania2018.wikimedia.org'
- }
-
- self.interwiki_forward = 'wikipedia'
+ interwiki_forward = 'wikipedia'
diff --git a/pywikibot/families/wikimediachapter_family.py b/pywikibot/families/wikimediachapter_family.py
index 4181d3c..d564b70 100644
--- a/pywikibot/families/wikimediachapter_family.py
+++ b/pywikibot/families/wikimediachapter_family.py
@@ -8,7 +8,7 @@
from __future__ import absolute_import, unicode_literals

from pywikibot import family
-from pywikibot.tools import deprecated
+from pywikibot.tools import deprecated, classproperty


class Family(family.SubdomainFamily, family.WikimediaFamily):
@@ -26,8 +26,8 @@
'se', 'tr', 'ua', 'uk', 've', 'wb',
]

- @property
+ @classproperty
@deprecated
- def countries(self):
+ def countries(cls):
"""Deprecated."""
- return self.codes
+ return cls.codes
diff --git a/pywikibot/families/wikinews_family.py b/pywikibot/families/wikinews_family.py
index 327955d..5d317ae 100644
--- a/pywikibot/families/wikinews_family.py
+++ b/pywikibot/families/wikinews_family.py
@@ -22,35 +22,31 @@
'hu', 'sd', 'th',
]

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'sr', 'en', 'fr', 'ru', 'de', 'pt', 'pl', 'es', 'it', 'ar', 'zh',
- 'cs', 'ca', 'nl', 'el', 'ta', 'sv', 'uk', 'fa', 'ro', 'tr', 'ja',
- 'sq', 'no', 'eo', 'fi', 'bs', 'ko', 'he', 'bg',
- ]
+ languages_by_size = [
+ 'sr', 'en', 'fr', 'ru', 'de', 'pt', 'pl', 'es', 'it', 'ar', 'zh',
+ 'cs', 'ca', 'nl', 'el', 'ta', 'sv', 'uk', 'fa', 'ro', 'tr', 'ja',
+ 'sq', 'no', 'eo', 'fi', 'bs', 'ko', 'he', 'bg',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'ar': ('قالب:تحويل تصنيف',),
+ 'fa': ('الگو:رده بهتر',),
+ 'no': ('Kategoriomdirigering',),
+ 'ro': ('Redirect categorie',),
+ 'ru': ('Category redirect',),
+ 'tr': ('Kategori yönlendirme',),
+ 'zh': ('分类重定向',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'ar': ('قالب:تحويل تصنيف',),
- 'fa': ('الگو:رده بهتر',),
- 'no': ('Kategoriomdirigering',),
- 'ro': ('Redirect categorie',),
- 'ru': ('Category redirect',),
- 'tr': ('Kategori yönlendirme',),
- 'zh': ('分类重定向',),
- }
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
+ cross_allowed = [
+ 'ar', 'bg', 'bs', 'ca', 'cs', 'el', 'en', 'eo', 'fa', 'fi', 'he',
+ 'ja', 'ko', 'nl', 'no', 'pt', 'ro', 'sq', 'sr', 'sv', 'ta', 'tr',
+ 'uk', 'zh',
+ ]

- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
- self.cross_allowed = [
- 'ar', 'bg', 'bs', 'ca', 'cs', 'el', 'en', 'eo', 'fa', 'fi', 'he',
- 'ja', 'ko', 'nl', 'no', 'pt', 'ro', 'sq', 'sr', 'sv', 'ta', 'tr',
- 'uk', 'zh',
- ]
-
- # TODO:
- # Change site_tests.py when wikinews will have doc_subpage.
+ # TODO:
+ # Change site_tests.py when wikinews will have doc_subpage.
diff --git a/pywikibot/families/wikipedia_family.py b/pywikibot/families/wikipedia_family.py
index 300622c..812de86 100644
--- a/pywikibot/families/wikipedia_family.py
+++ b/pywikibot/families/wikipedia_family.py
@@ -28,203 +28,197 @@
'dk', 'ru-sib', 'tlh', 'tokipona', 'zh_cn', 'zh_tw',
]

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'en', 'ceb', 'sv', 'de', 'fr', 'nl', 'ru', 'it', 'es', 'pl', 'war',
- 'vi', 'ja', 'zh', 'pt', 'uk', 'fa', 'sr', 'ca', 'ar', 'no', 'sh',
- 'fi', 'hu', 'id', 'ko', 'cs', 'ro', 'ms', 'tr', 'eu', 'eo', 'bg',
- 'hy', 'da', 'zh-min-nan', 'sk', 'he', 'min', 'kk', 'hr', 'lt',
- 'et', 'ce', 'sl', 'be', 'gl', 'el', 'ur', 'nn', 'az', 'simple',
- 'uz', 'la', 'hi', 'th', 'ka', 'vo', 'ta', 'cy', 'mk', 'tg', 'mg',
- 'lv', 'oc', 'tl', 'ky', 'tt', 'bs', 'ast', 'azb', 'sq', 'new',
- 'te', 'zh-yue', 'br', 'pms', 'be-tarask', 'bn', 'ml', 'jv', 'lb',
- 'ht', 'sco', 'mr', 'af', 'ga', 'pnb', 'is', 'ba', 'sw', 'cv', 'fy',
- 'su', 'my', 'lmo', 'an', 'yo', 'ne', 'nds', 'pa', 'gu', 'io',
- 'scn', 'bar', 'bpy', 'als', 'ku', 'kn', 'ckb', 'ia', 'qu', 'arz',
- 'mn', 'bat-smg', 'si', 'gd', 'wa', 'nap', 'yi', 'am', 'bug', 'or',
- 'cdo', 'map-bms', 'hsb', 'fo', 'mzn', 'mai', 'xmf', 'li', 'sah',
- 'sa', 'vec', 'ilo', 'os', 'mrj', 'eml', 'mhr', 'hif', 'sd', 'bh',
- 'roa-tara', 'wuu', 'ps', 'diq', 'pam', 'hak', 'nso',
- 'zh-classical', 'bcl', 'se', 'ace', 'szl', 'mi', 'nah', 'nds-nl',
- 'frr', 'rue', 'vls', 'gan', 'km', 'bo', 'crh', 'sc', 'vep', 'glk',
- 'co', 'fiu-vro', 'tk', 'lrc', 'kv', 'myv', 'csb', 'gv', 'as', 'nv',
- 'so', 'zea', 'udm', 'ay', 'ie', 'lez', 'stq', 'ug', 'nrm', 'kw',
- 'lad', 'pcd', 'sn', 'mwl', 'gn', 'rm', 'gom', 'koi', 'ab', 'lij',
- 'mt', 'fur', 'dsb', 'frp', 'dv', 'ang', 'ln', 'cbk-zam', 'kab',
- 'ext', 'dty', 'ksh', 'lo', 'gag', 'olo', 'pag', 'pi', 'av', 'haw',
- 'bxr', 'pfl', 'xal', 'krc', 'lfn', 'pap', 'kaa', 'rw', 'bjn',
- 'pdc', 'ha', 'to', 'nov', 'kl', 'arc', 'jam', 'kbd', 'tyv', 'tpi',
- 'kbp', 'tet', 'ki', 'ig', 'na', 'jbo', 'lbe', 'roa-rup', 'gor',
- 'ty', 'mdf', 'za', 'kg', 'bi', 'wo', 'lg', 'srn', 'tcy', 'zu',
- 'chr', 'ltg', 'sm', 'om', 'inh', 'xh', 'rmy', 'bm', 'cu', 'tn',
- 'pih', 'rn', 'chy', 'tw', 'ts', 'tum', 'ak', 'got', 'st', 'atj',
- 'pnt', 'ss', 'ch', 'fj', 'iu', 'ady', 'ny', 'ee', 'ks', 'ik', 've',
- 'sg', 'ff', 'dz', 'ti', 'cr', 'din',
- ]
+ languages_by_size = [
+ 'en', 'ceb', 'sv', 'de', 'fr', 'nl', 'ru', 'it', 'es', 'war', 'pl',
+ 'vi', 'ja', 'pt', 'zh', 'uk', 'fa', 'ca', 'ar', 'no', 'sh', 'fi', 'hu',
+ 'id', 'ko', 'cs', 'ro', 'sr', 'ms', 'tr', 'eu', 'eo', 'bg', 'hy', 'da',
+ 'zh-min-nan', 'sk', 'min', 'kk', 'he', 'lt', 'hr', 'ce', 'et', 'sl',
+ 'be', 'gl', 'el', 'nn', 'simple', 'uz', 'az', 'la', 'ur', 'hi', 'vo',
+ 'th', 'ka', 'ta', 'cy', 'mk', 'tg', 'tl', 'mg', 'oc', 'ky', 'lv', 'bs',
+ 'tt', 'new', 'sq', 'te', 'pms', 'br', 'zh-yue', 'be-tarask', 'ast',
+ 'bn', 'ml', 'ht', 'lb', 'jv', 'mr', 'azb', 'af', 'sco', 'pnb', 'ga',
+ 'is', 'cv', 'ba', 'fy', 'su', 'sw', 'my', 'lmo', 'an', 'yo', 'ne',
+ 'gu', 'io', 'pa', 'nds', 'scn', 'bpy', 'als', 'bar', 'ku', 'kn', 'ia',
+ 'qu', 'ckb', 'mn', 'arz', 'bat-smg', 'wa', 'gd', 'nap', 'yi', 'bug',
+ 'si', 'am', 'cdo', 'map-bms', 'or', 'fo', 'mzn', 'hsb', 'xmf', 'li',
+ 'mai', 'sah', 'sa', 'vec', 'ilo', 'os', 'mrj', 'hif', 'mhr', 'bh',
+ 'eml', 'roa-tara', 'ps', 'diq', 'pam', 'sd', 'hak', 'nso', 'se', 'ace',
+ 'bcl', 'mi', 'zh-classical', 'nah', 'nds-nl', 'szl', 'gan', 'wuu',
+ 'vls', 'rue', 'km', 'frr', 'bo', 'glk', 'vep', 'sc', 'fiu-vro', 'co',
+ 'crh', 'lrc', 'tk', 'kv', 'csb', 'so', 'gv', 'as', 'lad', 'zea', 'ay',
+ 'myv', 'udm', 'lez', 'nv', 'stq', 'kw', 'ie', 'nrm', 'pcd', 'mwl',
+ 'rm', 'koi', 'gom', 'ug', 'ab', 'lij', 'gn', 'mt', 'fur', 'dsb',
+ 'cbk-zam', 'dv', 'ang', 'ln', 'ext', 'sn', 'kab', 'ksh', 'lo', 'gag',
+ 'frp', 'pag', 'pi', 'olo', 'dty', 'av', 'xal', 'pfl', 'bxr', 'haw',
+ 'krc', 'lfn', 'kaa', 'pap', 'rw', 'pdc', 'bjn', 'to', 'nov', 'kl',
+ 'arc', 'jam', 'kbd', 'ha', 'tyv', 'tpi', 'tet', 'ig', 'ki', 'na',
+ 'lbe', 'roa-rup', 'jbo', 'ty', 'gor', 'mdf', 'kg', 'za', 'wo', 'lg',
+ 'bi', 'srn', 'zu', 'chr', 'tcy', 'ltg', 'sm', 'om', 'xh', 'inh', 'tn',
+ 'pih', 'cu', 'chy', 'rmy', 'tw', 'kbp', 'tum', 'ts', 'st', 'got', 'rn',
+ 'pnt', 'ss', 'bm', 'fj', 'ch', 'ady', 'iu', 'ny', 'ee', 'ks', 'ak',
+ 'ik', 've', 'sg', 'atj', 'dz', 'ff', 'ti', 'cr', 'din',
+ ]

- # Sites we want to edit but not count as real languages
- self.test_codes = ['test', 'test2']
+ # Sites we want to edit but not count as real languages
+ test_codes = ['test', 'test2']

- super(Family, self).__init__()
+ # Templates that indicate a category redirect
+ # Redirects to these templates are automatically included
+ category_redirect_templates = {
+ '_default': (),
+ 'ar': ('تحويل تصنيف',),
+ 'arz': ('تحويل تصنيف',),
+ 'bn': ('বিষয়শ্রেণী পুনর্নির্দেশ',),
+ 'bs': ('Category redirect',),
+ 'cs': ('Zastaralá kategorie',),
+ 'da': ('Kategoriomdirigering',),
+ 'en': ('Category redirect',),
+ 'es': ('Categoría redirigida',),
+ 'eu': ('Kategoria birzuzendu',),
+ 'fa': ('رده بهتر',),
+ 'fr': ('Catégorie redirigée',),
+ 'gv': ('Aastiurey ronney',),
+ 'hi': ('श्रेणी अनुप्रेषित',),
+ 'hu': ('Kat-redir',),
+ 'id': ('Alih kategori',),
+ 'ja': ('Category redirect',),
+ 'ko': ('분류 넘겨주기',),
+ 'mk': ('Премести категорија',),
+ 'ml': ('Category redirect',),
+ 'ms': ('Pengalihan kategori',),
+ 'mt': ('Rindirizzament kategorija',),
+ 'ne': ('श्रेणी अनुप्रेषण',),
+ 'no': ('Kategoriomdirigering',),
+ 'pt': ('Redirecionamento de categoria',),
+ 'ro': ('Redirect categorie',),
+ 'ru': ('Переименованная категория',),
+ 'sco': ('Category redirect',),
+ 'sh': ('Prekat',),
+ 'simple': ('Category redirect',),
+ 'sl': ('Preusmeritev kategorije',),
+ 'sr': ('Category redirect',),
+ 'sq': ('Kategori e zhvendosur',),
+ 'sv': ('Kategoriomdirigering',),
+ 'tl': ('Category redirect',),
+ 'tr': ('Kategori yönlendirme',),
+ 'uk': ('Categoryredirect',),
+ 'ur': ('زمرہ رجوع مکرر',),
+ 'vi': ('Đổi hướng thể loại',),
+ 'yi': ('קאטעגאריע אריבערפירן',),
+ 'zh': ('分类重定向',),
+ 'zh-yue': ('分類彈去',),
+ }

- # Templates that indicate a category redirect
- # Redirects to these templates are automatically included
- self.category_redirect_templates = {
- '_default': (),
- 'ar': ('تحويل تصنيف',),
- 'arz': (u'تحويل تصنيف',),
- 'bn': ('বিষয়শ্রেণী পুনর্নির্দেশ',),
- 'bs': ('Category redirect',),
- 'cs': (u'Zastaralá kategorie',),
- 'da': (u'Kategoriomdirigering',),
- 'en': (u'Category redirect',),
- 'es': (u'Categoría redirigida',),
- 'eu': ('Kategoria birzuzendu',),
- 'fa': ('رده بهتر',),
- 'fr': ('Catégorie redirigée',),
- 'gv': (u'Aastiurey ronney',),
- 'hi': ('श्रेणी अनुप्रेषित',),
- 'hu': ('Kat-redir',),
- 'id': ('Alih kategori',),
- 'ja': (u'Category redirect',),
- 'ko': (u'분류 넘겨주기',),
- 'mk': (u'Премести категорија',),
- 'ml': (u'Category redirect',),
- 'ms': ('Pengalihan kategori',),
- 'mt': ('Rindirizzament kategorija',),
- 'ne': ('श्रेणी अनुप्रेषण',),
- 'no': ('Kategoriomdirigering',),
- 'pt': ('Redirecionamento de categoria',),
- 'ro': (u'Redirect categorie',),
- 'ru': ('Переименованная категория',),
- 'sco': ('Category redirect',),
- 'sh': ('Prekat',),
- 'simple': ('Category redirect',),
- 'sl': ('Preusmeritev kategorije',),
- 'sr': ('Category redirect',),
- 'sq': ('Kategori e zhvendosur',),
- 'sv': ('Kategoriomdirigering',),
- 'tl': (u'Category redirect',),
- 'tr': ('Kategori yönlendirme',),
- 'uk': (u'Categoryredirect',),
- 'ur': ('زمرہ رجوع مکرر',),
- 'vi': ('Đổi hướng thể loại',),
- 'yi': (u'קאטעגאריע אריבערפירן',),
- 'zh': ('分类重定向',),
- 'zh-yue': ('分類彈去',),
- }
+ # families that redirect their interlanguage links here.
+ interwiki_forwarded_from = [
+ 'commons',
+ 'incubator',
+ 'meta',
+ 'species',
+ 'strategy',
+ 'test',
+ 'wikimania'
+ ]

- # families that redirect their interlanguage links here.
- self.interwiki_forwarded_from = [
- 'commons',
- 'incubator',
- 'meta',
- 'species',
- 'strategy',
- 'test',
- 'wikimania'
- ]
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
+ cross_allowed = [
+ 'ab', 'ace', 'ady', 'af', 'ak', 'als', 'am', 'an', 'ang', 'ar',
+ 'arc', 'arz', 'as', 'ast', 'av', 'ay', 'az', 'ba', 'bar',
+ 'bat-smg', 'bcl', 'be', 'be-tarask', 'bg', 'bh', 'bi', 'bjn', 'bm',
+ 'bo', 'bpy', 'bug', 'bxr', 'ca', 'cbk-zam', 'cdo', 'ce', 'ceb',
+ 'ch', 'chr', 'chy', 'ckb', 'co', 'cr', 'crh', 'cs', 'csb', 'cu',
+ 'cv', 'cy', 'da', 'diq', 'dsb', 'dz', 'ee', 'el', 'eml', 'en',
+ 'eo', 'et', 'eu', 'ext', 'fa', 'ff', 'fi', 'fj', 'fo', 'frp',
+ 'frr', 'fur', 'ga', 'gag', 'gan', 'gd', 'glk', 'gn', 'got', 'gu',
+ 'gv', 'ha', 'hak', 'haw', 'he', 'hi', 'hif', 'hr', 'hsb', 'ht',
+ 'hu', 'hy', 'ia', 'ie', 'ig', 'ik', 'ilo', 'io', 'iu', 'ja', 'jam',
+ 'jbo', 'jv', 'ka', 'kaa', 'kab', 'kdb', 'kg', 'ki', 'kk', 'kl',
+ 'km', 'kn', 'ko', 'koi', 'krc', 'ks', 'ku', 'kv', 'kw', 'ky', 'la',
+ 'lad', 'lb', 'lbe', 'lez', 'lg', 'li', 'lij', 'lmo', 'ln', 'lo',
+ 'lt', 'ltg', 'lv', 'map-bms', 'mdf', 'mg', 'mhr', 'mi', 'mk', 'ml',
+ 'mn', 'mrj', 'ms', 'mwl', 'my', 'myv', 'mzn', 'na', 'nah', 'nap',
+ 'nds-nl', 'ne', 'new', 'nl', 'no', 'nov', 'nrm', 'nso', 'nv', 'ny',
+ 'oc', 'olo', 'om', 'or', 'os', 'pa', 'pag', 'pam', 'pap', 'pdc',
+ 'pfl', 'pi', 'pih', 'pms', 'pnb', 'pnt', 'ps', 'qu', 'rm', 'rmy',
+ 'rn', 'roa-rup', 'roa-tara', 'ru', 'rue', 'rw', 'sa', 'sah', 'sc',
+ 'scn', 'sco', 'sd', 'se', 'sg', 'sh', 'si', 'simple', 'sk', 'sm',
+ 'sn', 'so', 'srn', 'ss', 'st', 'stq', 'su', 'sv', 'sw', 'szl',
+ 'ta', 'tcy', 'te', 'tet', 'tg', 'th', 'ti', 'tk', 'tl', 'tn', 'to',
+ 'tpi', 'tr', 'ts', 'tt', 'tum', 'tw', 'ty', 'tyv', 'udm', 'ug',
+ 'uz', 've', 'vec', 'vep', 'vls', 'vo', 'wa', 'war', 'wo', 'wuu',
+ 'xal', 'xh', 'xmf', 'yi', 'yo', 'za', 'zea', 'zh', 'zh-classical',
+ 'zh-min-nan', 'zh-yue', 'zu',
+ ]

- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
- self.cross_allowed = [
- 'ab', 'ace', 'ady', 'af', 'ak', 'als', 'am', 'an', 'ang', 'ar',
- 'arc', 'arz', 'as', 'ast', 'av', 'ay', 'az', 'ba', 'bar',
- 'bat-smg', 'bcl', 'be', 'be-tarask', 'bg', 'bh', 'bi', 'bjn', 'bm',
- 'bo', 'bpy', 'bug', 'bxr', 'ca', 'cbk-zam', 'cdo', 'ce', 'ceb',
- 'ch', 'chr', 'chy', 'ckb', 'co', 'cr', 'crh', 'cs', 'csb', 'cu',
- 'cv', 'cy', 'da', 'diq', 'dsb', 'dz', 'ee', 'el', 'eml', 'en',
- 'eo', 'et', 'eu', 'ext', 'fa', 'ff', 'fi', 'fj', 'fo', 'frp',
- 'frr', 'fur', 'ga', 'gag', 'gan', 'gd', 'glk', 'gn', 'got', 'gu',
- 'gv', 'ha', 'hak', 'haw', 'he', 'hi', 'hif', 'hr', 'hsb', 'ht',
- 'hu', 'hy', 'ia', 'ie', 'ig', 'ik', 'ilo', 'io', 'iu', 'ja', 'jam',
- 'jbo', 'jv', 'ka', 'kaa', 'kab', 'kdb', 'kg', 'ki', 'kk', 'kl',
- 'km', 'kn', 'ko', 'koi', 'krc', 'ks', 'ku', 'kv', 'kw', 'ky', 'la',
- 'lad', 'lb', 'lbe', 'lez', 'lg', 'li', 'lij', 'lmo', 'ln', 'lo',
- 'lt', 'ltg', 'lv', 'map-bms', 'mdf', 'mg', 'mhr', 'mi', 'mk', 'ml',
- 'mn', 'mrj', 'ms', 'mwl', 'my', 'myv', 'mzn', 'na', 'nah', 'nap',
- 'nds-nl', 'ne', 'new', 'nl', 'no', 'nov', 'nrm', 'nso', 'nv', 'ny',
- 'oc', 'olo', 'om', 'or', 'os', 'pa', 'pag', 'pam', 'pap', 'pdc',
- 'pfl', 'pi', 'pih', 'pms', 'pnb', 'pnt', 'ps', 'qu', 'rm', 'rmy',
- 'rn', 'roa-rup', 'roa-tara', 'ru', 'rue', 'rw', 'sa', 'sah', 'sc',
- 'scn', 'sco', 'sd', 'se', 'sg', 'sh', 'si', 'simple', 'sk', 'sm',
- 'sn', 'so', 'srn', 'ss', 'st', 'stq', 'su', 'sv', 'sw', 'szl',
- 'ta', 'tcy', 'te', 'tet', 'tg', 'th', 'ti', 'tk', 'tl', 'tn', 'to',
- 'tpi', 'tr', 'ts', 'tt', 'tum', 'tw', 'ty', 'tyv', 'udm', 'ug',
- 'uz', 've', 'vec', 'vep', 'vls', 'vo', 'wa', 'war', 'wo', 'wuu',
- 'xal', 'xh', 'xmf', 'yi', 'yo', 'za', 'zea', 'zh', 'zh-classical',
- 'zh-min-nan', 'zh-yue', 'zu',
- ]
+ # On most Wikipedias page names must start with a capital letter,
+ # but some languages don't use this.
+ nocapitalize = ['jbo']

- # On most Wikipedias page names must start with a capital letter,
- # but some languages don't use this.
- self.nocapitalize = ['jbo']
+ # Languages that used to be coded in iso-8859-1
+ latin1old = [
+ 'de', 'en', 'et', 'es', 'ia', 'la', 'af', 'cs', 'fr', 'pt', 'sl',
+ 'bs', 'fy', 'vi', 'lt', 'fi', 'it', 'no', 'simple', 'gl', 'eu',
+ 'nds', 'co', 'mi', 'mr', 'id', 'lv', 'sw', 'tt', 'uk', 'vo', 'ga',
+ 'na', 'es', 'nl', 'da', 'dk', 'sv', 'test']

- # Languages that used to be coded in iso-8859-1
- self.latin1old = [
- 'de', 'en', 'et', 'es', 'ia', 'la', 'af', 'cs', 'fr', 'pt', 'sl',
- 'bs', 'fy', 'vi', 'lt', 'fi', 'it', 'no', 'simple', 'gl', 'eu',
- 'nds', 'co', 'mi', 'mr', 'id', 'lv', 'sw', 'tt', 'uk', 'vo', 'ga',
- 'na', 'es', 'nl', 'da', 'dk', 'sv', 'test']
+ # Subpages for documentation.
+ # TODO: List is incomplete, to be completed for missing languages.
+ # TODO: Remove comments for appropriate pages
+ doc_subpages = {
+ '_default': (('/doc', ),
+ ['ar', 'bn', 'cs', 'da', 'en', 'es', 'hr',
+ 'hu', 'id', 'ilo', 'ja', 'ms',
+ 'pt', 'ro', 'ru', 'simple', 'sh', 'vi', 'zh']
+ ),
+ 'bs': ('/dok', ),
+ 'ca': ('/ús', ),
+ 'de': ('Doku', '/Meta'),
+ 'dsb': ('/Dokumentacija', ),
+ 'eu': ('txantiloi dokumentazioa', '/dok'),
+ 'fa': ('/doc', '/توضیحات'),
+ # fi: no idea how to handle this type of subpage at :Metasivu:
+ 'fi': ((), ),
+ 'fr': ('/Documentation',),
+ 'hsb': ('/Dokumentacija', ),
+ 'it': ('/Man', ),
+ 'ka': ('/ინფო', ),
+ 'ko': ('/설명문서', ),
+ 'no': ('/dok', ),
+ 'nn': ('/dok', ),
+ 'pl': ('/opis', ),
+ 'sk': ('/Dokumentácia', ),
+ 'sr': ('/док', ),
+ 'sv': ('/dok', ),
+ 'uk': ('/Документація', ),
+ 'ur': ('/doc', '/دستاویز'),
+ }

- # Subpages for documentation.
- # TODO: List is incomplete, to be completed for missing languages.
- # TODO: Remove comments for appropriate pages
- self.doc_subpages = {
- '_default': ((u'/doc', ),
- ['ar', 'bn', 'cs', 'da', 'en', 'es', 'hr',
- 'hu', 'id', 'ilo', 'ja', 'ms',
- 'pt', 'ro', 'ru', 'simple', 'sh', 'vi', 'zh']
- ),
- 'bs': ('/dok', ),
- 'ca': (u'/ús', ),
- 'de': (u'Doku', u'/Meta'),
- 'dsb': (u'/Dokumentacija', ),
- 'eu': (u'txantiloi dokumentazioa', u'/dok'),
- 'fa': (u'/doc', u'/توضیحات'),
- # fi: no idea how to handle this type of subpage at :Metasivu:
- 'fi': ((), ),
- 'fr': ('/Documentation',),
- 'hsb': (u'/Dokumentacija', ),
- 'it': (u'/Man', ),
- 'ka': (u'/ინფო', ),
- 'ko': (u'/설명문서', ),
- 'no': (u'/dok', ),
- 'nn': (u'/dok', ),
- 'pl': (u'/opis', ),
- 'sk': (u'/Dokumentácia', ),
- 'sr': ('/док', ),
- 'sv': (u'/dok', ),
- 'uk': (u'/Документація', ),
- 'ur': ('/doc', '/دستاویز'),
- }
+ # Templates that indicate an edit should be avoided
+ edit_restricted_templates = {
+ 'ar': ('تحرر',),
+ 'bs': ('Izmjena u toku',),
+ 'cs': ('Pracuje se',),
+ 'de': ('Inuse', 'In use', 'In bearbeitung', 'Inbearbeitung',),
+ 'en': ('Inuse', 'In use'),
+ 'fa': ('ویرایش',),
+ 'fr': ('En cours', 'Plusieurs en cours', 'Correction en cours',
+ 'Inuse', 'Remix',),
+ 'hr': ('Radovi',),
+ 'sr': ('Радови у току', 'Рут',),
+ 'ur': ('زیر ترمیم',),
+ 'zh': ('Inuse',),
+ }

- # Templates that indicate an edit should be avoided
- self.edit_restricted_templates = {
- 'ar': ('تحرر',),
- 'bs': ('Izmjena u toku',),
- 'cs': ('Pracuje se',),
- 'de': ('Inuse', 'In use', 'In bearbeitung', 'Inbearbeitung',),
- 'en': ('Inuse', 'In use'),
- 'fa': ('ویرایش',),
- 'fr': ('En cours', 'Plusieurs en cours', 'Correction en cours',
- 'Inuse', 'Remix',),
- 'hr': ('Radovi',),
- 'sr': ('Радови у току', 'Рут',),
- 'ur': ('زیر ترمیم',),
- 'zh': ('Inuse',),
- }
-
- # Archive templates that indicate an edit of non-archive bots
- # should be avoided
- self.archived_page_templates = {
- 'cs': ('Archiv', 'Archiv Wikipedie', 'Archiv diskuse',
- 'Archivace start', 'Posloupnost archivů',
- 'Rfa-archiv-start', 'Rfc-archiv-start',),
- 'de': ('Archiv',),
- }
+ # Archive templates that indicate an edit of non-archive bots
+ # should be avoided
+ archived_page_templates = {
+ 'cs': ('Archiv', 'Archiv Wikipedie', 'Archiv diskuse',
+ 'Archivace start', 'Posloupnost archivů',
+ 'Rfa-archiv-start', 'Rfc-archiv-start',),
+ 'de': ('Archiv',),
+ }

def get_known_families(self, site):
"""Override the family interwiki prefixes for each site."""
diff --git a/pywikibot/families/wikiquote_family.py b/pywikibot/families/wikiquote_family.py
index ad245dc..d5fdd41 100644
--- a/pywikibot/families/wikiquote_family.py
+++ b/pywikibot/families/wikiquote_family.py
@@ -29,48 +29,44 @@
'tokipona',
]

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'en', 'it', 'pl', 'ru', 'cs', 'fa', 'de', 'pt', 'es', 'uk', 'sk',
- 'fr', 'bs', 'he', 'tr', 'fi', 'ca', 'lt', 'th', 'bg', 'sl', 'eo',
- 'hy', 'el', 'hr', 'nn', 'id', 'zh', 'ar', 'su', 'hu', 'li', 'az',
- 'ko', 'nl', 'ja', 'gu', 'sv', 'sr', 'gl', 'ur', 'te', 'ta', 'cy',
- 'la', 'no', 'ml', 'vi', 'et', 'be', 'kn', 'ku', 'eu', 'ro', 'hi',
- 'ka', 'da', 'sa', 'is', 'sq', 'mr', 'br', 'af', 'uz', 'wo', 'ky',
- ]
+ languages_by_size = [
+ 'en', 'it', 'pl', 'ru', 'cs', 'fa', 'de', 'pt', 'es', 'uk', 'sk',
+ 'fr', 'bs', 'he', 'tr', 'fi', 'ca', 'lt', 'th', 'bg', 'sl', 'eo',
+ 'hy', 'el', 'hr', 'nn', 'id', 'zh', 'ar', 'su', 'hu', 'li', 'az',
+ 'ko', 'nl', 'ja', 'gu', 'sv', 'sr', 'gl', 'ur', 'te', 'ta', 'cy',
+ 'la', 'no', 'ml', 'vi', 'et', 'be', 'kn', 'ku', 'eu', 'ro', 'hi',
+ 'ka', 'da', 'sa', 'is', 'sq', 'mr', 'br', 'af', 'uz', 'wo', 'ky',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'ar': ('قالب:تحويل تصنيف',),
+ 'en': ('Category redirect',),
+ 'ro': ('Redirect categorie',),
+ 'sq': ('Kategori e zhvendosur',),
+ 'uk': ('Categoryredirect',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'ar': ('قالب:تحويل تصنيف',),
- 'en': ('Category redirect',),
- 'ro': ('Redirect categorie',),
- 'sq': ('Kategori e zhvendosur',),
- 'uk': ('Categoryredirect',),
- }
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
+ cross_allowed = [
+ 'af', 'ar', 'az', 'be', 'bg', 'br', 'bs', 'ca', 'cs',
+ 'cy', 'da', 'el', 'eo', 'es', 'et', 'eu', 'fa', 'fi',
+ 'fr', 'gl', 'gu', 'he', 'hi', 'hu', 'hy', 'id', 'is',
+ 'it', 'ja', 'ka', 'kn', 'ko', 'ku', 'ky', 'la', 'li',
+ 'lt', 'ml', 'mr', 'nl', 'nn', 'no', 'pt', 'ro', 'ru',
+ 'sk', 'sl', 'sq', 'sr', 'su', 'sv', 'ta', 'te', 'tr',
+ 'uk', 'ur', 'uz', 'vi', 'wo', 'zh',
+ ]

- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
- self.cross_allowed = [
- 'af', 'ar', 'az', 'be', 'bg', 'br', 'bs', 'ca', 'cs',
- 'cy', 'da', 'el', 'eo', 'es', 'et', 'eu', 'fa', 'fi',
- 'fr', 'gl', 'gu', 'he', 'hi', 'hu', 'hy', 'id', 'is',
- 'it', 'ja', 'ka', 'kn', 'ko', 'ku', 'ky', 'la', 'li',
- 'lt', 'ml', 'mr', 'nl', 'nn', 'no', 'pt', 'ro', 'ru',
- 'sk', 'sl', 'sq', 'sr', 'su', 'sv', 'ta', 'te', 'tr',
- 'uk', 'ur', 'uz', 'vi', 'wo', 'zh',
- ]
-
- # Subpages for documentation.
- # TODO: List is incomplete, to be completed for missing languages.
- self.doc_subpages = {
- '_default': ((u'/doc', ),
- ['en']
- ),
- }
+ # Subpages for documentation.
+ # TODO: List is incomplete, to be completed for missing languages.
+ doc_subpages = {
+ '_default': (('/doc', ),
+ ['en']
+ ),
+ }

def code2encodings(self, code):
"""
diff --git a/pywikibot/families/wikisource_family.py b/pywikibot/families/wikisource_family.py
index ddf990e..246118f 100644
--- a/pywikibot/families/wikisource_family.py
+++ b/pywikibot/families/wikisource_family.py
@@ -8,6 +8,7 @@
from __future__ import absolute_import, unicode_literals

from pywikibot import family
+from pywikibot.tools import classproperty


# The Wikimedia family that is known as Wikisource
@@ -26,101 +27,101 @@
'tokipona',
]

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'en', 'pl', 'ru', 'de', 'fr', 'zh', 'he', 'it', 'es', 'ar', 'cs',
- 'pt', 'www', 'fa', 'hu', 'ml', 'ko', 'sv', 'gu', 'sr', 'bn', 'sl',
- 'te', 'sa', 'el', 'ro', 'uk', 'fi', 'hy', 'ja', 'vi', 'az', 'th',
- 'ca', 'ta', 'kn', 'br', 'nl', 'hr', 'is', 'la', 'no', 'vec', 'eo',
- 'tr', 'et', 'be', 'mk', 'da', 'yi', 'id', 'bg', 'li', 'mr', 'as',
- 'or', 'bs', 'sah', 'lt', 'gl', 'sk', 'eu', 'cy', 'pa',
- 'zh-min-nan', 'fo',
- ]
+ languages_by_size = [
+ 'en', 'pl', 'ru', 'de', 'fr', 'zh', 'he', 'it', 'es', 'ar', 'cs', 'pt',
+ 'www', 'fa', 'hu', 'ml', 'ko', 'sv', 'gu', 'sr', 'bn', 'sl', 'te',
+ 'sa', 'el', 'ro', 'uk', 'fi', 'hy', 'ja', 'vi', 'az', 'th', 'ca', 'ta',
+ 'kn', 'br', 'nl', 'hr', 'is', 'la', 'no', 'vec', 'eo', 'tr', 'et',
+ 'be', 'mk', 'da', 'yi', 'id', 'bg', 'li', 'mr', 'as', 'or', 'bs',
+ 'sah', 'lt', 'gl', 'sk', 'eu', 'cy', 'pa', 'zh-min-nan', 'fo',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'ar': ('قالب:تحويل تصنيف',),
+ 'bn': ('বিষয়শ্রেণী পুনর্নির্দেশ',),
+ 'en': ('Category redirect',),
+ 'ro': ('Redirect categorie',),
+ 'zh': ('分類重定向',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'ar': ('قالب:تحويل تصنيف',),
- 'bn': ('বিষয়শ্রেণী পুনর্নির্দেশ',),
- 'en': ('Category redirect',),
- 'ro': ('Redirect categorie',),
- 'zh': ('分類重定向',),
- }
+ # All requests to 'mul.wikisource.org/*' are redirected to
+ # the main page, so using 'wikisource.org'
+ @classproperty
+ def langs(cls):
+ cls.langs = super(Family, cls).langs
+ cls.langs['mul'] = cls.domain
+ return cls.langs

- # All requests to 'mul.wikisource.org/*' are redirected to
- # the main page, so using 'wikisource.org'
- self.langs['mul'] = self.domain
- self.languages_by_size.append('mul')
+ languages_by_size.append('mul')

- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- self.cross_allowed = [
- 'ca', 'el', 'fa', 'it', 'ko', 'no', 'pl', 'vi', 'zh',
- ]
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ cross_allowed = [
+ 'ca', 'el', 'fa', 'it', 'ko', 'no', 'pl', 'vi', 'zh',
+ ]

- self.authornamespaces = {
- '_default': [0],
- 'ar': [102],
- 'be': [102],
- 'bn': [100],
- 'bg': [100],
- 'ca': [106],
- 'cs': [100],
- 'da': [102],
- 'en': [102],
- 'eo': [102],
- 'et': [106],
- 'fa': [102],
- 'fr': [102],
- 'he': [108],
- 'hr': [100],
- 'hu': [100],
- 'hy': [100],
- 'it': [102],
- 'ko': [100],
- 'la': [102],
- 'nl': [102],
- 'no': [102],
- 'pl': [104],
- 'pt': [102],
- 'ro': [102],
- 'sv': [106],
- 'tr': [100],
- 'vi': [102],
- 'zh': [102],
- }
+ authornamespaces = {
+ '_default': [0],
+ 'ar': [102],
+ 'be': [102],
+ 'bn': [100],
+ 'bg': [100],
+ 'ca': [106],
+ 'cs': [100],
+ 'da': [102],
+ 'en': [102],
+ 'eo': [102],
+ 'et': [106],
+ 'fa': [102],
+ 'fr': [102],
+ 'he': [108],
+ 'hr': [100],
+ 'hu': [100],
+ 'hy': [100],
+ 'it': [102],
+ 'ko': [100],
+ 'la': [102],
+ 'nl': [102],
+ 'no': [102],
+ 'pl': [104],
+ 'pt': [102],
+ 'ro': [102],
+ 'sv': [106],
+ 'tr': [100],
+ 'vi': [102],
+ 'zh': [102],
+ }

- # Subpages for documentation.
- # TODO: List is incomplete, to be completed for missing languages.
- # TODO: Remove comments for appropriate pages
- self.doc_subpages = {
- '_default': ((u'/doc', ),
- ['ar', 'as', 'az', 'bn', 'en', 'es',
- 'et', 'gu', 'hu', 'it', 'ja', 'kn', 'ml',
- 'mk', 'mr', 'pt', 'ro', 'sa', 'sah', 'ta',
- 'te', 'th', 'vi']
- ),
- 'be': (u'/Дакументацыя', ),
- 'bn': (u'/নথি', ),
- 'br': (u'/diellerezh', ),
- 'de': (u'/Doku', u'/Meta'),
- 'el': (u'/τεκμηρίωση', ),
- 'eo': ('u/dokumentado', ),
- # 'fa': (u'/صفحه الگو', ),
- # 'fa': (u'/فضای‌نام توضیحات', ),
- # 'fa': (u'/آغاز جعبه', ),
- # 'fa': (u'/پایان جعبه۲', ),
- # 'fa': (u'/آغاز جعبه۲', ),
- # 'fa': (u'/پایان جعبه', ),
- # 'fa': (u'/توضیحات', ),
- 'fr': (u'/documentation', ),
- 'id': (u'/dok', ),
- 'ko': (u'/설명문서', ),
- 'no': (u'/dok', ),
- 'ru': (u'/Документация', ),
- 'sl': (u'/dok', ),
- 'sv': (u'/dok', ),
- 'uk': (u'/документація', ),
- }
+ # Subpages for documentation.
+ # TODO: List is incomplete, to be completed for missing languages.
+ # TODO: Remove comments for appropriate pages
+ doc_subpages = {
+ '_default': (('/doc', ),
+ ['ar', 'as', 'az', 'bn', 'en', 'es',
+ 'et', 'gu', 'hu', 'it', 'ja', 'kn', 'ml',
+ 'mk', 'mr', 'pt', 'ro', 'sa', 'sah', 'ta',
+ 'te', 'th', 'vi']
+ ),
+ 'be': ('/Дакументацыя', ),
+ 'bn': ('/নথি', ),
+ 'br': ('/diellerezh', ),
+ 'de': ('/Doku', '/Meta'),
+ 'el': ('/τεκμηρίωση', ),
+ 'eo': ('/dokumentado', ),
+ # 'fa': ('/صفحه الگو', ),
+ # 'fa': ('/فضای‌نام توضیحات', ),
+ # 'fa': ('/آغاز جعبه', ),
+ # 'fa': ('/پایان جعبه۲', ),
+ # 'fa': ('/آغاز جعبه۲', ),
+ # 'fa': ('/پایان جعبه', ),
+ # 'fa': ('/توضیحات', ),
+ 'fr': ('/documentation', ),
+ 'id': ('/dok', ),
+ 'ko': ('/설명문서', ),
+ 'no': ('/dok', ),
+ 'ru': ('/Документация', ),
+ 'sl': ('/dok', ),
+ 'sv': ('/dok', ),
+ 'uk': ('/документація', ),
+ }
diff --git a/pywikibot/families/wikiversity_family.py b/pywikibot/families/wikiversity_family.py
index 3316b02..f7210d3 100644
--- a/pywikibot/families/wikiversity_family.py
+++ b/pywikibot/families/wikiversity_family.py
@@ -17,22 +17,18 @@

name = 'wikiversity'

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'de', 'en', 'fr', 'ru', 'it', 'cs', 'beta', 'pt', 'es', 'ar', 'sv',
- 'fi', 'sl', 'el', 'hi', 'ja', 'ko',
- ]
+ languages_by_size = [
+ 'de', 'en', 'fr', 'ru', 'it', 'cs', 'beta', 'pt', 'es', 'ar', 'sv',
+ 'fi', 'sl', 'el', 'hi', 'ja', 'ko',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'ar': ('قالب:تحويل تصنيف',),
+ 'en': ('Category redirect',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'ar': ('قالب:تحويل تصنيف',),
- 'en': ('Category redirect',),
- }
-
- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
- self.cross_allowed = ['ja', 'ko', ]
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
+ cross_allowed = ['ja', 'ko', ]
diff --git a/pywikibot/families/wikivoyage_family.py b/pywikibot/families/wikivoyage_family.py
index ec46056..7d5131d 100644
--- a/pywikibot/families/wikivoyage_family.py
+++ b/pywikibot/families/wikivoyage_family.py
@@ -17,23 +17,19 @@

name = 'wikivoyage'

- def __init__(self):
- """Constructor."""
- self.languages_by_size = [
- 'en', 'de', 'fa', 'it', 'fr', 'pl', 'ru', 'nl', 'pt', 'zh', 'es',
- 'he', 'fi', 'vi', 'sv', 'el', 'ro', 'uk', 'hi',
- ]
+ languages_by_size = [
+ 'en', 'de', 'fa', 'it', 'fr', 'pl', 'ru', 'nl', 'pt', 'zh', 'es',
+ 'he', 'fi', 'vi', 'sv', 'el', 'ro', 'uk', 'hi',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'zh': ('分类重定向',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'zh': ('分类重定向',),
- }
-
- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
- self.cross_allowed = [
- 'el', 'en', 'es', 'fa', 'ru',
- ]
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
+ cross_allowed = [
+ 'el', 'en', 'es', 'fa', 'ru',
+ ]
diff --git a/pywikibot/families/wiktionary_family.py b/pywikibot/families/wiktionary_family.py
index 13afb40..a9555f9 100644
--- a/pywikibot/families/wiktionary_family.py
+++ b/pywikibot/families/wiktionary_family.py
@@ -8,6 +8,7 @@
from __future__ import absolute_import, unicode_literals

from pywikibot import family
+from pywikibot.tools import classproperty


# The Wikimedia family that is known as Wiktionary
@@ -29,103 +30,104 @@
'ba', 'dk', 'tlh', 'tokipona',
]

- def __init__(self):
- """Initializer."""
- self.languages_by_size = [
- 'en', 'mg', 'fr', 'sh', 'ru', 'es', 'zh', 'de', 'nl', 'ku', 'sv',
- 'pl', 'lt', 'el', 'it', 'fi', 'ta', 'hu', 'ca', 'tr', 'ko', 'io',
- 'kn', 'pt', 'hy', 'vi', 'sr', 'ja', 'chr', 'hi', 'th', 'ro', 'no',
- 'id', 'ml', 'et', 'my', 'uz', 'li', 'or', 'te', 'cs', 'fa', 'eo',
- 'ar', 'jv', 'az', 'eu', 'gl', 'oc', 'da', 'br', 'lo', 'uk', 'hr',
- 'fj', 'tg', 'bg', 'simple', 'ps', 'sk', 'cy', 'vo', 'wa', 'la',
- 'ky', 'is', 'zh-min-nan', 'af', 'scn', 'ast', 'he', 'tl', 'sw',
- 'fy', 'nn', 'lv', 'bn', 'pa', 'co', 'pnb', 'mn', 'ka', 'nds', 'sl',
- 'sq', 'lb', 'bs', 'nah', 'sa', 'kk', 'ur', 'tk', 'km', 'sm', 'mk',
- 'hsb', 'be', 'ms', 'ga', 'an', 'wo', 'vec', 'ang', 'tt', 'sd',
- 'mt', 'gn', 'mr', 'ie', 'so', 'csb', 'ug', 'gd', 'st', 'roa-rup',
- 'si', 'hif', 'ia', 'mi', 'ay', 'kl', 'fo', 'jbo', 'ln', 'zu', 'na',
- 'gu', 'gv', 'kw', 'rw', 'ts', 'ne', 'om', 'qu', 'su', 'ss', 'ha',
- 'iu', 'am', 'dv', 'tpi', 'yi', 'ti', 'sg', 'tn', 'ks',
- ]
+ languages_by_size = [
+ 'en', 'mg', 'fr', 'sh', 'ru', 'es', 'zh', 'de', 'nl', 'ku', 'sv', 'pl',
+ 'lt', 'el', 'it', 'fi', 'ta', 'hu', 'ca', 'tr', 'ko', 'io', 'kn', 'pt',
+ 'hy', 'vi', 'sr', 'ja', 'chr', 'hi', 'th', 'ro', 'no', 'id', 'ml',
+ 'et', 'my', 'uz', 'li', 'or', 'te', 'cs', 'fa', 'eo', 'ar', 'jv', 'az',
+ 'eu', 'gl', 'oc', 'da', 'br', 'lo', 'uk', 'hr', 'fj', 'tg', 'bg',
+ 'simple', 'ps', 'sk', 'cy', 'vo', 'wa', 'la', 'ky', 'is', 'zh-min-nan',
+ 'af', 'scn', 'ast', 'he', 'tl', 'sw', 'fy', 'nn', 'lv', 'bn', 'pa',
+ 'co', 'pnb', 'mn', 'ka', 'nds', 'sl', 'sq', 'lb', 'bs', 'nah', 'sa',
+ 'kk', 'ur', 'tk', 'km', 'sm', 'mk', 'hsb', 'be', 'ms', 'ga', 'an',
+ 'wo', 'vec', 'ang', 'tt', 'sd', 'mt', 'gn', 'mr', 'ie', 'so', 'csb',
+ 'ug', 'gd', 'st', 'roa-rup', 'si', 'hif', 'ia', 'mi', 'ay', 'kl', 'fo',
+ 'jbo', 'ln', 'zu', 'na', 'gu', 'gv', 'kw', 'rw', 'ts', 'ne', 'om',
+ 'qu', 'su', 'ss', 'ha', 'iu', 'am', 'dv', 'tpi', 'yi', 'ti', 'sg',
+ 'tn', 'ks',
+ ]

- super(Family, self).__init__()
+ category_redirect_templates = {
+ '_default': (),
+ 'zh': ('分类重定向',),
+ }

- self.category_redirect_templates = {
- '_default': (),
- 'zh': ('分类重定向',),
- }
+ # Global bot allowed languages on
+ # https://meta.wikimedia.org/wiki/BPI#Current_implementation
+ # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
+ cross_allowed = [
+ 'am', 'af', 'am', 'ang', 'an', 'ar', 'ast', 'ay', 'az', 'be',
+ 'bg', 'bn', 'br', 'bs', 'ca', 'chr', 'co', 'csb', 'cs', 'cy',
+ 'da', 'dv', 'el', 'eo', 'es', 'et', 'eu', 'fa', 'fi', 'fj', 'fo',
+ 'fy', 'ga', 'gd', 'gl', 'gn', 'gu', 'gv', 'ha', 'hsb', 'hu', 'hy',
+ 'ia', 'id', 'ie', 'io', 'iu', 'jbo', 'jv', 'ka', 'kk', 'kl', 'km',
+ 'kn', 'ko', 'ks', 'ku', 'kw', 'ky', 'la', 'lb', 'ln', 'lo', 'lt',
+ 'lv', 'mg', 'mi', 'mk', 'ml', 'mn', 'ms', 'mt', 'my', 'nah', 'na',
+ 'nds', 'ne', 'nl', 'nn', 'no', 'oc', 'om', 'or', 'pa', 'pnb',
+ 'ps', 'pt', 'qu', 'roa_rup', 'rw', 'sa', 'scn', 'sd', 'sg', 'sh',
+ 'simple', 'si', 'sk', 'sl', 'sm', 'so', 'sq', 'sr', 'ss', 'st',
+ 'su', 'sv', 'sw', 'ta', 'te', 'tg', 'th', 'ti', 'tk', 'tl', 'tn',
+ 'tpi', 'tr', 'ts', 'tt', 'ug', 'uk', 'ur', 'uz', 'vec', 'vi', 'vo',
+ 'wa', 'wo', 'yi', 'zh_min_nan', 'zh', 'zu',
+ ]

- # Global bot allowed languages on
- # https://meta.wikimedia.org/wiki/BPI#Current_implementation
- # & https://meta.wikimedia.org/wiki/Special:WikiSets/2
- self.cross_allowed = [
- 'am', 'af', 'am', 'ang', 'an', 'ar', 'ast', 'ay', 'az', 'be',
- 'bg', 'bn', 'br', 'bs', 'ca', 'chr', 'co', 'csb', 'cs', 'cy',
- 'da', 'dv', 'el', 'eo', 'es', 'et', 'eu', 'fa', 'fi', 'fj', 'fo',
- 'fy', 'ga', 'gd', 'gl', 'gn', 'gu', 'gv', 'ha', 'hsb', 'hu', 'hy',
- 'ia', 'id', 'ie', 'io', 'iu', 'jbo', 'jv', 'ka', 'kk', 'kl', 'km',
- 'kn', 'ko', 'ks', 'ku', 'kw', 'ky', 'la', 'lb', 'ln', 'lo', 'lt',
- 'lv', 'mg', 'mi', 'mk', 'ml', 'mn', 'ms', 'mt', 'my', 'nah', 'na',
- 'nds', 'ne', 'nl', 'nn', 'no', 'oc', 'om', 'or', 'pa', 'pnb',
- 'ps', 'pt', 'qu', 'roa_rup', 'rw', 'sa', 'scn', 'sd', 'sg', 'sh',
- 'simple', 'si', 'sk', 'sl', 'sm', 'so', 'sq', 'sr', 'ss', 'st',
- 'su', 'sv', 'sw', 'ta', 'te', 'tg', 'th', 'ti', 'tk', 'tl', 'tn',
- 'tpi', 'tr', 'ts', 'tt', 'ug', 'uk', 'ur', 'uz', 'vec', 'vi', 'vo',
- 'wa', 'wo', 'yi', 'zh_min_nan', 'zh', 'zu',
- ]
+ # Other than most Wikipedias, page names must not start with a capital
+ # letter on ALL Wiktionaries.
+ @classproperty
+ def nocapitalize(cls):
+ return list(cls.langs.keys())

- # Other than most Wikipedias, page names must not start with a capital
- # letter on ALL Wiktionaries.
- self.nocapitalize = list(self.langs.keys())
+ # Which languages have a special order for putting interlanguage links,
+ # and what order is it? If a language is not in interwiki_putfirst,
+ # alphabetical order on language code is used. For languages that are in
+ # interwiki_putfirst, interwiki_putfirst is checked first, and
+ # languages are put in the order given there. All other languages are
+ # put after those, in code-alphabetical order.

- # Which languages have a special order for putting interlanguage links,
- # and what order is it? If a language is not in interwiki_putfirst,
- # alphabetical order on language code is used. For languages that are
- # in interwiki_putfirst, interwiki_putfirst is checked first, and
- # languages are put in the order given there. All other languages are
- # put after those, in code-alphabetical order.
+ alphabetic_sv = [
+ 'aa', 'af', 'ak', 'als', 'an', 'roa-rup', 'ast', 'gn', 'ay', 'az',
+ 'id', 'ms', 'bm', 'zh-min-nan', 'jv', 'su', 'mt', 'bi', 'bo', 'bs',
+ 'br', 'ca', 'cs', 'ch', 'sn', 'co', 'za', 'cy', 'da', 'de', 'na',
+ 'mh', 'et', 'ang', 'en', 'es', 'eo', 'eu', 'to', 'fr', 'fy', 'fo',
+ 'ga', 'gv', 'sm', 'gd', 'gl', 'hr', 'io', 'ia', 'ie', 'ik', 'xh',
+ 'is', 'zu', 'it', 'kl', 'csb', 'kw', 'rw', 'rn', 'sw', 'ky', 'ku',
+ 'la', 'lv', 'lb', 'lt', 'li', 'ln', 'jbo', 'hu', 'mg', 'mi', 'mo',
+ 'my', 'fj', 'nah', 'nl', 'cr', 'no', 'nn', 'hsb', 'oc', 'om', 'ug',
+ 'uz', 'nds', 'pl', 'pt', 'ro', 'rm', 'qu', 'sg', 'sc', 'st', 'tn',
+ 'sq', 'scn', 'simple', 'ss', 'sk', 'sl', 'so', 'sh', 'fi', 'sv',
+ 'tl', 'tt', 'vi', 'tpi', 'tr', 'tw', 'vo', 'wa', 'wo', 'ts', 'yo',
+ 'el', 'av', 'ab', 'ba', 'be', 'bg', 'mk', 'mn', 'ru', 'sr', 'tg',
+ 'uk', 'kk', 'hy', 'yi', 'he', 'ur', 'ar', 'tk', 'sd', 'fa', 'ha',
+ 'ps', 'dv', 'ks', 'ne', 'pi', 'bh', 'mr', 'sa', 'hi', 'as', 'bn',
+ 'pa', 'pnb', 'gu', 'or', 'ta', 'te', 'kn', 'ml', 'si', 'th', 'lo',
+ 'dz', 'ka', 'ti', 'am', 'chr', 'iu', 'km', 'zh', 'ja', 'ko',
+ ]

- self.alphabetic_sv = [
- 'aa', 'af', 'ak', 'als', 'an', 'roa-rup', 'ast', 'gn', 'ay', 'az',
- 'id', 'ms', 'bm', 'zh-min-nan', 'jv', 'su', 'mt', 'bi', 'bo', 'bs',
- 'br', 'ca', 'cs', 'ch', 'sn', 'co', 'za', 'cy', 'da', 'de', 'na',
- 'mh', 'et', 'ang', 'en', 'es', 'eo', 'eu', 'to', 'fr', 'fy', 'fo',
- 'ga', 'gv', 'sm', 'gd', 'gl', 'hr', 'io', 'ia', 'ie', 'ik', 'xh',
- 'is', 'zu', 'it', 'kl', 'csb', 'kw', 'rw', 'rn', 'sw', 'ky', 'ku',
- 'la', 'lv', 'lb', 'lt', 'li', 'ln', 'jbo', 'hu', 'mg', 'mi', 'mo',
- 'my', 'fj', 'nah', 'nl', 'cr', 'no', 'nn', 'hsb', 'oc', 'om', 'ug',
- 'uz', 'nds', 'pl', 'pt', 'ro', 'rm', 'qu', 'sg', 'sc', 'st', 'tn',
- 'sq', 'scn', 'simple', 'ss', 'sk', 'sl', 'so', 'sh', 'fi', 'sv',
- 'tl', 'tt', 'vi', 'tpi', 'tr', 'tw', 'vo', 'wa', 'wo', 'ts', 'yo',
- 'el', 'av', 'ab', 'ba', 'be', 'bg', 'mk', 'mn', 'ru', 'sr', 'tg',
- 'uk', 'kk', 'hy', 'yi', 'he', 'ur', 'ar', 'tk', 'sd', 'fa', 'ha',
- 'ps', 'dv', 'ks', 'ne', 'pi', 'bh', 'mr', 'sa', 'hi', 'as', 'bn',
- 'pa', 'pnb', 'gu', 'or', 'ta', 'te', 'kn', 'ml', 'si', 'th', 'lo',
- 'dz', 'ka', 'ti', 'am', 'chr', 'iu', 'km', 'zh', 'ja', 'ko',
- ]
-
- self.interwiki_putfirst = {
- 'da': self.alphabetic,
- 'en': self.alphabetic,
- 'et': self.alphabetic,
- 'fi': self.alphabetic,
- 'fy': self.fyinterwiki,
+ @classproperty
+ def interwiki_putfirst(cls):
+ cls.interwiki_putfirst = {
+ 'da': cls.alphabetic,
+ 'en': cls.alphabetic,
+ 'et': cls.alphabetic,
+ 'fi': cls.alphabetic,
+ 'fy': cls.fyinterwiki,
'he': ['en'],
'hu': ['en'],
- 'ms': self.alphabetic_revised,
- 'pl': self.alphabetic_revised,
- 'sv': self.alphabetic_sv,
- 'simple': self.alphabetic,
+ 'ms': cls.alphabetic_revised,
+ 'pl': cls.alphabetic_revised,
+ 'sv': cls.alphabetic_sv,
+ 'simple': cls.alphabetic,
}
+ return cls.interwiki_putfirst

- self.interwiki_on_one_line = ['pl']
+ interwiki_on_one_line = ['pl']

- self.interwiki_attop = ['pl']
+ interwiki_attop = ['pl']

- # Subpages for documentation.
- # TODO: List is incomplete, to be completed for missing languages.
- self.doc_subpages = {
- '_default': ((u'/doc', ),
- ['en']
- ),
- }
+ # Subpages for documentation.
+ # TODO: List is incomplete, to be completed for missing languages.
+ doc_subpages = {
+ '_default': (('/doc', ),
+ ['en']
+ ),
+ }
diff --git a/pywikibot/families/wowwiki_family.py b/pywikibot/families/wowwiki_family.py
index d8432cf..4d5ef32 100644
--- a/pywikibot/families/wowwiki_family.py
+++ b/pywikibot/families/wowwiki_family.py
@@ -8,7 +8,7 @@
from __future__ import absolute_import, unicode_literals

from pywikibot import family
-from pywikibot.tools import deprecated
+from pywikibot.tools import deprecated, classproperty


class Family(family.SubdomainFamily, family.WikiaFamily):
@@ -26,25 +26,38 @@

interwiki_removals = ['hr', 'ro', 'sr']

- def __init__(self):
- """Constructor."""
- super(Family, self).__init__()
- # Override 'sv'. http://sv.wow.wikia.com is an empty wiki.
- # The interwikimap in this family map 'sv' to this empty wiki.
- self.langs['sv'] = 'sv.warcraft.wikia.com'
+ # Override 'sv'. http://sv.wow.wikia.com is an empty wiki.
+ # The interwikimap in this family map 'sv' to this empty wiki.
+ @classproperty
+ def langs(cls):
+ cls.langs = super(Family, cls).langs
+ cls.langs['sv'] = 'sv.warcraft.wikia.com'
+ return cls.langs

- self.disambiguationTemplates['en'] = ['disambig', 'disambig/quest',
- 'disambig/quest2',
- 'disambig/achievement2']
- self.disambcatname['en'] = "Disambiguations"
+ @classproperty
+ def disambiguationTemplates(cls):
+ cls.disambiguationTemplates = \
+ super(Family, cls).disambiguationTemplates
+ cls.disambiguationTemplates['en'] = ['disambig', 'disambig/quest',
+ 'disambig/quest2',
+ 'disambig/achievement2']
+ return cls.disambiguationTemplates

- # Wikia's default CategorySelect extension always puts categories last
- self.categories_last = self.langs.keys()
+ @classproperty
+ def disambcatname(cls):
+ cls.disambcatname = super(Family, cls).disambcatname
+ cls.disambcatname['en'] = 'Disambiguations'
+ return cls.disambcatname

- @property
- def domains(self):
+ # Wikia's default CategorySelect extension always puts categories last
+ @classproperty
+ def categories_last(cls):
+ return cls.langs.keys()
+
+ @classproperty
+ def domains(cls):
"""List of domains used by family wowwiki."""
- return (self.domain, 'wowwiki.com', 'warcraft.wikia.com')
+ return (cls.domain, 'wowwiki.com', 'warcraft.wikia.com')

@deprecated('APISite.version()')
def version(self, code):
diff --git a/pywikibot/family.py b/pywikibot/family.py
index 6da09b9..e5513c0 100644
--- a/pywikibot/family.py
+++ b/pywikibot/family.py
@@ -23,7 +23,7 @@
from pywikibot.exceptions import UnknownFamily, FamilyMaintenanceWarning
from pywikibot.tools import (
deprecated, deprecated_args, issue_deprecation_warning,
- FrozenDict,
+ FrozenDict, classproperty
)

PY3 = sys.version_info[0] > 2
@@ -42,869 +42,893 @@

class Family(object):

- """Parent class for all wiki families."""
+ """Parent singleton class for all wiki families."""

- def __init__(self):
- """Constructor."""
- if not hasattr(self, 'name'):
- self.name = None
+ def __new__(cls):
+ """Allocator."""
+ if cls is Family:
+ raise TypeError('Base Family class cannot be instantiated; '
+ 'subclass it instead')

- if not hasattr(self, 'langs'):
- self.langs = {}
+ # Override classproperty
+ cls.instance = super(Family, cls).__new__(cls)
+ # staticmethod is because python 2.7 binds the lambda to the class
+ cls.__new__ = staticmethod(lambda cls: cls.instance) # shortcut

- # For interwiki sorting order see
- # https://meta.wikimedia.org/wiki/Interwiki_sorting_order
+ # don't use hasattr() here. consider only the class itself
+ if '__init__' in cls.__dict__:
+ # Initializer deprecated. Families should be immutable and any
+ # instance / class modification should go to allocator (__new__)
+ cls.__init__ = deprecated(cls.__init__)

- # The sorting order by language name from meta
- # MediaWiki:Interwiki_config-sorting_order-native-languagename
- self.alphabetic = [
- 'ace', 'kbd', 'ady', 'af', 'ak', 'als', 'am', 'ang', 'ab', 'ar',
- 'an', 'arc', 'roa-rup', 'frp', 'as', 'ast', 'atj', 'gn', 'av',
- 'ay', 'az', 'bm', 'bn', 'bjn', 'zh-min-nan', 'nan', 'map-bms',
- 'ba', 'be', 'be-tarask', 'bh', 'bcl', 'bi', 'bg', 'bar', 'bo',
- 'bs', 'br', 'bxr', 'ca', 'cv', 'ceb', 'cs', 'ch', 'cbk-zam', 'ny',
- 'sn', 'tum', 'cho', 'co', 'cy', 'da', 'dk', 'pdc', 'de', 'dv',
- 'nv', 'dsb', 'dty', 'dz', 'mh', 'et', 'el', 'eml', 'en', 'myv',
- 'es', 'eo', 'ext', 'eu', 'ee', 'fa', 'hif', 'fo', 'fr', 'fy', 'ff',
- 'fur', 'ga', 'gv', 'gag', 'gd', 'gl', 'gan', 'ki', 'glk', 'gu',
- 'got', 'hak', 'xal', 'ko', 'ha', 'haw', 'hy', 'hi', 'ho', 'hsb',
- 'hr', 'io', 'ig', 'ilo', 'bpy', 'id', 'ia', 'ie', 'iu', 'ik', 'os',
- 'xh', 'zu', 'is', 'it', 'he', 'jv', 'kbp', 'kl', 'kn', 'kr', 'pam',
- 'krc', 'ka', 'ks', 'csb', 'kk', 'kw', 'rw', 'rn', 'sw', 'kv', 'kg',
- 'gom', 'ht', 'ku', 'kj', 'ky', 'mrj', 'lad', 'lbe', 'lez', 'lo',
- 'ltg', 'la', 'lv', 'lb', 'lt', 'lij', 'li', 'ln', 'olo', 'jbo',
- 'lg', 'lmo', 'lrc', 'hu', 'mai', 'mk', 'mg', 'ml', 'mt', 'mi',
- 'mr', 'xmf', 'arz', 'mzn', 'ms', 'min', 'cdo', 'mwl', 'mdf', 'mo',
- 'mn', 'mus', 'my', 'nah', 'na', 'fj', 'nl', 'nds-nl', 'cr', 'ne',
- 'new', 'ja', 'nap', 'ce', 'frr', 'pih', 'no', 'nb', 'nn', 'nrm',
- 'nov', 'ii', 'oc', 'mhr', 'or', 'om', 'ng', 'hz', 'uz', 'pa', 'pi',
- 'pfl', 'pag', 'pnb', 'pap', 'ps', 'jam', 'koi', 'km', 'pcd', 'pms',
- 'tpi', 'nds', 'pl', 'pnt', 'pt', 'aa', 'kaa', 'crh', 'ty', 'ksh',
- 'ro', 'rmy', 'rm', 'qu', 'rue', 'ru', 'sah', 'se', 'sm', 'sa',
- 'sg', 'sc', 'sco', 'stq', 'st', 'nso', 'tn', 'sq', 'scn', 'si',
- 'simple', 'sd', 'ss', 'sk', 'sl', 'cu', 'szl', 'so', 'ckb', 'srn',
- 'sr', 'sh', 'su', 'fi', 'sv', 'tl', 'ta', 'kab', 'roa-tara', 'tt',
- 'te', 'tet', 'th', 'ti', 'tg', 'to', 'chr', 'chy', 've', 'tcy',
- 'tr', 'azb', 'tk', 'tw', 'tyv', 'udm', 'bug', 'uk', 'ur', 'ug',
- 'za', 'vec', 'vep', 'vi', 'vo', 'fiu-vro', 'wa', 'zh-classical',
- 'vls', 'war', 'wo', 'wuu', 'ts', 'yi', 'yo', 'zh-yue', 'diq',
- 'zea', 'bat-smg', 'zh', 'zh-tw', 'zh-cn',
- ]
+ # Invoke initializer immediately and make initializer no-op.
+ # This is to avoid repeated initializer invokation on repeated
+ # invokations of the metaclass's __call__.
+ cls.instance.__init__()
+ cls.__init__ = lambda self: None # no-op

- # The revised sorting order by first word from meta
- # MediaWiki:Interwiki_config-sorting_order-native-languagename-firstword
- self.alphabetic_revised = [
- 'ace', 'ady', 'kbd', 'af', 'ak', 'als', 'am', 'ang', 'ab', 'ar',
- 'an', 'arc', 'roa-rup', 'frp', 'as', 'ast', 'atj', 'gn', 'av',
- 'ay', 'az', 'bjn', 'id', 'ms', 'bm', 'bn', 'zh-min-nan', 'nan',
- 'map-bms', 'jv', 'su', 'ba', 'min', 'be', 'be-tarask', 'bh', 'bcl',
- 'bi', 'bar', 'bo', 'bs', 'br', 'bug', 'bg', 'bxr', 'ca', 'ceb',
- 'cv', 'cs', 'ch', 'cbk-zam', 'ny', 'sn', 'tum', 'cho', 'co', 'cy',
- 'da', 'dk', 'pdc', 'de', 'dv', 'nv', 'dsb', 'na', 'dty', 'dz',
- 'mh', 'et', 'el', 'eml', 'en', 'myv', 'es', 'eo', 'ext', 'eu',
- 'ee', 'fa', 'hif', 'fo', 'fr', 'fy', 'ff', 'fur', 'ga', 'gv', 'sm',
- 'gag', 'gd', 'gl', 'gan', 'ki', 'glk', 'gu', 'got', 'hak', 'xal',
- 'ko', 'ha', 'haw', 'hy', 'hi', 'ho', 'hsb', 'hr', 'io', 'ig',
- 'ilo', 'bpy', 'ia', 'ie', 'iu', 'ik', 'os', 'xh', 'zu', 'is', 'it',
- 'he', 'kl', 'kn', 'kr', 'pam', 'ka', 'ks', 'csb', 'kk', 'kw', 'rw',
- 'ky', 'rn', 'mrj', 'sw', 'kv', 'kg', 'gom', 'ht', 'ku', 'kj',
- 'lad', 'lbe', 'lez', 'lo', 'la', 'ltg', 'lv', 'to', 'lb', 'lt',
- 'lij', 'li', 'ln', 'olo', 'jbo', 'lg', 'lmo', 'lrc', 'hu', 'mai',
- 'mk', 'mg', 'ml', 'krc', 'mt', 'mi', 'mr', 'xmf', 'arz', 'mzn',
- 'cdo', 'mwl', 'koi', 'mdf', 'mo', 'mn', 'mus', 'my', 'nah', 'fj',
- 'nl', 'nds-nl', 'cr', 'ne', 'new', 'ja', 'nap', 'ce', 'frr', 'pih',
- 'no', 'nb', 'nn', 'nrm', 'nov', 'ii', 'oc', 'mhr', 'or', 'om',
- 'ng', 'hz', 'uz', 'pa', 'pi', 'pfl', 'pag', 'pnb', 'pap', 'ps',
- 'jam', 'km', 'pcd', 'pms', 'nds', 'pl', 'pnt', 'pt', 'aa', 'kaa',
- 'crh', 'ty', 'ksh', 'ro', 'rmy', 'rm', 'qu', 'ru', 'rue', 'sah',
- 'se', 'sa', 'sg', 'sc', 'sco', 'stq', 'st', 'nso', 'tn', 'sq',
- 'scn', 'si', 'simple', 'sd', 'ss', 'sk', 'sl', 'cu', 'szl', 'so',
- 'ckb', 'srn', 'sr', 'sh', 'fi', 'sv', 'tl', 'ta', 'kab',
- 'roa-tara', 'tt', 'te', 'tet', 'th', 'vi', 'ti', 'tg', 'tpi',
- 'chr', 'chy', 've', 'tcy', 'tr', 'azb', 'tk', 'tw', 'tyv', 'udm',
- 'uk', 'ur', 'ug', 'za', 'vec', 'vep', 'vo', 'fiu-vro', 'wa',
- 'zh-classical', 'vls', 'war', 'wo', 'wuu', 'ts', 'yi', 'yo',
- 'zh-yue', 'diq', 'zea', 'bat-smg', 'zh', 'zh-tw', 'zh-cn',
- ]
+ return cls.instance

- # Order for fy: alphabetical by code, but y counts as i
- self.fyinterwiki = self.alphabetic[:]
- self.fyinterwiki.remove('nb')
- self.fyinterwiki.sort(key=lambda x:
- x.replace("y", "i") + x.count("y") * "!")
+ @classproperty
+ def instance(cls):
+ """Get the singleton instance."""
+ # This is a placeholder to invoke allocator before it's allocated.
+ # Allocator will override this classproperty.
+ return cls()

- # letters that can follow a wikilink and are regarded as part of
- # this link
- # This depends on the linktrail setting in LanguageXx.php and on
- # [[MediaWiki:Linktrail]].
- # Note: this is a regular expression.
- self.linktrails = {
- '_default': u'[a-z]*',
- 'ab': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'als': u'[äöüßa-z]*',
- 'an': u'[a-záéíóúñ]*',
- 'ar': u'[a-zء-ي]*',
- 'ast': u'[a-záéíóúñ]*',
- 'atj': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'arz': u'[a-zء-ي]*',
- 'azb': u'[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
- 'av': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'ay': u'[a-záéíóúñ]*',
- 'bar': u'[äöüßa-z]*',
- 'bat-smg': '[a-ząčęėįšųūž]*',
- 'be': u'[абвгґджзеёжзійклмнопрстуўфхцчшыьэюяćčłńśšŭźža-z]*',
- 'be-tarask': u'[абвгґджзеёжзійклмнопрстуўфхцчшыьэюяćčłńśšŭźža-z]*',
- 'bg': u'[a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]*',
- 'bm': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'bn': '[ঀ-৿]*',
- 'bpy': '[ঀ-৿]*',
- 'bs': u'[a-zćčžšđž]*',
- 'bxr': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'ca': u'[a-zàèéíòóúç·ïü]*',
- 'cbk-zam': u'[a-záéíóúñ]*',
- 'ce': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'ckb': u'[ئابپتجچحخدرڕزژسشعغفڤقکگلڵمنوۆهھەیێ‌]*',
- 'co': u'[a-zàéèíîìóòúù]*',
- 'crh': u'[a-zâçğıñöşüа-яё“»]*',
- 'cs': u'[a-záčďéěíňóřšťúůýž]*',
- 'csb': u'[a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]*',
- 'cu': ('[a-zабвгдеєжѕзїіıићклмнопсстѹфхѡѿцчшщъыьѣюѥѧѩѫѭѯѱѳѷѵґѓђё'
- 'јйљњќуўџэ҄я“»]*'),
- 'cv': u'[a-zа-яĕçăӳ"»]*',
- 'cy': u'[àáâèéêìíîïòóôûŵŷa-z]*',
- 'da': u'[a-zæøå]*',
- 'de': u'[a-zäöüß]*',
- 'din': '[äëɛɛ̈éɣïŋöɔɔ̈óa-z]*',
- 'dsb': u'[äöüßa-z]*',
- 'el': ('[a-zαβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέή'
- 'ίόύώϊϋΐΰΆΈΉΊΌΎΏΪΫ]*'),
- 'eml': u'[a-zàéèíîìóòúù]*',
- 'es': u'[a-záéíóúñ]*',
- 'eu': u'[a-záéíóúñ]*',
- 'et': u'[äöõšüža-z]*',
- 'ext': u'[a-záéíóúñ]*',
- 'fa': u'[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
- 'ff': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'fi': u'[a-zäö]*',
- 'fiu-vro': u'[äöõšüža-z]*',
- 'fo': u'[áðíóúýæøa-z]*',
- 'fr': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'frp': u'[a-zàâçéèêîœôû·’æäåāăëēïīòöōùü‘]*',
- 'frr': u'[a-zäöüßåāđē]*',
- 'fur': u'[a-zàéèíîìóòúù]*',
- 'fy': u'[a-zàáèéìíòóùúâêîôûäëïöü]*',
- 'gag': u'[a-zÇĞçğİıÖöŞşÜüÂâÎîÛû]*',
- 'gl': u'[áâãàéêẽçíòóôõq̃úüűũa-z]*',
- 'glk': u'[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
- 'gn': u'[a-záéíóúñ]*',
- 'gu': u'[઀-૿]*',
- 'he': u'[a-zא-ת]*',
- 'hi': u'[a-zऀ-ॣ०-꣠-ꣿ]*',
- 'hr': u'[čšžćđßa-z]*',
- 'hsb': u'[äöüßa-z]*',
- 'ht': u'[a-zàèòÀÈÒ]*',
- 'hu': u'[a-záéíóúöüőűÁÉÍÓÚÖÜŐŰ]*',
- 'hy': u'[a-zաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև«»]*',
- 'is': u'[áðéíóúýþæöa-z-–]*',
- 'it': u'[a-zàéèíîìóòúù]*',
- 'ka': u'[a-zაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰ“»]*',
- 'kbp': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'kk': ('[a-zäçéğıïñöşüýʺʹа-яёәғіқңөұүһ'
- 'ٴابپتجحدرزسشعفقكلمنڭەوۇۋۆىيچھ“»]*'),
- 'kl': u'[a-zæøå]*',
- 'koi': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'krc': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'ksh': u'[a-zäöüėëijßəğåůæœç]*',
- 'ku': '[a-zçêîşûẍḧÇÊÎŞÛẌḦ]*',
- 'kv': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'lad': u'[a-záéíóúñ]*',
- 'lb': u'[äöüßa-z]*',
- 'lbe': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюяӀ1“»]*',
- 'lez': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'li': u'[a-zäöüïëéèà]*',
- 'lij': u'[a-zàéèíîìóòúù]*',
- 'lmo': u'[a-zàéèíîìóòúù]*',
- 'ln': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'lrc': u'[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
- 'lt': '[a-ząčęėįšųūž]*',
- 'ltg': u'[a-zA-ZĀāČčĒēĢģĪīĶķĻļŅņŠšŪūŽž]*',
- 'lv': u'[a-zA-ZĀāČčĒēĢģĪīĶķĻļŅņŠšŪūŽž]*',
- 'mai': '[a-zऀ-ॣ०-꣠-ꣿ]*',
- 'mdf': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'mg': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'mhr': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'mk': u'[a-zабвгдѓежзѕијклљмнњопрстќуфхцчџш]*',
- 'ml': u'[a-zം-ൿ]*',
- 'mn': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя“»]*',
- 'mr': u'[ऀ-ॣॱ-ॿ‍]*',
- 'mrj': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'mwl': u'[áâãàéêẽçíòóôõq̃úüűũa-z]*',
- 'myv': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'mzn': u'[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
- 'nah': u'[a-záéíóúñ]*',
- 'nap': u'[a-zàéèíîìóòúù]*',
- 'nds': u'[äöüßa-z]*',
- 'nds-nl': u'[a-zäöüïëéèà]*',
- 'nl': u'[a-zäöüïëéèà]*',
- 'nn': u'[æøåa-z]*',
- 'no': u'[æøåa-z]*',
- 'nrm': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'oc': u'[a-zàâçéèêîôû]*',
- 'olo': '[a-zčČšŠžŽäÄöÖ]*',
- 'or': u'[a-z଀-୿]*',
- 'pa': ('[ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾ'
- 'ਿੀੁੂੇੈੋੌ੍ਖ਼ਗ਼ਜ਼ੜਫ਼ੰੱੲੳa-z]*'),
- 'pcd': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'pdc': u'[äöüßa-z]*',
- 'pfl': u'[äöüßa-z]*',
- 'pl': u'[a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]*',
- 'pms': u'[a-zàéèíîìóòúù]*',
- 'pnt': ('[a-zαβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'
- 'άέήίόύώϊϋΐΰΆΈΉΊΌΎΏΪΫ]*'),
- 'pt': u'[a-záâãàéêẽçíòóôõq̃úüűũ]*',
- 'qu': u'[a-záéíóúñ]*',
- 'rmy': u'[a-zăâîşţșțĂÂÎŞŢȘȚ]*',
- 'ro': u'[a-zăâîşţșțĂÂÎŞŢȘȚ]*',
- 'roa-rup': '[a-zăâîşţșțĂÂÎŞŢȘȚ]*',
- 'roa-tara': '[a-zàéèíîìóòúù]*',
- 'ru': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'rue': u'[a-zабвгґдеєжзиіїйклмнопрстуфхцчшщьєюяёъы“»]*',
- 'sa': u'[a-zऀ-ॣ०-꣠-ꣿ]*',
- 'sah': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'scn': u'[a-zàéèíîìóòúù]*',
- 'sg': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'sh': u'[a-zčćđžš]*',
- 'sk': u'[a-záäčďéíľĺňóôŕšťúýž]*',
- 'sl': u'[a-zčćđžš]*',
- 'sr': ('[abvgdđežzijklljmnnjoprstćufhcčdžšабвгдђежзијклљмнњопрстћу'
- 'фхцчџш]*'),
- 'srn': u'[a-zäöüïëéèà]*',
- 'stq': u'[äöüßa-z]*',
- 'sv': u'[a-zåäöéÅÄÖÉ]*',
- 'szl': u'[a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]*',
- 'ta': u'[஀-௿]*',
- 'te': u'[ఁ-౯]*',
- 'tg': u'[a-zабвгдеёжзийклмнопрстуфхчшъэюяғӣқўҳҷцщыь]*',
- 'tk': u'[a-zÄäÇçĞğŇňÖöŞşÜüÝýŽž]*',
- 'tr': u'[a-zÇĞçğİıÖöŞşÜüÂâÎîÛû]*',
- 'tt': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюяӘәӨөҮүҖҗҢңҺһ]*',
- 'ty': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'tyv': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'udm': u'[a-zа-яёӝӟӥӧӵ]*',
- 'uk': u'[a-zабвгґдеєжзиіїйклмнопрстуфхцчшщьєюяёъы“»]*',
- 'ur': '[ابپتٹثجچحخدڈذر​ڑ​زژسشصضطظعغفقکگل​م​نںوؤہھیئےآأءۃ]*',
- 'uz': u'[a-zʻʼ“»]*',
- 'vec': u'[a-zàéèíîìóòúù]*',
- 'vep': u'[äöõšüža-z]*',
- 'vi': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'vls': u'[a-zäöüïëéèà]*',
- 'wa': u'[a-zåâêîôûçéè]*',
- 'wo': u'[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
- 'xal': u'[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
- 'xmf': u'[a-zაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰ“»]*',
- 'yi': u'[a-zא-ת]*',
- 'zea': u'[a-zäöüïëéèà]*',
- }
+ name = None

- # A dictionary where keys are family codes that can be used in
- # inter-family interwiki links. Do not use it directly but
- # get_known_families() instead.
+ langs = {}

- # TODO: replace this with API interwikimap call
- self.known_families = {
- 'abbenormal': 'abbenormal',
- 'acronym': 'acronym',
- 'advisory': 'advisory',
- 'advogato': 'advogato',
- 'aew': 'aew',
- 'airwarfare': 'airwarfare',
- 'aiwiki': 'aiwiki',
- 'allwiki': 'allwiki',
- 'appropedia': 'appropedia',
- 'aquariumwiki': 'aquariumwiki',
- 'arxiv': 'arxiv',
- 'aspienetwiki': 'aspienetwiki',
- 'atmwiki': 'atmwiki',
- 'b': 'wikibooks',
- 'bemi': 'bemi',
- 'benefitswiki': 'benefitswiki',
- 'betawiki': 'betawiki',
- 'betawikiversity': 'betawikiversity',
- 'biblewiki': 'biblewiki',
- 'bluwiki': 'bluwiki',
- 'botwiki': 'botwiki',
- 'boxrec': 'boxrec',
- 'brickwiki': 'brickwiki',
- 'bridgeswiki': 'bridgeswiki',
- 'bugzilla': 'bugzilla',
- 'buzztard': 'buzztard',
- 'bytesmiths': 'bytesmiths',
- 'c2': 'c2',
- 'c2find': 'c2find',
- 'cache': 'cache',
- 'canwiki': 'canwiki',
- 'canyonwiki': 'canyonwiki',
- 'Ĉej': 'Ĉej',
- 'cellwiki': 'cellwiki',
- 'centralwikia': 'centralwikia',
- 'chapter': 'chapter',
- 'chej': 'chej',
- 'choralwiki': 'choralwiki',
- 'ciscavate': 'ciscavate',
- 'citizendium': 'citizendium',
- 'ckwiss': 'ckwiss',
- 'closed-zh-tw': 'closed-zh-tw',
- 'cndbname': 'cndbname',
- 'cndbtitle': 'cndbtitle',
- 'colab': 'colab',
- 'comcom': 'comcom',
- 'comixpedia': 'comixpedia',
- 'commons': 'commons',
- 'communityscheme': 'communityscheme',
- 'comune': 'comune',
- 'consciousness': 'consciousness',
- 'corpknowpedia': 'corpknowpedia',
- 'crazyhacks': 'crazyhacks',
- 'creatureswiki': 'creatureswiki',
- 'cxej': 'cxej',
- 'dawiki': 'dawiki',
- 'dbdump': 'dbdump',
- 'dcc': 'dcc',
- 'dcdatabase': 'dcdatabase',
- 'dcma': 'dcma',
- 'dejanews': 'dejanews',
- 'delicious': 'delicious',
- 'demokraatia': 'demokraatia',
- 'devmo': 'devmo',
- 'dict': 'dict',
- 'dictionary': 'dictionary',
- 'disinfopedia': 'disinfopedia',
- 'distributedproofreaders': 'distributedproofreaders',
- 'distributedproofreadersca': 'distributedproofreadersca',
- 'dk': 'dk',
- 'dmoz': 'dmoz',
- 'dmozs': 'dmozs',
- 'docbook': 'docbook',
- 'doom_wiki': 'doom_wiki',
- 'download': 'download',
- 'drae': 'drae',
- 'dreamhost': 'dreamhost',
- 'drumcorpswiki': 'drumcorpswiki',
- 'dwjwiki': 'dwjwiki',
- 'eĉei': 'eĉei',
- 'echei': 'echei',
- 'ecoreality': 'ecoreality',
- 'ecxei': 'ecxei',
- 'efnetceewiki': 'efnetceewiki',
- 'efnetcppwiki': 'efnetcppwiki',
- 'efnetpythonwiki': 'efnetpythonwiki',
- 'efnetxmlwiki': 'efnetxmlwiki',
- 'elibre': 'elibre',
- 'emacswiki': 'emacswiki',
- 'energiewiki': 'energiewiki',
- 'eokulturcentro': 'eokulturcentro',
- 'epo': 'epo',
- 'ethnologue': 'ethnologue',
- 'evowiki': 'evowiki',
- 'exotica': 'exotica',
- 'fanimutationwiki': 'fanimutationwiki',
- 'finalempire': 'finalempire',
- 'finalfantasy': 'finalfantasy',
- 'finnix': 'finnix',
- 'flickruser': 'flickruser',
- 'floralwiki': 'floralwiki',
- 'flyerwiki-de': 'flyerwiki-de',
- 'foldoc': 'foldoc',
- 'forthfreak': 'forthfreak',
- 'foundation': 'foundation',
- 'foxwiki': 'foxwiki',
- 'freebio': 'freebio',
- 'freebsdman': 'freebsdman',
- 'freeculturewiki': 'freeculturewiki',
- 'freedomdefined': 'freedomdefined',
- 'freefeel': 'freefeel',
- 'freekiwiki': 'freekiwiki',
- 'ganfyd': 'ganfyd',
- 'gausswiki': 'gausswiki',
- 'gentoo-wiki': 'gentoo',
- 'genwiki': 'genwiki',
- 'globalvoices': 'globalvoices',
- 'glossarwiki': 'glossarwiki',
- 'glossarywiki': 'glossarywiki',
- 'golem': 'golem',
- 'google': 'google',
- 'googledefine': 'googledefine',
- 'googlegroups': 'googlegroups',
- 'gotamac': 'gotamac',
- 'greatlakeswiki': 'greatlakeswiki',
- 'guildwiki': 'guildwiki',
- 'gutenberg': 'gutenberg',
- 'gutenbergwiki': 'gutenbergwiki',
- 'h2wiki': 'h2wiki',
- 'hammondwiki': 'hammondwiki',
- 'heroeswiki': 'heroeswiki',
- 'herzkinderwiki': 'herzkinderwiki',
- 'hkmule': 'hkmule',
- 'holshamtraders': 'holshamtraders',
- 'hrfwiki': 'hrfwiki',
- 'hrwiki': 'hrwiki',
- 'humancell': 'humancell',
- 'hupwiki': 'hupwiki',
- 'imdbcharacter': 'imdbcharacter',
- 'imdbcompany': 'imdbcompany',
- 'imdbname': 'imdbname',
- 'imdbtitle': 'imdbtitle',
- 'incubator': 'incubator',
- 'infoanarchy': 'infoanarchy',
- 'infosecpedia': 'infosecpedia',
- 'infosphere': 'infosphere',
- 'iso639-3': 'iso639-3',
- 'iuridictum': 'iuridictum',
- 'jameshoward': 'jameshoward',
- 'javanet': 'javanet',
- 'javapedia': 'javapedia',
- 'jefo': 'jefo',
- 'jiniwiki': 'jiniwiki',
- 'jspwiki': 'jspwiki',
- 'jstor': 'jstor',
- 'kamelo': 'kamelo',
- 'karlsruhe': 'karlsruhe',
- 'kerimwiki': 'kerimwiki',
- 'kinowiki': 'kinowiki',
- 'kmwiki': 'kmwiki',
- 'kontuwiki': 'kontuwiki',
- 'koslarwiki': 'koslarwiki',
- 'kpopwiki': 'kpopwiki',
- 'linguistlist': 'linguistlist',
- 'linuxwiki': 'linuxwiki',
- 'linuxwikide': 'linuxwikide',
- 'liswiki': 'liswiki',
- 'literateprograms': 'literateprograms',
- 'livepedia': 'livepedia',
- 'lojban': 'lojban',
- 'lostpedia': 'lostpedia',
- 'lqwiki': 'lqwiki',
- 'lugkr': 'lugkr',
- 'luxo': 'luxo',
- 'lyricwiki': 'lyricwiki',
- 'm': 'meta',
- 'm-w': 'm-w',
- 'mail': 'mail',
- 'mailarchive': 'mailarchive',
- 'mariowiki': 'mariowiki',
- 'marveldatabase': 'marveldatabase',
- 'meatball': 'meatball',
- 'mediazilla': 'mediazilla',
- 'memoryalpha': 'memoryalpha',
- 'meta': 'meta',
- 'metawiki': 'metawiki',
- 'metawikipedia': 'metawikipedia',
- 'mineralienatlas': 'mineralienatlas',
- 'moinmoin': 'moinmoin',
- 'monstropedia': 'monstropedia',
- 'mosapedia': 'mosapedia',
- 'mozcom': 'mozcom',
- 'mozillawiki': 'mozillawiki',
- 'mozillazinekb': 'mozillazinekb',
- 'musicbrainz': 'musicbrainz',
- 'mw': 'mw',
- 'mwod': 'mwod',
- 'mwot': 'mwot',
- 'n': 'wikinews',
- 'netvillage': 'netvillage',
- 'nkcells': 'nkcells',
- 'nomcom': 'nomcom',
- 'nosmoke': 'nosmoke',
- 'nost': 'nost',
- 'oeis': 'oeis',
- 'oldwikisource': 'oldwikisource',
- 'olpc': 'olpc',
- 'onelook': 'onelook',
- 'openfacts': 'openfacts',
- 'openstreetmap': 'openstreetmap',
- 'openwetware': 'openwetware',
- 'openwiki': 'openwiki',
- 'opera7wiki': 'opera7wiki',
- 'organicdesign': 'organicdesign',
- 'orgpatterns': 'orgpatterns',
- 'orthodoxwiki': 'orthodoxwiki',
- 'osi reference model': 'osi reference model',
- 'otrs': 'otrs',
- 'otrswiki': 'otrswiki',
- 'ourmedia': 'ourmedia',
- 'paganwiki': 'paganwiki',
- 'panawiki': 'panawiki',
- 'pangalacticorg': 'pangalacticorg',
- 'patwiki': 'patwiki',
- 'perlconfwiki': 'perlconfwiki',
- 'perlnet': 'perlnet',
- 'personaltelco': 'personaltelco',
- 'phpwiki': 'phpwiki',
- 'phwiki': 'phwiki',
- 'planetmath': 'planetmath',
- 'pmeg': 'pmeg',
- 'pmwiki': 'pmwiki',
- 'psycle': 'psycle',
- 'purlnet': 'purlnet',
- 'pythoninfo': 'pythoninfo',
- 'pythonwiki': 'pythonwiki',
- 'pywiki': 'pywiki',
- 'q': 'wikiquote',
- 'qcwiki': 'qcwiki',
- 'quality': 'quality',
- 'qwiki': 'qwiki',
- 'r3000': 'r3000',
- 'raec': 'raec',
- 'rakwiki': 'rakwiki',
- 'reuterswiki': 'reuterswiki',
- 'rev': 'rev',
- 'revo': 'revo',
- 'rfc': 'rfc',
- 'rheinneckar': 'rheinneckar',
- 'robowiki': 'robowiki',
- 'rowiki': 'rowiki',
- 's': 'wikisource',
- 's23wiki': 's23wiki',
- 'scholar': 'scholar',
- 'schoolswp': 'schoolswp',
- 'scores': 'scores',
- 'scoutwiki': 'scoutwiki',
- 'scramble': 'scramble',
- 'seapig': 'seapig',
- 'seattlewiki': 'seattlewiki',
- 'seattlewireless': 'seattlewireless',
- 'senseislibrary': 'senseislibrary',
- 'silcode': 'silcode',
- 'slashdot': 'slashdot',
- 'slwiki': 'slwiki',
- 'smikipedia': 'smikipedia',
- 'sourceforge': 'sourceforge',
- 'spcom': 'spcom',
- 'species': 'species',
- 'squeak': 'squeak',
- 'stable': 'stable',
- 'strategywiki': 'strategywiki',
- 'sulutil': 'sulutil',
- 'susning': 'susning',
- 'svgwiki': 'svgwiki',
- 'svn': 'svn',
- 'swinbrain': 'swinbrain',
- 'swingwiki': 'swingwiki',
- 'swtrain': 'swtrain',
- 'tabwiki': 'tabwiki',
- 'takipedia': 'takipedia',
- 'tavi': 'tavi',
- 'tclerswiki': 'tclerswiki',
- 'technorati': 'technorati',
- 'tejo': 'tejo',
- 'tesoltaiwan': 'tesoltaiwan',
- 'testwiki': 'testwiki',
- 'thelemapedia': 'thelemapedia',
- 'theopedia': 'theopedia',
- 'theppn': 'theppn',
- 'thinkwiki': 'thinkwiki',
- 'tibiawiki': 'tibiawiki',
- 'ticket': 'ticket',
- 'tmbw': 'tmbw',
- 'tmnet': 'tmnet',
- 'tmwiki': 'tmwiki',
- 'tokyonights': 'tokyonights',
- 'tools': 'tools',
- 'translatewiki': 'translatewiki',
- 'trash!italia': 'trash!italia',
- 'tswiki': 'tswiki',
- 'turismo': 'turismo',
- 'tviv': 'tviv',
- 'tvtropes': 'tvtropes',
- 'twiki': 'twiki',
- 'twistedwiki': 'twistedwiki',
- 'tyvawiki': 'tyvawiki',
- 'uncyclopedia': 'uncyclopedia',
- 'unreal': 'unreal',
- 'urbandict': 'urbandict',
- 'usej': 'usej',
- 'usemod': 'usemod',
- 'v': 'wikiversity',
- 'valuewiki': 'valuewiki',
- 'veropedia': 'veropedia',
- 'vinismo': 'vinismo',
- 'vkol': 'vkol',
- 'vlos': 'vlos',
- 'voipinfo': 'voipinfo',
- 'voy': 'wikivoyage',
- 'w': 'wikipedia',
- 'warpedview': 'warpedview',
- 'webdevwikinl': 'webdevwikinl',
- 'webisodes': 'webisodes',
- 'webseitzwiki': 'webseitzwiki',
- 'wg': 'wg',
- 'wiki': 'wiki',
- 'wikia': 'wikia',
- 'wikianso': 'wikianso',
- 'wikiasite': 'wikiasite',
- 'wikible': 'wikible',
- 'wikibooks': 'wikibooks',
- 'wikichat': 'wikichat',
- 'wikichristian': 'wikichristian',
- 'wikicities': 'wikicities',
- 'wikicity': 'wikicity',
- 'wikif1': 'wikif1',
- 'wikifur': 'wikifur',
- 'wikihow': 'wikihow',
- 'wikiindex': 'wikiindex',
- 'wikilemon': 'wikilemon',
- 'wikilivres': 'wikilivres',
- 'wikimac-de': 'wikimac-de',
- 'wikimac-fr': 'wikimac-fr',
- 'wikimedia': 'wikimedia',
- 'wikinews': 'wikinews',
- 'wikinfo': 'wikinfo',
- 'wikinurse': 'wikinurse',
- 'wikinvest': 'wikinvest',
- 'wikipaltz': 'wikipaltz',
- 'wikipedia': 'wikipedia',
- 'wikipediawikipedia': 'wikipediawikipedia',
- 'wikiquote': 'wikiquote',
- 'wikireason': 'wikireason',
- 'wikischool': 'wikischool',
- 'wikisophia': 'wikisophia',
- 'wikisource': 'wikisource',
- 'wikispecies': 'wikispecies',
- 'wikispot': 'wikispot',
- 'wikiti': 'wikiti',
- 'wikitravel': 'wikitravel',
- 'wikitree': 'wikitree',
- 'wikiversity': 'wikiversity',
- 'wikiwikiweb': 'wikiwikiweb',
- 'wikt': 'wiktionary',
- 'wiktionary': 'wiktionary',
- 'wipipedia': 'wipipedia',
- 'wlug': 'wlug',
- 'wm2005': 'wm2005',
- 'wm2006': 'wm2006',
- 'wm2007': 'wm2007',
- 'wm2008': 'wm2008',
- 'wm2009': 'wm2009',
- 'wm2010': 'wm2010',
- 'wm2011': 'wm2011',
- 'wm2012': 'wm2012',
- 'wm2013': 'wm2013',
- 'wm2014': 'wm2014',
- 'wm2015': 'wm2015',
- 'wm2016': 'wm2016',
- 'wm2017': 'wm2017',
- 'wm2018': 'wm2018',
- 'wmania': 'wmania',
- 'wmcz': 'wmcz',
- 'wmf': 'wmf',
- 'wmrs': 'wmrs',
- 'wmse': 'wmse',
- 'wookieepedia': 'wookieepedia',
- 'world66': 'world66',
- 'wowwiki': 'wowwiki',
- 'wqy': 'wqy',
- 'wurmpedia': 'wurmpedia',
- 'wznan': 'wznan',
- 'xboxic': 'xboxic',
- 'zh-cfr': 'zh-cfr',
- 'zrhwiki': 'zrhwiki',
- 'zum': 'zum',
- 'zwiki': 'zwiki',
- 'zzz wiki': 'zzz wiki',
- }
+ # For interwiki sorting order see
+ # https://meta.wikimedia.org/wiki/Interwiki_sorting_order

- # A list of category redirect template names in different languages
- self.category_redirect_templates = {
- '_default': []
- }
+ # The sorting order by language name from meta
+ # MediaWiki:Interwiki_config-sorting_order-native-languagename
+ alphabetic = [
+ 'ace', 'kbd', 'ady', 'af', 'ak', 'als', 'am', 'ang', 'ab', 'ar',
+ 'an', 'arc', 'roa-rup', 'frp', 'as', 'ast', 'atj', 'gn', 'av',
+ 'ay', 'az', 'bm', 'bn', 'bjn', 'zh-min-nan', 'nan', 'map-bms',
+ 'ba', 'be', 'be-tarask', 'bh', 'bcl', 'bi', 'bg', 'bar', 'bo',
+ 'bs', 'br', 'bxr', 'ca', 'cv', 'ceb', 'cs', 'ch', 'cbk-zam', 'ny',
+ 'sn', 'tum', 'cho', 'co', 'cy', 'da', 'dk', 'pdc', 'de', 'dv',
+ 'nv', 'dsb', 'dty', 'dz', 'mh', 'et', 'el', 'eml', 'en', 'myv',
+ 'es', 'eo', 'ext', 'eu', 'ee', 'fa', 'hif', 'fo', 'fr', 'fy', 'ff',
+ 'fur', 'ga', 'gv', 'gag', 'gd', 'gl', 'gan', 'ki', 'glk', 'gu',
+ 'got', 'hak', 'xal', 'ko', 'ha', 'haw', 'hy', 'hi', 'ho', 'hsb',
+ 'hr', 'io', 'ig', 'ilo', 'bpy', 'id', 'ia', 'ie', 'iu', 'ik', 'os',
+ 'xh', 'zu', 'is', 'it', 'he', 'jv', 'kbp', 'kl', 'kn', 'kr', 'pam',
+ 'krc', 'ka', 'ks', 'csb', 'kk', 'kw', 'rw', 'rn', 'sw', 'kv', 'kg',
+ 'gom', 'ht', 'ku', 'kj', 'ky', 'mrj', 'lad', 'lbe', 'lez', 'lo',
+ 'ltg', 'la', 'lv', 'lb', 'lt', 'lij', 'li', 'ln', 'olo', 'jbo',
+ 'lg', 'lmo', 'lrc', 'hu', 'mai', 'mk', 'mg', 'ml', 'mt', 'mi',
+ 'mr', 'xmf', 'arz', 'mzn', 'ms', 'min', 'cdo', 'mwl', 'mdf', 'mo',
+ 'mn', 'mus', 'my', 'nah', 'na', 'fj', 'nl', 'nds-nl', 'cr', 'ne',
+ 'new', 'ja', 'nap', 'ce', 'frr', 'pih', 'no', 'nb', 'nn', 'nrm',
+ 'nov', 'ii', 'oc', 'mhr', 'or', 'om', 'ng', 'hz', 'uz', 'pa', 'pi',
+ 'pfl', 'pag', 'pnb', 'pap', 'ps', 'jam', 'koi', 'km', 'pcd', 'pms',
+ 'tpi', 'nds', 'pl', 'pnt', 'pt', 'aa', 'kaa', 'crh', 'ty', 'ksh',
+ 'ro', 'rmy', 'rm', 'qu', 'rue', 'ru', 'sah', 'se', 'sm', 'sa',
+ 'sg', 'sc', 'sco', 'stq', 'st', 'nso', 'tn', 'sq', 'scn', 'si',
+ 'simple', 'sd', 'ss', 'sk', 'sl', 'cu', 'szl', 'so', 'ckb', 'srn',
+ 'sr', 'sh', 'su', 'fi', 'sv', 'tl', 'ta', 'kab', 'roa-tara', 'tt',
+ 'te', 'tet', 'th', 'ti', 'tg', 'to', 'chr', 'chy', 've', 'tcy',
+ 'tr', 'azb', 'tk', 'tw', 'tyv', 'udm', 'bug', 'uk', 'ur', 'ug',
+ 'za', 'vec', 'vep', 'vi', 'vo', 'fiu-vro', 'wa', 'zh-classical',
+ 'vls', 'war', 'wo', 'wuu', 'ts', 'yi', 'yo', 'zh-yue', 'diq',
+ 'zea', 'bat-smg', 'zh', 'zh-tw', 'zh-cn',
+ ]

- # A list of languages that use hard (not soft) category redirects
- self.use_hard_category_redirects = []
+ # The revised sorting order by first word from meta
+ # MediaWiki:Interwiki_config-sorting_order-native-languagename-firstword
+ alphabetic_revised = [
+ 'ace', 'ady', 'kbd', 'af', 'ak', 'als', 'am', 'ang', 'ab', 'ar',
+ 'an', 'arc', 'roa-rup', 'frp', 'as', 'ast', 'atj', 'gn', 'av',
+ 'ay', 'az', 'bjn', 'id', 'ms', 'bm', 'bn', 'zh-min-nan', 'nan',
+ 'map-bms', 'jv', 'su', 'ba', 'min', 'be', 'be-tarask', 'bh', 'bcl',
+ 'bi', 'bar', 'bo', 'bs', 'br', 'bug', 'bg', 'bxr', 'ca', 'ceb',
+ 'cv', 'cs', 'ch', 'cbk-zam', 'ny', 'sn', 'tum', 'cho', 'co', 'cy',
+ 'da', 'dk', 'pdc', 'de', 'dv', 'nv', 'dsb', 'na', 'dty', 'dz',
+ 'mh', 'et', 'el', 'eml', 'en', 'myv', 'es', 'eo', 'ext', 'eu',
+ 'ee', 'fa', 'hif', 'fo', 'fr', 'fy', 'ff', 'fur', 'ga', 'gv', 'sm',
+ 'gag', 'gd', 'gl', 'gan', 'ki', 'glk', 'gu', 'got', 'hak', 'xal',
+ 'ko', 'ha', 'haw', 'hy', 'hi', 'ho', 'hsb', 'hr', 'io', 'ig',
+ 'ilo', 'bpy', 'ia', 'ie', 'iu', 'ik', 'os', 'xh', 'zu', 'is', 'it',
+ 'he', 'kl', 'kn', 'kr', 'pam', 'ka', 'ks', 'csb', 'kk', 'kw', 'rw',
+ 'ky', 'rn', 'mrj', 'sw', 'kv', 'kg', 'gom', 'ht', 'ku', 'kj',
+ 'lad', 'lbe', 'lez', 'lo', 'la', 'ltg', 'lv', 'to', 'lb', 'lt',
+ 'lij', 'li', 'ln', 'olo', 'jbo', 'lg', 'lmo', 'lrc', 'hu', 'mai',
+ 'mk', 'mg', 'ml', 'krc', 'mt', 'mi', 'mr', 'xmf', 'arz', 'mzn',
+ 'cdo', 'mwl', 'koi', 'mdf', 'mo', 'mn', 'mus', 'my', 'nah', 'fj',
+ 'nl', 'nds-nl', 'cr', 'ne', 'new', 'ja', 'nap', 'ce', 'frr', 'pih',
+ 'no', 'nb', 'nn', 'nrm', 'nov', 'ii', 'oc', 'mhr', 'or', 'om',
+ 'ng', 'hz', 'uz', 'pa', 'pi', 'pfl', 'pag', 'pnb', 'pap', 'ps',
+ 'jam', 'km', 'pcd', 'pms', 'nds', 'pl', 'pnt', 'pt', 'aa', 'kaa',
+ 'crh', 'ty', 'ksh', 'ro', 'rmy', 'rm', 'qu', 'ru', 'rue', 'sah',
+ 'se', 'sa', 'sg', 'sc', 'sco', 'stq', 'st', 'nso', 'tn', 'sq',
+ 'scn', 'si', 'simple', 'sd', 'ss', 'sk', 'sl', 'cu', 'szl', 'so',
+ 'ckb', 'srn', 'sr', 'sh', 'fi', 'sv', 'tl', 'ta', 'kab',
+ 'roa-tara', 'tt', 'te', 'tet', 'th', 'vi', 'ti', 'tg', 'tpi',
+ 'chr', 'chy', 've', 'tcy', 'tr', 'azb', 'tk', 'tw', 'tyv', 'udm',
+ 'uk', 'ur', 'ug', 'za', 'vec', 'vep', 'vo', 'fiu-vro', 'wa',
+ 'zh-classical', 'vls', 'war', 'wo', 'wuu', 'ts', 'yi', 'yo',
+ 'zh-yue', 'diq', 'zea', 'bat-smg', 'zh', 'zh-tw', 'zh-cn',
+ ]

- # A list of disambiguation template names in different languages
- self.disambiguationTemplates = {
- '_default': []
- }
+ # Order for fy: alphabetical by code, but y counts as i
+ fyinterwiki = alphabetic[:]
+ fyinterwiki.remove('nb')
+ fyinterwiki.sort(key=lambda x:
+ x.replace('y', 'i') + x.count('y') * '!')

- # A dict of tuples for different sites with names of templates
- # that indicate an edit should be avoided
- self.edit_restricted_templates = {}
+ # letters that can follow a wikilink and are regarded as part of
+ # this link
+ # This depends on the linktrail setting in LanguageXx.php and on
+ # [[MediaWiki:Linktrail]].
+ # Note: this is a regular expression.
+ linktrails = {
+ '_default': '[a-z]*',
+ 'ab': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'als': '[äöüßa-z]*',
+ 'an': '[a-záéíóúñ]*',
+ 'ar': '[a-zء-ي]*',
+ 'ast': '[a-záéíóúñ]*',
+ 'atj': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'arz': '[a-zء-ي]*',
+ 'azb': '[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
+ 'av': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'ay': '[a-záéíóúñ]*',
+ 'bar': '[äöüßa-z]*',
+ 'bat-smg': '[a-ząčęėįšųūž]*',
+ 'be': '[абвгґджзеёжзійклмнопрстуўфхцчшыьэюяćčłńśšŭźža-z]*',
+ 'be-tarask': '[абвгґджзеёжзійклмнопрстуўфхцчшыьэюяćčłńśšŭźža-z]*',
+ 'bg': '[a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]*',
+ 'bm': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'bn': '[ঀ-৿]*',
+ 'bpy': '[ঀ-৿]*',
+ 'bs': '[a-zćčžšđž]*',
+ 'bxr': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'ca': '[a-zàèéíòóúç·ïü]*',
+ 'cbk-zam': '[a-záéíóúñ]*',
+ 'ce': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'ckb': '[ئابپتجچحخدرڕزژسشعغفڤقکگلڵمنوۆهھەیێ‌]*',
+ 'co': '[a-zàéèíîìóòúù]*',
+ 'crh': '[a-zâçğıñöşüа-яё“»]*',
+ 'cs': '[a-záčďéěíňóřšťúůýž]*',
+ 'csb': '[a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]*',
+ 'cu': ('[a-zабвгдеєжѕзїіıићклмнопсстѹфхѡѿцчшщъыьѣюѥѧѩѫѭѯѱѳѷѵґѓђё'
+ 'јйљњќуўџэ҄я“»]*'),
+ 'cv': '[a-zа-яĕçăӳ"»]*',
+ 'cy': '[àáâèéêìíîïòóôûŵŷa-z]*',
+ 'da': '[a-zæøå]*',
+ 'de': '[a-zäöüß]*',
+ 'din': '[äëɛɛ̈éɣïŋöɔɔ̈óa-z]*',
+ 'dsb': '[äöüßa-z]*',
+ 'el': ('[a-zαβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέή'
+ 'ίόύώϊϋΐΰΆΈΉΊΌΎΏΪΫ]*'),
+ 'eml': '[a-zàéèíîìóòúù]*',
+ 'es': '[a-záéíóúñ]*',
+ 'eu': '[a-záéíóúñ]*',
+ 'et': '[äöõšüža-z]*',
+ 'ext': '[a-záéíóúñ]*',
+ 'fa': '[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
+ 'ff': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'fi': '[a-zäö]*',
+ 'fiu-vro': '[äöõšüža-z]*',
+ 'fo': '[áðíóúýæøa-z]*',
+ 'fr': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'frp': '[a-zàâçéèêîœôû·’æäåāăëēïīòöōùü‘]*',
+ 'frr': '[a-zäöüßåāđē]*',
+ 'fur': '[a-zàéèíîìóòúù]*',
+ 'fy': '[a-zàáèéìíòóùúâêîôûäëïöü]*',
+ 'gag': '[a-zÇĞçğİıÖöŞşÜüÂâÎîÛû]*',
+ 'gl': '[áâãàéêẽçíòóôõq̃úüűũa-z]*',
+ 'glk': '[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
+ 'gn': '[a-záéíóúñ]*',
+ 'gu': '[઀-૿]*',
+ 'he': '[a-zא-ת]*',
+ 'hi': '[a-zऀ-ॣ०-꣠-ꣿ]*',
+ 'hr': '[čšžćđßa-z]*',
+ 'hsb': '[äöüßa-z]*',
+ 'ht': '[a-zàèòÀÈÒ]*',
+ 'hu': '[a-záéíóúöüőűÁÉÍÓÚÖÜŐŰ]*',
+ 'hy': '[a-zաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև«»]*',
+ 'is': '[áðéíóúýþæöa-z-–]*',
+ 'it': '[a-zàéèíîìóòúù]*',
+ 'ka': '[a-zაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰ“»]*',
+ 'kbp': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'kk': ('[a-zäçéğıïñöşüýʺʹа-яёәғіқңөұүһ'
+ 'ٴابپتجحدرزسشعفقكلمنڭەوۇۋۆىيچھ“»]*'),
+ 'kl': '[a-zæøå]*',
+ 'koi': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'krc': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'ksh': '[a-zäöüėëijßəğåůæœç]*',
+ 'ku': '[a-zçêîşûẍḧÇÊÎŞÛẌḦ]*',
+ 'kv': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'lad': '[a-záéíóúñ]*',
+ 'lb': '[äöüßa-z]*',
+ 'lbe': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюяӀ1“»]*',
+ 'lez': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'li': '[a-zäöüïëéèà]*',
+ 'lij': '[a-zàéèíîìóòúù]*',
+ 'lmo': '[a-zàéèíîìóòúù]*',
+ 'ln': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'lrc': '[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
+ 'lt': '[a-ząčęėįšųūž]*',
+ 'ltg': '[a-zA-ZĀāČčĒēĢģĪīĶķĻļŅņŠšŪūŽž]*',
+ 'lv': '[a-zA-ZĀāČčĒēĢģĪīĶķĻļŅņŠšŪūŽž]*',
+ 'mai': '[a-zऀ-ॣ०-꣠-ꣿ]*',
+ 'mdf': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'mg': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'mhr': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'mk': '[a-zабвгдѓежзѕијклљмнњопрстќуфхцчџш]*',
+ 'ml': '[a-zം-ൿ]*',
+ 'mn': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя“»]*',
+ 'mr': '[ऀ-ॣॱ-ॿ‍]*',
+ 'mrj': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'mwl': '[áâãàéêẽçíòóôõq̃úüűũa-z]*',
+ 'myv': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'mzn': '[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیآأئؤة‌]*',
+ 'nah': '[a-záéíóúñ]*',
+ 'nap': '[a-zàéèíîìóòúù]*',
+ 'nds': '[äöüßa-z]*',
+ 'nds-nl': '[a-zäöüïëéèà]*',
+ 'nl': '[a-zäöüïëéèà]*',
+ 'nn': '[æøåa-z]*',
+ 'no': '[æøåa-z]*',
+ 'nrm': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'oc': '[a-zàâçéèêîôû]*',
+ 'olo': '[a-zčČšŠžŽäÄöÖ]*',
+ 'or': '[a-z଀-୿]*',
+ 'pa': ('[ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹ਼ਾ'
+ 'ਿੀੁੂੇੈੋੌ੍ਖ਼ਗ਼ਜ਼ੜਫ਼ੰੱੲੳa-z]*'),
+ 'pcd': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'pdc': '[äöüßa-z]*',
+ 'pfl': '[äöüßa-z]*',
+ 'pl': '[a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]*',
+ 'pms': '[a-zàéèíîìóòúù]*',
+ 'pnt': ('[a-zαβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ'
+ 'άέήίόύώϊϋΐΰΆΈΉΊΌΎΏΪΫ]*'),
+ 'pt': '[a-záâãàéêẽçíòóôõq̃úüűũ]*',
+ 'qu': '[a-záéíóúñ]*',
+ 'rmy': '[a-zăâîşţșțĂÂÎŞŢȘȚ]*',
+ 'ro': '[a-zăâîşţșțĂÂÎŞŢȘȚ]*',
+ 'roa-rup': '[a-zăâîşţșțĂÂÎŞŢȘȚ]*',
+ 'roa-tara': '[a-zàéèíîìóòúù]*',
+ 'ru': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'rue': '[a-zабвгґдеєжзиіїйклмнопрстуфхцчшщьєюяёъы“»]*',
+ 'sa': '[a-zऀ-ॣ०-꣠-ꣿ]*',
+ 'sah': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'scn': '[a-zàéèíîìóòúù]*',
+ 'sg': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'sh': '[a-zčćđžš]*',
+ 'sk': '[a-záäčďéíľĺňóôŕšťúýž]*',
+ 'sl': '[a-zčćđžš]*',
+ 'sr': ('[abvgdđežzijklljmnnjoprstćufhcčdžšабвгдђежзијклљмнњопрстћу'
+ 'фхцчџш]*'),
+ 'srn': '[a-zäöüïëéèà]*',
+ 'stq': '[äöüßa-z]*',
+ 'sv': '[a-zåäöéÅÄÖÉ]*',
+ 'szl': '[a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]*',
+ 'ta': '[஀-௿]*',
+ 'te': '[ఁ-౯]*',
+ 'tg': '[a-zабвгдеёжзийклмнопрстуфхчшъэюяғӣқўҳҷцщыь]*',
+ 'tk': '[a-zÄäÇçĞğŇňÖöŞşÜüÝýŽž]*',
+ 'tr': '[a-zÇĞçğİıÖöŞşÜüÂâÎîÛû]*',
+ 'tt': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюяӘәӨөҮүҖҗҢңҺһ]*',
+ 'ty': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'tyv': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'udm': '[a-zа-яёӝӟӥӧӵ]*',
+ 'uk': '[a-zабвгґдеєжзиіїйклмнопрстуфхцчшщьєюяёъы“»]*',
+ 'ur': '[ابپتٹثجچحخدڈذر​ڑ​زژسشصضطظعغفقکگل​م​نںوؤہھیئےآأءۃ]*',
+ 'uz': '[a-zʻʼ“»]*',
+ 'vec': '[a-zàéèíîìóòúù]*',
+ 'vep': '[äöõšüža-z]*',
+ 'vi': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'vls': '[a-zäöüïëéèà]*',
+ 'wa': '[a-zåâêîôûçéè]*',
+ 'wo': '[a-zàâçéèêîôûäëïöüùÇÉÂÊÎÔÛÄËÏÖÜÀÈÙ]*',
+ 'xal': '[a-zабвгдеёжзийклмнопрстуфхцчшщъыьэюя]*',
+ 'xmf': '[a-zაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰ“»]*',
+ 'yi': '[a-zא-ת]*',
+ 'zea': '[a-zäöüïëéèà]*',
+ }

- # A dict of tuples for different sites with names of archive
- # templates that indicate an edit of non-archive bots
- # should be avoided
- self.archived_page_templates = {}
+ # A dictionary where keys are family codes that can be used in
+ # inter-family interwiki links. Do not use it directly but
+ # get_known_families() instead.

- # A list of projects that share cross-project sessions.
- if not hasattr(self, 'cross_projects'):
- self.cross_projects = []
+ # TODO: replace this with API interwikimap call
+ known_families = {
+ 'abbenormal': 'abbenormal',
+ 'acronym': 'acronym',
+ 'advisory': 'advisory',
+ 'advogato': 'advogato',
+ 'aew': 'aew',
+ 'airwarfare': 'airwarfare',
+ 'aiwiki': 'aiwiki',
+ 'allwiki': 'allwiki',
+ 'appropedia': 'appropedia',
+ 'aquariumwiki': 'aquariumwiki',
+ 'arxiv': 'arxiv',
+ 'aspienetwiki': 'aspienetwiki',
+ 'atmwiki': 'atmwiki',
+ 'b': 'wikibooks',
+ 'bemi': 'bemi',
+ 'benefitswiki': 'benefitswiki',
+ 'betawiki': 'betawiki',
+ 'betawikiversity': 'betawikiversity',
+ 'biblewiki': 'biblewiki',
+ 'bluwiki': 'bluwiki',
+ 'botwiki': 'botwiki',
+ 'boxrec': 'boxrec',
+ 'brickwiki': 'brickwiki',
+ 'bridgeswiki': 'bridgeswiki',
+ 'bugzilla': 'bugzilla',
+ 'buzztard': 'buzztard',
+ 'bytesmiths': 'bytesmiths',
+ 'c2': 'c2',
+ 'c2find': 'c2find',
+ 'cache': 'cache',
+ 'canwiki': 'canwiki',
+ 'canyonwiki': 'canyonwiki',
+ 'Ĉej': 'Ĉej',
+ 'cellwiki': 'cellwiki',
+ 'centralwikia': 'centralwikia',
+ 'chapter': 'chapter',
+ 'chej': 'chej',
+ 'choralwiki': 'choralwiki',
+ 'ciscavate': 'ciscavate',
+ 'citizendium': 'citizendium',
+ 'ckwiss': 'ckwiss',
+ 'closed-zh-tw': 'closed-zh-tw',
+ 'cndbname': 'cndbname',
+ 'cndbtitle': 'cndbtitle',
+ 'colab': 'colab',
+ 'comcom': 'comcom',
+ 'comixpedia': 'comixpedia',
+ 'commons': 'commons',
+ 'communityscheme': 'communityscheme',
+ 'comune': 'comune',
+ 'consciousness': 'consciousness',
+ 'corpknowpedia': 'corpknowpedia',
+ 'crazyhacks': 'crazyhacks',
+ 'creatureswiki': 'creatureswiki',
+ 'cxej': 'cxej',
+ 'dawiki': 'dawiki',
+ 'dbdump': 'dbdump',
+ 'dcc': 'dcc',
+ 'dcdatabase': 'dcdatabase',
+ 'dcma': 'dcma',
+ 'dejanews': 'dejanews',
+ 'delicious': 'delicious',
+ 'demokraatia': 'demokraatia',
+ 'devmo': 'devmo',
+ 'dict': 'dict',
+ 'dictionary': 'dictionary',
+ 'disinfopedia': 'disinfopedia',
+ 'distributedproofreaders': 'distributedproofreaders',
+ 'distributedproofreadersca': 'distributedproofreadersca',
+ 'dk': 'dk',
+ 'dmoz': 'dmoz',
+ 'dmozs': 'dmozs',
+ 'docbook': 'docbook',
+ 'doom_wiki': 'doom_wiki',
+ 'download': 'download',
+ 'drae': 'drae',
+ 'dreamhost': 'dreamhost',
+ 'drumcorpswiki': 'drumcorpswiki',
+ 'dwjwiki': 'dwjwiki',
+ 'eĉei': 'eĉei',
+ 'echei': 'echei',
+ 'ecoreality': 'ecoreality',
+ 'ecxei': 'ecxei',
+ 'efnetceewiki': 'efnetceewiki',
+ 'efnetcppwiki': 'efnetcppwiki',
+ 'efnetpythonwiki': 'efnetpythonwiki',
+ 'efnetxmlwiki': 'efnetxmlwiki',
+ 'elibre': 'elibre',
+ 'emacswiki': 'emacswiki',
+ 'energiewiki': 'energiewiki',
+ 'eokulturcentro': 'eokulturcentro',
+ 'epo': 'epo',
+ 'ethnologue': 'ethnologue',
+ 'evowiki': 'evowiki',
+ 'exotica': 'exotica',
+ 'fanimutationwiki': 'fanimutationwiki',
+ 'finalempire': 'finalempire',
+ 'finalfantasy': 'finalfantasy',
+ 'finnix': 'finnix',
+ 'flickruser': 'flickruser',
+ 'floralwiki': 'floralwiki',
+ 'flyerwiki-de': 'flyerwiki-de',
+ 'foldoc': 'foldoc',
+ 'forthfreak': 'forthfreak',
+ 'foundation': 'foundation',
+ 'foxwiki': 'foxwiki',
+ 'freebio': 'freebio',
+ 'freebsdman': 'freebsdman',
+ 'freeculturewiki': 'freeculturewiki',
+ 'freedomdefined': 'freedomdefined',
+ 'freefeel': 'freefeel',
+ 'freekiwiki': 'freekiwiki',
+ 'ganfyd': 'ganfyd',
+ 'gausswiki': 'gausswiki',
+ 'gentoo-wiki': 'gentoo',
+ 'genwiki': 'genwiki',
+ 'globalvoices': 'globalvoices',
+ 'glossarwiki': 'glossarwiki',
+ 'glossarywiki': 'glossarywiki',
+ 'golem': 'golem',
+ 'google': 'google',
+ 'googledefine': 'googledefine',
+ 'googlegroups': 'googlegroups',
+ 'gotamac': 'gotamac',
+ 'greatlakeswiki': 'greatlakeswiki',
+ 'guildwiki': 'guildwiki',
+ 'gutenberg': 'gutenberg',
+ 'gutenbergwiki': 'gutenbergwiki',
+ 'h2wiki': 'h2wiki',
+ 'hammondwiki': 'hammondwiki',
+ 'heroeswiki': 'heroeswiki',
+ 'herzkinderwiki': 'herzkinderwiki',
+ 'hkmule': 'hkmule',
+ 'holshamtraders': 'holshamtraders',
+ 'hrfwiki': 'hrfwiki',
+ 'hrwiki': 'hrwiki',
+ 'humancell': 'humancell',
+ 'hupwiki': 'hupwiki',
+ 'imdbcharacter': 'imdbcharacter',
+ 'imdbcompany': 'imdbcompany',
+ 'imdbname': 'imdbname',
+ 'imdbtitle': 'imdbtitle',
+ 'incubator': 'incubator',
+ 'infoanarchy': 'infoanarchy',
+ 'infosecpedia': 'infosecpedia',
+ 'infosphere': 'infosphere',
+ 'iso639-3': 'iso639-3',
+ 'iuridictum': 'iuridictum',
+ 'jameshoward': 'jameshoward',
+ 'javanet': 'javanet',
+ 'javapedia': 'javapedia',
+ 'jefo': 'jefo',
+ 'jiniwiki': 'jiniwiki',
+ 'jspwiki': 'jspwiki',
+ 'jstor': 'jstor',
+ 'kamelo': 'kamelo',
+ 'karlsruhe': 'karlsruhe',
+ 'kerimwiki': 'kerimwiki',
+ 'kinowiki': 'kinowiki',
+ 'kmwiki': 'kmwiki',
+ 'kontuwiki': 'kontuwiki',
+ 'koslarwiki': 'koslarwiki',
+ 'kpopwiki': 'kpopwiki',
+ 'linguistlist': 'linguistlist',
+ 'linuxwiki': 'linuxwiki',
+ 'linuxwikide': 'linuxwikide',
+ 'liswiki': 'liswiki',
+ 'literateprograms': 'literateprograms',
+ 'livepedia': 'livepedia',
+ 'lojban': 'lojban',
+ 'lostpedia': 'lostpedia',
+ 'lqwiki': 'lqwiki',
+ 'lugkr': 'lugkr',
+ 'luxo': 'luxo',
+ 'lyricwiki': 'lyricwiki',
+ 'm': 'meta',
+ 'm-w': 'm-w',
+ 'mail': 'mail',
+ 'mailarchive': 'mailarchive',
+ 'mariowiki': 'mariowiki',
+ 'marveldatabase': 'marveldatabase',
+ 'meatball': 'meatball',
+ 'mediazilla': 'mediazilla',
+ 'memoryalpha': 'memoryalpha',
+ 'meta': 'meta',
+ 'metawiki': 'metawiki',
+ 'metawikipedia': 'metawikipedia',
+ 'mineralienatlas': 'mineralienatlas',
+ 'moinmoin': 'moinmoin',
+ 'monstropedia': 'monstropedia',
+ 'mosapedia': 'mosapedia',
+ 'mozcom': 'mozcom',
+ 'mozillawiki': 'mozillawiki',
+ 'mozillazinekb': 'mozillazinekb',
+ 'musicbrainz': 'musicbrainz',
+ 'mw': 'mw',
+ 'mwod': 'mwod',
+ 'mwot': 'mwot',
+ 'n': 'wikinews',
+ 'netvillage': 'netvillage',
+ 'nkcells': 'nkcells',
+ 'nomcom': 'nomcom',
+ 'nosmoke': 'nosmoke',
+ 'nost': 'nost',
+ 'oeis': 'oeis',
+ 'oldwikisource': 'oldwikisource',
+ 'olpc': 'olpc',
+ 'onelook': 'onelook',
+ 'openfacts': 'openfacts',
+ 'openstreetmap': 'openstreetmap',
+ 'openwetware': 'openwetware',
+ 'openwiki': 'openwiki',
+ 'opera7wiki': 'opera7wiki',
+ 'organicdesign': 'organicdesign',
+ 'orgpatterns': 'orgpatterns',
+ 'orthodoxwiki': 'orthodoxwiki',
+ 'osi reference model': 'osi reference model',
+ 'otrs': 'otrs',
+ 'otrswiki': 'otrswiki',
+ 'ourmedia': 'ourmedia',
+ 'paganwiki': 'paganwiki',
+ 'panawiki': 'panawiki',
+ 'pangalacticorg': 'pangalacticorg',
+ 'patwiki': 'patwiki',
+ 'perlconfwiki': 'perlconfwiki',
+ 'perlnet': 'perlnet',
+ 'personaltelco': 'personaltelco',
+ 'phpwiki': 'phpwiki',
+ 'phwiki': 'phwiki',
+ 'planetmath': 'planetmath',
+ 'pmeg': 'pmeg',
+ 'pmwiki': 'pmwiki',
+ 'psycle': 'psycle',
+ 'purlnet': 'purlnet',
+ 'pythoninfo': 'pythoninfo',
+ 'pythonwiki': 'pythonwiki',
+ 'pywiki': 'pywiki',
+ 'q': 'wikiquote',
+ 'qcwiki': 'qcwiki',
+ 'quality': 'quality',
+ 'qwiki': 'qwiki',
+ 'r3000': 'r3000',
+ 'raec': 'raec',
+ 'rakwiki': 'rakwiki',
+ 'reuterswiki': 'reuterswiki',
+ 'rev': 'rev',
+ 'revo': 'revo',
+ 'rfc': 'rfc',
+ 'rheinneckar': 'rheinneckar',
+ 'robowiki': 'robowiki',
+ 'rowiki': 'rowiki',
+ 's': 'wikisource',
+ 's23wiki': 's23wiki',
+ 'scholar': 'scholar',
+ 'schoolswp': 'schoolswp',
+ 'scores': 'scores',
+ 'scoutwiki': 'scoutwiki',
+ 'scramble': 'scramble',
+ 'seapig': 'seapig',
+ 'seattlewiki': 'seattlewiki',
+ 'seattlewireless': 'seattlewireless',
+ 'senseislibrary': 'senseislibrary',
+ 'silcode': 'silcode',
+ 'slashdot': 'slashdot',
+ 'slwiki': 'slwiki',
+ 'smikipedia': 'smikipedia',
+ 'sourceforge': 'sourceforge',
+ 'spcom': 'spcom',
+ 'species': 'species',
+ 'squeak': 'squeak',
+ 'stable': 'stable',
+ 'strategywiki': 'strategywiki',
+ 'sulutil': 'sulutil',
+ 'susning': 'susning',
+ 'svgwiki': 'svgwiki',
+ 'svn': 'svn',
+ 'swinbrain': 'swinbrain',
+ 'swingwiki': 'swingwiki',
+ 'swtrain': 'swtrain',
+ 'tabwiki': 'tabwiki',
+ 'takipedia': 'takipedia',
+ 'tavi': 'tavi',
+ 'tclerswiki': 'tclerswiki',
+ 'technorati': 'technorati',
+ 'tejo': 'tejo',
+ 'tesoltaiwan': 'tesoltaiwan',
+ 'testwiki': 'testwiki',
+ 'thelemapedia': 'thelemapedia',
+ 'theopedia': 'theopedia',
+ 'theppn': 'theppn',
+ 'thinkwiki': 'thinkwiki',
+ 'tibiawiki': 'tibiawiki',
+ 'ticket': 'ticket',
+ 'tmbw': 'tmbw',
+ 'tmnet': 'tmnet',
+ 'tmwiki': 'tmwiki',
+ 'tokyonights': 'tokyonights',
+ 'tools': 'tools',
+ 'translatewiki': 'translatewiki',
+ 'trash!italia': 'trash!italia',
+ 'tswiki': 'tswiki',
+ 'turismo': 'turismo',
+ 'tviv': 'tviv',
+ 'tvtropes': 'tvtropes',
+ 'twiki': 'twiki',
+ 'twistedwiki': 'twistedwiki',
+ 'tyvawiki': 'tyvawiki',
+ 'uncyclopedia': 'uncyclopedia',
+ 'unreal': 'unreal',
+ 'urbandict': 'urbandict',
+ 'usej': 'usej',
+ 'usemod': 'usemod',
+ 'v': 'wikiversity',
+ 'valuewiki': 'valuewiki',
+ 'veropedia': 'veropedia',
+ 'vinismo': 'vinismo',
+ 'vkol': 'vkol',
+ 'vlos': 'vlos',
+ 'voipinfo': 'voipinfo',
+ 'voy': 'wikivoyage',
+ 'w': 'wikipedia',
+ 'warpedview': 'warpedview',
+ 'webdevwikinl': 'webdevwikinl',
+ 'webisodes': 'webisodes',
+ 'webseitzwiki': 'webseitzwiki',
+ 'wg': 'wg',
+ 'wiki': 'wiki',
+ 'wikia': 'wikia',
+ 'wikianso': 'wikianso',
+ 'wikiasite': 'wikiasite',
+ 'wikible': 'wikible',
+ 'wikibooks': 'wikibooks',
+ 'wikichat': 'wikichat',
+ 'wikichristian': 'wikichristian',
+ 'wikicities': 'wikicities',
+ 'wikicity': 'wikicity',
+ 'wikif1': 'wikif1',
+ 'wikifur': 'wikifur',
+ 'wikihow': 'wikihow',
+ 'wikiindex': 'wikiindex',
+ 'wikilemon': 'wikilemon',
+ 'wikilivres': 'wikilivres',
+ 'wikimac-de': 'wikimac-de',
+ 'wikimac-fr': 'wikimac-fr',
+ 'wikimedia': 'wikimedia',
+ 'wikinews': 'wikinews',
+ 'wikinfo': 'wikinfo',
+ 'wikinurse': 'wikinurse',
+ 'wikinvest': 'wikinvest',
+ 'wikipaltz': 'wikipaltz',
+ 'wikipedia': 'wikipedia',
+ 'wikipediawikipedia': 'wikipediawikipedia',
+ 'wikiquote': 'wikiquote',
+ 'wikireason': 'wikireason',
+ 'wikischool': 'wikischool',
+ 'wikisophia': 'wikisophia',
+ 'wikisource': 'wikisource',
+ 'wikispecies': 'wikispecies',
+ 'wikispot': 'wikispot',
+ 'wikiti': 'wikiti',
+ 'wikitravel': 'wikitravel',
+ 'wikitree': 'wikitree',
+ 'wikiversity': 'wikiversity',
+ 'wikiwikiweb': 'wikiwikiweb',
+ 'wikt': 'wiktionary',
+ 'wiktionary': 'wiktionary',
+ 'wipipedia': 'wipipedia',
+ 'wlug': 'wlug',
+ 'wm2005': 'wm2005',
+ 'wm2006': 'wm2006',
+ 'wm2007': 'wm2007',
+ 'wm2008': 'wm2008',
+ 'wm2009': 'wm2009',
+ 'wm2010': 'wm2010',
+ 'wm2011': 'wm2011',
+ 'wm2012': 'wm2012',
+ 'wm2013': 'wm2013',
+ 'wm2014': 'wm2014',
+ 'wm2015': 'wm2015',
+ 'wm2016': 'wm2016',
+ 'wm2017': 'wm2017',
+ 'wm2018': 'wm2018',
+ 'wmania': 'wmania',
+ 'wmcz': 'wmcz',
+ 'wmf': 'wmf',
+ 'wmrs': 'wmrs',
+ 'wmse': 'wmse',
+ 'wookieepedia': 'wookieepedia',
+ 'world66': 'world66',
+ 'wowwiki': 'wowwiki',
+ 'wqy': 'wqy',
+ 'wurmpedia': 'wurmpedia',
+ 'wznan': 'wznan',
+ 'xboxic': 'xboxic',
+ 'zh-cfr': 'zh-cfr',
+ 'zrhwiki': 'zrhwiki',
+ 'zum': 'zum',
+ 'zwiki': 'zwiki',
+ 'zzz wiki': 'zzz wiki',
+ }

- # A list with the name for cross-project cookies.
- # default for wikimedia centralAuth extensions.
- self.cross_projects_cookies = ['centralauth_Session',
- 'centralauth_Token',
- 'centralauth_User']
- self.cross_projects_cookie_username = 'centralauth_User'
+ # A list of category redirect template names in different languages
+ category_redirect_templates = {
+ '_default': []
+ }

- # A list with the name in the cross-language flag permissions
- self.cross_allowed = []
+ # A list of languages that use hard (not soft) category redirects
+ use_hard_category_redirects = []

- # A dict with the name of the category containing disambiguation
- # pages for the various languages. Only one category per language,
- # and without the namespace, so add things like:
- # 'en': "Disambiguation"
- self.disambcatname = {}
+ # A list of disambiguation template names in different languages
+ disambiguationTemplates = {
+ '_default': []
+ }

- # DEPRECATED, stores the code of the site which have a case sensitive
- # main namespace. Use the Namespace given from the Site instead
- self.nocapitalize = []
+ # A dict of tuples for different sites with names of templates
+ # that indicate an edit should be avoided
+ edit_restricted_templates = {}

- # attop is a list of languages that prefer to have the interwiki
- # links at the top of the page.
- self.interwiki_attop = []
- # on_one_line is a list of languages that want the interwiki links
- # one-after-another on a single line
- self.interwiki_on_one_line = []
- # String used as separator between interwiki links and the text
- self.interwiki_text_separator = config.line_separator * 2
+ # A dict of tuples for different sites with names of archive
+ # templates that indicate an edit of non-archive bots
+ # should be avoided
+ archived_page_templates = {}

- # Similar for category
- self.category_attop = []
- # on_one_line is a list of languages that want the category links
- # one-after-another on a single line
- self.category_on_one_line = []
- # String used as separator between category links and the text
- self.category_text_separator = config.line_separator * 2
- # When both at the bottom should categories come after interwikilinks?
- # TODO: T86284 Needed on Wikia sites, as it uses the CategorySelect
- # extension which puts categories last on all sites. TO BE DEPRECATED!
- self.categories_last = []
+ # A list of projects that share cross-project sessions.
+ cross_projects = []

- # Which languages have a special order for putting interlanguage
- # links, and what order is it? If a language is not in
- # interwiki_putfirst, alphabetical order on language code is used.
- # For languages that are in interwiki_putfirst, interwiki_putfirst
- # is checked first, and languages are put in the order given there.
- # All other languages are put after those, in code-alphabetical
- # order.
- self.interwiki_putfirst = {}
+ # A list with the name for cross-project cookies.
+ # default for wikimedia centralAuth extensions.
+ cross_projects_cookies = ['centralauth_Session',
+ 'centralauth_Token',
+ 'centralauth_User']
+ cross_projects_cookie_username = 'centralauth_User'

- # Some families, e. g. commons and meta, are not multilingual and
- # forward interlanguage links to another family (wikipedia).
- # These families can set this variable to the name of the target
- # family.
- self.interwiki_forward = None
+ # A list with the name in the cross-language flag permissions
+ cross_allowed = []

- # Some families, e. g. wikipedia, receive forwarded interlanguage
- # links from other families, e. g. incubator, commons, or meta.
- # These families can set this variable to the names of their source
- # families.
- self.interwiki_forwarded_from = {}
+ # A dict with the name of the category containing disambiguation
+ # pages for the various languages. Only one category per language,
+ # and without the namespace, so add things like:
+ # 'en': "Disambiguation"
+ disambcatname = {}

- # Which language codes no longer exist and by which language code
- # should they be replaced. If for example the language with code xx:
- # now should get code yy:, add {'xx':'yy'} to obsolete.
- if not hasattr(self, 'interwiki_replacements'):
- self.interwiki_replacements = {}
+ # DEPRECATED, stores the code of the site which have a case sensitive
+ # main namespace. Use the Namespace given from the Site instead
+ nocapitalize = []

- # Codes that should be removed, usually because the site has been
- # taken down.
- if not hasattr(self, 'interwiki_removals'):
- self.interwiki_removals = []
+ # attop is a list of languages that prefer to have the interwiki
+ # links at the top of the page.
+ interwiki_attop = []
+ # on_one_line is a list of languages that want the interwiki links
+ # one-after-another on a single line
+ interwiki_on_one_line = []
+ # String used as separator between interwiki links and the text
+ interwiki_text_separator = config.line_separator * 2

- # Language codes of the largest wikis. They should be roughly sorted
- # by size.
- if not hasattr(self, 'languages_by_size'):
- self.languages_by_size = []
+ # Similar for category
+ category_attop = []
+ # on_one_line is a list of languages that want the category links
+ # one-after-another on a single line
+ category_on_one_line = []
+ # String used as separator between category links and the text
+ category_text_separator = config.line_separator * 2
+ # When both at the bottom should categories come after interwikilinks?
+ # TODO: T86284 Needed on Wikia sites, as it uses the CategorySelect
+ # extension which puts categories last on all sites. TO BE DEPRECATED!
+ categories_last = []

- # Some languages belong to a group where the possibility is high that
- # equivalent articles have identical titles among the group.
- self.language_groups = {
- # languages using the arabic script (incomplete)
- 'arab': [
- 'ar', 'arz', 'ps', 'sd', 'ur', 'bjn', 'ckb',
- # languages using multiple scripts, including arabic
- 'kk', 'ku', 'tt', 'ug', 'pnb'
- ],
- # languages that use chinese symbols
- 'chinese': [
- 'wuu', 'zh', 'zh-classical', 'zh-yue', 'gan', 'ii',
- # languages using multiple/mixed scripts, including chinese
- 'ja', 'za'
- ],
- # languages that use the cyrillic alphabet
- 'cyril': [
- 'ab', 'av', 'ba', 'be', 'be-tarask', 'bg', 'bxr', 'ce', 'cu',
- 'cv', 'kbd', 'koi', 'kv', 'ky', 'mk', 'lbe', 'mdf', 'mn', 'mo',
- 'myv', 'mhr', 'mrj', 'os', 'ru', 'rue', 'sah', 'tg', 'tk',
- 'udm', 'uk', 'xal',
- # languages using multiple scripts, including cyrillic
- 'ha', 'kk', 'sh', 'sr', 'tt'
- ],
- # languages that use a greek script
- 'grec': [
- 'el', 'grc', 'pnt'
- # languages using multiple scripts, including greek
- ],
- # languages that use the latin alphabet
- 'latin': [
- 'aa', 'ace', 'af', 'ak', 'als', 'an', 'ang', 'ast', 'ay', 'bar',
- 'bat-smg', 'bcl', 'bi', 'bm', 'br', 'bs', 'ca', 'cbk-zam',
- 'cdo', 'ceb', 'ch', 'cho', 'chy', 'co', 'crh', 'cs', 'csb',
- 'cy', 'da', 'de', 'diq', 'dsb', 'ee', 'eml', 'en', 'eo', 'es',
- 'et', 'eu', 'ext', 'ff', 'fi', 'fiu-vro', 'fj', 'fo', 'fr',
- 'frp', 'frr', 'fur', 'fy', 'ga', 'gag', 'gd', 'gl', 'gn', 'gv',
- 'hak', 'haw', 'hif', 'ho', 'hr', 'hsb', 'ht', 'hu', 'hz', 'ia',
- 'id', 'ie', 'ig', 'ik', 'ilo', 'io', 'is', 'it', 'jbo', 'jv',
- 'kaa', 'kab', 'kg', 'ki', 'kj', 'kl', 'kr', 'ksh', 'kw', 'la',
- 'lad', 'lb', 'lg', 'li', 'lij', 'lmo', 'ln', 'lt', 'ltg', 'lv',
- 'map-bms', 'mg', 'mh', 'mi', 'ms', 'mt', 'mus', 'mwl', 'na',
- 'nah', 'nap', 'nds', 'nds-nl', 'ng', 'nl', 'nn', 'no', 'nov',
- 'nrm', 'nv', 'ny', 'oc', 'om', 'pag', 'pam', 'pap', 'pcd',
- 'pdc', 'pfl', 'pih', 'pl', 'pms', 'pt', 'qu', 'rm', 'rn', 'ro',
- 'roa-rup', 'roa-tara', 'rw', 'sc', 'scn', 'sco', 'se', 'sg',
- 'simple', 'sk', 'sl', 'sm', 'sn', 'so', 'sq', 'srn', 'ss',
- 'st', 'stq', 'su', 'sv', 'sw', 'szl', 'tet', 'tl', 'tn', 'to',
- 'tpi', 'tr', 'ts', 'tum', 'tw', 'ty', 'uz', 've', 'vec', 'vi',
- 'vls', 'vo', 'wa', 'war', 'wo', 'xh', 'yo', 'zea',
- 'zh-min-nan', 'zu',
- # languages using multiple scripts, including latin
- 'az', 'chr', 'ckb', 'ha', 'iu', 'kk', 'ku', 'rmy', 'sh', 'sr',
- 'tt', 'ug', 'za'
- ],
- # Scandinavian languages
- 'scand': [
- 'da', 'fo', 'is', 'nb', 'nn', 'no', 'sv'
- ],
- }
+ # Which languages have a special order for putting interlanguage
+ # links, and what order is it? If a language is not in
+ # interwiki_putfirst, alphabetical order on language code is used.
+ # For languages that are in interwiki_putfirst, interwiki_putfirst
+ # is checked first, and languages are put in the order given there.
+ # All other languages are put after those, in code-alphabetical
+ # order.
+ interwiki_putfirst = {}

- # LDAP domain if your wiki uses LDAP authentication,
- # https://www.mediawiki.org/wiki/Extension:LDAP_Authentication
- self.ldapDomain = ()
+ # Some families, e. g. commons and meta, are not multilingual and
+ # forward interlanguage links to another family (wikipedia).
+ # These families can set this variable to the name of the target
+ # family.
+ interwiki_forward = None

- # Allows crossnamespace interwiki linking.
- # Lists the possible crossnamespaces combinations
- # keys are originating NS
- # values are dicts where:
- # keys are the originating langcode, or _default
- # values are dicts where:
- # keys are the languages that can be linked to from the lang+ns, or
- # '_default'; values are a list of namespace numbers
- self.crossnamespace = collections.defaultdict(dict)
- ##
- # Examples :
- #
- # Allowing linking to pt' 102 NS from any other lang' 0 NS is
- #
- # self.crossnamespace[0] = {
- # '_default': { 'pt': [102]}
- # }
- #
- # While allowing linking from pt' 102 NS to any other lang' = NS is
- #
- # self.crossnamespace[102] = {
- # 'pt': { '_default': [0]}
- # }
+ # Some families, e. g. wikipedia, receive forwarded interlanguage
+ # links from other families, e. g. incubator, commons, or meta.
+ # These families can set this variable to the names of their source
+ # families.
+ interwiki_forwarded_from = {}
+
+ # Which language codes no longer exist and by which language code
+ # should they be replaced. If for example the language with code xx:
+ # now should get code yy:, add {'xx':'yy'} to obsolete.
+ interwiki_replacements = {}
+
+ # Codes that should be removed, usually because the site has been
+ # taken down.
+ interwiki_removals = []
+
+ # Language codes of the largest wikis. They should be roughly sorted
+ # by size.
+ languages_by_size = []
+
+ # Some languages belong to a group where the possibility is high that
+ # equivalent articles have identical titles among the group.
+ language_groups = {
+ # languages using the arabic script (incomplete)
+ 'arab': [
+ 'ar', 'arz', 'ps', 'sd', 'ur', 'bjn', 'ckb',
+ # languages using multiple scripts, including arabic
+ 'kk', 'ku', 'tt', 'ug', 'pnb'
+ ],
+ # languages that use chinese symbols
+ 'chinese': [
+ 'wuu', 'zh', 'zh-classical', 'zh-yue', 'gan', 'ii',
+ # languages using multiple/mixed scripts, including chinese
+ 'ja', 'za'
+ ],
+ # languages that use the cyrillic alphabet
+ 'cyril': [
+ 'ab', 'av', 'ba', 'be', 'be-tarask', 'bg', 'bxr', 'ce', 'cu',
+ 'cv', 'kbd', 'koi', 'kv', 'ky', 'mk', 'lbe', 'mdf', 'mn', 'mo',
+ 'myv', 'mhr', 'mrj', 'os', 'ru', 'rue', 'sah', 'tg', 'tk',
+ 'udm', 'uk', 'xal',
+ # languages using multiple scripts, including cyrillic
+ 'ha', 'kk', 'sh', 'sr', 'tt'
+ ],
+ # languages that use a greek script
+ 'grec': [
+ 'el', 'grc', 'pnt'
+ # languages using multiple scripts, including greek
+ ],
+ # languages that use the latin alphabet
+ 'latin': [
+ 'aa', 'ace', 'af', 'ak', 'als', 'an', 'ang', 'ast', 'ay', 'bar',
+ 'bat-smg', 'bcl', 'bi', 'bm', 'br', 'bs', 'ca', 'cbk-zam',
+ 'cdo', 'ceb', 'ch', 'cho', 'chy', 'co', 'crh', 'cs', 'csb',
+ 'cy', 'da', 'de', 'diq', 'dsb', 'ee', 'eml', 'en', 'eo', 'es',
+ 'et', 'eu', 'ext', 'ff', 'fi', 'fiu-vro', 'fj', 'fo', 'fr',
+ 'frp', 'frr', 'fur', 'fy', 'ga', 'gag', 'gd', 'gl', 'gn', 'gv',
+ 'hak', 'haw', 'hif', 'ho', 'hr', 'hsb', 'ht', 'hu', 'hz', 'ia',
+ 'id', 'ie', 'ig', 'ik', 'ilo', 'io', 'is', 'it', 'jbo', 'jv',
+ 'kaa', 'kab', 'kg', 'ki', 'kj', 'kl', 'kr', 'ksh', 'kw', 'la',
+ 'lad', 'lb', 'lg', 'li', 'lij', 'lmo', 'ln', 'lt', 'ltg', 'lv',
+ 'map-bms', 'mg', 'mh', 'mi', 'ms', 'mt', 'mus', 'mwl', 'na',
+ 'nah', 'nap', 'nds', 'nds-nl', 'ng', 'nl', 'nn', 'no', 'nov',
+ 'nrm', 'nv', 'ny', 'oc', 'om', 'pag', 'pam', 'pap', 'pcd',
+ 'pdc', 'pfl', 'pih', 'pl', 'pms', 'pt', 'qu', 'rm', 'rn', 'ro',
+ 'roa-rup', 'roa-tara', 'rw', 'sc', 'scn', 'sco', 'se', 'sg',
+ 'simple', 'sk', 'sl', 'sm', 'sn', 'so', 'sq', 'srn', 'ss',
+ 'st', 'stq', 'su', 'sv', 'sw', 'szl', 'tet', 'tl', 'tn', 'to',
+ 'tpi', 'tr', 'ts', 'tum', 'tw', 'ty', 'uz', 've', 'vec', 'vi',
+ 'vls', 'vo', 'wa', 'war', 'wo', 'xh', 'yo', 'zea',
+ 'zh-min-nan', 'zu',
+ # languages using multiple scripts, including latin
+ 'az', 'chr', 'ckb', 'ha', 'iu', 'kk', 'ku', 'rmy', 'sh', 'sr',
+ 'tt', 'ug', 'za'
+ ],
+ # Scandinavian languages
+ 'scand': [
+ 'da', 'fo', 'is', 'nb', 'nn', 'no', 'sv'
+ ],
+ }
+
+ # LDAP domain if your wiki uses LDAP authentication,
+ # https://www.mediawiki.org/wiki/Extension:LDAP_Authentication
+ ldapDomain = ()
+
+ # Allows crossnamespace interwiki linking.
+ # Lists the possible crossnamespaces combinations
+ # keys are originating NS
+ # values are dicts where:
+ # keys are the originating langcode, or _default
+ # values are dicts where:
+ # keys are the languages that can be linked to from the lang+ns, or
+ # '_default'; values are a list of namespace numbers
+ crossnamespace = collections.defaultdict(dict)
+ ##
+ # Examples :
+ #
+ # Allowing linking to pt' 102 NS from any other lang' 0 NS is
+ #
+ # crossnamespace[0] = {
+ # '_default': { 'pt': [102]}
+ # }
+ #
+ # While allowing linking from pt' 102 NS to any other lang' = NS is
+ #
+ # crossnamespace[102] = {
+ # 'pt': { '_default': [0]}
+ # }

_families = {}

@@ -967,7 +991,7 @@
mod = import_module(splitext(basename(family_file))[0])
except ImportError:
raise UnknownFamily(u'Family %s does not exist' % fam)
- cls = mod.Family()
+ cls = mod.Family.instance
if cls.name != fam:
warn(u'Family name %s does not match family module name %s'
% (cls.name, fam), FamilyMaintenanceWarning)
@@ -985,13 +1009,13 @@
Family._families[fam] = cls
return cls

- @property
+ @classproperty
@deprecated('Family.codes or APISite.validLanguageLinks')
- def iwkeys(self):
+ def iwkeys(cls):
"""DEPRECATED: List of (interwiki_forward's) family codes."""
- if self.interwiki_forward:
- return list(pywikibot.Family(self.interwiki_forward).langs.keys())
- return list(self.langs.keys())
+ if cls.interwiki_forward:
+ return list(pywikibot.Family(cls.interwiki_forward).langs.keys())
+ return list(cls.langs.keys())

@deprecated('APISite.interwiki')
def get_known_families(self, site):
@@ -1362,10 +1386,8 @@
"""
if not isinstance(other, Family):
other = self.load(other)
- try:
- return self.name == other.name
- except AttributeError:
- return id(self) == id(other)
+
+ return self is other

def __ne__(self, other):
try:
@@ -1452,8 +1474,8 @@
for (old, new) in data.items()
if new is not None)

- @property
- def domains(self):
+ @classproperty
+ def domains(cls):
"""
Get list of unique domain names included in this family.

@@ -1461,37 +1483,37 @@

@rtype: iterable of str
"""
- return set(self.langs.values())
+ return set(cls.langs.values())

- @property
- def codes(self):
+ @classproperty
+ def codes(cls):
"""
Get list of codes used by this family.

@rtype: iterable of str
"""
- return set(self.langs.keys())
+ return set(cls.langs.keys())


class SingleSiteFamily(Family):

"""Single site family."""

- def __init__(self):
+ def __new__(cls):
"""Constructor."""
- if not hasattr(self, 'code'):
- self.code = self.name
+ if not hasattr(cls, 'code'):
+ cls.code = cls.name

- assert self.domain
+ assert cls.domain

- super(SingleSiteFamily, self).__init__()
+ cls.langs = {cls.code: cls.domain}

- self.langs = {self.code: self.domain}
+ return super(SingleSiteFamily, cls).__new__(cls)

- @property
- def domains(self):
+ @classproperty
+ def domains(cls):
"""Return the full domain name of the site."""
- return (self.domain, )
+ return (cls.domain, )

def hostname(self, code):
"""Return the domain as the hostname."""
@@ -1502,32 +1524,36 @@

"""Multi site wikis that are subdomains of the same top level domain."""

- def __init__(self):
+ def __new__(cls):
"""Constructor."""
- assert self.domain
+ assert cls.domain
+ return super(SubdomainFamily, cls).__new__(cls)

- codes = self.codes
- if hasattr(self, 'test_codes'):
- codes = codes + self.test_codes
+ @classproperty
+ def langs(cls):
+ """Property listing family languages."""
+ codes = cls.codes
+ if hasattr(cls, 'test_codes'):
+ codes = codes + cls.test_codes

- self.langs = {code: '{0}.{1}'.format(code, self.domain)
- for code in codes}
+ # shortcut this classproperty
+ cls.langs = {code: '{0}.{1}'.format(code, cls.domain)
+ for code in codes}
+ return cls.langs

- super(SubdomainFamily, self).__init__()
-
- @property
- def codes(self):
+ @classproperty
+ def codes(cls):
"""Property listing family codes."""
- if hasattr(self, 'languages_by_size'):
- return self.languages_by_size
+ if hasattr(cls, 'languages_by_size'):
+ return cls.languages_by_size
raise NotImplementedError(
'Family %s needs property "languages_by_size" or "codes"'
- % self.name)
+ % cls.name)

- @property
- def domains(self):
+ @classproperty
+ def domains(cls):
"""Return the domain name of the sites in this family."""
- return [self.domain]
+ return [cls.domain]


class WikiaFamily(Family):
@@ -1630,36 +1656,33 @@
'mo': 'ro',
}

- def __init__(self):
- """Constructor."""
- super(WikimediaFamily, self).__init__()
- # WikimediaFamily uses wikibase for the category name containing
- # disambiguation pages for the various languages. We need the
- # wikibase code and item number:
- self.disambcatname = {'wikidata': 'Q1982926'}
+ # WikimediaFamily uses wikibase for the category name containing
+ # disambiguation pages for the various languages. We need the
+ # wikibase code and item number:
+ disambcatname = {'wikidata': 'Q1982926'}

- @property
- def domain(self):
+ @classproperty
+ def domain(cls):
"""Domain property."""
- if self.name in (self.multi_language_content_families
- + self.other_content_families):
- return self.name + '.org'
- elif self.name in self.wikimedia_org_families:
+ if cls.name in (cls.multi_language_content_families
+ + cls.other_content_families):
+ return cls.name + '.org'
+ elif cls.name in cls.wikimedia_org_families:
return 'wikimedia.org'

raise NotImplementedError(
- 'Family %s needs to define property \'domain\'' % self.name)
+ 'Family %s needs to define property \'domain\'' % cls.name)

- @property
- def interwiki_removals(self):
+ @classproperty
+ def interwiki_removals(cls):
"""Return a list of interwiki codes to be removed from wiki pages."""
- return frozenset(self.removed_wikis + self.closed_wikis)
+ return frozenset(cls.removed_wikis + cls.closed_wikis)

- @property
- def interwiki_replacements(self):
+ @classproperty
+ def interwiki_replacements(cls):
"""Return an interwiki code replacement mapping."""
- rv = self.code_aliases.copy()
- rv.update(self.interwiki_replacement_overrides)
+ rv = cls.code_aliases.copy()
+ rv.update(cls.interwiki_replacement_overrides)
return FrozenDict(rv)

def shared_image_repository(self, code):
@@ -1688,30 +1711,26 @@

"""Single site family for sites hosted at C{*.wikimedia.org}."""

- @property
- def domain(self):
+ @classproperty
+ def domain(cls):
"""Return the parents domain with a subdomain prefix."""
- return '{0}.wikimedia.org'.format(self.name)
+ return '{0}.wikimedia.org'.format(cls.name)


-class AutoFamily(SingleSiteFamily):
+@deprecated_args(site=None)
+def AutoFamily(name, url):
+ """
+ Family that automatically loads the site configuration.

- """Family that automatically loads the site configuration."""
-
- @deprecated_args(site=None)
- def __init__(self, name, url):
- """
- Constructor.
-
- @param name: Name for the family
- @type name: str
- @param url: API endpoint URL of the wiki
- @type url: str
- """
- self.name = name
- self.url = urlparse.urlparse(url)
- self.domain = self.url.netloc
- super(AutoFamily, self).__init__()
+ @param name: Name for the family
+ @type name: str
+ @param url: API endpoint URL of the wiki
+ @type url: str
+ @return: Generated family class
+ @rtype: SingleSiteFamily
+ """
+ url = urlparse.urlparse(url)
+ domain = url.netloc

def protocol(self, code):
"""Return the protocol of the URL."""
@@ -1722,4 +1741,9 @@
if self.url.path.endswith('/api.php'):
return self.url.path[0:-8]
else:
+ # AutoFamily refers to the variable set below, not the function
return super(AutoFamily, self).scriptpath(code)
+
+ # str() used because py2 can't accept a unicode as the name of a class
+ AutoFamily = type(str('AutoFamily'), (SingleSiteFamily,), locals())
+ return AutoFamily()
diff --git a/scripts/maintenance/wikimedia_sites.py b/scripts/maintenance/wikimedia_sites.py
index 8f87d60..6cd0395 100755
--- a/scripts/maintenance/wikimedia_sites.py
+++ b/scripts/maintenance/wikimedia_sites.py
@@ -73,22 +73,22 @@
pywikibot.output(u'The lists match!')
else:
pywikibot.output(u"The lists don't match, the new list is:")
- text = ' self.languages_by_size = [\n'
- line = ' ' * 11
+ text = ' languages_by_size = [\n'
+ line = ' ' * 7
for code in new:
if len(line) + len(code) < 76:
line += u" '%s'," % code
else:
text += '%s\n' % line
- line = ' ' * 11
+ line = ' ' * 7
line += u" '%s'," % code
text += '%s\n' % line
- text += u' ]'
+ text += ' ]'
pywikibot.output(text)
family_file_name = 'pywikibot/families/%s_family.py' % family
with codecs.open(family_file_name, 'r', 'utf8') as family_file:
family_text = family_file.read()
- family_text = re.sub(r'(?msu)^ {8}self.languages_by_size.+?\]',
+ family_text = re.sub(r'(?msu)^ {4}languages_by_size.+?\]',
text, family_text, 1)
with codecs.open(family_file_name, 'w', 'utf8') as family_file:
family_file.write(family_text)
diff --git a/tests/family_tests.py b/tests/family_tests.py
index 36fc96e..ae016b7 100644
--- a/tests/family_tests.py
+++ b/tests/family_tests.py
@@ -67,22 +67,18 @@
Family.load,
'unknown')

- def test_eq_different_families_by_name(self):
- """Test that two Family with same name are equal."""
- family_1 = Family()
- family_2 = Family()
- family_1.name = 'a'
- family_2.name = 'a'
- self.assertNotEqual(id(family_1), id(family_2))
+ def test_new_same_family_singleton(self):
+ """Test that two same Family are the same object and equal."""
+ family_1 = Family.load('wikipedia')
+ family_2 = Family.load('wikipedia')
+ self.assertIs(family_1, family_2)
self.assertEqual(family_1, family_2)

- def test_eq_different_families_by_id(self):
- """Test that two Family with no name attribute are not equal."""
- family_1 = Family()
- family_2 = Family()
- family_1.name = 'a'
- del family_2.name
- self.assertNotEqual(id(family_1), id(family_2))
+ def test_new_different_families_ne(self):
+ """Test that two different Family are not same nor equal."""
+ family_1 = Family.load('wikipedia')
+ family_2 = Family.load('wiktionary')
+ self.assertIsNot(family_1, family_2)
self.assertNotEqual(family_1, family_2)

def test_eq_family_with_string_repr_same_family(self):
@@ -130,7 +126,9 @@

def test_set_obsolete(self):
"""Test obsolete can be set."""
- family = Family()
+ # Construct a temporary family and instantiate it
+ family = type(str('TempFamily'), (Family,), {})()
+
self.assertEqual(family.obsolete, {})
self.assertEqual(family.interwiki_replacements, {})
self.assertEqual(family.interwiki_removals, [])
diff --git a/tox.ini b/tox.ini
index 44c0235..7b7c4f7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -174,7 +174,9 @@
# __dict__ used in a discouraged manner
# regex matches the first physical line of logical line of the error
pywikibot/exceptions.py : H501
- pywikibot/family.py : E241, N803, N806
+ # classproperties; most docs should go to family.py
+ pywikibot/families/* : N805, D102
+ pywikibot/family.py : E241, N803, N806, N805
pywikibot/fixes.py : E241
pywikibot/interwiki_graph.py : N803, N806
pywikibot/logging.py : N803

To view, visit change 433712. To unsubscribe, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I2a3cb83c5fb6fb3648c9ef2e08313cf77dbb9c29
Gerrit-Change-Number: 433712
Gerrit-PatchSet: 16
Gerrit-Owner: Zhuyifei1999 <zhuyifei1999@gmail.com>
Gerrit-Reviewer: Dalba <dalba.wiki@gmail.com>
Gerrit-Reviewer: Dvorapa <dvorapa@seznam.cz>
Gerrit-Reviewer: Framawiki <framawiki@tools.wmflabs.org>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: Zhuyifei1999 <zhuyifei1999@gmail.com>
Gerrit-Reviewer: jenkins-bot <>