Adapted test to new behavior.
[philipp/winterrodeln/wrpylib.git] / wrpylib / wrmwmarkup.py
1 #!/usr/bin/python2.6
2 # -*- coding: iso-8859-15 -*-
3 # $Id$
4 # $HeadURL$
5 """This module contains winterrodeln specific functions that are prcocessing the MediaWiki markup.
6 """
7 import re
8 import formencode
9 import wrpylib.wrvalidators
10 import wrpylib.mwmarkup
11
12
13 def _conv(fnct, value, fieldname):
14     """Internal function.
15     Like one of the to_xxx functions (e.g. to_bool), but adds the field name to the error message"""
16     try: return fnct(value)
17     except formencode.Invalid as e: raise formencode.Invalid(u"Conversion error in field '%s': %s" % (fieldname, unicode(e)), e.value, e.state)
18
19
20 def rodelbahnbox_to_sledrun(wikitext, sledrun=None):
21     """Converts a sledrun wiki page containing the {{Rodelbahnbox}}
22     to a sledrun. sledrun may be an instance of WrSledrunCache or an "empty" class (object()) (default).
23     Raises a formencode.Invalid exception if the format is not OK or the Rodelbahnbox is not found.
24     :return: (start, end, sledrun) tuple of the Rodelbahnbox."""
25     if sledrun is None:
26         class Sledrun(object): pass
27         sledrun = Sledrun()
28
29     # match Rodelbahnbox
30     start, end = wrpylib.mwmarkup.find_template(wikitext, u'Rodelbahnbox')
31     if start is None: raise formencode.Invalid(u"Rodelbahnbox nicht gefunden", wikitext, None)
32     template_title, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
33     
34     # process properties
35     for key, value in properties.iteritems():
36         if   key == u'Position': sledrun.position_latitude, sledrun.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
37         elif key == u'Position oben': sledrun.top_latitude, sledrun.top_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
38         elif key == u'Höhe oben': sledrun.top_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # '2000'
39         elif key == u'Position unten': sledrun.bottom_latitude, sledrun.bottom_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
40         elif key == u'Höhe unten': sledrun.bottom_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # '1200'
41         elif key == u'Länge': sledrun.length = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 3500
42         elif key == u'Schwierigkeit': sledrun.difficulty = _conv(wrpylib.wrvalidators.GermanDifficulty().to_python, value, key) # 'mittel' elif key == u'Lawinen': sledrun.avalanches = _conv(wrpylib.wrvalidators.GermanAvalanches().to_python, value, key) # 'kaum'
43         elif key == u'Lawinen': sledrun.avalanches = _conv(wrpylib.wrvalidators.GermanAvalanches().to_python, value, key) # 'kaum'
44         elif key == u'Betreiber': sledrun.operator = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key) # 'Max Mustermann'
45         elif key == u'Öffentliche Anreise': sledrun.public_transport = _conv(wrpylib.wrvalidators.GermanPublicTransport().to_python, value, key) # 'Mittelmäßig'
46         elif key == u'Aufstieg möglich': sledrun.walkup_possible = _conv(wrpylib.wrvalidators.GermanBoolNone().to_python, value, key) # 'Ja'
47         elif key == u'Aufstieg getrennt': sledrun.walkup_separate, sledrun.walkup_separate_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key) # 'Ja'
48         elif key == u'Gehzeit': sledrun.walkup_time = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 90
49         elif key == u'Aufstiegshilfe': sledrun.lift, sledrun.lift_details = _conv(wrpylib.wrvalidators.GermanLift().to_python, value, key) # 'Gondel (unterer Teil)'
50         elif key == u'Beleuchtungsanlage': sledrun.night_light, sledrun.night_light_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key)
51         elif key == u'Beleuchtungstage': sledrun.night_light_days, sledrun.night_light_days_comment = _conv(wrpylib.wrvalidators.UnsignedCommentNone(7).to_python, value, key) # '3 (Montag, Mittwoch, Freitag)'
52         elif key == u'Rodelverleih': sledrun.sled_rental, sledrun.sled_rental_comment = _conv(wrpylib.wrvalidators.SledRental().to_python, value, key) # 'Talstation Serlesbahnan'
53         elif key == u'Gütesiegel': sledrun.cachet = _conv(wrpylib.wrvalidators.GermanCachet().to_python, value, key) # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
54         elif key == u'Webauskunft': sledrun.information_web = _conv(wrpylib.wrvalidators.UrlNeinNone().to_python, value, key) # 'http://www.nösslachhütte.at/page9.php'
55         elif key == u'Telefonauskunft': sledrun.information_phone = _conv(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=False).to_python, value, key) # '+43-664-5487520 (Mitterer Alm)'
56         elif key == u'Bild': sledrun.image = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
57         elif key == u'In Übersichtskarte': sledrun.show_in_overview = _conv(wrpylib.wrvalidators.GermanBoolNone().to_python, value, key)
58         elif key == u'Forumid': sledrun.forum_id = _conv(wrpylib.wrvalidators.UnsignedNeinNone().to_python, value, key)
59         else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Rodelbahnbox: '%s' (mit Wert '%s')" % (key, value), value, None)
60     return start, end, sledrun
61
62
63 def sledrun_to_rodelbahnbox(sledrun, version):
64     """Converts a sledrun class to the {{Rodelbahnbox}} representation.
65     The sledrun class has to have properties like position_latitude, ...
66     See the table sledruncache for field (column) values.
67     :param sledrun: an arbitrary class that contains the right properties
68     :param version: a string specifying the version of the rodelbahnbox zu produce.
69         Version '1.3' and '1.4' are supported."""
70     keys = []
71     values = []
72     keys.append(u'Position')
73     values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.position_latitude, sledrun.position_longitude)))
74     keys.append(u'Position oben')
75     values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.top_latitude, sledrun.top_longitude)))
76     keys.append(u'Höhe oben')
77     values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.top_elevation))
78     keys.append(u'Position unten')
79     values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.bottom_latitude, sledrun.bottom_longitude)))
80     keys.append(u'Höhe unten')
81     values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.bottom_elevation))
82     keys.append(u'Länge')
83     values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.length))
84     keys.append(u'Schwierigkeit')
85     values.append(wrpylib.wrvalidators.GermanDifficulty().from_python(sledrun.difficulty))
86     keys.append(u'Lawinen')
87     values.append(wrpylib.wrvalidators.GermanAvalanches().from_python(sledrun.avalanches))
88     keys.append(u'Betreiber')
89     values.append(wrpylib.wrvalidators.UnicodeNone().from_python(sledrun.operator))
90     keys.append(u'Öffentliche Anreise')
91     values.append(wrpylib.wrvalidators.GermanPublicTransport().from_python(sledrun.public_transport))
92     if version == '1.4':
93         keys.append(u'Aufstieg möglich')
94         values.append(wrpylib.wrvalidators.GermanBoolNone().from_python(sledrun.walkup_possible))
95     keys.append(u'Aufstieg getrennt')
96     values.append(wrpylib.wrvalidators.GermanTristateFloatComment().from_python((sledrun.walkup_separate, sledrun.walkup_separate_comment)))
97     keys.append(u'Gehzeit')
98     values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.walkup_time))
99     keys.append(u'Aufstiegshilfe')
100     values.append(wrpylib.wrvalidators.GermanLift().from_python((sledrun.lift, sledrun.lift_details)))
101     keys.append(u'Beleuchtungsanlage')
102     values.append(wrpylib.wrvalidators.GermanTristateFloatComment().from_python((sledrun.night_light, sledrun.night_light_comment)))
103     keys.append(u'Beleuchtungstage')
104     values.append(wrpylib.wrvalidators.UnsignedCommentNone(max=7).from_python((sledrun.night_light_days, sledrun.night_light_days_comment)))
105     keys.append(u'Rodelverleih')
106     values.append(wrpylib.wrvalidators.SledRental().from_python((sledrun.sled_rental, sledrun.sled_rental_comment)))
107     keys.append(u'Gütesiegel')
108     values.append(wrpylib.wrvalidators.GermanCachet().from_python(sledrun.cachet))
109     keys.append(u'Webauskunft')
110     values.append(wrpylib.wrvalidators.UrlNeinNone().from_python(sledrun.information_web))
111     keys.append(u'Telefonauskunft')
112     values.append(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=False).from_python(sledrun.information_phone))
113     keys.append(u'Bild')
114     values.append(wrpylib.wrvalidators.UnicodeNone().from_python(sledrun.image))
115     keys.append(u'In Übersichtskarte')
116     values.append(wrpylib.wrvalidators.GermanBoolNone().from_python(sledrun.show_in_overview))
117     keys.append(u'Forumid')
118     values.append(wrpylib.wrvalidators.UnsignedNeinNone().from_python(sledrun.forum_id))
119     return wrpylib.mwmarkup.create_template(u'Rodelbahnbox', [], keys, values, True, 20)
120
121
122 def gasthausbox_to_inn(wikitext, inn=None):
123     """Converts a inn wiki page containing a {{Gasthausbox}} to an inn.
124     raises a formencode.Invalid exception if an error occurs.
125     :return: (start, end, inn) tuple."""
126     if inn is None:
127         class Inn(object): pass
128         inn = Inn()
129
130     # Match Gasthausbox
131     start, end = wrpylib.mwmarkup.find_template(wikitext, u'Gasthausbox')
132     if start is None: raise formencode.Invalid(u"No 'Gasthausbox' found", wikitext, None)
133     template_title, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
134
135     # Process properties
136     for key, value in properties.iteritems():
137         if   key == u'Position': inn.position_latitude, inn.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
138         elif key == u'Höhe': inn.position_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key)
139         elif key == u'Betreiber': inn.operator = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
140         elif key == u'Sitzplätze': inn.seats = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key)
141         elif key == u'Übernachtung': inn.overnight, inn.overnight_comment = _conv(wrpylib.wrvalidators.BoolUnicodeTupleValidator().to_python, value, key)
142         elif key == u'Rauchfrei': inn.nonsmoker_area, inn.smoker_area = _conv(wrpylib.wrvalidators.GermanTristateTuple().to_python, value, key)
143         elif key == u'Rodelverleih': inn.sled_rental, inn.sled_rental_comment = _conv(wrpylib.wrvalidators.BoolUnicodeTupleValidator().to_python, value, key)
144         elif key == u'Handyempfang': inn.mobile_provider = _conv(wrpylib.wrvalidators.ValueCommentListNeinLoopNone().to_python, value, key)
145         elif key == u'Homepage': inn.homepage = _conv(wrpylib.wrvalidators.UrlNeinNone().to_python, value, key)
146         elif key == u'E-Mail': inn.email_list = _conv(wrpylib.wrvalidators.EmailCommentListNeinLoopNone().to_python, value, key)
147         elif key == u'Telefon': inn.phone_list = _conv(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True).to_python, value, key)
148         elif key == u'Bild': inn.image = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
149         elif key == u'Rodelbahnen': inn.sledding_list = _conv(wrpylib.wrvalidators.WikiPageListLoopNone().to_python, value, key)
150         else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value), value, None)
151     return start, end, inn
152
153
154 def inn_to_gasthausbox(inn):
155     """Converts the inn class to the {{Gasthausbox}} representation."""
156     keys = []
157     values = []
158     keys.append(u'Position')
159     values.append(wrpylib.wrvalidators.GeoNone().from_python((inn.position_latitude, inn.position_longitude)))
160     keys.append(u'Höhe')
161     values.append(wrpylib.wrvalidators.UnsignedNone().from_python(inn.position_elevation))
162     keys.append(u'Betreiber')
163     values.append(wrpylib.wrvalidators.UnicodeNone().from_python(inn.operator))
164     keys.append(u'Sitzplätze')
165     values.append(wrpylib.wrvalidators.UnsignedNone().from_python(inn.seats))
166     keys.append(u'Übernachtung')
167     values.append(wrpylib.wrvalidators.BoolUnicodeTupleValidator().from_python((inn.overnight, inn.overnight_comment)))
168     keys.append(u'Rauchfrei')
169     values.append(wrpylib.wrvalidators.GermanTristateTuple().from_python((inn.nonsmoker_area, inn.smoker_area)))
170     keys.append(u'Rodelverleih')
171     values.append(wrpylib.wrvalidators.BoolUnicodeTupleValidator().from_python((inn.sled_rental, inn.sled_rental_comment)))
172     keys.append(u'Handyempfang')
173     values.append(wrpylib.wrvalidators.ValueCommentListNeinLoopNone().from_python(inn.mobile_provider))
174     keys.append(u'Homepage')
175     values.append(wrpylib.wrvalidators.UrlNeinNone().from_python(inn.homepage))
176     keys.append(u'E-Mail')
177     values.append(wrpylib.wrvalidators.EmailCommentListNeinLoopNone().from_python(inn.email_list))
178     keys.append(u'Telefon')
179     values.append(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True).from_python(inn.phone_list))
180     keys.append(u'Bild')
181     values.append(wrpylib.wrvalidators.UnicodeNone().from_python(inn.image))
182     keys.append(u'Rodelbahnen')
183     values.append(wrpylib.wrvalidators.WikiPageListLoopNone().from_python(inn.sledding_list))
184     result = [u'{{Gasthausbox']
185     return wrpylib.mwmarkup.create_template(u'Gasthausbox', [], keys, values, True)
186
187
188 def find_template_latlon_ele(wikitext, template_title):
189     """Finds the first occurance of the '{{template_title|47.076207 N 11.453553 E|1890}}' template
190     and returns the tuple (start, end, lat, lon, ele) or (None, None, None, None, None) if the
191     template was not found. If the template has no valid format, an exception is thrown."""
192     start, end = wrpylib.mwmarkup.find_template(wikitext, template_title)
193     if start is None: return (None,) * 5
194     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
195     lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'1'].strip())
196     ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'2'].strip())
197     return start, end, lat, lon, ele
198
199
200 def create_template_latlon_ele(template_title, lat, lon, ele):
201     geo = wrpylib.wrvalidators.GeoNone().from_python((lat, lon))
202     if len(geo) == 0: geo = u' '
203     ele = wrpylib.wrvalidators.UnsignedNone().from_python(ele)
204     if len(ele) == 0: ele = u' '
205     return wrpylib.mwmarkup.create_template(template_title, [geo, ele])
206
207
208 def find_template_PositionOben(wikitext):
209     """Same as find_template_latlon_ele with template '{{Position oben|47.076207 N 11.453553 E|1890}}'"""
210     return find_template_latlon_ele(wikitext, u'Position oben')
211
212
213 def create_template_PositionOben(lat, lon, ele):
214     return create_template_latlon_ele(u'Position, oben', lat, lon, ele)
215
216
217 def find_template_PositionUnten(wikitext):
218     """Same as find_template_latlon_ele with template '{{Position unten|47.076207 N 11.453553 E|1890}}'"""
219     return find_template_latlon_ele(wikitext, u'Position unten')
220
221
222 def find_template_unsigned(wikitext, template_title):
223     """Finds the first occurance of the '{{template_title|1890}}' template
224     and returns the tuple (start, end, unsigned_value) or (None, None, None) if the
225     template was not found. If the template has no valid format, an exception is thrown."""
226     start, end = wrpylib.mwmarkup.find_template(wikitext, template_title)
227     if start is None: return (None,) * 3
228     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
229     unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'1'].strip())
230     return start, end, unsigned_value
231
232
233 def find_template_Hoehenunterschied(wikitext):
234     """Same as find_template_unsigned with template '{{Höhenunterschied|350}}'"""
235     return find_template_unsigned(wikitext, u'Höhenunterschied')
236
237
238 def find_template_Bahnlaenge(wikitext):
239     """Same as find_template_unsigned with template '{{Bahnlänge|4500}}'"""
240     return find_template_unsigned(wikitext, u'Bahnlänge')
241
242
243 def find_template_Gehzeit(wikitext):
244     """Same as find_template_unsigned with template '{{Gehzeit|60}}'"""
245     return find_template_unsigned(wikitext, u'Gehzeit')
246
247
248 def find_template_Forumlink(wikitext):
249     """Same as find_template_unsigned with template '{{Forumlink|26}}'"""
250     start, end = wrpylib.mwmarkup.find_template(wikitext, u'Forumlink')
251     if start is None: return (None,) * 3
252     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
253     forumid = params[u'1'].strip()
254     if forumid == u'<nummer einfügen>': unsigned_value = None
255     else: unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(forumid)
256     return start, end, unsigned_value
257     # return find_template_unsigned(wikitext, u'Forumlink')
258
259
260 def find_template_Parkplatz(wikitext):
261     """Same as find_template_latlon_ele with template '{{Parkplatz|47.076207 N 11.453553 E|1890}}'"""
262     return find_template_latlon_ele(wikitext, u'Parkplatz')
263
264
265 def find_template_Haltestelle(wikitext):
266     """Finds the first occurance of the '{{Haltestelle|Ortsname|Haltestellenname|47.076207 N 11.453553 E|1890}}' template
267     and returns the tuple (start, end, city, stop, lat, lon, ele) or (None, None, None, None, None, None, None) if the
268     template was not found. If the template has no valid format, an exception is thrown."""
269     start, end = wrpylib.mwmarkup.find_template(wikitext, u'Haltestelle')
270     if start is None: return (None,) * 7
271     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
272     city = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'1'].strip())
273     stop = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'2'].strip())
274     lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'3'].strip())
275     ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'4'].strip())
276     return start, end, city, stop, lat, lon, ele
277
278
279 def find_all_templates(wikitext, find_func):
280     """Returns a list of return values of find_func that searches for a template.
281     Example:
282     >>> find_all_tempaltes(wikitext, find_template_Haltestelle)
283     Returns an empty list if the template was not found at all.
284     """
285     results = []
286     result = find_func(wikitext)
287     start, end = result[:2]
288     while start is not None:
289         results.append(result)
290         result = find_func(wikitext[end:])
291         if result[0] is None:
292             start = None
293         else:
294             start = result[0] + end
295             end  += result[1]
296             result = (start, end) + result[2:]
297     return results
298