2 This module contains functions that convert winterrodeln specific strings (like geographic coordinates) from string
3 to appropriate python types and the other way round.
4 Functions that take strings to convert it to python types are called *_from_str(value, [...]) and are supposed to
5 validate the string. In case of errors, a ValueError (or a subclass thereof) is returned.
6 Functions that take python types and convert it to Winterrodeln strings are called *_to_str(value, [...]) and can
7 assume that the value they get is valid. If it is not, the behavior is undefined.
8 The namedtuple FromToConverter groups corresponding *_from_str and *_to_str converters.
10 import email.headerregistry
13 from collections import OrderedDict, namedtuple
14 from email.errors import HeaderParseError
16 import mwparserfromhell # https://github.com/earwig/mwparserfromhell
18 from wrpylib.mwmarkup import format_template_table
21 # FromToConverter type
22 # --------------------
24 # namedtuple that groups corresponding *_from_str and *_to_str functions.
25 FromToConverter = namedtuple('FromToConverter', ['from_str', 'to_str'])
31 def opt_from_str(value, from_str, empty=None):
32 """Makes the converter `from_str` "optional"
33 by replacing the empty string with a predefined value (default: None)."""
34 return empty if value == '' else from_str(value)
37 def opt_to_str(value, to_str, empty=None):
38 return '' if value == empty else to_str(value)
44 def no_german_from_str(value, from_str, use_tuple=True, no_value=None):
45 """Makes it possible to have "Nein" as special value. If use_tuple is True, a tuple is returned. The first
46 entry of the tuple is False in case the value is "Nein", otherwiese the first value is True. The second value is
47 no_value in case of the value being "Nein", otherwise it is the result of from_str(value).
48 If use_tuple is False, no_value is returned in case the value is "Nein", otherwise the result of from_str(value)."""
50 return (False, no_value) if use_tuple else no_value
51 return (True, from_str(value)) if use_tuple else from_str(value)
54 def no_german_to_str(value, to_str, use_tuple=True, no_value=None):
58 return to_str(value[1])
65 # "optional"/"no" converter
66 # -------------------------
68 def opt_no_german_from_str(value, from_str, use_tuple=True, no_value=None, empty=(None, None)):
69 return opt_from_str(value, lambda v: no_german_from_str(v, from_str, use_tuple, no_value), empty)
72 def opt_no_german_to_str(value, to_str, use_tuple=True, no_value=None, empty=(None, None)):
73 return opt_to_str(value, lambda v: no_german_to_str(v, to_str, use_tuple, no_value), empty)
79 def choice_from_str(value, choices):
80 """Returns the value if it is a member of the choices iterable."""
81 if value not in choices:
82 raise ValueError('{} is an invalid value')
89 def dictkey_from_str(value, key_str_dict):
90 """Returns the key of an entry in the key_str_dict if the value of the entry corresponds to the given value."""
92 return dict(list(zip(key_str_dict.values(), key_str_dict.keys())))[value]
94 raise ValueError("Invalid value '{}'".format(value))
97 def dictkey_to_str(value, key_str_dict):
99 return key_str_dict[value]
101 raise ValueError("Invalid value '{}'".format(value))
104 # enum/"list" converter
105 # ---------------------
107 def enum_from_str(value, from_str, separator=';', min_len=0):
108 """Semicolon separated list of entries with the same "type"."""
109 values = value.split(separator)
110 if len(values) == 1 and values[0] == '':
112 if len(values) < min_len:
113 raise ValueError('at least {} entry/entries have to be in the enumeration'.format(min_len))
114 return list(map(from_str, map(str.strip, values)))
117 def enum_to_str(value, to_str, separator='; '):
118 return separator.join(map(to_str, value))
121 # value/comment converter
122 # -----------------------
124 def value_comment_from_str(value, value_from_str, comment_from_str, comment_optional=False):
125 """Makes it possible to have a mandatory comment in parenthesis at the end of the string."""
127 if value.endswith(')'):
129 for i, char in enumerate(value[::-1]):
134 if open_brackets == 0:
135 comment = value[-i:-1]
137 if len(value) > 1 and value[-1] != ' ':
138 raise ValueError('there has to be a space before the opening bracket of the comment')
142 if open_brackets > 0:
143 raise ValueError('bracket mismatch')
144 if not comment_optional:
145 raise ValueError('mandatory comment not found')
147 if not comment_optional:
148 raise ValueError('mandatory comment not found in "{}"'.format(value))
149 return value_from_str(value), comment_from_str(comment)
152 def value_comment_to_str(value, value_to_str, comment_to_str, comment_optional=False):
153 left = value_to_str(value[0])
154 comment = comment_to_str(value[1])
155 if len(comment) > 0 or not comment_optional:
156 comment = '({})'.format(comment)
159 if len(comment) == 0:
161 return '{} {}'.format(left, comment)
167 def str_from_str(value):
168 """Converter that takes any string and returns it as string without validation.
169 In other words, this function does nothing and just returns its argument."""
173 def str_to_str(value):
177 def req_str_from_str(value):
179 raise ValueError('missing required value')
180 return str_from_str(value)
183 def opt_str_from_str(value):
184 return opt_from_str(value, str_from_str)
187 def opt_str_to_str(value):
188 return opt_to_str(value, str_to_str)
191 opt_str_converter = FromToConverter(opt_str_from_str, opt_str_to_str)
194 # optional no or string converter
195 # -------------------------------
197 def opt_no_or_str_from_str(value):
199 'Nein' => (False, None); 'Nur Wochenende' => (True, 'Nur Wochenende'); 'Ja' => (True, 'Ja'); '' => (None, None)"""
200 return opt_no_german_from_str(value, req_str_from_str)
203 def opt_no_or_str_to_str(value):
204 return opt_no_german_to_str(value, str_to_str)
207 opt_no_or_str_converter = FromToConverter(opt_no_or_str_from_str, opt_no_or_str_to_str)
213 def int_from_str(value, min=None, max=None):
214 """Converter that takes a string representation of an integer and returns the integer.
215 :param value: string representation of an integer
216 :param min: If not None, the integer has to be at least min
217 :param max: If not None, the integer has to be no more than max
220 if min is not None and value < min:
221 raise ValueError('{} must be >= than {}'.format(value, min))
222 if max is not None and value > max:
223 raise ValueError('{} must be <= than {}'.format(value, max))
227 def int_to_str(value):
231 def opt_int_from_str(value, min=None, max=None):
232 return opt_from_str(value, lambda val: int_from_str(val, min, max))
235 def opt_int_to_str(value):
236 return opt_to_str(value, int_to_str)
239 def opt_uint_from_str(value, min=0, max=None):
240 """Optional positive integer."""
241 return opt_int_from_str(value, min, max)
244 def opt_uint_to_str(value):
245 return opt_int_to_str(value)
248 opt_uint_converter = FromToConverter(opt_uint_from_str, opt_uint_to_str)
254 BOOL_GERMAN = OrderedDict([(False, 'Nein'), (True, 'Ja')])
257 def bool_german_from_str(value):
258 return dictkey_from_str(value, BOOL_GERMAN)
261 def bool_german_to_str(value):
262 return dictkey_to_str(value, BOOL_GERMAN)
265 def opt_bool_german_from_str(value):
266 return opt_from_str(value, bool_german_from_str)
269 def opt_bool_german_to_str(value):
270 return opt_to_str(value, bool_german_to_str)
273 opt_bool_german_converter = FromToConverter(opt_bool_german_from_str, opt_bool_german_to_str)
279 TRISTATE_GERMAN = OrderedDict([(0.0, 'Nein'), (0.5, 'Teilweise'), (1.0, 'Ja')])
282 def tristate_german_from_str(value):
283 return dictkey_from_str(value, TRISTATE_GERMAN)
286 def tristate_german_to_str(value):
287 return dictkey_to_str(value, TRISTATE_GERMAN)
290 def opt_tristate_german_from_str(value):
291 return opt_from_str(value, tristate_german_from_str)
294 def opt_tristate_german_to_str(value):
295 return opt_to_str(value, tristate_german_to_str)
298 opt_tristate_german_converter = FromToConverter(opt_tristate_german_from_str, opt_tristate_german_to_str)
301 # tristate with comment converter
302 # -------------------------------
304 def opt_tristate_german_comment_from_str(value):
305 """Ja, Nein or Teilweise, optionally with comment in parenthesis."""
306 return value_comment_from_str(value, opt_tristate_german_from_str, opt_str_from_str, True)
309 def opt_tristate_german_comment_to_str(value):
310 return value_comment_to_str(value, opt_tristate_german_to_str, opt_str_to_str, True)
313 opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str, opt_tristate_german_comment_to_str)
319 def url_from_str(value):
320 result = urllib.parse.urlparse(value)
321 if result.scheme not in ['http', 'https']:
322 raise ValueError('scheme has to be http or https')
323 if not result.netloc:
324 raise ValueError('url does not contain netloc')
328 def url_to_str(value):
332 # webauskunft converter
333 # ---------------------
335 def webauskunft_from_str(value):
336 """Converts a URL or 'Nein' to a tuple
337 'http://www.example.com/' -> (True, 'http://www.example.com/')
338 'Nein' -> (False, None)
341 :param value: URL or 'Nein'
344 return opt_no_german_from_str(value, url_from_str)
347 def webauskunft_to_str(value):
348 return opt_no_german_to_str(value, url_to_str)
351 webauskunft_converter = FromToConverter(webauskunft_from_str, webauskunft_to_str)
357 def wikipage_from_str(value):
358 """Validates wiki page name like '[[Birgitzer Alm]]'.
359 The page is not checked for existence.
360 An empty string is an error.
361 '[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
363 if re.match(r'\[\[[^\[\]]+]]$', value) is None:
364 raise ValueError('No valid wiki page name "{}"'.format(value))
368 def wikipage_to_str(value):
372 def opt_wikipage_enum_from_str(value):
373 """Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
374 '[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
375 '[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
379 return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
382 def opt_wikipage_enum_to_str(value):
383 return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
386 opt_wikipage_enum_converter = FromToConverter(opt_wikipage_enum_from_str, opt_wikipage_enum_to_str)
392 def email_from_str(value):
393 """Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
395 email.headerregistry.Address(addr_spec=value)
396 except HeaderParseError as e:
397 raise ValueError('Invalid email address: {}'.format(value), e)
401 def email_to_str(value):
405 def masked_email_from_str(value, mask='(at)', masked_only=False):
406 """Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
407 email address as string, the second is a boolean telling whether the address was masked."""
408 unmasked = value.replace(mask, '@')
409 was_masked = unmasked != value
410 if masked_only and not was_masked:
411 raise ValueError('E-Mail address not masked')
412 return email_from_str(unmasked), was_masked
415 def masked_email_to_str(value, mask='(at)'):
416 """Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
417 email address should be masked."""
418 email, do_masking = value
419 email = email_to_str(email)
421 email = email.replace('@', mask)
425 def emails_from_str(value):
426 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)
429 def emails_to_str(value):
430 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)
433 emails_converter = FromToConverter(emails_from_str, emails_to_str)
439 def phone_number_from_str(value):
440 match = re.match(r'\+\d+(-\d+)*$', value)
442 raise ValueError('invalid format of phone number - use something like +43-699-1234567')
446 def phone_number_to_str(value):
450 def opt_phone_comment_enum_from_str(value, comment_optional=False):
451 return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, phone_number_from_str, opt_str_from_str if comment_optional else req_str_from_str, comment_optional)), False, [], None)
454 def opt_phone_comment_enum_to_str(value, comment_optional=False):
455 return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, phone_number_to_str, opt_str_to_str if comment_optional else str_to_str, comment_optional)), False, [], None)
458 opt_phone_comment_enum_converter = FromToConverter(opt_phone_comment_enum_from_str, opt_phone_comment_enum_to_str)
461 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))
464 # longitude/latitude converter
465 # ----------------------------
467 LonLat = namedtuple('LonLat', ['lon', 'lat'])
470 lonlat_none = LonLat(None, None)
473 def lonlat_from_str(value: str) -> LonLat:
474 """Converts a Winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
475 to the LonLat(lon, lat) named tuple."""
476 r = re.match(r'(\d+\.\d+) N (\d+\.\d+) E', value)
477 if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
478 return LonLat(float(r.groups()[1]), float(r.groups()[0]))
481 def lonlat_to_str(value: LonLat) -> str:
482 return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
485 def opt_lonlat_from_str(value):
486 return opt_from_str(value, lonlat_from_str, lonlat_none)
489 def opt_lonlat_to_str(value):
490 return opt_to_str(value, lonlat_to_str, lonlat_none)
493 opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
496 # difficulty converter
497 # --------------------
499 DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
502 def difficulty_german_from_str(value):
503 return dictkey_from_str(value, DIFFICULTY_GERMAN)
506 def difficulty_german_to_str(value):
507 return dictkey_to_str(value, DIFFICULTY_GERMAN)
510 def opt_difficulty_german_from_str(value):
511 return opt_from_str(value, difficulty_german_from_str)
514 def opt_difficulty_german_to_str(value):
515 return opt_to_str(value, difficulty_german_to_str)
518 opt_difficulty_german_converter = FromToConverter(opt_difficulty_german_from_str, opt_difficulty_german_to_str)
521 # avalanches converter
522 # --------------------
524 AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
527 def avalanches_german_from_str(value):
528 return dictkey_from_str(value, AVALANCHES_GERMAN)
531 def avalanches_german_to_str(value):
532 return dictkey_to_str(value, AVALANCHES_GERMAN)
535 def opt_avalanches_german_from_str(value):
536 return opt_from_str(value, avalanches_german_from_str)
539 def opt_avalanches_german_to_str(value):
540 return opt_to_str(value, avalanches_german_to_str)
543 opt_avalanches_german_converter = FromToConverter(opt_avalanches_german_from_str, opt_avalanches_german_to_str)
549 LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
552 def lift_german_from_str(value):
553 """Checks a lift_details property. It is a value comment property with the following
560 Alternatively, the value u'Nein' is allowed.
561 An empty string maps to (None, None).
566 'Sessellift <=> [('Sessellift', None)]
567 'Gondel (nur bis zur Hälfte)' <=> [('Gondel', 'nur bis zur Hälfte')]
568 'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
569 'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
571 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)
574 def lift_german_to_str(value):
575 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)
578 lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
581 # public transport converter
582 # --------------------------
584 PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
587 def public_transport_german_from_str(value):
588 return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
591 def public_transport_german_to_str(value):
592 return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
595 def opt_public_transport_german_from_str(value):
596 return opt_from_str(value, public_transport_german_from_str)
599 def opt_public_transport_german_to_str(value):
600 return opt_to_str(value, public_transport_german_to_str)
603 opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
609 CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
612 def single_cachet_german_from_str(value):
613 for pattern in CACHET_REGEXP:
614 match = re.match(pattern, value)
616 return match.groups()
617 raise ValueError("'{}' is no valid cachet".format(value))
620 def single_cachet_german_to_str(value):
621 return ' '.join(value)
624 def cachet_german_from_str(value):
625 """Converts a "Gütesiegel":
628 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel' => [('Tiroler Naturrodelbahn-Gütesiegel', '2009', 'mittel')]"""
629 return opt_no_german_from_str(value, lambda val: enum_from_str(val, single_cachet_german_from_str), False, [], None)
632 def cachet_german_to_str(value):
633 return opt_no_german_to_str(value, lambda val: enum_to_str(val, single_cachet_german_to_str), False, [], None)
636 cachet_german_converter = FromToConverter(cachet_german_from_str, cachet_german_to_str)
639 # night light days converter
640 # --------------------------
642 def nightlightdays_from_str(value):
643 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)
646 def nightlightdays_to_str(value):
647 return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
650 nightlightdays_converter = FromToConverter(nightlightdays_from_str, nightlightdays_to_str)
653 # string with optional comment enum/list converter
654 # ------------------------------------------------
656 def opt_str_opt_comment_enum_from_str(value):
657 """The value can be an empty string, 'Nein' or a semicolon-separated list of strings with optional comments.
660 'Talstation (nur mit Ticket); Schneealm' => [('Talstation', 'nur mit Ticket'), ('Schneealm', None)]"""
661 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)
664 def opt_str_opt_comment_enum_to_str(value):
665 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)
668 opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, opt_str_opt_comment_enum_to_str)
674 class ValueErrorList(ValueError):
678 def wikibox_from_template(template, converter_dict):
679 """Returns an ordered dict."""
680 result = OrderedDict()
681 exceptions_dict = OrderedDict()
683 for key, converter in converter_dict.items():
685 if not template.has(key):
686 raise ValueError('Missing parameter "{}"'.format(key))
687 result[key] = converter.from_str(str(template.get(key).value.strip()))
688 except ValueError as e:
689 exceptions_dict[key] = e
690 # check if keys are superfluous
691 superfluous_keys = {str(p.name.strip()) for p in template.params} - set(converter_dict.keys())
692 for key in superfluous_keys:
693 exceptions_dict[key] = ValueError('Superfluous parameter: "{}"'.format(key))
694 if len(exceptions_dict) > 0:
695 raise ValueErrorList('{} error(s) occurred when parsing template parameters.'.format(len(exceptions_dict)), exceptions_dict)
699 def wikibox_to_template(value, name, converter_dict):
700 template = mwparserfromhell.nodes.template.Template(name)
701 for key, converter in converter_dict.items():
702 template.add(key, converter.to_str(value[key]))
706 def template_from_str(value, name):
707 wikicode = mwparserfromhell.parse(value)
708 template_list = wikicode.filter_templates(recursive=False, matches=lambda t: t.name.strip() == name)
709 if len(template_list) == 0:
710 raise ValueError('No "{}" template was found'.format(name))
711 if len(template_list) > 1:
712 raise ValueError('{} "{}" templates were found'.format(len(template_list), name))
713 return template_list[0]
716 def wikibox_from_str(value, name, converter_dict):
717 template = template_from_str(value, name)
718 return wikibox_from_template(template, converter_dict)
721 def wikibox_to_str(value, name, converter_dict):
722 return str(wikibox_to_template(value, name, converter_dict))
725 # Rodelbahnbox converter
726 # ----------------------
728 RODELBAHNBOX_TEMPLATE_NAME = 'Rodelbahnbox'
731 RODELBAHNBOX_DICT = OrderedDict([
732 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
733 ('Position oben', opt_lonlat_converter), # '47.583333 N 15.75 E'
734 ('Höhe oben', opt_uint_converter), # '2000'
735 ('Position unten', opt_lonlat_converter), # '47.583333 N 15.75 E'
736 ('Höhe unten', opt_uint_converter), # '1200'
737 ('Länge', opt_uint_converter), # 3500
738 ('Schwierigkeit', opt_difficulty_german_converter), # 'mittel'
739 ('Lawinen', opt_avalanches_german_converter), # 'kaum'
740 ('Betreiber', opt_str_converter), # 'Max Mustermann'
741 ('Öffentliche Anreise', opt_public_transport_german_converter), # 'Mittelmäßig'
742 ('Aufstieg möglich', opt_bool_german_converter), # 'Ja'
743 ('Aufstieg getrennt', opt_tristate_german_comment_converter), # 'Ja'
744 ('Gehzeit', opt_uint_converter), # 90
745 ('Aufstiegshilfe', lift_german_converter), # 'Gondel (unterer Teil)'
746 ('Beleuchtungsanlage', opt_tristate_german_comment_converter),
747 ('Beleuchtungstage', nightlightdays_converter), # '3 (Montag, Mittwoch, Freitag)'
748 ('Rodelverleih', opt_str_opt_comment_enum_converter), # 'Talstation Serlesbahnan'
749 ('Gütesiegel', cachet_german_converter), # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
750 ('Webauskunft', webauskunft_converter), # 'http://www.nösslachhütte.at/page9.php'
751 ('Telefonauskunft', opt_phone_comment_enum_converter), # '+43-664-5487520 (Mitterer Alm)'
752 ('Bild', opt_str_converter),
753 ('In Übersichtskarte', opt_bool_german_converter),
754 ('Forumid', opt_uint_converter)
758 def rodelbahnbox_from_template(template):
759 """Returns an ordered dict."""
760 return wikibox_from_template(template, RODELBAHNBOX_DICT)
763 def rodelbahnbox_to_template(value):
764 return wikibox_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
767 def rodelbahnbox_from_str(value):
768 """Returns an ordered dict."""
769 return wikibox_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
772 def rodelbahnbox_to_str(value):
773 template = rodelbahnbox_to_template(value)
774 format_template_table(template, 20)
778 # Gasthausbox converter
779 # ---------------------
781 GASTHAUSBOX_TEMPLATE_NAME = 'Gasthausbox'
784 GASTHAUSBOX_DICT = OrderedDict([
785 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
786 ('Höhe', opt_uint_converter),
787 ('Betreiber', opt_str_converter),
788 ('Sitzplätze', opt_uint_converter),
789 ('Übernachtung', opt_no_or_str_converter),
790 ('Rauchfrei', opt_tristate_german_converter),
791 ('Rodelverleih', opt_no_or_str_converter),
792 ('Handyempfang', opt_str_opt_comment_enum_converter),
793 ('Homepage', webauskunft_converter),
794 ('E-Mail', emails_converter),
795 ('Telefon', opt_phone_comment_opt_enum_converter),
796 ('Bild', opt_str_converter),
797 ('Rodelbahnen', opt_wikipage_enum_converter)])
800 def gasthausbox_from_template(template):
801 """Returns an ordered dict."""
802 return wikibox_from_template(template, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
805 def gasthausbox_to_template(value):
806 return wikibox_to_template(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
809 def gasthausbox_from_str(value):
810 """Returns an ordered dict."""
811 return wikibox_from_str(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
814 def gasthausbox_to_str(value):
815 template = gasthausbox_to_template(value)
816 format_template_table(template, 17)
820 # Helper function to make page title pretty
821 # -----------------------------------------
823 def sledrun_page_title_to_pretty_url(page_title):
824 """Converts a page_title from the page_title column of wrsledruncache to name_url.
825 name_url is not used by MediaWiki but by new applications like wrweb."""
826 return page_title.lower().replace(' ', '-').replace('_', '-').replace('(', '').replace(')', '')