]> code.communitydata.science - rises_declines_wikia_code.git/blob - mediawiki_dump_tools/Mediawiki-Utilities/mw/lib/title/parser.py
Initial commit
[rises_declines_wikia_code.git] / mediawiki_dump_tools / Mediawiki-Utilities / mw / lib / title / parser.py
1 from ...types import Namespace
2 from ...util import autovivifying, none_or
3 from .functions import normalize
4
5
6 class Parser:
7     """
8     Constructs a page name parser from a set of :class:`mw.Namespace`.  Such a
9     parser can be used to convert a full page name (namespace included with a
10     colon; e.g, ``"Talk:Foo"``) into a namespace ID and
11     :func:`mw.lib.title.normalize`'d page title (e.g., ``(1, "Foo")``).
12
13     :Parameters:
14         namespaces : set( :class:`mw.Namespace` )
15     :Example:
16         >>> from mw import Namespace
17         >>> from mw.lib import title
18         >>>
19         >>> parser = title.Parser(
20         ...     [
21         ...             Namespace(0, "", case="first-letter"),
22         ...             Namespace(1, "Discuss\u00e3o", canonical="Talk", case="first-letter"),
23         ...             Namespace(2, "Usu\u00e1rio(a)", canonical="User", aliases={"U"}, case="first-letter")
24         ...     ]
25         ... )
26         >>>
27         >>> parser.parse("Discuss\u00e3o:Foo") # Using the standard name
28         (1, 'Foo')
29         >>> parser.parse("Talk:Foo bar") # Using the cannonical name
30         (1, 'Foo_bar')
31         >>> parser.parse("U:Foo bar") # Using an alias
32         (2, 'Foo_bar')
33         >>> parser.parse("Herpderp:Foo bar") # Psuedo namespace
34         (0, 'Herpderp:Foo_bar')
35     """
36
37     def __init__(self, namespaces=None):
38         namespaces = none_or(namespaces, set)
39
40         self.ids = {}
41         self.names = {}
42
43         if namespaces is not None:
44             for namespace in namespaces:
45                 self.add_namespace(namespace)
46
47     def parse(self, page_name):
48         """
49         Parses a page name to extract the namespace.
50
51         :Parameters:
52             page_name : str
53                 A page name including the namespace prefix and a colon (if not Main)
54
55         :Returns:
56             A tuple of (namespace : `int`, title : `str`)
57         """
58         parts = page_name.split(":", 1)
59         if len(parts) == 1:
60             ns_id = 0
61             title = normalize(page_name)
62         else:
63             ns_name, title = parts
64             ns_name, title = normalize(ns_name), normalize(title)
65
66             if self.contains_name(ns_name):
67                 ns_id = self.get_namespace(name=ns_name).id
68             else:
69                 ns_id = 0
70                 title = normalize(page_name)
71
72         return ns_id, title
73
74     def add_namespace(self, namespace):
75         """
76         Adds a namespace to the parser.
77
78         :Parameters:
79             namespace : :class:`mw.Namespace`
80                 A namespace
81         """
82         self.ids[namespace.id] = namespace
83         self.names[namespace.name] = namespace
84
85         for alias in namespace.aliases:
86             self.names[alias] = namespace
87
88         if namespace.canonical is not None:
89             self.names[namespace.canonical] = namespace
90
91     def contains_name(self, name):
92         return normalize(name) in self.names
93
94     def get_namespace(self, id=None, name=None):
95         """
96         Gets a namespace from the parser.  Throws a :class:`KeyError` if a
97         namespace cannot be found.
98
99         :Parameters:
100             id : int
101                 A namespace ID
102             name : str
103                 A namespace name (standard, cannonical names and aliases
104                 will be searched)
105         :Returns:
106             A :class:`mw.Namespace`.
107         """
108         if id is not None:
109             return self.ids[int(id)]
110         else:
111             return self.names[normalize(name)]
112
113     @classmethod
114     def from_site_info(cls, si_doc):
115         """
116         Constructs a parser from the result of a :meth:`mw.api.SiteInfo.query`.
117
118         :Parameters:
119             si_doc : dict
120                 The result of a site_info request.
121
122         :Returns:
123             An initialized :class:`mw.lib.title.Parser`
124         """
125         aliases = autovivifying.Dict(vivifier=lambda k: [])
126         # get aliases
127         if 'namespacealiases' in si_doc:
128             for alias_doc in si_doc['namespacealiases']:
129                 aliases[alias_doc['id']].append(alias_doc['*'])
130
131         namespaces = []
132         for ns_doc in si_doc['namespaces'].values():
133             namespaces.append(
134                 Namespace.from_doc(ns_doc, aliases)
135             )
136
137         return Parser(namespaces)
138
139     @classmethod
140     def from_api(cls, session):
141         """
142         Constructs a parser from a :class:`mw.api.Session`
143
144         :Parameters:
145             session : :class:`mw.api.Session`
146                 An open API session
147
148         :Returns:
149             An initialized :class:`mw.lib.title.Parser`
150         """
151         si_doc = session.site_info.query(
152             properties={'namespaces', 'namespacealiases'}
153         )
154
155         return cls.from_site_info(si_doc)
156
157     @classmethod
158     def from_dump(cls, dump):
159         """
160         Constructs a parser from a :class:`mw.xml_dump.Iterator`.  Note that
161         XML database dumps do not include namespace aliases or cannonical names
162         so the parser that will be constructed will only work in common cases.
163
164         :Parameters:
165             dump : :class:`mw.xml_dump.Iterator`
166                 An XML dump iterator
167
168         :Returns:
169             An initialized :class:`mw.lib.title.Parser`
170         """
171         return cls(dump.namespaces)

Community Data Science Collective || Want to submit a patch?