from distutils.core import setup
setup(name='wrpylib',
- version='0.0.0',
+ version='0.0.1',
description='Winterrodeln Python Library',
author='Philipp Spitzer',
author_email='philipp.spitzer@winterrodeln.org',
--- /dev/null
+#!/usr/bin/python2.6
+# -*- coding: iso-8859-15 -*-
+import wrpylib.wrmwmarkup
+import formencode
+
+
+def test_rodelbahnbox_to_sledrun():
+ wikitext = u'''== Allgemeines ==
+ {{Rodelbahnbox
+ | Position = 47.309820 N 9.986508 E
+ | Position oben =
+ | Höhe oben = 1244
+ | Position unten =
+ | Höhe unten = 806
+ | Länge = 5045
+ | Schwierigkeit =
+ | Lawinen = gelegentlich
+ | Betreiber =
+ | Öffentliche Anreise = Ja
+ | Gehzeit = 105
+ | Aufstieg getrennt = Nein
+ | Aufstiegshilfe = Nein
+ | Beleuchtungsanlage = Nein
+ | Beleuchtungstage =
+ | Rodelverleih = Ja
+ | Gütesiegel =
+ | Webauskunft =
+ | Telefonauskunft = +43-664-1808482 (Bergkristallhütte)
+ | Bild = Rodelbahn Bergkristallhütte 2009-03-03.jpg
+ | In Übersichtskarte = Ja
+ | Forumid = 72
+ }}
+ Die Rodelbahn zur Bergkristallhütte ist durchaus abwechslungsreich.'''
+ class Sledrun(object): pass
+ sledrun = Sledrun()
+ wrpylib.wrmwmarkup.rodelbahnbox_to_sledrun(wikitext, sledrun)
+ wrpylib.wrmwmarkup.sledrun_to_rodelbahnbox(sledrun, '1.3')
+
+
+
+def test_gasthausbox_to_inn():
+ wikitext = u'''{{Gasthausbox
+ | Position = 47.295549 N 9.986970 E
+ | Höhe = 1250
+ | Betreiber =
+ | Sitzplätze =
+ | Übernachtung =
+ | Rauchfrei = Nein
+ | Rodelverleih =
+ | Handyempfang = A1; T-Mobile/Telering
+ | Homepage = http://www.bergkristallhuette.com/
+ | E-Mail = bergkristallhuette@gmx.at
+ | Telefon = +43-664-1808482
+ | Bild = Bergkritsallhütte 2009-02-07.JPG
+ | Rodelbahnen = [[Bergkristallhütte]]
+ }}
+ Die Bergkristallhütte ist Teil des Boden-Vorsäß.'''
+ class Inn(object): pass
+ inn = Inn()
+ wrpylib.wrmwmarkup.gasthausbox_to_inn(wikitext, inn)
+ wrpylib.wrmwmarkup.inn_to_gasthausbox(inn)
+
#!/usr/bin/python2.6
# -*- coding: iso-8859-15 -*-
-import wrpylib.wrmwmarkup
-import formencode
+import wrpylib.mwmarkup
-def test_rodelbahnbox_to_sledrun():
+def test_find_template():
wikitext = u'''== Allgemeines ==
{{Rodelbahnbox
| Position = 47.309820 N 9.986508 E
| Forumid = 72
}}
Die Rodelbahn zur Bergkristallhütte ist durchaus abwechslungsreich.'''
- class Sledrun(object): pass
- sledrun = Sledrun()
- wrpylib.wrmwmarkup.rodelbahnbox_to_sledrun(wikitext, sledrun)
- wrpylib.wrmwmarkup.sledrun_to_rodelbahnbox(sledrun)
+ start, end = wrpylib.mwmarkup.find_template(wikitext, u'Rodelbahnbox')
+ assert start == wikitext.find(u'{{')
+ assert end == wikitext.find(u'}}')+2
-
-def test_gasthausbox_to_inn():
- wikitext = u'''{{Gasthausbox
- | Position = 47.295549 N 9.986970 E
- | Höhe = 1250
- | Betreiber =
- | Sitzplätze =
- | Übernachtung =
- | Rauchfrei = Nein
- | Rodelverleih =
- | Handyempfang = A1; T-Mobile/Telering
- | Homepage = http://www.bergkristallhuette.com/
- | E-Mail = bergkristallhuette@gmx.at
- | Telefon = +43-664-1808482
- | Bild = Bergkritsallhütte 2009-02-07.JPG
- | Rodelbahnen = [[Bergkristallhütte]]
+def test_split_template():
+ wikitext = u'''== Allgemeines ==
+ {{Rodelbahnbox
+ | Position = 47.309820 N 9.986508 E
+ | Position oben =
+ | Höhe oben = 1244
+ | Position unten =
+ | Höhe unten = 806
+ | Länge = 5045
+ | Schwierigkeit =
+ | Lawinen = gelegentlich
+ | Betreiber =
+ | Öffentliche Anreise = Ja
+ | Gehzeit = 105
+ | Aufstieg getrennt = Nein
+ | Aufstiegshilfe = Nein
+ | Beleuchtungsanlage = Nein
+ | Beleuchtungstage =
+ | Rodelverleih = Ja
+ | Gütesiegel =
+ | Webauskunft =
+ | Telefonauskunft = +43-664-1808482 (Bergkristallhütte)
+ | Bild = Rodelbahn Bergkristallhütte 2009-03-03.jpg
+ | In Übersichtskarte = Ja
+ | Forumid = 72
}}
- Die Bergkristallhütte ist Teil des Boden-Vorsäß.'''
- class Inn(object): pass
- inn = Inn()
- wrpylib.wrmwmarkup.gasthausbox_to_inn(wikitext, inn)
- wrpylib.wrmwmarkup.inn_to_gasthausbox(inn)
+ Die Rodelbahn zur Bergkristallhütte ist durchaus abwechslungsreich.'''
+ start, end = wrpylib.mwmarkup.find_template(wikitext, u'Rodelbahnbox')
+ template_title, parameters = wrpylib.mwmarkup.split_template(wikitext[start:end])
+ assert template_title == u'Rodelbahnbox'
+ assert len(parameters) == 22
+ assert parameters['Position'] == u'47.309820 N 9.986508 E'
+ assert parameters['Telefonauskunft'] == u'+43-664-1808482 (Bergkristallhütte)'
+ assert parameters['Schwierigkeit'] == u''
+
+
+def test_create_template():
+ wikitext = u'''{{Nicetemplate|Red|Bold|Position=Top|Alignment=Right}}'''
+ template_title, parameters = wrpylib.mwmarkup.split_template(wikitext)
+ print parameters
+ keys = [u'1', u'2', u'Position', u'Alignment']
+ values = [parameters[k] for k in keys]
+ wikitext_generated = wrpylib.mwmarkup.create_template(template_title, values[:2], keys[2:], values[2:])
+ wikitext_table = wrpylib.mwmarkup.create_template(template_title, values[:2], keys[2:], values[2:], True)
+ assert wikitext_generated == wikitext
* py-wikimarkup https://github.com/dcramer/py-wikimarkup
* mwlib http://code.pediapress.com/wiki/wiki
"""
+import re
+
+
+def find_template(wikitext, template_title):
+ """Returns the tuple (start, end) of the first occurence of the template '{{template ...}} within wikitext'.
+ (None, None) is returned if the template is not found.
+ If you are sure that the wikitext contains the template, the template could be extracted like follows:
+
+ >>> wikitext = u'This is a {{Color|red|red text}} template.'
+ >>> start, end = find_template(wikitext, u'Color')
+ >>> print wikitext[start:end]
+ {{Color|red|red text}}
+
+ or just:
+
+ >>> print wikitext.__getslice__(*find_template(wikitext, u'Color'))
+ {{Color|red|red text}}
+
+ The search is done with regular expression.
+
+ :param wikitext: The text (preferalbe unicode) that has the template in it.
+ :param template_title: The page title of the template with or without namespace (but as in the wikitext).
+ :return:
+ (start, end) of the first occurence with start >= 0 and end > start.
+ (None, None) if the template is not found.
+ """
+ match = re.search(u"\{\{" + template_title + "[^\}]*\}\}", wikitext, re.DOTALL)
+ if match is None: return None, None
+ return match.start(), match.end()
+
+
+
+def split_template(template):
+ """Takes a template, like u'{{Color|red|text=Any text}}' and translates it to a Python tuple
+ (template_title, parameters) where parameters is a Python dictionary {1: u'red', u'text'=u'Any text'}.
+ Anonymous parameters get integer keys (converted to unicode) starting with 1
+ like in MediaWiki, named parameters are unicode strings.
+ Whitespace is stripped.
+ If an unexpected format is encountered, a ValueError is raised."""
+ if not template.startswith(u'{{'): raise ValueError(u'Template does not start with "{{"')
+ if not template.endswith(u'}}'): raise ValueError(u'Template does not end with "}}"')
+ parts = template[2:-2].split(u'|')
+
+ # template name
+ template_title = parts[0].strip()
+ if len(template_title) == 0: raise ValueError(u'Empty template tilte.')
+ del parts[0]
+
+ # anonymous parameters
+ params = {} # result dictionary
+ param_num = 1
+ while len(parts) > 0:
+ equalsign_pos = parts[0].find(u'=')
+ if equalsign_pos >= 0: break # named parameter
+ params[unicode(param_num)] = parts[0].strip()
+ del parts[0]
+ param_num += 1
+
+ # named or numbered parameters
+ while len(parts) > 0:
+ equalsign_pos = parts[0].find(u'=')
+ if equalsign_pos < 0: raise ValueError(u'Anonymous parameter after named parameter.')
+ key, sep, value = parts[0].partition(u'=')
+ key = key.strip()
+ if len(key) == 0: raise ValueError(u'Empty key.')
+ if params.has_key(key): raise ValueError(u'Duplicate key: "{0}"'.format(key))
+ params[key] = value.strip()
+ del parts[0]
+
+ return template_title, params
+
+
+def create_template(template_title, anonym_params=[], named_param_keys=[], named_param_values=[], as_table=False):
+ """Formats a MediaWiki template.
+ :param template_title: Unicode string with the template name
+ :param anonym_params: list with parameters without keys
+ :param named_param_keys: list with keys of named parameters
+ :param named_param_values: list with values of named parameters, corresponding to named_param_keys.
+ :return: unicode template"""
+ pipe_char, equal_char, end_char = (u'\n| ', u' = ', u'\n}}') if as_table else (u'|', u'=', u'}}')
+ parts = [u"{{" + template_title]
+ parts += anonym_params
+ if as_table: max_key_len = max([len(k) for k in named_param_keys])
+ for i in xrange(len(named_param_keys)):
+ key = named_param_keys[i]
+ if as_table: key = key.ljust(max_key_len)
+ parts.append(key + equal_char + named_param_values[i])
+ return pipe_char.join(parts) + end_char
def _conv(fnct, value, fieldname):
- "Like one of the to_xxx functions (e.g. to_bool), but adds the field name to the error message"
+ """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, e: raise formencode.Invalid(u"Conversion error in field '%s': %s" % (fieldname, unicode_e(e)), e.value, e.state)
+ except formencode.Invalid as e: raise formencode.Invalid(u"Conversion error in field '%s': %s" % (fieldname, unicode_e(e)), e.value, e.state)
-def rodelbahnbox_to_sledrun(wikitext, sledrun):
+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.
- Raises a formencode.Invalid exception if the format is not OK.
- :return: (start, end) tuple of the Rodelbahnbox."""
- # Match Rodelbahnbox
- regexp = re.compile(u"\{\{(Rodelbahnbox[^\}]*)\}\}", re.DOTALL)
- match = regexp.search(wikitext)
- if not match:
- raise formencode.Invalid(u"Rodelbahnbox nicht gefunden", wikitext, None)
- box = match.group(1)
+ 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: sledrun = object()
+
+ # 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_name, properties = wrpylib.mwmarkup.split_template(wikitext[start:end])
- # Process Rodelbahnbox
- for property in box.split('|'):
- property = property.strip()
- if property == u'Rodelbahnbox': continue
- equalsign_pos = property.find('=')
- if equalsign_pos < 0:
- raise formencode.Invalid(u"Die Eigenschaft '%s' hat ein unerwartetes Format." % property, wikitext, None)
- key = property[:equalsign_pos].strip()
- value = property[equalsign_pos+1:].strip()
- if key in [u'Rodelbahnnummer', u'Lift']:
- errors.append("Eigenschaft '%s' wird nicht mehr unterstuetzt, siehe %s." % (key, 'http://www.winterrodeln.org/wiki/Vorlage:Rodelbahnbox'))
- elif key == u'Position': sledrun.position_latitude, sledrun.position_longitude = _conv(wrpylib.wrvalidators.GeoNone().to_python, value, key) # '47.583333 N 15.75 E'
+ # 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'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'Gehzeit': sledrun.walkup_time = _conv(wrpylib.wrvalidators.UnsignedNone().to_python, value, key) # 90
- elif key == u'Aufstieg möglich': sledrun.walkup_separate, sledrun.walkup_separate_comment = _conv(wrpylib.wrvalidators.GermanTristateFloatComment().to_python, value, key) # 'Ja'
+ 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'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'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 match.span()
-
+ return start, end, sledrun
-def sledrun_to_rodelbahnbox(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."""
+ 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.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'Gehzeit')
values.append(wrpylib.wrvalidators.UnsignedNone().from_python(sledrun.walkup_time))
keys.append(u'Aufstieg getrennt')