jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/909314 )

Change subject: [IMPR] Revise Family class
......................................................................

[IMPR] Revise Family class

- remove obsolete.setter which is only used for tests
- move interwiki_replacements and interwiki_removals class
  properties from WikimediaFamily to Family class to have
  a unique result for all families
- add empty closed_wikis, removed_wikis and code_aliases to
  Family class which are used by interwiki_replacements and
  interwiki_removals; remove closed_wikis and removed_wikis
  from WikimediaFamily.
- simplify SingleSiteFamily because closed_wikis is always present
- codes must be a List not a Tuple in Family classes because SubdomainFamily
  modifies codes; update wikihow and wowwiki families
- update tests accordingly

This changes enables to change the interface for removed or closed sites
with wowwiki and others.

Bug: T334834
Change-Id: Ib22cbb964670471a60b47d89734fb4d63cea5710
---
M pywikibot/families/wikihow_family.py
M pywikibot/family.py
M pywikibot/families/wowwiki_family.py
M tests/family_tests.py
4 files changed, 95 insertions(+), 61 deletions(-)

Approvals:
  Xqt: Looks good to me, approved
  jenkins-bot: Verified




diff --git a/pywikibot/families/wikihow_family.py 
b/pywikibot/families/wikihow_family.py
index d72fe38..d49b642 100644
--- a/pywikibot/families/wikihow_family.py
+++ b/pywikibot/families/wikihow_family.py
@@ -3,7 +3,7 @@
 .. versionadded:: 3.0
 """
 #
-# (C) Pywikibot team, 2020-2022
+# (C) Pywikibot team, 2020-2023
 #
 # Distributed under the terms of the MIT license.
 #
@@ -21,10 +21,10 @@
     name = 'wikihow'
     domain = 'wikihow.com'

-    codes = (
+    codes = [
         'ar', 'cs', 'de', 'en', 'es', 'fr', 'hi', 'id', 'it', 'ja', 'ko', 'nl',
         'pt', 'ru', 'th', 'tr', 'vi', 'zh',
-    )
+    ]

     removed_wikis = ['ca', 'cy', 'fa', 'he', 'pl', 'ur']

diff --git a/pywikibot/families/wowwiki_family.py 
b/pywikibot/families/wowwiki_family.py
index b683c71..fdb5871 100644
--- a/pywikibot/families/wowwiki_family.py
+++ b/pywikibot/families/wowwiki_family.py
@@ -15,11 +15,11 @@
     name = 'wowwiki'
     domain = 'wowwiki.fandom.com'

-    codes = (
+    codes = [
         'ar', 'cs', 'da', 'de', 'el', 'en', 'es', 'et', 'fa', 'fi', 'fr', 'he',
         'hu', 'it', 'ja', 'ko', 'nl', 'no', 'pl', 'pt', 'pt-br', 'ru', 'uk',
         'zh', 'zh-tw',
-    )
+    ]

     removed_wikis = ['is', 'hr', 'lt', 'lv', 'ro', 'sk', 'sr', 'sv', 'tr']

diff --git a/pywikibot/family.py b/pywikibot/family.py
index 9966afe..1d9d0b8 100644
--- a/pywikibot/family.py
+++ b/pywikibot/family.py
@@ -1,6 +1,6 @@
 """Objects representing MediaWiki families."""
 #
-# (C) Pywikibot team, 2004-2022
+# (C) Pywikibot team, 2004-2023
 #
 # Distributed under the terms of the MIT license.
 #
@@ -18,9 +18,11 @@

 import pywikibot
 from pywikibot import config
-from pywikibot.backports import (  # skipcq: PY-W2000
+from pywikibot.backports import (
     Dict,
+    FrozenSet,
     List,
+    Mapping,
     Set,
     Tuple,
     removesuffix,
@@ -45,6 +47,8 @@
     .. versionchanged:: 8.0
        ``alphabetic``, ``alphabetic_revised`` and ``fyinterwiki``
        attributes where removed.
+    .. versionchanged:: 8.2
+       :attr:`obsolete` setter was removed.
     """

     def __new__(cls):
