62bf20a4e1f0030f129be282568f42ee190e8348
[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(allow_masked_email=True).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(allow_masked_email=True).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 create_template_unsigned(template_title, unsigned):
234     unsigned = wrpylib.wrvalidators.UnsignedNone().from_python(unsigned)
235     if len(unsigned) == 0: unsigned = u' '
236     return wrpylib.mwmarkup.create_template(template_title, [unsigned])
237
238
239 def find_template_Hoehenunterschied(wikitext):
240     """Same as find_template_unsigned with template '{{Höhenunterschied|350}}'"""
241     return find_template_unsigned(wikitext, u'Höhenunterschied')
242
243
244 def create_template_Hoehenunterschied(ele_diff):
245     return create_template_unsigned(u'Höhenunterschied', ele_diff)
246
247
248 def find_template_Bahnlaenge(wikitext):
249     """Same as find_template_unsigned with template '{{Bahnlänge|4500}}'"""
250     return find_template_unsigned(wikitext, u'Bahnlänge')
251
252
253 def create_template_Bahnlaenge(length):
254     return create_template_unsigned(u'Bahnlänge', length)
255
256
257 def find_template_Gehzeit(wikitext):
258     """Same as find_template_unsigned with template '{{Gehzeit|60}}'"""
259     return find_template_unsigned(wikitext, u'Gehzeit')
260
261
262 def create_template_Gehzeit(walkup_time):
263     return create_template_unsigned(u'Gehzeit', walkup_time)
264
265
266 def find_template_Forumlink(wikitext):
267     """Same as find_template_unsigned with template '{{Forumlink|26}}'"""
268     start, end = wrpylib.mwmarkup.find_template(wikitext, u'Forumlink')
269     if start is None: return (None,) * 3
270     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
271     forumid = params[u'1'].strip()
272     if forumid == u'<nummer einfügen>': unsigned_value = None
273     else: unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(forumid)
274     return start, end, unsigned_value
275     # return find_template_unsigned(wikitext, u'Forumlink')
276
277
278 def find_template_Parkplatz(wikitext):
279     """Same as find_template_latlon_ele with template '{{Parkplatz|47.076207 N 11.453553 E|1890}}'"""
280     return find_template_latlon_ele(wikitext, u'Parkplatz')
281
282
283 def find_template_Haltestelle(wikitext):
284     """Finds the first occurance of the '{{Haltestelle|Ortsname|Haltestellenname|47.076207 N 11.453553 E|1890}}' template
285     and returns the tuple (start, end, city, stop, lat, lon, ele) or (None, None, None, None, None, None, None) if the
286     template was not found. If the template has no valid format, an exception is thrown."""
287     start, end = wrpylib.mwmarkup.find_template(wikitext, u'Haltestelle')
288     if start is None: return (None,) * 7
289     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
290     city = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'1'].strip())
291     stop = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'2'].strip())
292     lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'3'].strip())
293     ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'4'].strip())
294     return start, end, city, stop, lat, lon, ele
295
296
297 def find_all_templates(wikitext, find_func):
298     """Returns a list of return values of find_func that searches for a template.
299     Example:
300     >>> find_all_tempaltes(wikitext, find_template_Haltestelle)
301     Returns an empty list if the template was not found at all.
302     """
303     results = []
304     result = find_func(wikitext)
305     start, end = result[:2]
306     while start is not None:
307         results.append(result)
308         result = find_func(wikitext[end:])
309         if result[0] is None:
310             start = None
311         else:
312             start = result[0] + end
313             end  += result[1]
314             result = (start, end) + result[2:]
315     return results
316