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 return opt_no_german_from_str(value, url_from_str)
341 def webauskunft_to_str(value):
342 return opt_no_german_to_str(value, url_to_str)
345 webauskunft_converter = FromToConverter(webauskunft_from_str, webauskunft_to_str)
351 def wikipage_from_str(value):
352 """Validates wiki page name like '[[Birgitzer Alm]]'.
353 The page is not checked for existence.
354 An empty string is an error.
355 '[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
357 if re.match(r'\[\[[^\[\]]+\]\]$', value) is None:
358 raise ValueError('No valid wiki page name "{}"'.format(value))
362 def wikipage_to_str(value):
366 def opt_wikipage_enum_from_str(value):
367 """Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
368 '[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
369 '[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
373 return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
376 def opt_wikipage_enum_to_str(value):
377 return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
380 opt_wikipage_enum_converter = FromToConverter(opt_wikipage_enum_from_str, opt_wikipage_enum_to_str)
386 def email_from_str(value):
387 """Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
389 email.headerregistry.Address(addr_spec=value)
390 except email.errors.HeaderParseError as e:
391 raise ValueError('Invalid email address: {}'.format(value), e)
395 def email_to_str(value):
399 def masked_email_from_str(value, mask='(at)', masked_only=False):
400 """Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
401 email address as string, the second is a boolean telling whether the address was masked."""
402 unmasked = value.replace(mask, '@')
403 was_masked = unmasked != value
404 if masked_only and not was_masked:
405 raise ValueError('E-Mail address not masked')
406 return email_from_str(unmasked), was_masked
409 def masked_email_to_str(value, mask='(at)'):
410 """Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
411 email address should be masked."""
412 email, do_masking = value
413 email = email_to_str(email)
415 email = email.replace('@', mask)
419 def emails_from_str(value):
420 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)
423 def emails_to_str(value):
424 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)
427 emails_converter = FromToConverter(emails_from_str, emails_to_str)
433 def phone_number_from_str(value):
434 match = re.match(r'\+\d+(-\d+)*$', value)
436 raise ValueError('invalid format of phone number - use something like +43-699-1234567')
440 def phone_number_to_str(value):
444 def opt_phone_comment_enum_from_str(value, comment_optional=False):
445 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)
448 def opt_phone_comment_enum_to_str(value, comment_optional=False):
449 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)
452 opt_phone_comment_enum_converter = FromToConverter(opt_phone_comment_enum_from_str, opt_phone_comment_enum_to_str)
455 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))
458 # longitude/latitude converter
459 # ----------------------------
461 LonLat = namedtuple('LonLat', ['lon', 'lat'])
464 lonlat_none = LonLat(None, None)
467 def lonlat_from_str(value):
468 """Converts a winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
469 to the LonLat(lon, lat) named tupel."""
470 r = re.match('(\d+\.\d+) N (\d+\.\d+) E', value)
471 if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
472 return LonLat(float(r.groups()[1]), float(r.groups()[0]))
475 def lonlat_to_str(value):
476 return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
479 def opt_lonlat_from_str(value):
480 return opt_from_str(value, lonlat_from_str, lonlat_none)
483 def opt_lonlat_to_str(value):
484 return opt_to_str(value, lonlat_to_str, lonlat_none)
487 opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
490 # difficulty converter
491 # --------------------
493 DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
496 def difficulty_german_from_str(value):
497 return dictkey_from_str(value, DIFFICULTY_GERMAN)
500 def difficulty_german_to_str(value):
501 return dictkey_to_str(value, DIFFICULTY_GERMAN)
504 def opt_difficulty_german_from_str(value):
505 return opt_from_str(value, difficulty_german_from_str)
508 def opt_difficulty_german_to_str(value):
509 return opt_to_str(value, difficulty_german_to_str)
512 opt_difficulty_german_converter = FromToConverter(opt_difficulty_german_from_str, opt_difficulty_german_to_str)
515 # avalanches converter
516 # --------------------
518 AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
521 def avalanches_german_from_str(value):
522 return dictkey_from_str(value, AVALANCHES_GERMAN)
525 def avalanches_german_to_str(value):
526 return dictkey_to_str(value, AVALANCHES_GERMAN)
529 def opt_avalanches_german_from_str(value):
530 return opt_from_str(value, avalanches_german_from_str)
533 def opt_avalanches_german_to_str(value):
534 return opt_to_str(value, avalanches_german_to_str)
537 opt_avalanches_german_converter = FromToConverter(opt_avalanches_german_from_str, opt_avalanches_german_to_str)
543 LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
546 def lift_german_from_str(value):
547 """Checks a lift_details property. It is a value comment property with the following
554 Alternatively, the value u'Nein' is allowed.
555 An empty string maps to (None, None).
560 'Sessellift <=> [('Sessellift', None)]
561 'Gondel (nur bis zur Hälfte)' <=> [('Gondel', 'nur bis zur Hälfte')]
562 'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
563 'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
565 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)
568 def lift_german_to_str(value):
569 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)
572 lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
575 # public transport converter
576 # --------------------------
578 PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
581 def public_transport_german_from_str(value):
582 return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
585 def public_transport_german_to_str(value):
586 return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
589 def opt_public_transport_german_from_str(value):
590 return opt_from_str(value, public_transport_german_from_str)
593 def opt_public_transport_german_to_str(value):
594 return opt_to_str(value, public_transport_german_to_str)
597 opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
603 CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
606 def single_cachet_german_from_str(value):
607 for pattern in CACHET_REGEXP:
608 match = re.match(pattern, value)
610 return match.groups()
611 raise ValueError("'{}' is no valid cachet".format(value))
614 def single_cachet_german_to_str(value):
615 return ' '.join(value)
618 def cachet_german_from_str(value):
619 """Converts a "Gütesiegel":
622 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel' => [('Tiroler Naturrodelbahn-Gütesiegel', '2009', 'mittel')]"""
623 return opt_no_german_from_str(value, lambda val: enum_from_str(val, single_cachet_german_from_str), False, [], None)
626 def cachet_german_to_str(value):
627 return opt_no_german_to_str(value, lambda val: enum_to_str(val, single_cachet_german_to_str), False, [], None)
630 cachet_german_converter = FromToConverter(cachet_german_from_str, cachet_german_to_str)
633 # night light days converter
634 # --------------------------
636 def nightlightdays_from_str(value):
637 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)
640 def nightlightdays_to_str(value):
641 return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
644 nightlightdays_converter = FromToConverter(nightlightdays_from_str, nightlightdays_to_str)
647 # string with optional comment enum/list converter
648 # ------------------------------------------------
650 def opt_str_opt_comment_enum_from_str(value):
651 """The value can be an empty string, 'Nein' or a semicolon-separated list of strings with optional comments.
654 'Talstation (nur mit Ticket); Schneealm' => [('Talstation', 'nur mit Ticket'), ('Schneealm', None)]"""
655 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)
658 def opt_str_opt_comment_enum_to_str(value):
659 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)
662 opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, opt_str_opt_comment_enum_to_str)
668 class ValueErrorList(ValueError):
672 def wikibox_from_template(template, converter_dict):
673 """Returns an ordered dict."""
674 result = OrderedDict()
675 exceptions_dict = OrderedDict()
677 for key, converter in converter_dict.items():
679 if not template.has(key):
680 raise ValueError('Missing parameter "{}"'.format(key))
681 result[key] = converter.from_str(str(template.get(key).value.strip()))
682 except ValueError as e:
683 exceptions_dict[key] = e
684 # check if keys are superfluous
685 superfluous_keys = {str(p.name.strip()) for p in template.params} - set(converter_dict.keys())
686 for key in superfluous_keys:
687 exceptions_dict[key] = ValueError('Superfluous parameter: "{}"'.format(key))
688 if len(exceptions_dict) > 0:
689 raise ValueErrorList('{} error(s) occurred when parsing template parameters.'.format(len(exceptions_dict)), exceptions_dict)
693 def wikibox_to_template(value, name, converter_dict):
694 template = mwparserfromhell.nodes.template.Template(name)
695 for key, converter in converter_dict.items():
696 template.add(key, converter.to_str(value[key]))
700 def template_from_str(value, name):
701 wikicode = mwparserfromhell.parse(value)
702 template_list = wikicode.filter_templates(recursive=False, matches=lambda t: t.name.strip() == name)
703 if len(template_list) == 0:
704 raise ValueError('No "{}" template was found'.format(name))
705 if len(template_list) > 1:
706 raise ValueError('{} "{}" templates were found'.format(len(template_list), name))
707 return template_list[0]
710 def wikibox_from_str(value, name, converter_dict):
711 template = template_from_str(value, name)
712 return wikibox_from_template(template, converter_dict)
715 def wikibox_to_str(value, name, converter_dict):
716 return str(wikibox_to_template(value, name, converter_dict))
719 # Rodelbahnbox converter
720 # ----------------------
722 RODELBAHNBOX_TEMPLATE_NAME = 'Rodelbahnbox'
725 RODELBAHNBOX_DICT = OrderedDict([
726 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
727 ('Position oben', opt_lonlat_converter), # '47.583333 N 15.75 E'
728 ('Höhe oben', opt_uint_converter), # '2000'
729 ('Position unten', opt_lonlat_converter), # '47.583333 N 15.75 E'
730 ('Höhe unten', opt_uint_converter), # '1200'
731 ('Länge', opt_uint_converter), # 3500
732 ('Schwierigkeit', opt_difficulty_german_converter), # 'mittel'
733 ('Lawinen', opt_avalanches_german_converter), # 'kaum'
734 ('Betreiber', opt_str_converter), # 'Max Mustermann'
735 ('Öffentliche Anreise', opt_public_transport_german_converter), # 'Mittelmäßig'
736 ('Aufstieg möglich', opt_bool_german_converter), # 'Ja'
737 ('Aufstieg getrennt', opt_tristate_german_comment_converter), # 'Ja'
738 ('Gehzeit', opt_uint_converter), # 90
739 ('Aufstiegshilfe', lift_german_converter), # 'Gondel (unterer Teil)'
740 ('Beleuchtungsanlage', opt_tristate_german_comment_converter),
741 ('Beleuchtungstage', nightlightdays_converter), # '3 (Montag, Mittwoch, Freitag)'
742 ('Rodelverleih', opt_str_opt_comment_enum_converter), # 'Talstation Serlesbahnan'
743 ('Gütesiegel', cachet_german_converter), # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
744 ('Webauskunft', webauskunft_converter), # 'http://www.nösslachhütte.at/page9.php'
745 ('Telefonauskunft', opt_phone_comment_enum_converter), # '+43-664-5487520 (Mitterer Alm)'
746 ('Bild', opt_str_converter),
747 ('In Übersichtskarte', opt_bool_german_converter),
748 ('Forumid', opt_uint_converter)
752 def rodelbahnbox_from_template(template):
753 """Returns an ordered dict."""
754 return wikibox_from_template(template, RODELBAHNBOX_DICT)
757 def rodelbahnbox_to_template(value):
758 return wikibox_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
761 def rodelbahnbox_from_str(value):
762 """Returns an ordered dict."""
763 return wikibox_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
766 def rodelbahnbox_to_str(value):
767 template = rodelbahnbox_to_template(value)
768 format_template_table(template, 20)
772 # Gasthausbox converter
773 # ---------------------
775 GASTHAUSBOX_TEMPLATE_NAME = 'Gasthausbox'
778 GASTHAUSBOX_DICT = OrderedDict([
779 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
780 ('Höhe', opt_uint_converter),
781 ('Betreiber', opt_str_converter),
782 ('Sitzplätze', opt_uint_converter),
783 ('Übernachtung', opt_no_or_str_converter),
784 ('Rauchfrei', opt_tristate_german_converter),
785 ('Rodelverleih', opt_no_or_str_converter),
786 ('Handyempfang', opt_str_opt_comment_enum_converter),
787 ('Homepage', webauskunft_converter),
788 ('E-Mail', emails_converter),
789 ('Telefon', opt_phone_comment_opt_enum_converter),
790 ('Bild', opt_str_converter),
791 ('Rodelbahnen', opt_wikipage_enum_converter)])
794 def gasthausbox_from_template(template):
795 """Returns an ordered dict."""
796 return wikibox_from_template(template, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
799 def gasthausbox_to_template(value):
800 return wikibox_to_template(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
803 def gasthausbox_from_str(value):
804 """Returns an ordered dict."""
805 return wikibox_from_str(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
808 def gasthausbox_to_str(value):
809 template = gasthausbox_to_template(value)
810 format_template_table(template, 17)
814 # Helper function to make page title pretty
815 # -----------------------------------------
817 def sledrun_page_title_to_pretty_url(page_title):
818 """Converts a page_title from the page_title column of wrsledruncache to name_url.
819 name_url is not used by MediaWiki but by new applications like wrweb."""
820 return page_title.lower().replace(' ', '-').replace('_', '-').replace('(', '').replace(')', '')