@@ -82,6 +86,19 @@

     name = None

+    #: Not open for edits; stewards can still edit.
+    closed_wikis: List[str] = []
+
+    #: Completely removed sites
+    removed_wikis: List[str] = []
+
+    code_aliases: Dict[str, str] = {}
+    """Code mappings which are only an alias, and there is no 'old' wiki.
+
+    For all except 'nl_nds', subdomains do exist as a redirect, but that
+    should not be relied upon.
+    """
+
     langs: Dict[str, str] = {}

     # A list of category redirect template names in different languages
@@ -161,15 +178,6 @@
     # family.
     interwiki_forward = None

-    # 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: Dict[str, str] = {}
-
-    # Codes that should be removed, usually because the site has been
-    # taken down.
-    interwiki_removals: List[str] = []
-
     # Language codes of the largest wikis. They should be roughly sorted
     # by size.
     languages_by_size: List[str] = []
@@ -528,7 +536,7 @@
         """Return the path to title using index.php with redirects disabled."""
         return f'{self.path(code)}?title={title}&redirect=no'

-    def interface(self, code) -> str:
+    def interface(self, code: str) -> str:
         """Return interface to use for code."""
         if code in self.interwiki_removals:
             if code in self.codes:
@@ -691,16 +699,6 @@
         data.update(self.interwiki_replacements)
         return types.MappingProxyType(data)

-    @obsolete.setter
-    def obsolete(self, data) -> None:
-        """Split obsolete dict into constituent parts."""
-        self.interwiki_removals[:] = [old for (old, new) in data.items()
-                                      if new is None]
-        self.interwiki_replacements.clear()
-        self.interwiki_replacements.update((old, new)
-                                           for (old, new) in data.items()
-                                           if new is not None)
-
     @classproperty
     def domains(cls) -> Set[str]:
         """
@@ -719,6 +717,32 @@
         """
         return set(cls.langs.keys())

+    @classproperty
+    def interwiki_replacements(cls) -> Mapping[str, str]:
+        """Return an interwiki code replacement mapping.
+
+        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
+        :attr:`code_aliases`.
+
+        .. versionchanged:: 8.2
+           changed from dict to invariant mapping.
+        """
+        return types.MappingProxyType(cls.code_aliases)
+
+    @classproperty
+    def interwiki_removals(cls) -> FrozenSet[str]:
+        """Return a list of interwiki codes to be removed from wiki pages.
+
+        Codes that should be removed, usually because the site has been
+        taken down.
+
+        .. versionchanged:: 8.2
+           changed from list to invariant frozenset.
+        """
+        return frozenset(cls.removed_wikis + cls.closed_wikis)
+

 class SingleSiteFamily(Family):

@@ -761,16 +785,13 @@

         if hasattr(cls, 'test_codes'):
             codes += cls.test_codes
-        if hasattr(cls, 'closed_wikis'):
-            codes += cls.closed_wikis
+
+        codes += cls.closed_wikis

         # shortcut this classproperty
-        cls.langs = {code: f'{code}.{cls.domain}'
-                     for code in codes}
-
-        if hasattr(cls, 'code_aliases'):
-            cls.langs.update({alias: f'{code}.{cls.domain}'
-                              for alias, code in cls.code_aliases.items()})
+        cls.langs = {code: f'{code}.{cls.domain}' for code in codes}
+        cls.langs.update({alias: f'{code}.{cls.domain}'
+                          for alias, code in cls.code_aliases.items()})

         return cls.langs

@@ -934,11 +955,6 @@
         'be-x-old': 'be-tarask',
     }

-    # Not open for edits; stewards can still edit.
-    closed_wikis: List[str] = []
-    # Completely removed
-    removed_wikis: List[str] = []
-
     # WikimediaFamily uses Wikibase for the category name containing
     # disambiguation pages for the various languages. We need the
     # Wikibase code and item number:
