5 This module contains functions that convert winterrodeln specific strings (like geographic coordinates) from string
6 to appropriate python types and the other way round.
7 Functions that take strings to convert it to python types are called *_from_str(value, [...]) and are supposed to
8 validate the string. In case of errors, a ValueError (or a subclass thereof) is returned.
9 Functions that take python types and convert it to Winterrodeln strings are called *_to_str(value, [...]) and can
10 assume that the value they get is valid. If it is not, the behavior is undefined.
11 The namedtuple FromToConverter groups corresponding *_from_str and *_to_str converters.
13 import email.headerregistry
16 from collections import OrderedDict, namedtuple
18 import mwparserfromhell # https://github.com/earwig/mwparserfromhell
20 from wrpylib.mwmarkup import format_template_table
23 # FromToConverter type
24 # --------------------
26 # namedtuple that groups corresponding *_from_str and *_to_str functions.
27 FromToConverter = namedtuple('FromToConverter', ['from_str', 'to_str'])
33 def opt_from_str(value, from_str, empty=None):
34 """Makes the converter `from_str` "optional"
35 by replacing the empty string with a predefined value (default: None)."""
36 return empty if value == '' else from_str(value)
39 def opt_to_str(value, to_str, empty=None):
40 return '' if value == empty else to_str(value)
46 def no_german_from_str(value, from_str, use_tuple=True, no_value=None):
47 """Makes it possible to have "Nein" as special value. If use_tuple is True, a tuple is returned. The first
48 entry of the tuple is False in case the value is "Nein", otherwiese the first value is True. The second value is
49 no_value in case of the value being "Nein", otherwise it is the result of from_str(value).
50 If use_tuple is False, no_value is returned in case the value is "Nein", otherwise the result of from_str(value)."""
52 return (False, no_value) if use_tuple else no_value
53 return (True, from_str(value)) if use_tuple else from_str(value)
56 def no_german_to_str(value, to_str, use_tuple=True, no_value=None):
60 return to_str(value[1])
67 # "optional"/"no" converter
68 # -------------------------
70 def opt_no_german_from_str(value, from_str, use_tuple=True, no_value=None, empty=(None, None)):
71 return opt_from_str(value, lambda v: no_german_from_str(v, from_str, use_tuple, no_value), empty)
74 def opt_no_german_to_str(value, to_str, use_tuple=True, no_value=None, empty=(None, None)):
75 return opt_to_str(value, lambda v: no_german_to_str(v, to_str, use_tuple, no_value), empty)
81 def choice_from_str(value, choices):
82 """Returns the value if it is a member of the choices iterable."""
83 if value not in choices:
84 raise ValueError('{} is an invalid value')
91 def dictkey_from_str(value, key_str_dict):
92 """Returns the key of an entry in the key_str_dict if the value of the entry corresponds to the given value."""
94 return dict(list(zip(key_str_dict.values(), key_str_dict.keys())))[value]
96 raise ValueError("Invalid value '{}'".format(value))
99 def dictkey_to_str(value, key_str_dict):
101 return key_str_dict[value]
103 raise ValueError("Invalid value '{}'".format(value))
106 # enum/"list" converter
107 # ---------------------
109 def enum_from_str(value, from_str, separator=';', min_len=0):
110 """Semicolon separated list of entries with the same "type"."""
111 values = value.split(separator)
112 if len(values) == 1 and values[0] == '':
114 if len(values) < min_len:
115 raise ValueError('at least {} entry/entries have to be in the enumeration'.format(min_len))
116 return list(map(from_str, map(str.strip, values)))
119 def enum_to_str(value, to_str, separator='; '):
120 return separator.join(map(to_str, value))
123 # value/comment converter
124 # -----------------------
126 def value_comment_from_str(value, value_from_str, comment_from_str, comment_optional=False):
127 """Makes it possible to have a mandatory comment in parenthesis at the end of the string."""
129 if value.endswith(')'):
131 for i, char in enumerate(value[::-1]):
136 if open_brackets == 0:
137 comment = value[-i:-1]
139 if len(value) > 1 and value[-1] != ' ':
140 raise ValueError('there has to be a space before the opening bracket of the comment')
144 if open_brackets > 0:
145 raise ValueError('bracket mismatch')
146 if not comment_optional:
147 raise ValueError('mandatory comment not found')
149 if not comment_optional:
150 raise ValueError('mandatory comment not found in "{}"'.format(value))
151 return value_from_str(value), comment_from_str(comment)
154 def value_comment_to_str(value, value_to_str, comment_to_str, comment_optional=False):
155 left = value_to_str(value[0])
156 comment = comment_to_str(value[1])
157 if len(comment) > 0 or not comment_optional:
158 comment = '({})'.format(comment)
161 if len(comment) == 0:
163 return '{} {}'.format(left, comment)
169 def str_from_str(value):
170 """Converter that takes any string and returns it as string without validation.
171 In other words, this function does nothing and just returns its argument."""
175 def str_to_str(value):
179 def req_str_from_str(value):
181 raise ValueError('missing required value')
182 return str_from_str(value)
185 def opt_str_from_str(value):
186 return opt_from_str(value, str_from_str)
189 def opt_str_to_str(value):
190 return opt_to_str(value, str_to_str)
193 opt_str_converter = FromToConverter(opt_str_from_str, opt_str_to_str)
196 # optional no or string converter
197 # -------------------------------
199 def opt_no_or_str_from_str(value):
201 'Nein' => (False, None); 'Nur Wochenende' => (True, 'Nur Wochenende'); 'Ja' => (True, 'Ja'); '' => (None, None)"""
202 return opt_no_german_from_str(value, req_str_from_str)
205 def opt_no_or_str_to_str(value):
206 return opt_no_german_to_str(value, str_to_str)
209 opt_no_or_str_converter = FromToConverter(opt_no_or_str_from_str, opt_no_or_str_to_str)
215 def int_from_str(value, min=None, max=None):
216 """Converter that takes a string representation of an integer and returns the integer.
217 :param value: string representation of an integer
218 :param min: If not None, the integer has to be at least min
219 :param max: If not None, the integer has to be no more than max
222 if min is not None and value < min:
223 raise ValueError('{} must be >= than {}'.format(value, min))
224 if max is not None and value > max:
225 raise ValueError('{} must be <= than {}'.format(value, max))
229 def int_to_str(value):
233 def opt_int_from_str(value, min=None, max=None):
234 return opt_from_str(value, lambda val: int_from_str(val, min, max))
237 def opt_int_to_str(value):
238 return opt_to_str(value, int_to_str)
241 def opt_uint_from_str(value, min=0, max=None):
242 """Optional positive integer."""
243 return opt_int_from_str(value, min, max)
246 def opt_uint_to_str(value):
247 return opt_int_to_str(value)
250 opt_uint_converter = FromToConverter(opt_uint_from_str, opt_uint_to_str)
256 BOOL_GERMAN = OrderedDict([(False, 'Nein'), (True, 'Ja')])
259 def bool_german_from_str(value):
260 return dictkey_from_str(value, BOOL_GERMAN)
263 def bool_german_to_str(value):
264 return dictkey_to_str(value, BOOL_GERMAN)
267 def opt_bool_german_from_str(value):
268 return opt_from_str(value, bool_german_from_str)
271 def opt_bool_german_to_str(value):
272 return opt_to_str(value, bool_german_to_str)
275 opt_bool_german_converter = FromToConverter(opt_bool_german_from_str, opt_bool_german_to_str)
281 TRISTATE_GERMAN = OrderedDict([(0.0, 'Nein'), (0.5, 'Teilweise'), (1.0, 'Ja')])
284 def tristate_german_from_str(value):
285 return dictkey_from_str(value, TRISTATE_GERMAN)
288 def tristate_german_to_str(value):
289 return dictkey_to_str(value, TRISTATE_GERMAN)
292 def opt_tristate_german_from_str(value):
293 return opt_from_str(value, tristate_german_from_str)
296 def opt_tristate_german_to_str(value):
297 return opt_to_str(value, tristate_german_to_str)
300 opt_tristate_german_converter = FromToConverter(opt_tristate_german_from_str, opt_tristate_german_to_str)
303 # tristate with comment converter
304 # -------------------------------
306 def opt_tristate_german_comment_from_str(value):
307 """Ja, Nein or Teilweise, optionally with comment in parenthesis."""
308 return value_comment_from_str(value, opt_tristate_german_from_str, opt_str_from_str, True)
311 def opt_tristate_german_comment_to_str(value):
312 return value_comment_to_str(value, opt_tristate_german_to_str, opt_str_to_str, True)
315 opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str, opt_tristate_german_comment_to_str)
321 def url_from_str(value):
322 result = urllib.parse.urlparse(value)
323 if result.scheme not in ['http', 'https']:
324 raise ValueError('scheme has to be http or https')
325 if not result.netloc:
326 raise ValueError('url does not contain netloc')
330 def url_to_str(value):
334 # webauskunft converter
335 # ---------------------
337 def webauskunft_from_str(value):
338 """Converts a URL or 'Nein' to a tuple
339 'http://www.example.com/' -> (True, 'http://www.example.com/')
340 'Nein' -> (False, None)
343 :param value: URL or 'Nein'
346 return opt_no_german_from_str(value, url_from_str)
349 def webauskunft_to_str(value):
350 return opt_no_german_to_str(value, url_to_str)
353 webauskunft_converter = FromToConverter(webauskunft_from_str, webauskunft_to_str)
359 def wikipage_from_str(value):
360 """Validates wiki page name like '[[Birgitzer Alm]]'.
361 The page is not checked for existence.
362 An empty string is an error.
363 '[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
365 if re.match(r'\[\[[^\[\]]+\]\]$', value) is None:
366 raise ValueError('No valid wiki page name "{}"'.format(value))
370 def wikipage_to_str(value):
374 def opt_wikipage_enum_from_str(value):
375 """Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
376 '[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
377 '[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
381 return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
384 def opt_wikipage_enum_to_str(value):
385 return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
388 opt_wikipage_enum_converter = FromToConverter(opt_wikipage_enum_from_str, opt_wikipage_enum_to_str)
394 def email_from_str(value):
395 """Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
397 email.headerregistry.Address(addr_spec=value)
398 except email.errors.HeaderParseError as e:
399 raise ValueError('Invalid email address: {}'.format(value), e)
403 def email_to_str(value):
407 def masked_email_from_str(value, mask='(at)', masked_only=False):
408 """Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
409 email address as string, the second is a boolean telling whether the address was masked."""
410 unmasked = value.replace(mask, '@')
411 was_masked = unmasked != value
412 if masked_only and not was_masked:
413 raise ValueError('E-Mail address not masked')
414 return email_from_str(unmasked), was_masked
417 def masked_email_to_str(value, mask='(at)'):
418 """Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
419 email address should be masked."""
420 email, do_masking = value
421 email = email_to_str(email)
423 email = email.replace('@', mask)
427 def emails_from_str(value):
428 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)
431 def emails_to_str(value):
432 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)
435 emails_converter = FromToConverter(emails_from_str, emails_to_str)
441 def phone_number_from_str(value):
442 match = re.match(r'\+\d+(-\d+)*$', value)
444 raise ValueError('invalid format of phone number - use something like +43-699-1234567')
448 def phone_number_to_str(value):
452 def opt_phone_comment_enum_from_str(value, comment_optional=False):
453 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)
456 def opt_phone_comment_enum_to_str(value, comment_optional=False):
457 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)
460 opt_phone_comment_enum_converter = FromToConverter(opt_phone_comment_enum_from_str, opt_phone_comment_enum_to_str)
463 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))
466 # longitude/latitude converter
467 # ----------------------------
469 LonLat = namedtuple('LonLat', ['lon', 'lat'])
472 lonlat_none = LonLat(None, None)
475 def lonlat_from_str(value):
476 """Converts a winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
477 to the LonLat(lon, lat) named tupel."""
478 r = re.match('(\d+\.\d+) N (\d+\.\d+) E', value)
479 if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
480 return LonLat(float(r.groups()[1]), float(r.groups()[0]))
483 def lonlat_to_str(value):
484 return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
487 def opt_lonlat_from_str(value):
488 return opt_from_str(value, lonlat_from_str, lonlat_none)
491 def opt_lonlat_to_str(value):
492 return opt_to_str(value, lonlat_to_str, lonlat_none)
495 opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
498 # difficulty converter
499 # --------------------
501 DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
504 def difficulty_german_from_str(value):
505 return dictkey_from_str(value, DIFFICULTY_GERMAN)
508 def difficulty_german_to_str(value):
509 return dictkey_to_str(value, DIFFICULTY_GERMAN)
512 def opt_difficulty_german_from_str(value):
513 return opt_from_str(value, difficulty_german_from_str)
516 def opt_difficulty_german_to_str(value):
517 return opt_to_str(value, difficulty_german_to_str)
520 opt_difficulty_german_converter = FromToConverter(opt_difficulty_german_from_str, opt_difficulty_german_to_str)
523 # avalanches converter
524 # --------------------
526 AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
529 def avalanches_german_from_str(value):
530 return dictkey_from_str(value, AVALANCHES_GERMAN)
533 def avalanches_german_to_str(value):
534 return dictkey_to_str(value, AVALANCHES_GERMAN)
537 def opt_avalanches_german_from_str(value):
538 return opt_from_str(value, avalanches_german_from_str)
541 def opt_avalanches_german_to_str(value):
542 return opt_to_str(value, avalanches_german_to_str)
545 opt_avalanches_german_converter = FromToConverter(opt_avalanches_german_from_str, opt_avalanches_german_to_str)
551 LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
554 def lift_german_from_str(value):
555 """Checks a lift_details property. It is a value comment property with the following
562 Alternatively, the value u'Nein' is allowed.
563 An empty string maps to (None, None).
568 'Sessellift <=> [('Sessellift', None)]
569 'Gondel (nur bis zur Hälfte)' <=> [('Gondel', 'nur bis zur Hälfte')]
570 'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
571 'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
573 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)
576 def lift_german_to_str(value):
577 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)
580 lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
583 # public transport converter
584 # --------------------------
586 PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
589 def public_transport_german_from_str(value):
590 return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
593 def public_transport_german_to_str(value):
594 return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
597 def opt_public_transport_german_from_str(value):
598 return opt_from_str(value, public_transport_german_from_str)
601 def opt_public_transport_german_to_str(value):
602 return opt_to_str(value, public_transport_german_to_str)
605 opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
611 CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
614 def single_cachet_german_from_str(value):
615 for pattern in CACHET_REGEXP:
616 match = re.match(pattern, value)
618 return match.groups()
619 raise ValueError("'{}' is no valid cachet".format(value))
622 def single_cachet_german_to_str(value):
623 return ' '.join(value)
626 def cachet_german_from_str(value):
627 """Converts a "Gütesiegel":
630 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel' => [('Tiroler Naturrodelbahn-Gütesiegel', '2009', 'mittel')]"""
631 return opt_no_german_from_str(value, lambda val: enum_from_str(val, single_cachet_german_from_str), False, [], None)
634 def cachet_german_to_str(value):
635 return opt_no_german_to_str(value, lambda val: enum_to_str(val, single_cachet_german_to_str), False, [], None)
638 cachet_german_converter = FromToConverter(cachet_german_from_str, cachet_german_to_str)
641 # night light days converter
642 # --------------------------
644 def nightlightdays_from_str(value):
645 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)
648 def nightlightdays_to_str(value):
649 return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
652 nightlightdays_converter = FromToConverter(nightlightdays_from_str, nightlightdays_to_str)
655 # string with optional comment enum/list converter
656 # ------------------------------------------------
658 def opt_str_opt_comment_enum_from_str(value):
659 """The value can be an empty string, 'Nein' or a semicolon-separated list of strings with optional comments.
662 'Talstation (nur mit Ticket); Schneealm' => [('Talstation', 'nur mit Ticket'), ('Schneealm', None)]"""
663 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)
666 def opt_str_opt_comment_enum_to_str(value):
667 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)
670 opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, opt_str_opt_comment_enum_to_str)
676 class ValueErrorList(ValueError):
680 def wikibox_from_template(template, converter_dict):
681 """Returns an ordered dict."""
682 result = OrderedDict()
683 exceptions_dict = OrderedDict()
685 for key, converter in converter_dict.items():
687 if not template.has(key):
688 raise ValueError('Missing parameter "{}"'.format(key))
689 result[key] = converter.from_str(str(template.get(key).value.strip()))
690 except ValueError as e:
691 exceptions_dict[key] = e
692 # check if keys are superfluous
693 superfluous_keys = {str(p.name.strip()) for p in template.params} - set(converter_dict.keys())
694 for key in superfluous_keys:
695 exceptions_dict[key] = ValueError('Superfluous parameter: "{}"'.format(key))
696 if len(exceptions_dict) > 0:
697 raise ValueErrorList('{} error(s) occurred when parsing template parameters.'.format(len(exceptions_dict)), exceptions_dict)
701 def wikibox_to_template(value, name, converter_dict):
702 template = mwparserfromhell.nodes.template.Template(name)
703 for key, converter in converter_dict.items():
704 template.add(key, converter.to_str(value[key]))
708 def template_from_str(value, name):
709 wikicode = mwparserfromhell.parse(value)
710 template_list = wikicode.filter_templates(recursive=False, matches=lambda t: t.name.strip() == name)
711 if len(template_list) == 0:
712 raise ValueError('No "{}" template was found'.format(name))
713 if len(template_list) > 1:
714 raise ValueError('{} "{}" templates were found'.format(len(template_list), name))
715 return template_list[0]
718 def wikibox_from_str(value, name, converter_dict):
719 template = template_from_str(value, name)
720 return wikibox_from_template(template, converter_dict)
723 def wikibox_to_str(value, name, converter_dict):
724 return str(wikibox_to_template(value, name, converter_dict))
727 # Rodelbahnbox converter
728 # ----------------------
730 RODELBAHNBOX_TEMPLATE_NAME = 'Rodelbahnbox'
733 RODELBAHNBOX_DICT = OrderedDict([
734 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
735 ('Position oben', opt_lonlat_converter), # '47.583333 N 15.75 E'
736 ('Höhe oben', opt_uint_converter), # '2000'
737 ('Position unten', opt_lonlat_converter), # '47.583333 N 15.75 E'
738 ('Höhe unten', opt_uint_converter), # '1200'
739 ('Länge', opt_uint_converter), # 3500
740 ('Schwierigkeit', opt_difficulty_german_converter), # 'mittel'
741 ('Lawinen', opt_avalanches_german_converter), # 'kaum'
742 ('Betreiber', opt_str_converter), # 'Max Mustermann'
743 ('Öffentliche Anreise', opt_public_transport_german_converter), # 'Mittelmäßig'
744 ('Aufstieg möglich', opt_bool_german_converter), # 'Ja'
745 ('Aufstieg getrennt', opt_tristate_german_comment_converter), # 'Ja'
746 ('Gehzeit', opt_uint_converter), # 90
747 ('Aufstiegshilfe', lift_german_converter), # 'Gondel (unterer Teil)'
748 ('Beleuchtungsanlage', opt_tristate_german_comment_converter),
749 ('Beleuchtungstage', nightlightdays_converter), # '3 (Montag, Mittwoch, Freitag)'
750 ('Rodelverleih', opt_str_opt_comment_enum_converter), # 'Talstation Serlesbahnan'
751 ('Gütesiegel', cachet_german_converter), # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
752 ('Webauskunft', webauskunft_converter), # 'http://www.nösslachhütte.at/page9.php'
753 ('Telefonauskunft', opt_phone_comment_enum_converter), # '+43-664-5487520 (Mitterer Alm)'
754 ('Bild', opt_str_converter),
755 ('In Übersichtskarte', opt_bool_german_converter),
756 ('Forumid', opt_uint_converter)
760 def rodelbahnbox_from_template(template):
761 """Returns an ordered dict."""
762 return wikibox_from_template(template, RODELBAHNBOX_DICT)
765 def rodelbahnbox_to_template(value):
766 return wikibox_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
769 def rodelbahnbox_from_str(value):
770 """Returns an ordered dict."""
771 return wikibox_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
774 def rodelbahnbox_to_str(value):
775 template = rodelbahnbox_to_template(value)
776 format_template_table(template, 20)
780 # Gasthausbox converter
781 # ---------------------
783 GASTHAUSBOX_TEMPLATE_NAME = 'Gasthausbox'
786 GASTHAUSBOX_DICT = OrderedDict([
787 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
788 ('Höhe', opt_uint_converter),
789 ('Betreiber', opt_str_converter),
790 ('Sitzplätze', opt_uint_converter),
791 ('Übernachtung', opt_no_or_str_converter),
792 ('Rauchfrei', opt_tristate_german_converter),
793 ('Rodelverleih', opt_no_or_str_converter),
794 ('Handyempfang', opt_str_opt_comment_enum_converter),
795 ('Homepage', webauskunft_converter),
796 ('E-Mail', emails_converter),
797 ('Telefon', opt_phone_comment_opt_enum_converter),
798 ('Bild', opt_str_converter),
799 ('Rodelbahnen', opt_wikipage_enum_converter)])
802 def gasthausbox_from_template(template):
803 """Returns an ordered dict."""
804 return wikibox_from_template(template, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
807 def gasthausbox_to_template(value):
808 return wikibox_to_template(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
811 def gasthausbox_from_str(value):
812 """Returns an ordered dict."""
813 return wikibox_from_str(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
816 def gasthausbox_to_str(value):
817 template = gasthausbox_to_template(value)
818 format_template_table(template, 17)
822 # Helper function to make page title pretty
823 # -----------------------------------------
825 def sledrun_page_title_to_pretty_url(page_title):
826 """Converts a page_title from the page_title column of wrsledruncache to name_url.
827 name_url is not used by MediaWiki but by new applications like wrweb."""
828 return page_title.lower().replace(' ', '-').replace('_', '-').replace('(', '').replace(')', '')