Converted encoding to UTF-8.
[philipp/winterrodeln/wrpylib.git] / wrpylib / wrmwmarkup.py
index 04fc1cc8e4c39664e5e6b9120e1de031161abf58..264c7e23e9d9351f5595e1ee1d13692543bbbd92 100644 (file)
-#!/usr/bin/python2.7
-# -*- coding: iso-8859-15 -*-
+#!/usr/bin/python3.4
 # $Id$
 # $HeadURL$
-"""This module contains winterrodeln specific functions that are prcocessing the MediaWiki markup.
+"""This module contains winterrodeln specific functions that are processing the MediaWiki markup.
 """
 import re
 import xml.etree.ElementTree
-import formencode
+import collections
+import mwparserfromhell
 import wrpylib.wrvalidators
 import wrpylib.mwmarkup
+import wrpylib.wrmwdb
+from wrpylib.wrvalidators import LonLat, opt_lonlat_from_str, opt_lonlat_to_str, opt_uint_from_str, opt_uint_to_str, \
+    opt_str_opt_comment_enum_to_str, lift_german_to_str, webauskunft_to_str, cachet_german_to_str, \
+    opt_phone_comment_enum_to_str, lift_german_from_str
+
+
+def sledrun_from_rodelbahnbox(value, sledrun):
+    """Takes a Rodelbahnbox as returned by rodelbahnbox_from_str (that is, an OrderedDict) and
+    updates the sledrun instance with all values present in the Rodelbahnbox. Other values are not
+    updated. Does not validate the arguments."""
+    # sledrun.page_id = None # this field is not updated because it is not present in the RodelbahnBox
+    # sledrun.page_title = None # this field is not updated because it is not present in the RodelbahnBox
+    # sledrun.name_url = None # this field is not updated because it is not present in the RodelbahnBox
+    sledrun.position_longitude, sledrun.position_latitude = value['Position']
+    sledrun.top_longitude, sledrun.top_latitude = value['Position oben']
+    sledrun.top_elevation = value['Höhe oben']
+    sledrun.bottom_longitude, sledrun.bottom_latitude = value['Position unten']
+    sledrun.bottom_elevation = value['Höhe unten']
+    sledrun.length = value['Länge']
+    sledrun.difficulty = value['Schwierigkeit']
+    sledrun.avalanches = value['Lawinen']
+    sledrun.operator = value['Betreiber']
+    sledrun.public_transport = value['Öffentliche Anreise']
+    sledrun.walkup_possible = value['Aufstieg möglich']
+    sledrun.walkup_time = value['Gehzeit']
+    sledrun.walkup_separate, sledrun.walkup_separate_comment = value['Aufstieg getrennt']
+    sledrun.lift = None if value['Aufstiegshilfe'] is None else len(value['Aufstiegshilfe']) > 0
+    sledrun.lift_details = lift_german_to_str(value['Aufstiegshilfe'])
+    sledrun.night_light, sledrun.night_light_comment = value['Beleuchtungsanlage']
+    sledrun.night_light_days, sledrun.night_light_days_comment = value['Beleuchtungstage']
+    sledrun.sled_rental = None if value['Rodelverleih'] is None else len(value['Rodelverleih']) > 0
+    sledrun.sled_rental_comment = opt_str_opt_comment_enum_to_str(value['Rodelverleih'])
+    sledrun.cachet = cachet_german_to_str(value['Gütesiegel'])
+    sledrun.information_web = webauskunft_to_str(value['Webauskunft'])
+    sledrun.information_phone = opt_phone_comment_enum_to_str(value['Telefonauskunft'])
+    sledrun.image = value['Bild']
+    sledrun.show_in_overview = value['In Übersichtskarte']
+    sledrun.forum_id = value['Forumid']
+    # sledrun.under_construction = None # this field is not updated because it is not present in the RodelbahnBox
+    return sledrun
+
+
+def sledrun_to_rodelbahnbox(sledrun):
+    """Takes a sledrun instance that might come from the database and converts it to a OrderedDict ready
+    to be formatted as RodelbahnBox."""
+    value = collections.OrderedDict()
+    value['Position'] = LonLat(sledrun.position_longitude, sledrun.position_latitude)
+    value['Position oben'] = LonLat(sledrun.top_longitude, sledrun.top_latitude)
+    value['Höhe oben'] = sledrun.top_elevation
+    value['Position unten'] = LonLat(sledrun.bottom_longitude, sledrun.bottom_latitude)
+    value['Höhe unten'] = sledrun.bottom_elevation
+    value['Länge'] = sledrun.length
+    value['Schwierigkeit'] = sledrun.difficulty
+    value['Lawinen'] = sledrun.avalanches
+    value['Betreiber'] = sledrun.operator
+    value['Öffentliche Anreise'] = sledrun.public_transport
+    value['Aufstieg möglich'] = sledrun.walkup_possible
+    value['Gehzeit'] = sledrun.walkup_time
+    value['Aufstieg getrennt'] = sledrun.walkup_separate, sledrun.walkup_separate_comment
+    value['Aufstiegshilfe'] = lift_german_from_str(sledrun.lift_details)
+    value['Beleuchtungsanlage'] = sledrun.night_light, sledrun.night_light_comment
+    value['Beleuchtungstage'] = sledrun.night_light_days, sledrun.night_light_days_comment
+    value['Rodelverleih'] = sledrun.sled_rental, sledrun.sled_rental_comment
+    value['Gütesiegel'] = sledrun.cachet
+    value['Webauskunft'] = sledrun.information_web
+    value['Telefonauskunft'] = sledrun.information_phone
+    value['Bild'] = sledrun.image
+    value['In Übersichtskarte'] = sledrun.show_in_overview
+    value['Forumid'] = sledrun.forum_id
+    return value
+
+
+def inn_from_gasthausbox(value, inn):
+    """Converts a dict with Gasthausbox properties to a Inn class. Does no validation.
+    value is a dict of properties as returned by gasthausbox_from_str."""
+    inn.position_longitude, inn.position_latitude = value['Position']
+    inn.position_elevation = value['Höhe']
+    inn.operator = value['Betreiber']
+    inn.seats = value['Sitzplätze']
+    inn.overnight, inn.overnight_comment = value['Übernachtung']
+    inn.nonsmoker_area, inn.smoker_area = value['Rauchfrei']
+    inn.sled_rental, inn.sled_rental_comment = value['Rodelverleih']
+    inn.mobile_provider = value['Handyempfang']
+    inn.homepage = value['Homepage']
+    inn.email_list = value['E-Mail']
+    inn.phone_list = value['Telefon']
+    inn.image = value['Bild']
+    inn.sledding_list = value['Rodelbahnen']
+    return inn
 
-WRMAP_POINT_TYPES = ['gasthaus', 'haltestelle', 'parkplatz', 'achtung', 'punkt']
-WRMAP_LINE_TYPES = ['rodelbahn', 'gehweg', 'alternative', 'lift', 'anfahrt', 'linie']
+
+def inn_to_gasthausbox(inn):
+    """Converts an inn class to a dict of Gasthausbox properties. value is an Inn instance."""
+    value = collections.OrderedDict()
+    value['Position'] = LonLat(inn.position_longitude, inn.position_latitude)
+    value['Höhe'] = inn.position_elevation
+    value['Betreiber'] = inn.operator
+    value['Sitzplätze'] = inn.seats
+    value['Übernachtung'] = (inn.overnight, inn.overnight_comment)
+    value['Rauchfrei'] = (inn.nonsmoker_area, inn.smoker_area)
+    value['Rodelverleih'] = (inn.sled_rental, inn.sled_rental_comment)
+    value['Handyempfang'] = inn.mobile_provider
+    value['Homepage'] = inn.homepage
+    value['E-Mail'] = inn.email_list
+    value['Telefon'] = inn.phone_list
+    value['Bild'] = inn.image
+    value['Rodelbahnen'] = inn.sledding_list
+    return value
+
+
+def lonlat_ele_from_template(template):
+    """Template is a mwparserfromhell.nodes.template.Template instance. Returns (lonlat, ele)."""
+    lonlat = opt_lonlat_from_str(template.params[0].strip())
+    ele = opt_uint_from_str(template.params[1].strip())
+    return lonlat, ele
+
+
+def latlon_ele_to_template(lonlat_ele, name):
+    lonlat, ele = lonlat_ele
+    template = mwparserfromhell.nodes.template.Template(name)
+    template.add(1, opt_lonlat_to_str(lonlat))
+    template.add(2, opt_uint_to_str(ele))
+    wrpylib.mwmarkup.format_template_oneline(template)
+    return template
 
 
 class ParseError(RuntimeError):
@@ -19,213 +140,19 @@ class ParseError(RuntimeError):
     pass
 
 
-def _conv(fnct, value, fieldname):
-    """Internal function.
-    Like one of the to_xxx functions (e.g. to_bool), but adds the field name to the error message"""
-    try: return fnct(value)
-    except formencode.Invalid as e: raise formencode.Invalid(u"Conversion error in field '%s': %s" % (fieldname, unicode(e)), e.value, e.state)
-
-
-def rodelbahnbox_to_sledrun(wikitext, sledrun=None):
-    """Converts a sledrun wiki page containing the {{Rodelbahnbox}}
-    to a sledrun. sledrun may be an instance of WrSledrunCache or an "empty" class (object()) (default).
-    Raises a formencode.Invalid exception if the format is not OK or the Rodelbahnbox is not found.
-    :return: (start, end, sledrun) tuple of the Rodelbahnbox."""
-    if sledrun is None:
-        class Sledrun(object): pass
-        sledrun = Sledrun()
-
-    # match Rodelbahnbox
-    start, end = wrpylib.mwmarkup.find_template(wikitext, u'Rodelbahnbox')
-    if start is None: raise formencode.Invalid(u"Rodelbahnbox nicht gefunden", wikitext, None)
-    template_title, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
-    
-    # process properties
-    for key, value in properties.iteritems():
-        if   key == u'Position': sledrun.position_latitude, sledrun.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
-        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'
-        elif key == u'Höhe oben': sledrun.top_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # '2000'
-        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'
-        elif key == u'Höhe unten': sledrun.bottom_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # '1200'
-        elif key == u'Länge': sledrun.length = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 3500
-        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'
-        elif key == u'Lawinen': sledrun.avalanches = _conv(wrpylib.wrvalidators.GermanAvalanches().to_python, value, key) # 'kaum'
-        elif key == u'Betreiber': sledrun.operator = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key) # 'Max Mustermann'
-        elif key == u'Öffentliche Anreise': sledrun.public_transport = _conv(wrpylib.wrvalidators.GermanPublicTransport().to_python, value, key) # 'Mittelmäßig'
-        elif key == u'Aufstieg möglich': sledrun.walkup_possible = _conv(wrpylib.wrvalidators.GermanBoolNone().to_python, value, key) # 'Ja'
-        elif key == u'Aufstieg getrennt': sledrun.walkup_separate, sledrun.walkup_separate_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key) # 'Ja'
-        elif key == u'Gehzeit': sledrun.walkup_time = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 90
-        elif key == u'Aufstiegshilfe': sledrun.lift, sledrun.lift_details = _conv(wrpylib.wrvalidators.GermanLift().to_python, value, key) # 'Gondel (unterer Teil)'
-        elif key == u'Beleuchtungsanlage': sledrun.night_light, sledrun.night_light_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key)
-        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)'
-        elif key == u'Rodelverleih': sledrun.sled_rental, sledrun.sled_rental_comment = _conv(wrpylib.wrvalidators.SledRental().to_python, value, key) # 'Talstation Serlesbahnan'
-        elif key == u'Gütesiegel': sledrun.cachet = _conv(wrpylib.wrvalidators.GermanCachet().to_python, value, key) # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
-        elif key == u'Webauskunft': sledrun.information_web = _conv(wrpylib.wrvalidators.UrlNeinNone().to_python, value, key) # 'http://www.nösslachhütte.at/page9.php'
-        elif key == u'Telefonauskunft': sledrun.information_phone = _conv(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=False).to_python, value, key) # '+43-664-5487520 (Mitterer Alm)'
-        elif key == u'Bild': sledrun.image = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
-        elif key == u'In Übersichtskarte': sledrun.show_in_overview = _conv(wrpylib.wrvalidators.GermanBoolNone().to_python, value, key)
-        elif key == u'Forumid': sledrun.forum_id = _conv(wrpylib.wrvalidators.UnsignedNeinNone().to_python, value, key)
-        else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Rodelbahnbox: '%s' (mit Wert '%s')" % (key, value), value, None)
-    return start, end, sledrun
-
-
-def sledrun_to_rodelbahnbox(sledrun, version):
-    """Converts a sledrun class to the {{Rodelbahnbox}} representation.
-    The sledrun class has to have properties like position_latitude, ...
-    See the table sledruncache for field (column) values.
-    :param sledrun: an arbitrary class that contains the right properties
-    :param version: a string specifying the version of the rodelbahnbox zu produce.
-        Version '1.3' and '1.4' are supported."""
-    keys = []
-    values = []
-    keys.append(u'Position')
-    values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.position_latitude, sledrun.position_longitude)))
-    keys.append(u'Position oben')
-    values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.top_latitude, sledrun.top_longitude)))
-    keys.append(u'Höhe oben')
-    values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.top_elevation))
-    keys.append(u'Position unten')
-    values.append(wrpylib.wrvalidators.GeoNone().from_python((sledrun.bottom_latitude, sledrun.bottom_longitude)))
-    keys.append(u'Höhe unten')
-    values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.bottom_elevation))
-    keys.append(u'Länge')
-    values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.length))
-    keys.append(u'Schwierigkeit')
-    values.append(wrpylib.wrvalidators.GermanDifficulty().from_python(sledrun.difficulty))
-    keys.append(u'Lawinen')
-    values.append(wrpylib.wrvalidators.GermanAvalanches().from_python(sledrun.avalanches))
-    keys.append(u'Betreiber')
-    values.append(wrpylib.wrvalidators.UnicodeNone().from_python(sledrun.operator))
-    keys.append(u'Öffentliche Anreise')
-    values.append(wrpylib.wrvalidators.GermanPublicTransport().from_python(sledrun.public_transport))
-    if version == '1.4':
-        keys.append(u'Aufstieg möglich')
-        values.append(wrpylib.wrvalidators.GermanBoolNone().from_python(sledrun.walkup_possible))
-    keys.append(u'Aufstieg getrennt')
-    values.append(wrpylib.wrvalidators.GermanTristateFloatComment().from_python((sledrun.walkup_separate, sledrun.walkup_separate_comment)))
-    keys.append(u'Gehzeit')
-    values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.walkup_time))
-    keys.append(u'Aufstiegshilfe')
-    values.append(wrpylib.wrvalidators.GermanLift().from_python((sledrun.lift, sledrun.lift_details)))
-    keys.append(u'Beleuchtungsanlage')
-    values.append(wrpylib.wrvalidators.GermanTristateFloatComment().from_python((sledrun.night_light, sledrun.night_light_comment)))
-    keys.append(u'Beleuchtungstage')
-    values.append(wrpylib.wrvalidators.UnsignedCommentNone(max=7).from_python((sledrun.night_light_days, sledrun.night_light_days_comment)))
-    keys.append(u'Rodelverleih')
-    values.append(wrpylib.wrvalidators.SledRental().from_python((sledrun.sled_rental, sledrun.sled_rental_comment)))
-    keys.append(u'Gütesiegel')
-    values.append(wrpylib.wrvalidators.GermanCachet().from_python(sledrun.cachet))
-    keys.append(u'Webauskunft')
-    values.append(wrpylib.wrvalidators.UrlNeinNone().from_python(sledrun.information_web))
-    keys.append(u'Telefonauskunft')
-    values.append(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=False).from_python(sledrun.information_phone))
-    keys.append(u'Bild')
-    values.append(wrpylib.wrvalidators.UnicodeNone().from_python(sledrun.image))
-    keys.append(u'In Übersichtskarte')
-    values.append(wrpylib.wrvalidators.GermanBoolNone().from_python(sledrun.show_in_overview))
-    keys.append(u'Forumid')
-    values.append(wrpylib.wrvalidators.UnsignedNeinNone().from_python(sledrun.forum_id))
-    return wrpylib.mwmarkup.create_template(u'Rodelbahnbox', [], keys, values, True, 20)
-
-
-def gasthausbox_to_inn(wikitext, inn=None):
-    """Converts a inn wiki page containing a {{Gasthausbox}} to an inn.
-    raises a formencode.Invalid exception if an error occurs.
-    :return: (start, end, inn) tuple."""
-    if inn is None:
-        class Inn(object): pass
-        inn = Inn()
-
-    # Match Gasthausbox
-    start, end = wrpylib.mwmarkup.find_template(wikitext, u'Gasthausbox')
-    if start is None: raise formencode.Invalid(u"No 'Gasthausbox' found", wikitext, None)
-    template_title, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
-
-    # Process properties
-    for key, value in properties.iteritems():
-        if   key == u'Position': inn.position_latitude, inn.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
-        elif key == u'Höhe': inn.position_elevation = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key)
-        elif key == u'Betreiber': inn.operator = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
-        elif key == u'Sitzplätze': inn.seats = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key)
-        elif key == u'Übernachtung': inn.overnight, inn.overnight_comment = _conv(wrpylib.wrvalidators.BoolUnicodeTupleValidator().to_python, value, key)
-        elif key == u'Rauchfrei': inn.nonsmoker_area, inn.smoker_area = _conv(wrpylib.wrvalidators.GermanTristateTuple().to_python, value, key)
-        elif key == u'Rodelverleih': inn.sled_rental, inn.sled_rental_comment = _conv(wrpylib.wrvalidators.BoolUnicodeTupleValidator().to_python, value, key)
-        elif key == u'Handyempfang': inn.mobile_provider = _conv(wrpylib.wrvalidators.ValueCommentListNeinLoopNone().to_python, value, key)
-        elif key == u'Homepage': inn.homepage = _conv(wrpylib.wrvalidators.UrlNeinNone().to_python, value, key)
-        elif key == u'E-Mail': inn.email_list = _conv(wrpylib.wrvalidators.EmailCommentListNeinLoopNone(allow_masked_email=True).to_python, value, key)
-        elif key == u'Telefon': inn.phone_list = _conv(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True).to_python, value, key)
-        elif key == u'Bild': inn.image = _conv(wrpylib.wrvalidators.UnicodeNone().to_python, value, key)
-        elif key == u'Rodelbahnen': inn.sledding_list = _conv(wrpylib.wrvalidators.WikiPageListLoopNone().to_python, value, key)
-        else: raise formencode.Invalid(u"Unbekannte Eigenschaft der Gasthausbox: '%s' (mit Wert '%s')" % (key, value), value, None)
-    return start, end, inn
-
-
-def inn_to_gasthausbox(inn):
-    """Converts the inn class to the {{Gasthausbox}} representation."""
-    keys = []
-    values = []
-    keys.append(u'Position')
-    values.append(wrpylib.wrvalidators.GeoNone().from_python((inn.position_latitude, inn.position_longitude)))
-    keys.append(u'Höhe')
-    values.append(wrpylib.wrvalidators.UnsignedNone().from_python(inn.position_elevation))
-    keys.append(u'Betreiber')
-    values.append(wrpylib.wrvalidators.UnicodeNone().from_python(inn.operator))
-    keys.append(u'Sitzplätze')
-    values.append(wrpylib.wrvalidators.UnsignedNone().from_python(inn.seats))
-    keys.append(u'Übernachtung')
-    values.append(wrpylib.wrvalidators.BoolUnicodeTupleValidator().from_python((inn.overnight, inn.overnight_comment)))
-    keys.append(u'Rauchfrei')
-    values.append(wrpylib.wrvalidators.GermanTristateTuple().from_python((inn.nonsmoker_area, inn.smoker_area)))
-    keys.append(u'Rodelverleih')
-    values.append(wrpylib.wrvalidators.BoolUnicodeTupleValidator().from_python((inn.sled_rental, inn.sled_rental_comment)))
-    keys.append(u'Handyempfang')
-    values.append(wrpylib.wrvalidators.ValueCommentListNeinLoopNone().from_python(inn.mobile_provider))
-    keys.append(u'Homepage')
-    values.append(wrpylib.wrvalidators.UrlNeinNone().from_python(inn.homepage))
-    keys.append(u'E-Mail')
-    values.append(wrpylib.wrvalidators.EmailCommentListNeinLoopNone(allow_masked_email=True).from_python(inn.email_list))
-    keys.append(u'Telefon')
-    values.append(wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True).from_python(inn.phone_list))
-    keys.append(u'Bild')
-    values.append(wrpylib.wrvalidators.UnicodeNone().from_python(inn.image))
-    keys.append(u'Rodelbahnen')
-    values.append(wrpylib.wrvalidators.WikiPageListLoopNone().from_python(inn.sledding_list))
-    result = [u'{{Gasthausbox']
-    return wrpylib.mwmarkup.create_template(u'Gasthausbox', [], keys, values, True)
-
-
-def find_template_latlon_ele(wikitext, template_title):
-    """Finds the first occurance of the '{{template_title|47.076207 N 11.453553 E|1890}}' template
-    and returns the tuple (start, end, lat, lon, ele) or (None, None, None, None, None) if the
-    template was not found. If the template has no valid format, an exception is thrown."""
-    start, end = wrpylib.mwmarkup.find_template(wikitext, template_title)
-    if start is None: return (None,) * 5
-    title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
-    lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'1'].strip())
-    ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'2'].strip())
-    return start, end, lat, lon, ele
-
-
-def create_template_latlon_ele(template_title, lat, lon, ele):
-    geo = wrpylib.wrvalidators.GeoNone().from_python((lat, lon))
-    if len(geo) == 0: geo = u' '
-    ele = wrpylib.wrvalidators.UnsignedNone().from_python(ele)
-    if len(ele) == 0: ele = u' '
-    return wrpylib.mwmarkup.create_template(template_title, [geo, ele])
-
 
 def find_template_PositionOben(wikitext):
     """Same as find_template_latlon_ele with template '{{Position oben|47.076207 N 11.453553 E|1890}}'"""
-    return find_template_latlon_ele(wikitext, u'Position oben')
+    return find_template_latlon_ele(wikitext, 'Position oben')
 
 
 def create_template_PositionOben(lat, lon, ele):
-    return create_template_latlon_ele(u'Position, oben', lat, lon, ele)
+    return create_template_latlon_ele('Position, oben', lat, lon, ele)
 
 
 def find_template_PositionUnten(wikitext):
     """Same as find_template_latlon_ele with template '{{Position unten|47.076207 N 11.453553 E|1890}}'"""
-    return find_template_latlon_ele(wikitext, u'Position unten')
+    return find_template_latlon_ele(wikitext, 'Position unten')
 
 
 def find_template_unsigned(wikitext, template_title):
@@ -235,50 +162,50 @@ def find_template_unsigned(wikitext, template_title):
     start, end = wrpylib.mwmarkup.find_template(wikitext, template_title)
     if start is None: return (None,) * 3
     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
-    unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'1'].strip())
+    unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(params['1'].strip())
     return start, end, unsigned_value
 
 
 def create_template_unsigned(template_title, unsigned):
     unsigned = wrpylib.wrvalidators.UnsignedNone().from_python(unsigned)
-    if len(unsigned) == 0: unsigned = u' '
+    if len(unsigned) == 0: unsigned = ' '
     return wrpylib.mwmarkup.create_template(template_title, [unsigned])
 
 
 def find_template_Hoehenunterschied(wikitext):
-    """Same as find_template_unsigned with template '{{Höhenunterschied|350}}'"""
-    return find_template_unsigned(wikitext, u'Höhenunterschied')
+    """Same as find_template_unsigned with template '{{Höhenunterschied|350}}'"""
+    return find_template_unsigned(wikitext, 'Höhenunterschied')
 
 
 def create_template_Hoehenunterschied(ele_diff):
-    return create_template_unsigned(u'Höhenunterschied', ele_diff)
+    return create_template_unsigned('Höhenunterschied', ele_diff)
 
 
 def find_template_Bahnlaenge(wikitext):
-    """Same as find_template_unsigned with template '{{Bahnlänge|4500}}'"""
-    return find_template_unsigned(wikitext, u'Bahnlänge')
+    """Same as find_template_unsigned with template '{{Bahnlänge|4500}}'"""
+    return find_template_unsigned(wikitext, 'Bahnlänge')
 
 
 def create_template_Bahnlaenge(length):
-    return create_template_unsigned(u'Bahnlänge', length)
+    return create_template_unsigned('Bahnlänge', length)
 
 
 def find_template_Gehzeit(wikitext):
     """Same as find_template_unsigned with template '{{Gehzeit|60}}'"""
-    return find_template_unsigned(wikitext, u'Gehzeit')
+    return find_template_unsigned(wikitext, 'Gehzeit')
 
 
 def create_template_Gehzeit(walkup_time):
-    return create_template_unsigned(u'Gehzeit', walkup_time)
+    return create_template_unsigned('Gehzeit', walkup_time)
 
 
 def find_template_Forumlink(wikitext):
     """Same as find_template_unsigned with template '{{Forumlink|26}}'"""
-    start, end = wrpylib.mwmarkup.find_template(wikitext, u'Forumlink')
+    start, end = wrpylib.mwmarkup.find_template(wikitext, 'Forumlink')
     if start is None: return (None,) * 3
     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
-    forumid = params[u'1'].strip()
-    if forumid == u'<nummer einfügen>': unsigned_value = None
+    forumid = params['1'].strip()
+    if forumid == '<nummer einfügen>': unsigned_value = None
     else: unsigned_value = wrpylib.wrvalidators.UnsignedNone().to_python(forumid)
     return start, end, unsigned_value
     # return find_template_unsigned(wikitext, u'Forumlink')
@@ -286,85 +213,23 @@ def find_template_Forumlink(wikitext):
 
 def find_template_Parkplatz(wikitext):
     """Same as find_template_latlon_ele with template '{{Parkplatz|47.076207 N 11.453553 E|1890}}'"""
-    return find_template_latlon_ele(wikitext, u'Parkplatz')
+    return find_template_latlon_ele(wikitext, 'Parkplatz')
 
 
 def find_template_Haltestelle(wikitext):
     """Finds the first occurance of the '{{Haltestelle|Ortsname|Haltestellenname|47.076207 N 11.453553 E|1890}}' template
     and returns the tuple (start, end, city, stop, lat, lon, ele) or (None, None, None, None, None, None, None) if the
     template was not found. If the template has no valid format, an exception is thrown."""
-    start, end = wrpylib.mwmarkup.find_template(wikitext, u'Haltestelle')
+    start, end = wrpylib.mwmarkup.find_template(wikitext, 'Haltestelle')
     if start is None: return (None,) * 7
     title, params = wrpylib.mwmarkup.split_template(wikitext[start:end])
-    city = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'1'].strip())
-    stop = wrpylib.wrvalidators.UnicodeNone().to_python(params[u'2'].strip())
-    lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params[u'3'].strip())
-    ele = wrpylib.wrvalidators.UnsignedNone().to_python(params[u'4'].strip())
+    city = wrpylib.wrvalidators.UnicodeNone().to_python(params['1'].strip())
+    stop = wrpylib.wrvalidators.UnicodeNone().to_python(params['2'].strip())
+    lat, lon = wrpylib.wrvalidators.GeoNone().to_python(params['3'].strip())
+    ele = wrpylib.wrvalidators.UnsignedNone().to_python(params['4'].strip())
     return start, end, city, stop, lat, lon, ele
 
 
-def find_all_templates(wikitext, find_func):
-    """Returns a list of return values of find_func that searches for a template.
-    Example:
-    >>> find_all_tempaltes(wikitext, find_template_Haltestelle)
-    Returns an empty list if the template was not found at all.
-    """
-    results = []
-    result = find_func(wikitext)
-    start, end = result[:2]
-    while start is not None:
-        results.append(result)
-        result = find_func(wikitext[end:])
-        if result[0] is None:
-            start = None
-        else:
-            start = result[0] + end
-            end  += result[1]
-            result = (start, end) + result[2:]
-    return results
-
-
-def googlemap_to_wrmap(center, zoom, coords, paths):
-    """Converts the output of parse_googlemap to the GeoJSON format wrmap uses.
-    :returns: (GeoJSON as nested Python datatypes)
-    """
-    json_features = []
-
-    # point
-    for point in coords:
-        lon, lat, symbol, title = point
-        properties = {'type': 'punkt' if symbol is None else symbol.lower()}
-        if title is not None: properties['name'] = title
-        json_features.append({
-            'type': 'Feature',
-            'geometry': {'type': 'Point', 'coordinates': [lon, lat]},
-            'properties': properties})
-        
-    # path
-    for path in paths:
-        style, entries = path
-        style = style.lower()
-        PATH_TYPES = {u'6#ff014e9a': u'rodelbahn', u'6#ffe98401': u'gehweg', u'6#ff7f7fff': u'alternative', u'3#ff000000': u'lift', u'3#ffe1e100': u'anfahrt'}
-        if PATH_TYPES.has_key(style):
-            properties = {'type': PATH_TYPES[style]}
-        else:
-            properties = {'type': 'line'}
-            properties['dicke'] = style[0]
-            properties['farbe'] = style[4:]
-        json_features.append({
-            'type': 'Feature',
-            'geometry': {
-                'type': 'LineString',
-                'coordinates': [[lon, lat] for lon, lat, symbol, title in entries]},
-            'properties': properties})
-
-    geojson = {
-            'type': 'FeatureCollection',
-            'features': json_features,
-            'properties': {'lon': center[0], 'lat': center[1], 'zoom': zoom}}
-    return geojson
-
-
 def parse_wrmap_coordinates(coords):
     '''gets a string coordinates and returns an array of lon/lat coordinate pairs, e.g.
     47.12 N 11.87 E
@@ -384,6 +249,10 @@ def parse_wrmap_coordinates(coords):
     raise RuntimeError('Wrong coordinate format: {}'.format(coords))
 
 
+WRMAP_POINT_TYPES = ['gasthaus', 'haltestelle', 'parkplatz', 'achtung', 'foto', 'verleih', 'punkt']
+WRMAP_LINE_TYPES = ['rodelbahn', 'gehweg', 'alternative', 'lift', 'anfahrt', 'linie']
+
+
 def parse_wrmap(wikitext):
     """Parses the (unicode) u'<wrmap ...>content</wrmap>' of the Winterrodeln wrmap extension.
     If wikitext does not contain the <wrmap> tag or if the <wrmap> tag contains 
