# -*- coding: iso-8859-15 -*-
import collections
import wrpylib.wrvalidators
-import formencode
import unittest
from wrpylib.wrvalidators import *
+# TODO: optional converter
+# ------------------
+
+# "no" converter
+# --------------
+
+class TestNoGermanConverter(unittest.TestCase):
+ def test_from_str(self):
+ self.assertEqual(no_german_from_str('abc'), (True, 'abc'))
+ self.assertEqual(no_german_from_str('Nein'), (False, None))
+ with self.assertRaises(ValueError):
+ no_german_from_str('')
+
+ def test_to_str(self):
+ self.assertEqual(no_german_to_str((True, 'abc')), 'abc')
+ self.assertEqual(no_german_to_str((False, None)), 'Nein')
+
+
+# "optional"/"no" converter
+# -------------------------
+
+class TestOptNoGerman(unittest.TestCase):
+ def test_from_str(self):
+ self.assertEqual(opt_no_german_from_str('abc'), (True, 'abc'))
+ self.assertEqual(opt_no_german_from_str('Nein'), (False, None))
+ self.assertEqual(opt_no_german_from_str(''), (None, None))
+
+ def test_to_str(self):
+ self.assertEqual(opt_no_german_to_str((True, 'abc')), 'abc')
+ self.assertEqual(opt_no_german_to_str((False, None)), 'Nein')
+ self.assertEqual(opt_no_german_to_str((None, None)), '')
+
+
+# TODO: choice converter
+# ----------------
+
+
+# TODO: dict converter
+# --------------
+
+
+# TODO: enum/"list" converter
+# ---------------------
+
+
+# TODO: value/comment converter
+# -----------------------
+
+
+# string converter
+# ----------------
+
+class TestStr(unittest.TestCase):
+ def test_from_str(self):
+ self.assertEqual('', str_from_str(''))
+ self.assertEqual('abc', str_from_str('abc'))
+
+ def test_to_str(self):
+ self.assertEqual('', str_to_str(''))
+ self.assertEqual('abc', str_to_str('abc'))
+
+
+class TestReqStr(unittest.TestCase):
+ def test_from_str(self):
+ self.assertEqual('abc', req_str_from_str('abc'))
+ self.assertEqual(' ', req_str_from_str(' '))
+ with self.assertRaises(ValueError):
+ req_str_from_str('')
+
+
+class TestOptStr(unittest.TestCase):
+ def test_from_str(self):
+ self.assertEqual('abc', opt_str_from_str('abc'))
+ self.assertEqual(' ', opt_str_from_str(' '))
+ self.assertEqual(None, opt_str_from_str(''))
+
+ def test_to_str(self):
+ self.assertEqual('abc', opt_str_to_str('abc'))
+ self.assertEqual(' ', opt_str_to_str(' '))
+ self.assertEqual('', opt_str_to_str(None))
+
+
+# TODO: optional no or string converter
+# -------------------------------
+
+
+# integer converter
+# -----------------
class TestInt(unittest.TestCase):
def test_from_str(self):
- self.assertEqual(int_from_str('42'), 42)
- self.assertEqual(int_from_str('+42'), 42)
- self.assertEqual(int_from_str('-20'), -20)
- self.assertEqual(int_from_str('0', min=0), 0)
- self.assertEqual(int_from_str('10', max=10), 10)
+ self.assertEqual(42, int_from_str('42'))
+ self.assertEqual(42, int_from_str('+42'))
+ self.assertEqual(-20, int_from_str('-20'))
+ self.assertEqual(0, int_from_str('0', min=0))
+ self.assertEqual(10, int_from_str('10', max=10))
with self.assertRaises(ValueError):
int_from_str('abc')
with self.assertRaises(ValueError):
int_from_str('0d')
def test_to_str(self):
- self.assertEqual(int_to_str(20), '20')
- self.assertEqual(int_to_str(-20), '-20')
- self.assertEqual(int_to_str(0), '0')
+ self.assertEqual('20', int_to_str(20))
+ self.assertEqual('-20', int_to_str(-20))
+ self.assertEqual('0', int_to_str(0))
class TestOptInt(unittest.TestCase):
def test_from_str(self):
- self.assertEqual(opt_int_from_str('42'), 42)
- self.assertEqual(opt_int_from_str('+42'), 42)
- self.assertEqual(opt_int_from_str('-20'), -20)
- self.assertEqual(opt_int_from_str(''), None)
+ self.assertEqual(42, opt_int_from_str('42'))
+ self.assertEqual(42, opt_int_from_str('+42'))
+ self.assertEqual(-20, opt_int_from_str('-20'))
+ self.assertEqual(None, opt_int_from_str(''))
with self.assertRaises(ValueError):
opt_int_from_str('abc')
with self.assertRaises(ValueError):
opt_int_from_str('0d')
def test_to_str(self):
- self.assertEqual(opt_int_to_str(20), '20')
- self.assertEqual(opt_int_to_str(-20), '-20')
- self.assertEqual(opt_int_to_str(0), '0')
- self.assertEqual(opt_int_to_str(None), '')
+ self.assertEqual('20', opt_int_to_str(20))
+ self.assertEqual('-20', opt_int_to_str(-20))
+ self.assertEqual('0', opt_int_to_str(0))
+ self.assertEqual('', opt_int_to_str(None))
+
+
+class TestOptUInt(unittest.TestCase):
+ def test_from_str(self):
+ self.assertEqual(42, opt_uint_from_str('42'))
+ self.assertEqual(0, opt_uint_from_str('0'))
+ self.assertEqual(None, opt_uint_from_str(''))
+ with self.assertRaises(ValueError):
+ opt_uint_from_str('-1')
+
+ def test_to_str(self):
+ self.assertEqual('20', opt_uint_to_str(20))
+ self.assertEqual('0', opt_uint_to_str(0))
+ self.assertEqual('', opt_uint_to_str(None))
+
+
+# bool converter
+# --------------
class TestEnumConverter(unittest.TestCase):
self.assertEqual(value_comment_to_str(('abc', ''), comment_optional=True), 'abc')
-class TestNoGermanConverter(unittest.TestCase):
- def test_from_str(self):
- self.assertEqual(no_german_from_str('abc'), (True, 'abc'))
- self.assertEqual(no_german_from_str('Nein'), (False, None))
- with self.assertRaises(ValueError):
- no_german_from_str('')
-
- def test_to_str(self):
- self.assertEqual(no_german_to_str((True, 'abc')), 'abc')
- self.assertEqual(no_german_to_str((False, None)), 'Nein')
-
-
-class TestOptNoGerman(unittest.TestCase):
- def test_from_str(self):
- self.assertEqual(opt_no_german_from_str('abc'), (True, 'abc'))
- self.assertEqual(opt_no_german_from_str('Nein'), (False, None))
- self.assertEqual(opt_no_german_from_str(''), (None, None))
-
- def test_to_str(self):
- self.assertEqual(opt_no_german_to_str((True, 'abc')), 'abc')
- self.assertEqual(opt_no_german_to_str((False, None)), 'Nein')
- self.assertEqual(opt_no_german_to_str((None, None)), '')
-
-
class TestLiftGermanValidator(unittest.TestCase):
def test_from_str(self):
self.assertEqual(lift_german_from_str(''), None)
opt_str_opt_comment_enum_from_str('Talstation (unten); ; Mittelstation')
def test_to_str(self):
- self.assertEqual(sledrental_to_str(None), '')
- self.assertEqual(sledrental_to_str([]), 'Nein')
- self.assertEqual(sledrental_to_str([('Talstation', None)]), 'Talstation')
- self.assertEqual(sledrental_to_str([('Talstation', 'unten')]), 'Talstation (unten)')
- self.assertEqual(sledrental_to_str([('Talstation', 'unten'), ('Mittelstation', None)]), 'Talstation (unten); Mittelstation')
+ self.assertEqual(opt_str_opt_comment_enum_to_str(None), '')
+ self.assertEqual(opt_str_opt_comment_enum_to_str([]), 'Nein')
+ self.assertEqual(opt_str_opt_comment_enum_to_str([('Talstation', None)]), 'Talstation')
+ self.assertEqual(opt_str_opt_comment_enum_to_str([('Talstation', 'unten')]), 'Talstation (unten)')
+ self.assertEqual(opt_str_opt_comment_enum_to_str([('Talstation', 'unten'), ('Mittelstation', None)]), 'Talstation (unten); Mittelstation')
class TestNoOrStr(unittest.TestCase):
class TestTelefonauskunft(unittest.TestCase):
def test_from_str(self):
- self.assertEqual(telefonauskunft_from_str(''), None)
- self.assertEqual(telefonauskunft_from_str('Nein'), [])
- self.assertEqual(telefonauskunft_from_str('+43-512-123456 (untertags)'), [('+43-512-123456', 'untertags')])
- self.assertEqual(telefonauskunft_from_str('+43-512-1234 (untertags); +43-664-123456 (Alm)'), [('+43-512-1234', 'untertags'), ('+43-664-123456', 'Alm')])
+ self.assertEqual(opt_phone_comment_enum_from_str(''), None)
+ self.assertEqual(opt_phone_comment_enum_from_str('Nein'), [])
+ self.assertEqual(opt_phone_comment_enum_from_str('+43-512-123456 (untertags)'), [('+43-512-123456', 'untertags')])
+ self.assertEqual(opt_phone_comment_enum_from_str('+43-512-1234 (untertags); +43-664-123456 (Alm)'), [('+43-512-1234', 'untertags'), ('+43-664-123456', 'Alm')])
with self.assertRaises(ValueError):
- telefonauskunft_from_str('+43-512-123456+ (untertags)')
+ opt_phone_comment_enum_from_str('+43-512-123456+ (untertags)')
with self.assertRaises(ValueError):
- telefonauskunft_from_str('+43-512-123456')
+ opt_phone_comment_enum_from_str('+43-512-123456')
def test_to_str(self):
- self.assertEqual(telefonauskunft_to_str(None), '')
- self.assertEqual(telefonauskunft_to_str([]), 'Nein')
- self.assertEqual(telefonauskunft_to_str([('+43-512-123456', 'untertags')]), '+43-512-123456 (untertags)')
- self.assertEqual(telefonauskunft_to_str([('+43-512-1234', 'untertags'), ('+43-664-123456', 'Alm')]), '+43-512-1234 (untertags); +43-664-123456 (Alm)')
+ self.assertEqual(opt_phone_comment_enum_to_str(None), '')
+ self.assertEqual(opt_phone_comment_enum_to_str([]), 'Nein')
+ self.assertEqual(opt_phone_comment_enum_to_str([('+43-512-123456', 'untertags')]), '+43-512-123456 (untertags)')
+ self.assertEqual(opt_phone_comment_enum_to_str([('+43-512-1234', 'untertags'), ('+43-664-123456', 'Alm')]), '+43-512-1234 (untertags); +43-664-123456 (Alm)')
class TestEmail(unittest.TestCase):
def test_from_str(self):
value = '{{MyTemplate|apple=2|banana=5}}'
converter_dict = OrderedDict([('apple', opt_uint_converter), ('banana', opt_uint_converter)])
- result = box_from_str(value, 'MyTemplate', converter_dict)
+ result = wikibox_from_str(value, 'MyTemplate', converter_dict)
self.assertEqual(result['apple'], 2)
self.assertEqual(result['banana'], 5)
value = '{{MyTemplate\n | apple = 2 \n| banana = 5 }}'
- result = box_from_str(value, 'MyTemplate', converter_dict)
+ result = wikibox_from_str(value, 'MyTemplate', converter_dict)
self.assertEqual(result['apple'], 2)
self.assertEqual(result['banana'], 5)
with self.assertRaises(ValueError):
- box_from_str(value, 'myTemplate', converter_dict)
+ wikibox_from_str(value, 'myTemplate', converter_dict)
with self.assertRaises(ValueError):
value = '{{MyTemplate|apple=2|banana=five}}'
- box_from_str(value, 'MyTemplate', converter_dict)
+ wikibox_from_str(value, 'MyTemplate', converter_dict)
with self.assertRaises(ValueError):
value = '{{MyTemplate|apple=2}}'
- box_from_str(value, 'MyTemplate', converter_dict)
+ wikibox_from_str(value, 'MyTemplate', converter_dict)
with self.assertRaises(ValueError):
value = '{{MyTemplate|apple=2|banana=5|cherry=6}}'
- box_from_str(value, 'MyTemplate', converter_dict)
+ wikibox_from_str(value, 'MyTemplate', converter_dict)
def test_to_str(self):
value = OrderedDict([('apple', 2), ('banana', 5)])
converter_dict = OrderedDict([('apple', opt_uint_converter), ('banana', opt_uint_converter)])
- result = box_to_str(value, 'MyTemplate', converter_dict)
+ result = wikibox_to_str(value, 'MyTemplate', converter_dict)
self.assertEqual(result, '{{MyTemplate|apple=2|banana=5}}')
assert v.from_python('T-Mobile (gut); A1') == 'T-Mobile (gut); A1'
- def test_PhoneCommentListNeinLoopNone(self):
- v = wrpylib.wrvalidators.PhoneCommentListNeinLoopNone(comments_are_optional=True)
- assert v.to_python('') == None
- assert v.to_python('Nein') == 'Nein'
- assert v.to_python('+43-699-1234567 (nicht nach 20:00 Uhr); +43-512-123456') == '+43-699-1234567 (nicht nach 20:00 Uhr); +43-512-123456'
- assert v.from_python(None) == ''
- assert v.from_python('Nein') == 'Nein'
- assert v.from_python('+43-699-1234567 (nicht nach 20:00 Uhr); +43-512-123456') == '+43-699-1234567 (nicht nach 20:00 Uhr); +43-512-123456'
-
-
+class TestGasthausbox(unittest.TestCase):
def test_GasthausboxDictValidator(self):
v = wrpylib.wrvalidators.GasthausboxDictValidator()
other = collections.OrderedDict([
# $Id$
# $HeadURL$
"""
-A converter is a Python variable (may be a class, class instance or anything else) that has the member
-functions from_str and to_str. From string takes a string "from the outside", checks it and returns a Python variable
-representing that value in Python. It reports error by raising ValueError. to_str does the opposite, however, it
-can assume that the value it has to convert to a string is valid. If it gets an invalid value, the behavior is
-undefined.
+This module contains functions that convert winterrodeln specific strings (like geographic coordinates) from string
+to appropriate python types and the other way round.
+Functions that take strings to convert it to python types are called *_from_str(value, [...]) and are supposed to
+validate the string. In case of errors, a ValueError (or a subclass thereof) is returned.
+Functions that take python types and convert it to Winterrodeln strings are called *_to_str(value, [...]) and can
+assume that the value they get is valid. If it is not, the behavior is undefined.
+The namedtuple FromToConverter groups corresponding *_from_str and *_to_str converters.
"""
-import datetime
import email.headerregistry
import urllib.parse
import re
-import xml.dom.minidom as minidom
-from xml.parsers.expat import ExpatError
from collections import OrderedDict, namedtuple
import mwparserfromhell
-import formencode
-import formencode.national
+
from wrpylib.mwmarkup import template_to_table
-# Meta converter types and functions
-# ----------------------------------
+# FromToConverter type
+# --------------------
+# namedtuple that groups corresponding *_from_str and *_to_str functions.
FromToConverter = namedtuple('FromToConverter', ['from_str', 'to_str'])
-def opt_from_str(value, from_str, none=None):
- return none if value == '' else from_str(value)
+# optional converter
+# ------------------
+
+def opt_from_str(value, from_str, empty=None):
+ """Makes the converter `from_str` "optional"
+ by replacing the empty string with a predefined value (default: None)."""
+ return empty if value == '' else from_str(value)
+
+
+def opt_to_str(value, to_str, empty=None):
+ return '' if value == empty else to_str(value)
+
+
+# "no" converter
+# --------------
+
+def no_german_from_str(value, from_str, use_tuple=True, no_value=None):
+ """Makes it possible to have "Nein" as special value. If use_tuple is True, a tuple is returned. The first
+ entry of the tuple is False in case the value is "Nein", otherwiese the first value is True. The second value is
+ no_value in case of the value being "Nein", otherwise it is the result of from_str(value).
+ If use_tuple is False, no_value is returned in case the value is "Nein", otherwise the result of from_str(value)."""
+ if value == 'Nein':
+ return (False, no_value) if use_tuple else no_value
+ return (True, from_str(value)) if use_tuple else from_str(value)
+
+
+def no_german_to_str(value, to_str, use_tuple=True, no_value=None):
+ if use_tuple:
+ if not value[0]:
+ return 'Nein'
+ return to_str(value[1])
+ else:
+ if value == no_value:
+ return 'Nein'
+ return to_str(value)
+
+
+# "optional"/"no" converter
+# -------------------------
+
+def opt_no_german_from_str(value, from_str, use_tuple=True, no_value=None, empty=(None, None)):
+ return opt_from_str(value, lambda v: no_german_from_str(v, from_str, use_tuple, no_value), empty)
+
+def opt_no_german_to_str(value, to_str, use_tuple=True, no_value=None, empty=(None, None)):
+ return opt_to_str(value, lambda v: no_german_to_str(v, to_str, use_tuple, no_value), empty)
-def opt_to_str(value, to_str, none=None):
- return '' if value == none else to_str(value)
+# choice converter
+# ----------------
def choice_from_str(value, choices):
+ """Returns the value if it is a member of the choices iterable."""
if value not in choices:
raise ValueError('{} is an invalid value')
return value
+# dict converter
+# --------------
+
def dictkey_from_str(value, key_str_dict):
+ """Returns the key of an entry in the key_str_dict if the value of the entry corresponds to the given value."""
try:
return dict(list(zip(key_str_dict.values(), key_str_dict.keys())))[value]
except KeyError:
raise ValueError("Invalid value '{}'".format(value))
-# Basic type converter functions
-# ------------------------------
+# enum/"list" converter
+# ---------------------
+
+def enum_from_str(value, from_str, separator=';', min_len=0):
+ """Semicolon separated list of entries with the same "type"."""
+ values = value.split(separator)
+ if len(values) == 1 and values[0] == '':
+ values = []
+ if len(values) < min_len:
+ raise ValueError('at least {} entry/entries have to be in the enumeration'.format(min_len))
+ return list(map(from_str, map(str.strip, values)))
+
+
+def enum_to_str(value, to_str, separator='; '):
+ return separator.join(map(to_str, value))
+
+
+# value/comment converter
+# -----------------------
+
+def value_comment_from_str(value, value_from_str, comment_from_str, comment_optional=False):
+ """Makes it possible to have a mandatory comment in parenthesis at the end of the string."""
+ open_brackets = 0
+ comment = ''
+ comment_end_pos = None
+ for i, char in enumerate(value[::-1]):
+ if char == ')':
+ open_brackets += 1
+ if open_brackets == 1:
+ comment_end_pos = i
+ if len(value[-1-comment_end_pos:].rstrip()) > 1:
+ raise ValueError('invalid characters after comment')
+ elif char == '(':
+ open_brackets -= 1
+ if open_brackets == 0:
+ comment = value[-i:-1-comment_end_pos]
+ value = value[:-i-1].rstrip()
+ break
+ else:
+ if open_brackets > 0:
+ raise ValueError('bracket mismatch')
+ if not comment_optional:
+ raise ValueError('mandatory comment not found')
+ return value_from_str(value), comment_from_str(comment)
+def value_comment_to_str(value, value_to_str, comment_to_str, comment_optional=False):
+ left = value_to_str(value[0])
+ comment = comment_to_str(value[1])
+ if len(comment) > 0 or not comment_optional:
+ comment = '({})'.format(comment)
+ if len(left) == 0:
+ return comment
+ if len(comment) == 0:
+ return left
+ return '{} {}'.format(left, comment)
+
+
+# string converter
+# ----------------
+
def str_from_str(value):
+ """Converter that takes any string and returns it as string without validation.
+ In other words, this function does nothing and just returns its argument."""
return value
return value
+def req_str_from_str(value):
+ if value == '':
+ raise ValueError('missing required value')
+ return str_from_str(value)
+
+
def opt_str_from_str(value):
return opt_from_str(value, str_from_str)
opt_str_converter = FromToConverter(opt_str_from_str, opt_str_to_str)
-def req_str_from_str(value):
- if value == '':
- raise ValueError('missing required value')
- return str_from_str(value)
+# optional no or string converter
+# -------------------------------
+
+def opt_no_or_str_from_str(value):
+ """
+ 'Nein' => (False, None); 'Nur Wochenende' => (True, 'Nur Wochenende'); 'Ja' => (True, 'Ja'); '' => (None, None)"""
+ return opt_no_german_from_str(value, req_str_from_str)
+
+def opt_no_or_str_to_str(value):
+ return opt_no_german_to_str(value, str_to_str)
+
+
+opt_no_or_str_converter = FromToConverter(opt_no_or_str_from_str, opt_no_or_str_to_str)
+
+
+# integer converter
+# -----------------
def int_from_str(value, min=None, max=None):
+ """Converter that takes a string representation of an integer and returns the integer.
+ :param value: string representation of an integer
+ :param min: If not None, the integer has to be at least min
+ :param max: If not None, the integer has to be no more than max
+ """
value = int(value)
if min is not None and value < min:
raise ValueError('{} must be >= than {}'.format(value, min))
opt_uint_converter = FromToConverter(opt_uint_from_str, opt_uint_to_str)
-
-# Complex types
-# -------------
-
-def enum_from_str(value, from_str=req_str_from_str, separator=';', min_len=0):
- """Semicolon separated list of entries with the same "type"."""
- values = value.split(separator)
- if len(values) == 1 and values[0] == '':
- values = []
- if len(values) < min_len:
- raise ValueError('at least {} entry/entries have to be in the enumeration'.format(min_len))
- return list(map(from_str, map(str.strip, values)))
-
-
-def enum_to_str(value, to_str=opt_str_to_str, separator='; '):
- return separator.join(map(to_str, value))
-
-
-# Specific converter functions
-# ----------------------------
+# bool converter
+# --------------
BOOL_GERMAN = OrderedDict([(False, 'Nein'), (True, 'Ja')])
opt_bool_german_converter = FromToConverter(opt_bool_german_from_str, opt_bool_german_to_str)
+# tristate converter
+# ------------------
+
TRISTATE_GERMAN = OrderedDict([(0.0, 'Nein'), (0.5, 'Teilweise'), (1.0, 'Ja')])
opt_tristate_german_converter = FromToConverter(opt_tristate_german_from_str, opt_tristate_german_to_str)
-LonLat = namedtuple('LonLat', ['lon', 'lat'])
-
-
-lonlat_none = LonLat(None, None)
+# tristate with comment converter
+# -------------------------------
-
-def lonlat_from_str(value):
- """Converts a winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
- to the LonLat(lon, lat) named tupel."""
- r = re.match('(\d+\.\d+) N (\d+\.\d+) E', value)
- if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
- return LonLat(float(r.groups()[1]), float(r.groups()[0]))
+def opt_tristate_german_comment_from_str(value):
+ """Ja, Nein or Vielleicht, optionally with comment in parenthesis."""
+ return value_comment_from_str(value, opt_tristate_german_from_str, opt_str_from_str, True)
-def lonlat_to_str(value):
- return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
+def opt_tristate_german_comment_to_str(value):
+ return value_comment_to_str(value, opt_tristate_german_to_str, opt_str_to_str, True)
-def opt_lonlat_from_str(value):
- return opt_from_str(value, lonlat_from_str, lonlat_none)
+opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str, opt_tristate_german_comment_to_str)
-def opt_lonlat_to_str(value):
- return opt_to_str(value, lonlat_to_str, lonlat_none)
+# url converter
+# -------------
+def url_from_str(value):
+ result = urllib.parse.urlparse(value)
+ if result.scheme not in ['http', 'https']:
+ raise ValueError('scheme has to be http or https')
+ if not result.netloc:
+ raise ValueError('url does not contain netloc')
+ return value
-opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
+def url_to_str(value):
+ return value
-class MultiGeo(formencode.FancyValidator):
- "Formats multiple coordinates, even in multiple lines to [(latitude, longitude, elevation), ...] or [(latitude, longitude, None), ...] tuplets."
-
- # Valid for input_format
- FORMAT_GUESS = 0 # guesses the input format; default for input_format
- FORMAT_NONE = -1 # indicates missing formats
-
- # Valid for input_format and output_format
- FORMAT_GEOCACHING = 1 # e.g. "N 47° 13.692 E 011° 25.535"
- FORMAT_WINTERRODELN = 2 # e.g. "47.222134 N 11.467211 E"
- FORMAT_GMAPPLUGIN = 3 # e.g. "47.232922, 11.452239"
- FORMAT_GPX = 4 # e.g. "<trkpt lat="47.181289" lon="11.408827"><ele>1090.57</ele></trkpt>"
-
- input_format = FORMAT_GUESS
- output_format = FORMAT_WINTERRODELN
- last_input_format = FORMAT_NONE
-
- def __init__(self, input_format = FORMAT_GUESS, output_format = FORMAT_WINTERRODELN, **keywords):
- self.input_format = input_format
- self.output_format = output_format
- formencode.FancyValidator.__init__(self, if_empty = (None, None, None), **keywords)
-
- def to_python(self, value, state=None):
- self.assert_string(value, state)
- input_format = self.input_format
- if not input_format in [self.FORMAT_GUESS, self.FORMAT_GEOCACHING, self.FORMAT_WINTERRODELN, self.FORMAT_GMAPPLUGIN, self.FORMAT_GPX]:
- raise formencode.Invalid("input_format %d is not recognized" % input_format, value, state) # Shouldn't it be an other type of runtime error?
- lines = [line.strip() for line in value.split("\n") if len(line.strip()) > 0]
-
- result = []
- for line in lines:
- if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_GEOCACHING:
- r = re.match('N ?(\d+)° ?(\d+\.\d+) +E ?(\d+)° ?(\d+\.\d+)', line)
- if not r is None:
- g = r.groups()
- result.append((float(g[0]) + float(g[1])/60, float(g[2]) + float(g[3])/60, None))
- last_input_format = self.FORMAT_WINTERRODELN
- continue
-
- if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_WINTERRODELN:
- r = re.match('(\d+\.\d+) N (\d+\.\d+) E', line)
- if not r is None:
- result.append((float(r.groups()[0]), float(r.groups()[1]), None))
- last_input_format = self.FORMAT_WINTERRODELN
- continue
-
- if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_GMAPPLUGIN:
- r = re.match('(\d+\.\d+), ?(\d+\.\d+)', line)
- if not r is None:
- result.append((float(r.groups()[0]), float(r.groups()[1]), None))
- last_input_format = self.FORMAT_GMAPPLUGIN
- continue
-
- if input_format == self.FORMAT_GUESS or input_format == self.FORMAT_GPX:
- try:
- xml = minidom.parseString(line)
- coord = xml.documentElement
- lat = float(coord.getAttribute('lat'))
- lon = float(coord.getAttribute('lon'))
- try: ele = float(coord.childNodes[0].childNodes[0].nodeValue)
- except (IndexError, ValueError): ele = None
- result.append((lat, lon, ele))
- last_input_format = self.FORMAT_GPX
- continue
- except (ExpatError, IndexError, ValueError): pass
-
- raise formencode.Invalid("Coordinates '%s' have no known format" % line, value, state)
-
- return result
-
- def from_python(self, value, state=None):
- output_format = self.output_format
- result = []
- for latitude, longitude, height in value:
- if output_format == self.FORMAT_GEOCACHING:
- degree = latitude
- result.append('N %02d° %02.3f E %03d° %02.3f' % (latitude, latitude % 1 * 60, longitude, longitude % 1 * 60))
-
- elif output_format == self.FORMAT_WINTERRODELN:
- result.append('%.6f N %.6f E' % (latitude, longitude))
-
- elif output_format == self.FORMAT_GMAPPLUGIN:
- result.append('%.6f, %.6f' % (latitude, longitude))
-
- elif output_format == self.FORMAT_GPX:
- if not height is None: result.append('<trkpt lat="%.6f" lon="%.6f"><ele>%.2f</ele></trkpt>' % (latitude, longitude, height))
- else: result.append('<trkpt lat="%.6f" lon="%.6f"/>' % (latitude, longitude))
-
- else:
- raise formencode.Invalid("output_format %d is not recognized" % output_format, value, state) # Shouldn't it be an other type of runtime error?
-
- return "\n".join(result)
+# webauskunft converter
+# ---------------------
+def webauskunft_from_str(value):
+ return opt_no_german_from_str(value, url_from_str)
-DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
+def webauskunft_to_str(value):
+ return opt_no_german_to_str(value, url_to_str)
-def difficulty_german_from_str(value):
- return dictkey_from_str(value, DIFFICULTY_GERMAN)
+webauskunft_converter = FromToConverter(webauskunft_from_str, webauskunft_to_str)
-def difficulty_german_to_str(value):
- return dictkey_to_str(value, DIFFICULTY_GERMAN)
+# wikipage converter
+# ------------------
-def opt_difficulty_german_from_str(value):
- return opt_from_str(value, difficulty_german_from_str)
+def wikipage_from_str(value):
+ """Validates wiki page name like '[[Birgitzer Alm]]'.
+ The page is not checked for existance.
+ An empty string is an error.
+ '[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
+ """
+ if not value.startswith('[[') or not value.endswith(']]'):
+ raise ValueError('No valid wiki page name "{}"'.format(value))
+ return value
-def opt_difficulty_german_to_str(value):
- return opt_to_str(value, difficulty_german_to_str)
+def wikipage_to_str(value):
+ return value
-opt_difficulty_german_converter = FromToConverter(opt_difficulty_german_from_str, opt_difficulty_german_to_str)
+def opt_wikipage_enum_from_str(value):
+ """Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
+ '[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
+ '[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
+ 'Nein' => []
+ '' => None
+ """
+ return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
-AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
+def opt_wikipage_enum_to_str(value):
+ return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
-def avalanches_german_from_str(value):
- return dictkey_from_str(value, AVALANCHES_GERMAN)
+opt_wikipage_enum_converter = FromToConverter(opt_wikipage_enum_from_str, opt_wikipage_enum_to_str)
-def avalanches_german_to_str(value):
- return dictkey_to_str(value, AVALANCHES_GERMAN)
+# email converter
+# ---------------
+def email_from_str(value):
+ """Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
+ try:
+ email.headerregistry.Address(addr_spec=value)
+ except email.errors.HeaderParseError as e:
+ raise ValueError('Invalid email address: {}'.format(value), e)
+ return value
-def opt_avalanches_german_from_str(value):
- return opt_from_str(value, avalanches_german_from_str)
+def email_to_str(value):
+ return str(value)
-def opt_avalanches_german_to_str(value):
- return opt_to_str(value, avalanches_german_to_str)
+def masked_email_from_str(value, mask='(at)', masked_only=False):
+ """Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
+ email address as string, the second is a boolean telling whether the address was masked."""
+ unmasked = value.replace(mask, '@')
+ was_masked = unmasked != value
+ if masked_only and not was_masked:
+ raise ValueError('E-Mail address not masked')
+ return email_from_str(unmasked), was_masked
-opt_avalanches_german_converter = FromToConverter(opt_avalanches_german_from_str, opt_avalanches_german_to_str)
+def masked_email_to_str(value, mask='(at)'):
+ """Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
+ email address should be masked."""
+ email, do_masking = value
+ email = email_to_str(email)
+ if do_masking:
+ email = email.replace('@', mask)
+ return email
-PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
+def emails_from_str(value):
+ return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, masked_email_from_str, opt_str_from_str, True)), False, [], None)
-def public_transport_german_from_str(value):
- return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
+def emails_to_str(value):
+ return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, masked_email_to_str, opt_str_to_str, True)), False, [], None)
-def public_transport_german_to_str(value):
- return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
+emails_converter = FromToConverter(emails_from_str, email_to_str)
-def opt_public_transport_german_from_str(value):
- return opt_from_str(value, public_transport_german_from_str)
+# phone converter
+# ---------------
-def opt_public_transport_german_to_str(value):
- return opt_to_str(value, public_transport_german_to_str)
+def phone_number_from_str(value):
+ match = re.match(r'\+\d+(-\d+)*$', value)
+ if match is None:
+ raise ValueError('invalid format of phone number - use something like +43-699-1234567')
+ return value
-opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
+def phone_number_to_str(value):
+ return value
-def value_comment_from_str(value, value_from_str=str_from_str, comment_from_str=str_from_str, comment_optional=False):
- """Makes it possible to have a mandatory comment in parenthesis at the end of the string."""
- open_brackets = 0
- comment = ''
- comment_end_pos = None
- for i, char in enumerate(value[::-1]):
- if char == ')':
- open_brackets += 1
- if open_brackets == 1:
- comment_end_pos = i
- if len(value[-1-comment_end_pos:].rstrip()) > 1:
- raise ValueError('invalid characters after comment')
- elif char == '(':
- open_brackets -= 1
- if open_brackets == 0:
- comment = value[-i:-1-comment_end_pos]
- value = value[:-i-1].rstrip()
- break
- else:
- if open_brackets > 0:
- raise ValueError('bracket mismatch')
- if not comment_optional:
- raise ValueError('mandatory comment not found')
- return value_from_str(value), comment_from_str(comment)
+def opt_phone_comment_enum_from_str(value, comment_optional=False):
+ return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, phone_number_from_str, req_str_from_str, comment_optional)), False, [], None)
-def value_comment_to_str(value, value_to_str=str_to_str, comment_to_str=str_to_str, comment_optional=False):
- left = value_to_str(value[0])
- comment = comment_to_str(value[1])
- if len(comment) > 0 or not comment_optional:
- comment = '({})'.format(comment)
- if len(left) == 0:
- return comment
- if len(comment) == 0:
- return left
- return '{} {}'.format(left, comment)
+def opt_phone_comment_enum_to_str(value, comment_optional=False):
+ return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, phone_number_to_str, str_to_str, comment_optional)), False, [], None)
-def opt_tristate_german_comment_from_str(value):
- """Ja, Nein or Vielleicht, optionally with comment in parenthesis."""
- return value_comment_from_str(value, opt_tristate_german_from_str, opt_str_from_str, True)
+opt_phone_comment_enum_converter = FromToConverter(opt_phone_comment_enum_from_str, opt_phone_comment_enum_to_str)
-def opt_tristate_german_comment_to_str(value):
- return value_comment_to_str(value, opt_tristate_german_to_str, opt_str_to_str, True)
+opt_phone_comment_opt_enum_converter = FromToConverter(lambda value: opt_phone_comment_enum_from_str(value, True), lambda value: opt_phone_comment_enum_to_str(value, True))
-opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str, opt_tristate_german_comment_to_str)
+# longitude/latitude converter
+# ----------------------------
+LonLat = namedtuple('LonLat', ['lon', 'lat'])
-def no_german_from_str(value, from_str=req_str_from_str, use_tuple=True, no_value=None):
- if value == 'Nein':
- return (False, no_value) if use_tuple else no_value
- return (True, from_str(value)) if use_tuple else from_str(value)
+lonlat_none = LonLat(None, None)
-def no_german_to_str(value, to_str=str_to_str, use_tuple=True, no_value=None):
- if use_tuple:
- if not value[0]:
- return 'Nein'
- return to_str(value[1])
- else:
- if value == no_value:
- return 'Nein'
- return to_str(value)
+def lonlat_from_str(value):
+ """Converts a winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
+ to the LonLat(lon, lat) named tupel."""
+ r = re.match('(\d+\.\d+) N (\d+\.\d+) E', value)
+ if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
+ return LonLat(float(r.groups()[1]), float(r.groups()[0]))
-def opt_no_german_from_str(value, from_str=str_from_str, use_tuple=True, no_value=None, none=(None, None)):
- return opt_from_str(value, lambda v: no_german_from_str(v, from_str, use_tuple, no_value), none)
+def lonlat_to_str(value):
+ return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
-def opt_no_german_to_str(value, to_str=str_to_str, use_tuple=True, no_value=None, none=(None, None)):
- return opt_to_str(value, lambda v: no_german_to_str(v, to_str, use_tuple, no_value), none)
+def opt_lonlat_from_str(value):
+ return opt_from_str(value, lonlat_from_str, lonlat_none)
-def night_light_from_str(value):
- """'Beleuchtungsanlage' Tristate with optional comment:
- '' <=> (None, None)
- 'Ja' <=> (1.0, None)
- 'Teilweise' <=> (0.5, None)
- 'Nein' <=> (0.0, None)
- 'Ja (aber schmal)' <=> (1.0, 'aber schmal')
- 'Teilweise (oben)' <=> (0.5, 'oben')
- 'Nein (aber breit)' <=> (0.0, 'aber breit')
- """
- return
+def opt_lonlat_to_str(value):
+ return opt_to_str(value, lonlat_to_str, lonlat_none)
-def nightlightdays_from_str(value):
- return value_comment_from_str(value, lambda val: opt_from_str(val, lambda v: int_from_str(v, min=0, max=7)), opt_str_from_str, comment_optional=True)
+opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
-def nightlightdays_to_str(value):
- return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
+# difficulty converter
+# --------------------
-nightlightdays_converter = FromToConverter(nightlightdays_from_str, nightlightdays_to_str)
+DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
-CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
+def difficulty_german_from_str(value):
+ return dictkey_from_str(value, DIFFICULTY_GERMAN)
-def single_cachet_german_from_str(value):
- for pattern in CACHET_REGEXP:
- match = re.match(pattern, value)
- if match:
- return match.groups()
- raise ValueError("'{}' is no valid cachet".format(value))
+def difficulty_german_to_str(value):
+ return dictkey_to_str(value, DIFFICULTY_GERMAN)
-def single_cachet_german_to_str(value):
- return ' '.join(value)
+def opt_difficulty_german_from_str(value):
+ return opt_from_str(value, difficulty_german_from_str)
-def cachet_german_from_str(value):
- """Converts a "Gütesiegel":
- '' => None
- 'Nein' => []
- 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel' => [('Tiroler Naturrodelbahn-Gütesiegel', '2009', 'mittel')]"""
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, single_cachet_german_from_str), False, [], None)
+def opt_difficulty_german_to_str(value):
+ return opt_to_str(value, difficulty_german_to_str)
-
-def cachet_german_to_str(value):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, single_cachet_german_to_str), False, [], None)
+opt_difficulty_german_converter = FromToConverter(opt_difficulty_german_from_str, opt_difficulty_german_to_str)
-cachet_german_converter = FromToConverter(cachet_german_from_str, cachet_german_to_str)
+# avalanches converter
+# --------------------
-def url_from_str(value):
- result = urllib.parse.urlparse(value)
- if result.scheme not in ['http', 'https']:
- raise ValueError('scheme has to be http or https')
- if not result.netloc:
- raise ValueError('url does not contain netloc')
- return value
+AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
-def url_to_str(value):
- return value
+def avalanches_german_from_str(value):
+ return dictkey_from_str(value, AVALANCHES_GERMAN)
-def webauskunft_from_str(value):
- return opt_no_german_from_str(value, url_from_str)
+def avalanches_german_to_str(value):
+ return dictkey_to_str(value, AVALANCHES_GERMAN)
-def webauskunft_to_str(value):
- return opt_no_german_to_str(value, url_to_str)
+def opt_avalanches_german_from_str(value):
+ return opt_from_str(value, avalanches_german_from_str)
-webauskunft_converter = FromToConverter(webauskunft_from_str, webauskunft_to_str)
+def opt_avalanches_german_to_str(value):
+ return opt_to_str(value, avalanches_german_to_str)
-class Url(formencode.FancyValidator):
- """Validates an URL. In contrast to fromencode.validators.URL, umlauts are allowed."""
- # formencode 1.2.5 to formencode 1.3.0a1 sometimes raise ValueError instead of Invalid exceptions
- # https://github.com/formencode/formencode/pull/61
- urlv = formencode.validators.URL()
+opt_avalanches_german_converter = FromToConverter(opt_avalanches_german_from_str, opt_avalanches_german_to_str)
- def to_python(self, value, state=None):
- self.assert_string(value, state)
- v = value
- v = v.replace('ä', 'a')
- v = v.replace('ö', 'o')
- v = v.replace('ü', 'u')
- v = v.replace('ß', 'ss')
- v = self.urlv.to_python(v, state)
- return value
-
- def from_python(self, value, state=None):
- return value
+# lift converter
+# --------------
-def phone_number_from_str(value):
- match = re.match(r'\+\d+(-\d+)*$', value)
- if match is None:
- raise ValueError('invalid format of phone number - use something like +43-699-1234567')
- return value
+LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
-def phone_number_to_str(value):
- return value
+def lift_german_from_str(value):
+ """Checks a lift_details property. It is a value comment property with the following
+ values allowed:
+ 'Sessellift'
+ 'Gondel'
+ 'Linienbus'
+ 'Taxi'
+ 'Sonstige'
+ Alternatively, the value u'Nein' is allowed.
+ An empty string maps to (None, None).
+ Examples:
+ '' <=> None
+ 'Nein' <=> []
+ 'Sessellift <=> [('Sessellift', None)]
+ 'Gondel (nur bis zur Hälfte)' <=> [('Gondel', 'nur bis zur Hälfte')]
+ 'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
+ 'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
+ """
+ return opt_no_german_from_str(value, lambda value_enum: enum_from_str(value_enum, lambda value_comment: value_comment_from_str(value_comment, lambda v: choice_from_str(v, LIFT_GERMAN), opt_str_from_str, comment_optional=True)), use_tuple=False, no_value=[], empty=None)
-def telefonauskunft_from_str(value):
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, phone_number_from_str, req_str_from_str, False)), False, [], None)
+def lift_german_to_str(value):
+ return opt_no_german_to_str(value, lambda value_enum: enum_to_str(value_enum, lambda value_comment: value_comment_to_str(value_comment, str_to_str, opt_str_to_str, comment_optional=True)), use_tuple=False, no_value=[], empty=None)
-def telefonauskunft_to_str(value):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, phone_number_to_str, str_to_str)), False, [], None)
+lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
-telefonauskunft_converter = FromToConverter(telefonauskunft_from_str, telefonauskunft_to_str)
+# public transport converter
+# --------------------------
-def email_from_str(value):
- """Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
- try:
- email.headerregistry.Address(addr_spec=value)
- except email.errors.HeaderParseError as e:
- raise ValueError('Invalid email address: {}'.format(value), e)
- return value
+PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
-def email_to_str(value):
- return str(value)
+def public_transport_german_from_str(value):
+ return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
-def masked_email_from_str(value, mask='(at)', masked_only=False):
- """Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
- email address as string, the second is a boolean telling whether the address was masked."""
- unmasked = value.replace(mask, '@')
- was_masked = unmasked != value
- if masked_only and not was_masked:
- raise ValueError('E-Mail address not masked')
- return email_from_str(unmasked), was_masked
+def public_transport_german_to_str(value):
+ return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
-def masked_email_to_str(value, mask='(at)'):
- """Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
- email address should be masked."""
- email, do_masking = value
- email = email_to_str(email)
- if do_masking:
- email = email.replace('@', mask)
- return email
+def opt_public_transport_german_from_str(value):
+ return opt_from_str(value, public_transport_german_from_str)
-def emails_from_str(value):
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, masked_email_from_str, opt_str_from_str, True)), False, [], None)
+def opt_public_transport_german_to_str(value):
+ return opt_to_str(value, public_transport_german_to_str)
-def emails_to_str(value):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, masked_email_to_str, opt_str_to_str, True)), False, [], None)
+opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
-emails_converter = FromToConverter(emails_from_str, email_to_str)
+# cachet converter
+# ----------------
+CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
-def wikipage_from_str(value):
- """Validates wiki page name like '[[Birgitzer Alm]]'.
- The page is not checked for existance.
- An empty string is an error.
- '[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
- """
- if not value.startswith('[[') or not value.endswith(']]'):
- raise ValueError('No valid wiki page name "{}"'.format(value))
- return value
+def single_cachet_german_from_str(value):
+ for pattern in CACHET_REGEXP:
+ match = re.match(pattern, value)
+ if match:
+ return match.groups()
+ raise ValueError("'{}' is no valid cachet".format(value))
-def wikipage_to_str(value):
- return value
+def single_cachet_german_to_str(value):
+ return ' '.join(value)
-def opt_wikipage_enum_from_str(value):
- """Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
- '[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
- '[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
- 'Nein' => []
- '' => None
- """
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
+def cachet_german_from_str(value):
+ """Converts a "Gütesiegel":
+ '' => None
+ 'Nein' => []
+ 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel' => [('Tiroler Naturrodelbahn-Gütesiegel', '2009', 'mittel')]"""
+ return opt_no_german_from_str(value, lambda val: enum_from_str(val, single_cachet_german_from_str), False, [], None)
-def opt_wikipage_enum_to_str(value):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
+def cachet_german_to_str(value):
+ return opt_no_german_to_str(value, lambda val: enum_to_str(val, single_cachet_german_to_str), False, [], None)
-opt_wikipage_enum_converter = FromToConverter(opt_wikipage_enum_from_str, opt_wikipage_enum_to_str)
+cachet_german_converter = FromToConverter(cachet_german_from_str, cachet_german_to_str)
-LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
+# night light days converter
+# --------------------------
-def lift_german_from_str(value):
- """Checks a lift_details property. It is a value comment property with the following
- values allowed:
- 'Sessellift'
- 'Gondel'
- 'Linienbus'
- 'Taxi'
- 'Sonstige'
- Alternatively, the value u'Nein' is allowed.
- An empty string maps to (None, None).
+def nightlightdays_from_str(value):
+ return value_comment_from_str(value, lambda val: opt_from_str(val, lambda v: int_from_str(v, min=0, max=7)), opt_str_from_str, comment_optional=True)
- Examples:
- '' <=> None
- 'Nein' <=> []
- 'Sessellift <=> [('Sessellift', None)]
- 'Gondel (nur bis zur Hälfte)' <=> [('Gondel', 'nur bis zur Hälfte')]
- 'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
- 'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
- """
- return opt_no_german_from_str(value, lambda value_enum: enum_from_str(value_enum, lambda value_comment: value_comment_from_str(value_comment, lambda v: choice_from_str(v, LIFT_GERMAN), opt_str_from_str, comment_optional=True)), use_tuple=False, no_value=[], none=None)
+def nightlightdays_to_str(value):
+ return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
-def lift_german_to_str(value):
- return opt_no_german_to_str(value, lambda value_enum: enum_to_str(value_enum, lambda value_comment: value_comment_to_str(value_comment, str_to_str, opt_str_to_str, comment_optional=True)), use_tuple=False, no_value=[], none=None)
+nightlightdays_converter = FromToConverter(nightlightdays_from_str, nightlightdays_to_str)
-lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
+# string with optional comment enum/list converter
+# ------------------------------------------------
def opt_str_opt_comment_enum_from_str(value):
"""The value can be an empty string, 'Nein' or a semicolon-separated list of strings with optional comments.
return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, req_str_from_str, opt_str_from_str, True)), False, [], None)
-def sledrental_to_str(value):
+def opt_str_opt_comment_enum_to_str(value):
return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, str_to_str, opt_str_to_str, True)), False, [], None)
-opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, sledrental_to_str)
+opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, opt_str_opt_comment_enum_to_str)
-def opt_no_or_str_from_str(value):
- """Übernachtung. 'Nein' => (False, None); 'Nur Wochenende' => (True, 'Nur Wochenende'); 'Ja' => (True, 'Ja'); '' => (None, None)"""
- return opt_no_german_from_str(value)
-
-
-def opt_no_or_str_to_str(value):
- return opt_no_german_to_str(value)
-
-
-opt_no_or_str_converter = FromToConverter(opt_no_or_str_from_str, opt_no_or_str_to_str)
-
+# wikibox converter
+# -----------------
class ValueErrorList(ValueError):
pass
-def box_from_template(template, name, converter_dict):
+def wikibox_from_template(template, name, converter_dict):
if template.name.strip() != name:
raise ValueError('Box name has to be "{}"'.format(name))
result = OrderedDict()
return result
-def box_to_template(value, name, converter_dict):
+def wikibox_to_template(value, name, converter_dict):
template = mwparserfromhell.nodes.template.Template(name)
for key, converter in converter_dict.items():
template.add(key, converter.to_str(value[key]))
return template_list[0]
-def box_from_str(value, name, converter_dict):
+def wikibox_from_str(value, name, converter_dict):
template = template_from_str(value, name)
- return box_from_template(template, name, converter_dict)
+ return wikibox_from_template(template, name, converter_dict)
-def box_to_str(value, name, converter_dict):
- return str(box_to_template(value, name, converter_dict))
+def wikibox_to_str(value, name, converter_dict):
+ return str(wikibox_to_template(value, name, converter_dict))
+# Rodelbahnbox converter
+# ----------------------
+
RODELBAHNBOX_TEMPLATE_NAME = 'Rodelbahnbox'
('Rodelverleih', opt_str_opt_comment_enum_converter), # 'Talstation Serlesbahnan'
('Gütesiegel', cachet_german_converter), # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
('Webauskunft', webauskunft_converter), # 'http://www.nösslachhütte.at/page9.php'
- ('Telefonauskunft', telefonauskunft_converter), # '+43-664-5487520 (Mitterer Alm)'
+ ('Telefonauskunft', opt_phone_comment_enum_converter), # '+43-664-5487520 (Mitterer Alm)'
('Bild', opt_str_converter),
('In Übersichtskarte', opt_bool_german_converter),
('Forumid', opt_uint_converter)
def rodelbahnbox_from_template(template):
- return box_from_template(template, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
+ return wikibox_from_template(template, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
def rodelbahnbox_to_template(value):
- return box_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
+ return wikibox_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
def rodelbahnbox_from_str(value):
- return box_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
+ return wikibox_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
def rodelbahnbox_to_str(value):
return str(template)
+# Gasthausbox converter
+# ---------------------
+
GASTHAUSBOX_TEMPLATE_NAME = 'Gasthausbox'
('Handyempfang', opt_str_opt_comment_enum_converter),
('Homepage', webauskunft_converter),
('E-Mail', emails_converter),
- ('Telefon', None), # PhoneCommentListNeinLoopNone(comments_are_optional=True)),
+ ('Telefon', opt_phone_comment_opt_enum_converter),
('Bild', opt_str_converter),
('Rodelbahnen', opt_wikipage_enum_converter)])
+# Helper function to make page title pretty
+# -----------------------------------------
+
def sledrun_page_title_to_pretty_url(page_title):
"""Converts a page_title from the page_title column of wrsledruncache to name_url.
name_url is not used by MediaWiki but by new applications like wrweb."""