Source code for tests.family_tests

#!/usr/bin/env python3
"""Tests for the family module."""
# (C) Pywikibot team, 2014-2024
# Distributed under the terms of the MIT license.
from __future__ import annotations

from import Mapping
from contextlib import suppress

import pywikibot
from pywikibot.exceptions import UnknownFamilyError
from import Family, SingleSiteFamily
from tests.aspects import PatchingTestCase, TestCase, unittest
from tests.utils import DrySite

[docs] class TestFamily(TestCase): """Test cases for Family methods.""" net = False
[docs] def test_family_load_valid(self): """Test that a family can be loaded via Family.load.""" for name in pywikibot.config.family_files: with self.subTest(family=name): f = Family.load(name) self.assertIsInstance(f.langs, dict) self.assertTrue(f.langs) self.assertTrue( self.assertTrue(iter( self.assertIsInstance(next(iter(, str) self.assertTrue( self.assertTrue(iter( for domain in self.assertIsInstance(domain, str) if not domain.startswith('localhost:'): self.assertIn('.', domain) self.assertEqual(, name) self.assertIsInstance(, set) self.assertGreaterEqual(set(f.langs), set( if isinstance(f, SingleSiteFamily): self.assertIsNotNone(f.code) self.assertIsNotNone(f.domain) self.assertEqual(set(f.langs), {f.code}) self.assertEqual(set(, {f.code})
[docs] def test_family_load_invalid(self): """Test that an invalid family raised UnknownFamilyError.""" with self.assertRaisesRegex( UnknownFamilyError, 'Family unknown does not exist'): Family.load('unknown')
[docs] 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)
[docs] 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)
[docs] def test_eq_family_with_string_repr_same_family(self): """Test that Family and string with same name are equal.""" family = Family.load('wikipedia') other = 'wikipedia' self.assertEqual(family, other) self.assertFalse(family != other) # noqa: H204
[docs] def test_ne_family_with_string_repr_different_family(self): """Test that Family and string with different name are not equal.""" family = Family.load('wikipedia') other = 'wikisource' self.assertNotEqual(family, other) self.assertFalse(family == other) # noqa: H204
[docs] def test_eq_family_with_string_repr_not_existing_family(self): """Test that Family and string with different name are not equal.""" family = Family.load('wikipedia') other = 'unknown' with self.assertRaisesRegex( UnknownFamilyError, 'Family unknown does not exist'): family.__eq__(other)
[docs] def test_get_obsolete_wp(self): """Test three types of obsolete codes.""" 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']) # offline site (see site tests test_removed_site) self.assertIsNone(family.obsolete['ru-sib']) self.assertIn('dk', family.interwiki_replacements)
[docs] 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, frozenset()) # 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, frozenset('c'))
[docs] def test_obsolete_readonly(self): """Test obsolete result not updatable.""" family = Family.load('wikipedia') with self.assertRaisesRegex( AttributeError, "'mappingproxy' object has no attribute 'update'"): family.obsolete.update({}) with self.assertRaisesRegex( TypeError, "'mappingproxy' object does not support item assignment"): family.obsolete['a'] = 'b' with self.assertRaisesRegex( AttributeError, "property 'obsolete' of 'Family' object has no setter|" "can't set attribute"): family.obsolete = {'a': 'b', 'c': None}
[docs] class TestFamilyUrlRegex(PatchingTestCase): """Test family URL regex.""" net = False
[docs] @PatchingTestCase.patched(pywikibot, 'Site') def Site(self, *args, **kwargs): """Own DrySite creator.""" code, fam, *args = args self.assertEqual(args, []) self.assertEqual(kwargs, {}) self.assertEqual(code, self.current_code) self.assertEqual(fam, self.current_family) site = DrySite(code, fam, None) site._siteinfo._cache['general'] = ({'articlepath': self.articlepath}, True) return site
[docs] def setUp(self): """Setup default article path.""" super().setUp() self.articlepath = '/wiki/$1'
[docs] def test_from_url_wikipedia_extra(self): """Test various URLs against wikipedia regex.""" self.current_code = 'vo' self.current_family = 'wikipedia' f = Family.load('wikipedia') prefix = '' self.assertEqual(f.from_url(prefix + '/wiki/'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php/'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php?title=$1'), 'vo') self.assertEqual(f.from_url(prefix + '/wiki/$1'), 'vo') self.assertEqual(f.from_url('//$1'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php/$1'), 'vo') self.assertEqual(f.from_url('//$1'), 'vo') # including title self.assertEqual(f.from_url(prefix + '/wiki/Main_page'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php?title=Foo'), 'vo') # Text after $1 is allowed self.assertEqual(f.from_url('//$1/foo'), 'vo') # the IWM may contain the wrong protocol, but it's only used to # determine a site so using HTTP or HTTPS is not an issue self.assertEqual(f.from_url('$1'), 'vo') # wrong protocol self.assertIsNone(f.from_url('$1')) # wrong code self.assertIsNone(f.from_url('$1')) # wrong family self.assertIsNone(f.from_url('$1')) self.assertIsNone(f.from_url('$1')) # invalid path self.assertIsNone(f.from_url('$1')) self.assertIsNone(f.from_url('$1'))
[docs] def test_each_family(self): """Test each family builds a working regex.""" for family in pywikibot.config.family_files: if family == 'wowwiki': self.skipTest( f'Family.from_url() does not work for {family} (T215077)') self.current_family = family family = Family.load(family) for code in self.current_code = code url = ('{}://{}{}/$1'.format(family.protocol(code), family.hostname(code), family.path(code))) # Families can switch off if they want to be detected using # URL. This applies for test:test (there is test:wikipedia) with self.subTest(url=url): self.assertEqual(family.from_url(url), code)
if __name__ == '__main__': with suppress(SystemExit): unittest.main()