@@ -960,16 +976,6 @@
         raise NotImplementedError(
             f"Family {cls.name} needs to define property 'domain'")

-    @classproperty
-    def interwiki_removals(cls):
-        """Return a list of interwiki codes to be removed from wiki pages."""
-        return frozenset(cls.removed_wikis + cls.closed_wikis)
-
-    @classproperty
-    def interwiki_replacements(cls):
-        """Return an interwiki code replacement mapping."""
-        return types.MappingProxyType(cls.code_aliases)
-
     def shared_image_repository(self, code):
         """Return Wikimedia Commons as the shared image repository."""
         return ('commons', 'commons')
diff --git a/tests/family_tests.py b/tests/family_tests.py
index 2e65095..3ca109e 100755
--- a/tests/family_tests.py
+++ b/tests/family_tests.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 """Tests for the family module."""
 #
-# (C) Pywikibot team, 2014-2022
+# (C) Pywikibot team, 2014-2023
 #
 # Distributed under the terms of the MIT license.
 #
@@ -103,6 +103,8 @@
         family = Family.load('wikipedia')
         self.assertIsInstance(family.obsolete, Mapping)
         # redirected code (see site tests test_alias_code_site)
+        self.assertEqual(family.code_aliases['dk'], 'da')
+        self.assertEqual(family.interwiki_replacements['dk'], 'da')
         self.assertEqual(family.obsolete['dk'], 'da')
         # closed/locked site (see site tests test_locked_site)
         self.assertIsNone(family.obsolete['mh'])
@@ -110,19 +112,21 @@
         self.assertIsNone(family.obsolete['ru-sib'])
         self.assertIn('dk', family.interwiki_replacements)

-    def test_set_obsolete(self):
-        """Test obsolete can be set."""
+    def test_obsolete_from_attributes(self):
+        """Test obsolete property for given class attributes."""
         # Construct a temporary family and instantiate it
         family = type('TempFamily', (Family,), {})()

         self.assertEqual(family.obsolete, {})
         self.assertEqual(family.interwiki_replacements, {})
-        self.assertEqual(family.interwiki_removals, [])
+        self.assertEqual(family.interwiki_removals, frozenset())

-        family.obsolete = {'a': 'b', 'c': None}
+        # Construct a temporary family with other attributes and instantiate it
+        family = type('TempFamily', (Family,),
+                      {'code_aliases': {'a': 'b'}, 'closed_wikis': ['c']})()
         self.assertEqual(family.obsolete, {'a': 'b', 'c': None})
         self.assertEqual(family.interwiki_replacements, {'a': 'b'})
-        self.assertEqual(family.interwiki_removals, ['c'])
+        self.assertEqual(family.interwiki_removals, frozenset('c'))

     def test_obsolete_readonly(self):
         """Test obsolete result not updatable."""
@@ -137,12 +141,10 @@
                 "'mappingproxy' object does not support item assignment"):
             family.obsolete['a'] = 'b'

-    def test_WikimediaFamily_obsolete_readonly(self):
-        """Test WikimediaFamily obsolete is readonly."""
-        family = Family.load('wikipedia')
         with self.assertRaisesRegex(
-                TypeError,
-                "'frozenset' object does not support item assignment"):
+                AttributeError,
+                "property 'obsolete' of 'Family' object has no setter|"
+                "can't set attribute"):
             family.obsolete = {'a': 'b', 'c': None}



-- 
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/909314
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ib22cbb964670471a60b47d89734fb4d63cea5710
Gerrit-Change-Number: 909314
Gerrit-PatchSet: 9
Gerrit-Owner: Xqt <i...@gno.de>
Gerrit-Reviewer: Xqt <i...@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- pywikibot-commits@lists.wikimedia.org
To unsubscribe send an email to pywikibot-commits-le...@lists.wikimedia.org

Reply via email to