1"""Objects representing interwiki map of MediaWiki site."""
2#
3# (C) Pywikibot team, 2015-2021
4#
5# Distributed under the terms of the MIT license.
6#
7import pywikibot
8from pywikibot.backports import Set
9
10
11class _IWEntry:
12
13    """An entry of the _InterwikiMap with a lazy loading site."""
14
15    def __init__(self, local, url, prefix=None):
16        self._site = None
17        self.local = local
18        self.url = url
19        self.prefix = prefix
20
21    @property
22    def site(self):
23        if self._site is None:
24            try:
25                self._site = pywikibot.Site(
26                    url=self.url, fam=None if self.local else self.prefix)
27            except Exception as e:
28                self._site = e
29        return self._site
30
31
32class _InterwikiMap:
33
34    """A representation of the interwiki map of a site."""
35
36    def __init__(self, site):
37        """
38        Create an empty uninitialized interwiki map for the given site.
39
40        :param site: Given site for which interwiki map is to be created
41        :type site: pywikibot.site.APISite
42        """
43        super().__init__()
44        self._site = site
45        self._map = None
46
47    def reset(self):
48        """Remove all mappings to force building a new mapping."""
49        self._map = None
50
51    @property
52    def _iw_sites(self):
53        """Fill the interwikimap cache with the basic entries."""
54        # _iw_sites is a local cache to return an APISite instance depending
55        # on the interwiki prefix of that site
56        if self._map is None:
57            self._map = {iw['prefix']: _IWEntry('local' in iw,
58                                                iw['url'],
59                                                iw['prefix'])
60                         for iw in self._site.siteinfo['interwikimap']}
61        return self._map
62
63    def __getitem__(self, prefix):
64        """
65        Return the site, locality and url for the requested prefix.
66
67        :param prefix: Interwiki prefix
68        :type prefix: Dictionary key
69        :rtype: _IWEntry
70        :raises KeyError: Prefix is not a key
71        :raises TypeError: Site for the prefix is of wrong type
72        """
73        if prefix not in self._iw_sites:
74            raise KeyError("'{}' is not an interwiki prefix.".format(prefix))
75        if isinstance(self._iw_sites[prefix].site, pywikibot.site.BaseSite):
76            return self._iw_sites[prefix]
77        if isinstance(self._iw_sites[prefix].site, Exception):
78            raise self._iw_sites[prefix].site
79        raise TypeError('_iw_sites[{}] is wrong type: {}'
80                        .format(prefix, type(self._iw_sites[prefix].site)))
81
82    def get_by_url(self, url: str) -> Set[str]:
83        """
84        Return a set of prefixes applying to the URL.
85
86        :param url: URL for the interwiki
87        """
88        return {prefix for prefix, iw_entry in self._iw_sites.items()
89                if iw_entry.url == url}
90