@@ -395,9 +264,9 @@ def parse_wrmap(wikitext):
 
     wikitext = u'''
     <wrmap lat="47.2417134" lon="11.21408895" zoom="14" width="700" height="400">
-    <gasthaus name="Rosskogelhütte" wiki="Rosskogelhütte">47.240689 11.190454</gasthaus>
+    <gasthaus name="Rosskogelhütte" wiki="Rosskogelhütte">47.240689 11.190454</gasthaus>
     <parkplatz>47.245789 11.238971</parkplatz>
-    <haltestelle name="Oberperfuss Rangger Köpfl Lift">47.245711 11.238283</haltestelle>
+    <haltestelle name="Oberperfuss Rangger Köpfl Lift">47.245711 11.238283</haltestelle>
     <rodelbahn>
         47.238587 11.203360
         47.244951 11.230868
@@ -428,7 +297,7 @@ def parse_wrmap(wikitext):
         # point
         if is_point:
             properties = {'type': feature.tag}
-            allowed_properties = set(['name', 'wiki'])
+            allowed_properties = {'name', 'wiki'}
             wrong_properties = set(feature.attrib.keys()) - allowed_properties
             if len(wrong_properties) > 0:
                 raise ParseError("The attribute '{}' is not allowed at <{}>.".format(list(wrong_properties)[0], feature.tag))
@@ -444,15 +313,15 @@ def parse_wrmap(wikitext):
         # line
         if is_line:
             properties = {'type': feature.tag}
-            allowed_properties = set(['farbe', 'dicke'])
+            allowed_properties = {'farbe', 'dicke'}
             wrong_properties = set(feature.attrib.keys()) - allowed_properties
             if len(wrong_properties) > 0:
                 raise ParseError("The attribute '{}' is not allowed at <{}>.".format(list(wrong_properties)[0], feature.tag))
-            if feature.attrib.has_key('farbe')
+            if 'farbe' in feature.attrib
                 if not re.match('#[0-9a-fA-F]{6}$', feature.attrib['farbe']):
                     raise ParseError('The attribute "farbe" has to have a format like "#a0bb43".')
                 properties['strokeColor'] = feature.attrib['farbe'] # e.g. #a200b7
-            if feature.attrib.has_key('dicke'):
+            if 'dicke' in feature.attrib:
                 try:
                     properties['strokeWidth'] = int(feature.attrib['dicke']) # e.g. 6
                 except ValueError:
@@ -464,7 +333,7 @@ def parse_wrmap(wikitext):
 
     # attributes
     properties = {}
-    for k, v in wrmap_xml.attrib.iteritems():
+    for k, v in wrmap_xml.attrib.items():
         if k in ['lat', 'lon']:
             try:
                 properties[k] = float(v)
@@ -497,8 +366,11 @@ def create_wrmap(geojson):
     """Creates a <wrmap> wikitext from geojson (as python types)."""
     wrmap_xml = xml.etree.ElementTree.Element('wrmap')
     wrmap_xml.text = '\n\n'
-    for k, v in geojson['properties'].iteritems():
-        wrmap_xml.attrib[k] = str(v)
+    for k, v in geojson['properties'].items():
+        if k in ['lon', 'lat']:
+            wrmap_xml.attrib[k] = '{:.6f}'.format(v)
+        else:
+            wrmap_xml.attrib[k] = str(v)
 
     assert geojson['type'] == 'FeatureCollection'
     json_features = geojson['features']
@@ -521,4 +393,3 @@ def create_wrmap(geojson):
     if last_json_feature is not None:
         last_json_feature.tail = '\n\n'
     return xml.etree.ElementTree.tostring(wrmap_xml, encoding='utf-8').decode('utf-8')
-